feat(plugins): allow to load classes using input stream or byte array in jadx-input plugin (#1457)

This commit is contained in:
Skylot
2023-04-10 21:03:54 +01:00
parent 1ad6527de5
commit 4230cd5b5a
7 changed files with 191 additions and 4 deletions
@@ -19,8 +19,8 @@ import org.slf4j.LoggerFactory;
import jadx.api.plugins.utils.CommonFileUtils;
import jadx.api.plugins.utils.ZipSecurity;
public class JavaFileLoader {
private static final Logger LOG = LoggerFactory.getLogger(JavaFileLoader.class);
public class JavaInputLoader {
private static final Logger LOG = LoggerFactory.getLogger(JavaInputLoader.class);
private static final int MAX_MAGIC_SIZE = 4;
private static final byte[] JAVA_CLASS_FILE_MAGIC = { (byte) 0xCA, (byte) 0xFE, (byte) 0xBA, (byte) 0xBE };
@@ -37,6 +37,14 @@ public class JavaFileLoader {
.collect(Collectors.toList());
}
public List<JavaClassReader> loadInputStream(InputStream in, String name) throws IOException {
return loadReader(in, name, null, null);
}
public JavaClassReader loadClass(byte[] content, String fileName) {
return new JavaClassReader(getNextUniqId(), fileName, content);
}
private List<JavaClassReader> loadFromFile(File file) {
try (InputStream inputStream = new BufferedInputStream(new FileInputStream(file))) {
return loadReader(inputStream, file.getName(), file, null);
@@ -1,8 +1,11 @@
package jadx.plugins.input.java;
import java.io.Closeable;
import java.io.InputStream;
import java.nio.file.Path;
import java.util.Collections;
import java.util.List;
import java.util.function.Function;
import org.jetbrains.annotations.Nullable;
@@ -10,6 +13,7 @@ import jadx.api.plugins.JadxPluginInfo;
import jadx.api.plugins.input.JadxInputPlugin;
import jadx.api.plugins.input.data.ILoadResult;
import jadx.api.plugins.input.data.impl.EmptyLoadResult;
import jadx.plugins.input.java.utils.JavaClassParseException;
public class JavaInputPlugin implements JadxInputPlugin {
@@ -29,10 +33,51 @@ public class JavaInputPlugin implements JadxInputPlugin {
}
public static ILoadResult loadClassFiles(List<Path> inputFiles, @Nullable Closeable closeable) {
List<JavaClassReader> readers = new JavaFileLoader().collectFiles(inputFiles);
List<JavaClassReader> readers = new JavaInputLoader().collectFiles(inputFiles);
if (readers.isEmpty()) {
return EmptyLoadResult.INSTANCE;
}
return new JavaLoadResult(readers, closeable);
}
public static ILoadResult loadClassFiles(List<Path> inputFiles) {
return loadClassFiles(inputFiles, null);
}
/**
* Method for provide several inputs by using load methods from {@link JavaInputLoader} class.
*/
public static ILoadResult load(Function<JavaInputLoader, List<JavaClassReader>> loader) {
return wrapClassReaders(loader.apply(new JavaInputLoader()));
}
/**
* Convenient method for load class file or jar from input stream.
* Should be used only once per JadxDecompiler instance.
* For load several times use {@link JavaInputPlugin#load(Function)} method.
*/
public static ILoadResult loadFromInputStream(InputStream in, String fileName) {
try {
return wrapClassReaders(new JavaInputLoader().loadInputStream(in, fileName));
} catch (Exception e) {
throw new JavaClassParseException("Failed to read input stream", e);
}
}
/**
* Convenient method for load single class file by content.
* Should be used only once per JadxDecompiler instance.
* For load several times use {@link JavaInputPlugin#load(Function)} method.
*/
public static ILoadResult loadSingleClass(byte[] content, String fileName) {
JavaClassReader reader = new JavaInputLoader().loadClass(content, fileName);
return new JavaLoadResult(Collections.singletonList(reader));
}
public static ILoadResult wrapClassReaders(List<JavaClassReader> readers) {
if (readers.isEmpty()) {
return EmptyLoadResult.INSTANCE;
}
return new JavaLoadResult(readers);
}
}
@@ -20,6 +20,10 @@ public class JavaLoadResult implements ILoadResult {
@Nullable
private final Closeable closeable;
public JavaLoadResult(List<JavaClassReader> readers) {
this(readers, null);
}
public JavaLoadResult(List<JavaClassReader> readers, @Nullable Closeable closeable) {
this.readers = readers;
this.closeable = closeable;
@@ -47,7 +51,6 @@ public class JavaLoadResult implements ILoadResult {
@Override
public void close() throws IOException {
readers.clear();
if (closeable != null) {
closeable.close();
}