Add AAR and JMOD files support

This commit is contained in:
emmanue1 2019-05-30 22:18:49 +02:00
parent 6ac9549549
commit cb8de5579d
30 changed files with 264 additions and 79 deletions

View File

@ -13,9 +13,9 @@ import org.jd.gui.api.model.Container;
import java.nio.file.Path;
public interface ContainerFactory {
String getType();
boolean accept(API api, Path rootPath);
Container make(API api, Container.Entry parentEntry, Path rootPath);
String getType();
boolean accept(API api, Path rootPath);
Container make(API api, Container.Entry parentEntry, Path rootPath);
}

View File

@ -21,12 +21,12 @@ public class FileLoaderService {
public static FileLoaderService getInstance() { return FILE_LOADER_SERVICE; }
protected final Collection<FileLoader> providers = ExtensionService.getInstance().load(FileLoader.class);
protected HashMap<String, FileLoader> mapProviders = new HashMap<>();
protected FileLoaderService() {
for (FileLoader provider : providers) {
for (String extension : provider.getExtensions()) {
protected HashMap<String, FileLoader> mapProviders = new HashMap<>();
protected FileLoaderService() {
for (FileLoader provider : providers) {
for (String extension : provider.getExtensions()) {
mapProviders.put(extension, provider);
}
}
@ -37,12 +37,7 @@ public class FileLoaderService {
int lastDot = name.lastIndexOf('.');
String extension = name.substring(lastDot+1);
FileLoader provider = mapProviders.get(extension);
if ((provider != null) && provider.accept(api, file)) {
return provider;
}
return null;
return provider;
}
public HashMap<String, FileLoader> getMapProviders() {

View File

@ -20,9 +20,9 @@ public class UriLoaderService {
public static UriLoaderService getInstance() { return URI_LOADER_SERVICE; }
protected HashMap<String, UriLoader> mapProviders = new HashMap<>();
protected HashMap<String, UriLoader> mapProviders = new HashMap<>();
protected UriLoaderService() {
protected UriLoaderService() {
Collection<UriLoader> providers = ExtensionService.getInstance().load(UriLoader.class);
for (UriLoader provider : providers) {

View File

@ -147,7 +147,20 @@ public class GenericContainer implements Container {
for (Path subPath : stream) {
if (subPath.getNameCount() > parentNameCount) {
children.add(newChildEntry(subPath));
ContainerFactory containerFactory = api.getContainerFactory(subPath);
if ((containerFactory == null) || "generic".equals(containerFactory.getType())) {
children.add(newChildEntry(subPath));
} else {
Entry childEntry = newChildEntry(subPath);
Container container = containerFactory.make(api, childEntry, subPath);
if (container != null) {
childEntry.children = container.getRoot().getChildren();
}
children.add(childEntry);
}
}
}

View File

@ -0,0 +1,21 @@
/*
* Copyright (c) 2008-2019 Emmanuel Dupuy.
* This project is distributed under the GPLv3 license.
* This is a Copyleft license that gives the user the right to use,
* copy and modify the code freely for non-commercial purposes.
*/
package org.jd.gui.model.container;
import org.jd.gui.api.API;
import org.jd.gui.api.model.Container;
import java.nio.file.Path;
public class JmodClassesDirectoryContainer extends GenericContainer {
public JmodClassesDirectoryContainer(API api, Container.Entry parentEntry, Path rootPath) {
super(api, parentEntry, rootPath);
}
public String getType() { return "jmodClassesDirectory"; }
}

View File

@ -18,9 +18,10 @@ import java.nio.file.InvalidPathException;
import java.nio.file.Path;
public class EarContainerFactoryProvider implements ContainerFactory {
@Override
public String getType() { return "ear"; }
@Override
public boolean accept(API api, Path rootPath) {
if (rootPath.toUri().toString().toLowerCase().endsWith(".ear!/")) {
return true;
@ -35,6 +36,7 @@ public class EarContainerFactoryProvider implements ContainerFactory {
}
}
@Override
public Container make(API api, Container.Entry parentEntry, Path rootPath) {
return new EarContainer(api, parentEntry, rootPath);
}

View File

@ -15,12 +15,14 @@ import org.jd.gui.spi.ContainerFactory;
import java.nio.file.Path;
public class GenericContainerFactoryProvider implements ContainerFactory {
@Override
public String getType() { return "generic"; }
public String getType() { return "generic"; }
@Override
public boolean accept(API api, Path rootPath) { return true; }
public boolean accept(API api, Path rootPath) { return true; }
public Container make(API api, Container.Entry parentEntry, Path rootPath) {
return new GenericContainer(api, parentEntry, rootPath);
}
@Override
public Container make(API api, Container.Entry parentEntry, Path rootPath) {
return new GenericContainer(api, parentEntry, rootPath);
}
}

View File

@ -18,9 +18,10 @@ import java.nio.file.InvalidPathException;
import java.nio.file.Path;
public class JarContainerFactoryProvider implements ContainerFactory {
@Override
public String getType() { return "jar"; }
@Override
public boolean accept(API api, Path rootPath) {
if (rootPath.toUri().toString().toLowerCase().endsWith(".jar!/")) {
// Specification: http://docs.oracle.com/javase/6/docs/technotes/guides/jar/jar.html
@ -36,7 +37,8 @@ public class JarContainerFactoryProvider implements ContainerFactory {
}
}
@Override
public Container make(API api, Container.Entry parentEntry, Path rootPath) {
return new JarContainer(api, parentEntry, rootPath);
}
return new JarContainer(api, parentEntry, rootPath);
}
}

View File

@ -0,0 +1,40 @@
/*
* Copyright (c) 2008-2019 Emmanuel Dupuy.
* This project is distributed under the GPLv3 license.
* This is a Copyleft license that gives the user the right to use,
* copy and modify the code freely for non-commercial purposes.
*/
package org.jd.gui.service.container;
import org.jd.gui.api.API;
import org.jd.gui.api.model.Container;
import org.jd.gui.model.container.JmodClassesDirectoryContainer;
import org.jd.gui.spi.ContainerFactory;
import java.nio.file.Files;
import java.nio.file.Path;
public class JmodClassesDirectoryContainerFactoryProvider implements ContainerFactory {
@Override
public String getType() { return "jmodClassesDirectory"; }
@Override
public boolean accept(API api, Path rootPath) {
if (Files.isDirectory(rootPath)) {
Path fileName = rootPath.getFileName();
if ((fileName != null) && "classes".equals(rootPath.getFileName().toString())) {
String fileStoreName = rootPath.getFileSystem().getFileStores().iterator().next().name();
return fileStoreName.endsWith(".jmod/");
}
}
return false;
}
@Override
public Container make(API api, Container.Entry parentEntry, Path rootPath) {
return new JmodClassesDirectoryContainer(api, parentEntry, rootPath);
}
}

View File

@ -18,9 +18,10 @@ import java.nio.file.InvalidPathException;
import java.nio.file.Path;
public class WarContainerFactoryProvider implements ContainerFactory {
@Override
public String getType() { return "war"; }
@Override
public boolean accept(API api, Path rootPath) {
if (rootPath.toUri().toString().toLowerCase().endsWith(".war!/")) {
return true;
@ -35,6 +36,7 @@ public class WarContainerFactoryProvider implements ContainerFactory {
}
}
@Override
public Container make(API api, Container.Entry parentEntry, Path rootPath) {
return new WarContainer(api, parentEntry, rootPath);
}

View File

@ -0,0 +1,24 @@
/*
* Copyright (c) 2008-2019 Emmanuel Dupuy.
* This project is distributed under the GPLv3 license.
* This is a Copyleft license that gives the user the right to use,
* copy and modify the code freely for non-commercial purposes.
*/
package org.jd.gui.service.fileloader;
import org.jd.gui.api.API;
import java.io.File;
public class AarFileLoaderProvider extends ZipFileLoaderProvider {
protected static final String[] EXTENSIONS = { "aar" };
@Override public String[] getExtensions() { return EXTENSIONS; }
@Override public String getDescription() { return "Android archive files (*.aar)"; }
@Override
public boolean accept(API api, File file) {
return file.exists() && file.isFile() && file.canRead() && file.getName().toLowerCase().endsWith(".aar");
}
}

View File

@ -57,8 +57,8 @@ public abstract class AbstractFileLoaderProvider implements FileLoader {
protected static class ContainerEntry implements Container.Entry {
protected static final Container PARENT_CONTAINER = new Container() {
public String getType() { return "generic"; }
public Container.Entry getRoot() { return null; }
@Override public String getType() { return "generic"; }
@Override public Container.Entry getRoot() { return null; }
};
protected Collection<Container.Entry> children = Collections.emptyList();
@ -76,14 +76,15 @@ public abstract class AbstractFileLoaderProvider implements FileLoader {
}
}
public Container getContainer() { return PARENT_CONTAINER; }
public Container.Entry getParent() { return null; }
public URI getUri() { return uri; }
public String getPath() { return path; }
public boolean isDirectory() { return file.isDirectory(); }
public long length() { return file.length(); }
public Collection<Container.Entry> getChildren() { return children; }
@Override public Container getContainer() { return PARENT_CONTAINER; }
@Override public Container.Entry getParent() { return null; }
@Override public URI getUri() { return uri; }
@Override public String getPath() { return path; }
@Override public boolean isDirectory() { return file.isDirectory(); }
@Override public long length() { return file.length(); }
@Override public Collection<Container.Entry> getChildren() { return children; }
@Override
public InputStream getInputStream() {
try {
return new BufferedInputStream(new FileInputStream(file));

View File

@ -18,14 +18,16 @@ import java.io.IOException;
public class ClassFileLoaderProvider extends AbstractTypeFileLoaderProvider {
protected static final String[] EXTENSIONS = { "class" };
public String[] getExtensions() { return EXTENSIONS; }
public String getDescription() { return "Class files (*.class)"; }
@Override public String[] getExtensions() { return EXTENSIONS; }
@Override public String getDescription() { return "Class files (*.class)"; }
@Override
public boolean accept(API api, File file) {
return file.exists() && file.canRead() && file.getName().toLowerCase().endsWith(".class");
return file.exists() && file.isFile() && file.canRead() && file.getName().toLowerCase().endsWith(".class");
}
@Override
public boolean load(API api, File file) {
try (BufferedInputStream bis = new BufferedInputStream(new FileInputStream(file))) {
ClassReader classReader = new ClassReader(bis);

View File

@ -14,10 +14,11 @@ import java.io.File;
public class EarFileLoaderProvider extends ZipFileLoaderProvider {
protected static final String[] EXTENSIONS = { "ear" };
public String[] getExtensions() { return EXTENSIONS; }
public String getDescription() { return "Ear files (*.ear)"; }
@Override public String[] getExtensions() { return EXTENSIONS; }
@Override public String getDescription() { return "Enterprise application archive files (*.ear)"; }
@Override
public boolean accept(API api, File file) {
return file.exists() && file.canRead() && file.getName().toLowerCase().endsWith(".ear");
return file.exists() && file.isFile() && file.canRead() && file.getName().toLowerCase().endsWith(".ear");
}
}

View File

@ -12,12 +12,13 @@ import org.jd.gui.api.API;
import java.io.File;
public class JarFileLoaderProvider extends ZipFileLoaderProvider {
protected static final String[] EXTENSIONS = { "jar" };
protected static final String[] EXTENSIONS = { "jar" };
public String[] getExtensions() { return EXTENSIONS; }
public String getDescription() { return "Jar files (*.jar)"; }
@Override public String[] getExtensions() { return EXTENSIONS; }
@Override public String getDescription() { return "Java archive files (*.jar)"; }
public boolean accept(API api, File file) {
return file.exists() && file.canRead() && file.getName().toLowerCase().endsWith(".jar");
}
@Override
public boolean accept(API api, File file) {
return file.exists() && file.isFile() && file.canRead() && file.getName().toLowerCase().endsWith(".jar");
}
}

View File

@ -17,13 +17,15 @@ import java.util.regex.Pattern;
public class JavaFileLoaderProvider extends AbstractTypeFileLoaderProvider {
protected static final String[] EXTENSIONS = { "java" };
public String[] getExtensions() { return EXTENSIONS; }
public String getDescription() { return "Java files (*.java)"; }
@Override public String[] getExtensions() { return EXTENSIONS; }
@Override public String getDescription() { return "Java files (*.java)"; }
@Override
public boolean accept(API api, File file) {
return file.exists() && file.canRead() && file.getName().toLowerCase().endsWith(".java");
return file.exists() && file.isFile() && file.canRead() && file.getName().toLowerCase().endsWith(".java");
}
@Override
public boolean load(API api, File file) {
String text = TextReader.getText(file);
Pattern pattern = Pattern.compile("(?s)(.*\\s)?package\\s+(\\S+)\\s*;.*");

View File

@ -0,0 +1,24 @@
/*
* Copyright (c) 2008-2019 Emmanuel Dupuy.
* This project is distributed under the GPLv3 license.
* This is a Copyleft license that gives the user the right to use,
* copy and modify the code freely for non-commercial purposes.
*/
package org.jd.gui.service.fileloader;
import org.jd.gui.api.API;
import java.io.File;
public class JmodFileLoaderProvider extends ZipFileLoaderProvider {
protected static final String[] EXTENSIONS = { "jmod" };
@Override public String[] getExtensions() { return EXTENSIONS; }
@Override public String getDescription() { return "Java module files (*.jmod)"; }
@Override
public boolean accept(API api, File file) {
return file.exists() && file.isFile() && file.canRead() && file.getName().toLowerCase().endsWith(".jmod");
}
}

View File

@ -16,13 +16,15 @@ import java.io.File;
public class LogFileLoaderProvider extends ZipFileLoaderProvider {
protected static final String[] EXTENSIONS = { "log" };
public String[] getExtensions() { return EXTENSIONS; }
public String getDescription() { return "Log files (*.log)"; }
@Override public String[] getExtensions() { return EXTENSIONS; }
@Override public String getDescription() { return "Log files (*.log)"; }
@Override
public boolean accept(API api, File file) {
return file.exists() && file.canRead() && file.getName().toLowerCase().endsWith(".log");
return file.exists() && file.isFile() && file.canRead() && file.getName().toLowerCase().endsWith(".log");
}
@Override
public boolean load(API api, File file) {
api.addPanel(file.getName(), null, "Location: " + file.getAbsolutePath(), new LogPage(api, file.toURI(), TextReader.getText(file)));
return true;

View File

@ -14,10 +14,11 @@ import java.io.File;
public class WarFileLoaderProvider extends ZipFileLoaderProvider {
protected static final String[] EXTENSIONS = { "war" };
public String[] getExtensions() { return EXTENSIONS; }
public String getDescription() { return "War files (*.war)"; }
@Override public String[] getExtensions() { return EXTENSIONS; }
@Override public String getDescription() { return "Web application archive files (*.war)"; }
@Override
public boolean accept(API api, File file) {
return file.exists() && file.canRead() && file.getName().toLowerCase().endsWith(".war");
return file.exists() && file.isFile() && file.canRead() && file.getName().toLowerCase().endsWith(".war");
}
}

View File

@ -24,13 +24,15 @@ import java.util.Iterator;
public class ZipFileLoaderProvider extends AbstractFileLoaderProvider {
protected static final String[] EXTENSIONS = { "zip" };
public String[] getExtensions() { return EXTENSIONS; }
public String getDescription() { return "Zip files (*.zip)"; }
@Override public String[] getExtensions() { return EXTENSIONS; }
@Override public String getDescription() { return "Zip files (*.zip)"; }
@Override
public boolean accept(API api, File file) {
return file.exists() && file.canRead() && file.getName().toLowerCase().endsWith(".zip");
return file.exists() && file.isFile() && file.canRead() && file.getName().toLowerCase().endsWith(".zip");
}
@Override
public boolean load(API api, File file) {
try {
URI fileUri = file.toURI();
@ -55,5 +57,5 @@ public class ZipFileLoaderProvider extends AbstractFileLoaderProvider {
}
return false;
}
}
}

View File

@ -14,7 +14,7 @@ import org.jd.gui.spi.Indexer;
public class ZipFileIndexerProvider extends AbstractIndexerProvider {
@Override public String[] getSelectors() { return appendSelectors("*:file:*.zip", "*:file:*.jar", "*:file:*.war", "*:file:*.ear"); }
@Override public String[] getSelectors() { return appendSelectors("*:file:*.zip", "*:file:*.jar", "*:file:*.war", "*:file:*.ear", "*:file:*.aar", "*:file:*.jmod"); }
@Override
public void index(API api, Container.Entry entry, Indexes indexes) {

View File

@ -22,7 +22,7 @@ import java.util.HashMap;
public class ZipFileSourceSaverProvider extends DirectorySourceSaverProvider {
@Override public String[] getSelectors() { return appendSelectors("*:file:*.zip", "*:file:*.jar", "*:file:*.war", "*:file:*.ear"); }
@Override public String[] getSelectors() { return appendSelectors("*:file:*.zip", "*:file:*.jar", "*:file:*.war", "*:file:*.ear", "*:file:*.aar", "*:file:*.jmod"); }
@Override
public void save(API api, SourceSaver.Controller controller, SourceSaver.Listener listener, Path rootPath, Container.Entry entry) {

View File

@ -0,0 +1,42 @@
/*
* Copyright (c) 2008-2019 Emmanuel Dupuy.
* This project is distributed under the GPLv3 license.
* This is a Copyleft license that gives the user the right to use,
* copy and modify the code freely for non-commercial purposes.
*/
package org.jd.gui.service.treenode;
import org.jd.gui.api.API;
import org.jd.gui.api.feature.ContainerEntryGettable;
import org.jd.gui.api.feature.UriGettable;
import org.jd.gui.api.model.Container;
import org.jd.gui.spi.TreeNodeFactory;
import org.jd.gui.view.data.TreeNodeBean;
import javax.swing.*;
import javax.swing.tree.DefaultMutableTreeNode;
public class JmodFileTreeNodeFactoryProvider extends ZipFileTreeNodeFactoryProvider {
@Override public String[] getSelectors() { return appendSelectors("*:file:*.jmod"); }
@Override
@SuppressWarnings("unchecked")
public <T extends DefaultMutableTreeNode & ContainerEntryGettable & UriGettable> T make(API api, Container.Entry entry) {
int lastSlashIndex = entry.getPath().lastIndexOf("/");
String name = entry.getPath().substring(lastSlashIndex+1);
T node = (T)new TreeNode(entry, "generic", new TreeNodeBean(name, ICON));
// Add dummy node
node.add(new DefaultMutableTreeNode());
return node;
}
}

View File

@ -21,7 +21,7 @@ import java.util.Collection;
public class PackageTreeNodeFactoryProvider extends DirectoryTreeNodeFactoryProvider {
protected static final ImageIcon ICON = new ImageIcon(PackageTreeNodeFactoryProvider.class.getClassLoader().getResource("org/jd/gui/images/package_obj.png"));
@Override public String[] getSelectors() { return appendSelectors("jar:dir:*"); }
@Override public String[] getSelectors() { return appendSelectors("jar:dir:*", "jmodClassesDirectory:dir:*"); }
@Override
@SuppressWarnings("unchecked")

View File

@ -38,7 +38,9 @@ public class TextFileTreeNodeFactoryProvider extends FileTreeNodeFactoryProvider
}
}
@Override public String[] getSelectors() { return appendSelectors("*:file:*.txt", "*:file:*.md", "*:file:*.SF", "*:file:*.policy", "*:file:*.yaml", "*:file:*.yml"); }
@Override public String[] getSelectors() {
return appendSelectors("*:file:*.txt", "*:file:*.md", "*:file:*.SF", "*:file:*.policy", "*:file:*.yaml", "*:file:*.yml", "*:file:*/COPYRIGHT", "*:file:*/LICENSE");
}
@Override
@SuppressWarnings("unchecked")

View File

@ -18,9 +18,9 @@ import javax.swing.*;
import javax.swing.tree.DefaultMutableTreeNode;
public class ZipFileTreeNodeFactoryProvider extends DirectoryTreeNodeFactoryProvider {
protected static final ImageIcon ICON = new ImageIcon(ZipFileTreeNodeFactoryProvider.class.getClassLoader().getResource("org/jd/gui/images/zip_obj.png"));
protected static final ImageIcon ICON = new ImageIcon(ZipFileTreeNodeFactoryProvider.class.getClassLoader().getResource("org/jd/gui/images/zip_obj.png"));
@Override public String[] getSelectors() { return appendSelectors("*:file:*.zip"); }
@Override public String[] getSelectors() { return appendSelectors("*:file:*.zip", "*:file:*.aar"); }
@Override
@SuppressWarnings("unchecked")
@ -31,7 +31,7 @@ public class ZipFileTreeNodeFactoryProvider extends DirectoryTreeNodeFactoryProv
// Add dummy node
node.add(new DefaultMutableTreeNode());
return node;
}
}
protected static class TreeNode extends DirectoryTreeNodeFactoryProvider.TreeNode {
protected String ct;

View File

@ -15,16 +15,16 @@ import java.io.File;
import java.net.URI;
public class FileUriLoaderProvider implements UriLoader {
protected static final String[] SCHEMES = { "file" };
protected static final String[] SCHEMES = { "file" };
public String[] getSchemes() { return SCHEMES; }
public String[] getSchemes() { return SCHEMES; }
public boolean accept(API api, URI uri) { return "file".equals(uri.getScheme()); }
public boolean accept(API api, URI uri) { return "file".equals(uri.getScheme()); }
public boolean load(API api, URI uri) {
public boolean load(API api, URI uri) {
File file = new File(uri.getPath());
FileLoader fileLoader = api.getFileLoader(file);
FileLoader fileLoader = api.getFileLoader(file);
return (fileLoader != null) && fileLoader.load(api, file);
}
}
}

View File

@ -1,4 +1,5 @@
# Order is important
# Order is important : 'GenericContainerFactoryProvider' must be the last
org.jd.gui.service.container.JmodClassesDirectoryContainerFactoryProvider
org.jd.gui.service.container.EarContainerFactoryProvider
org.jd.gui.service.container.WarContainerFactoryProvider
org.jd.gui.service.container.JarContainerFactoryProvider

View File

@ -1,7 +1,9 @@
org.jd.gui.service.fileloader.AarFileLoaderProvider
org.jd.gui.service.fileloader.ClassFileLoaderProvider
org.jd.gui.service.fileloader.EarFileLoaderProvider
org.jd.gui.service.fileloader.JarFileLoaderProvider
org.jd.gui.service.fileloader.JavaFileLoaderProvider
org.jd.gui.service.fileloader.JmodFileLoaderProvider
org.jd.gui.service.fileloader.LogFileLoaderProvider
org.jd.gui.service.fileloader.WarFileLoaderProvider
org.jd.gui.service.fileloader.ZipFileLoaderProvider

View File

@ -9,6 +9,7 @@ org.jd.gui.service.treenode.HtmlFileTreeNodeFactoryProvider
org.jd.gui.service.treenode.JarFileTreeNodeFactoryProvider
org.jd.gui.service.treenode.JavaFileTreeNodeFactoryProvider
org.jd.gui.service.treenode.JavascriptFileTreeNodeFactoryProvider
org.jd.gui.service.treenode.JmodFileTreeNodeFactoryProvider
org.jd.gui.service.treenode.JsonFileTreeNodeFactoryProvider
org.jd.gui.service.treenode.JspFileTreeNodeFactoryProvider
org.jd.gui.service.treenode.ManifestFileTreeNodeFactoryProvider