diff --git a/jadx-cli/src/main/java/jadx/cli/JadxCLI.java b/jadx-cli/src/main/java/jadx/cli/JadxCLI.java index 4ce788384..7d3a4ab4c 100644 --- a/jadx-cli/src/main/java/jadx/cli/JadxCLI.java +++ b/jadx-cli/src/main/java/jadx/cli/JadxCLI.java @@ -1,5 +1,8 @@ package jadx.cli; +import java.util.function.Consumer; + +import org.jetbrains.annotations.Nullable; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -26,10 +29,18 @@ public class JadxCLI { } public static int execute(String[] args) { + return execute(args, null); + } + + public static int execute(String[] args, @Nullable Consumer argsMod) { try { - JadxCLIArgs jadxArgs = new JadxCLIArgs(); - if (jadxArgs.processArgs(args)) { - return processAndSave(jadxArgs); + JadxCLIArgs cliArgs = new JadxCLIArgs(); + if (cliArgs.processArgs(args)) { + JadxArgs jadxArgs = buildArgs(cliArgs); + if (argsMod != null) { + argsMod.accept(jadxArgs); + } + return runSave(jadxArgs, cliArgs); } return 0; } catch (JadxArgsValidateException e) { @@ -41,7 +52,7 @@ public class JadxCLI { } } - private static int processAndSave(JadxCLIArgs cliArgs) { + private static JadxArgs buildArgs(JadxCLIArgs cliArgs) { LogHelper.initLogLevel(cliArgs); LogHelper.setLogLevelsForLoadingStage(); JadxArgs jadxArgs = cliArgs.toJadxArgs(); @@ -50,6 +61,10 @@ public class JadxCLI { jadxArgs.setFilesGetter(JadxFilesGetter.INSTANCE); initCodeWriterProvider(jadxArgs); JadxAppCommon.applyEnvVars(jadxArgs); + return jadxArgs; + } + + private static int runSave(JadxArgs jadxArgs, JadxCLIArgs cliArgs) { try (JadxDecompiler jadx = new JadxDecompiler(jadxArgs)) { jadx.load(); if (checkForErrors(jadx)) { diff --git a/jadx-cli/src/test/java/jadx/cli/TestInput.java b/jadx-cli/src/test/java/jadx/cli/TestInput.java index b11dfb4cf..11a4777ed 100644 --- a/jadx-cli/src/test/java/jadx/cli/TestInput.java +++ b/jadx-cli/src/test/java/jadx/cli/TestInput.java @@ -13,11 +13,15 @@ import java.util.stream.Collectors; import java.util.stream.Stream; import org.assertj.core.api.Condition; +import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.io.TempDir; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import jadx.api.plugins.loader.JadxBasePluginLoader; +import jadx.core.plugins.files.SingleDirFilesGetter; + import static org.assertj.core.api.Assertions.assertThat; public class TestInput { @@ -31,17 +35,24 @@ public class TestInput { @TempDir Path testDir; + Path outputDir; + + @BeforeEach + public void setUp() { + outputDir = testDir.resolve("output"); + } + @Test public void testHelp() { - int result = JadxCLI.execute(new String[] { "--help" }); + int result = execJadxCli(new String[] { "--help" }); assertThat(result).isEqualTo(0); } @Test public void testApkInput() throws Exception { - int result = JadxCLI.execute(buildArgs(List.of(), "samples/small.apk")); + int result = execJadxCli(buildArgs(List.of(), "samples/small.apk")); assertThat(result).isEqualTo(0); - List resultFiles = collectAllFilesInDir(testDir); + List resultFiles = collectAllFilesInDir(outputDir); printFiles(resultFiles); assertThat(resultFiles) .describedAs("check output files") @@ -75,48 +86,56 @@ public class TestInput { @Test public void testFallbackMode() throws Exception { - int result = JadxCLI.execute(buildArgs(List.of("-f"), "samples/hello.dex")); + int result = execJadxCli(buildArgs(List.of("-f"), "samples/hello.dex")); assertThat(result).isEqualTo(0); - List files = collectJavaFilesInDir(testDir); + List files = collectJavaFilesInDir(outputDir); assertThat(files).hasSize(1); } @Test public void testSimpleMode() throws Exception { - int result = JadxCLI.execute(buildArgs(List.of("--decompilation-mode", "simple"), "samples/hello.dex")); + int result = execJadxCli(buildArgs(List.of("--decompilation-mode", "simple"), "samples/hello.dex")); assertThat(result).isEqualTo(0); - List files = collectJavaFilesInDir(testDir); + List files = collectJavaFilesInDir(outputDir); assertThat(files).hasSize(1); } @Test public void testResourceOnly() throws Exception { - int result = JadxCLI.execute(buildArgs(List.of(), "samples/resources-only.apk")); + int result = execJadxCli(buildArgs(List.of(), "samples/resources-only.apk")); assertThat(result).isEqualTo(0); - List files = collectFilesInDir(testDir, + List files = collectFilesInDir(outputDir, path -> path.getFileName().toString().equalsIgnoreCase("AndroidManifest.xml")); assertThat(files).isNotEmpty(); } private void decompile(String... inputSamples) throws URISyntaxException, IOException { - int result = JadxCLI.execute(buildArgs(List.of(), inputSamples)); + int result = execJadxCli(buildArgs(List.of(), inputSamples)); assertThat(result).isEqualTo(0); - List resultJavaFiles = collectJavaFilesInDir(testDir); + List resultJavaFiles = collectJavaFilesInDir(outputDir); assertThat(resultJavaFiles).isNotEmpty(); // do not copy input files as resources - for (Path path : collectFilesInDir(testDir, LOG_ALL_FILES)) { + for (Path path : collectFilesInDir(outputDir, LOG_ALL_FILES)) { for (String inputSample : inputSamples) { assertThat(path.toAbsolutePath().toString()).doesNotContain(inputSample); } } } + private int execJadxCli(String[] args) { + return JadxCLI.execute(args, jadxArgs -> { + // don't use global config and plugins + jadxArgs.setFilesGetter(new SingleDirFilesGetter(testDir)); + jadxArgs.setPluginLoader(new JadxBasePluginLoader()); + }); + } + private String[] buildArgs(List options, String... inputSamples) throws URISyntaxException { List args = new ArrayList<>(options); args.add("-v"); args.add("-d"); - args.add(testDir.toAbsolutePath().toString()); + args.add(outputDir.toAbsolutePath().toString()); for (String inputSample : inputSamples) { URL resource = getClass().getClassLoader().getResource(inputSample); @@ -130,7 +149,7 @@ public class TestInput { private void printFiles(List files) { LOG.info("Output files (count: {}):", files.size()); for (Path file : files) { - LOG.info(" {}", testDir.relativize(file)); + LOG.info(" {}", outputDir.relativize(file)); } } diff --git a/jadx-core/src/main/java/jadx/core/plugins/files/SingleDirFilesGetter.java b/jadx-core/src/main/java/jadx/core/plugins/files/SingleDirFilesGetter.java new file mode 100644 index 000000000..07bdef598 --- /dev/null +++ b/jadx-core/src/main/java/jadx/core/plugins/files/SingleDirFilesGetter.java @@ -0,0 +1,37 @@ +package jadx.core.plugins.files; + +import java.nio.file.Path; + +import jadx.core.utils.files.FileUtils; + +/** + * Use single directory for all jadx files + */ +public class SingleDirFilesGetter implements IJadxFilesGetter { + private final Path baseDir; + + public SingleDirFilesGetter(Path baseDir) { + this.baseDir = baseDir; + } + + @Override + public Path getConfigDir() { + return makeSubDir("config"); + } + + @Override + public Path getCacheDir() { + return makeSubDir("cache"); + } + + @Override + public Path getTempDir() { + return makeSubDir("temp"); + } + + private Path makeSubDir(String subDir) { + Path dir = baseDir.resolve(subDir); + FileUtils.makeDirs(dir); + return dir; + } +} diff --git a/jadx-core/src/main/java/jadx/core/utils/files/FileUtils.java b/jadx-core/src/main/java/jadx/core/utils/files/FileUtils.java index 85d52d4ac..aed350185 100644 --- a/jadx-core/src/main/java/jadx/core/utils/files/FileUtils.java +++ b/jadx-core/src/main/java/jadx/core/utils/files/FileUtils.java @@ -178,7 +178,9 @@ public class FileUtils { } public static void clearTempRootDir() { - clearDir(tempRootDir); + if (Files.isDirectory(tempRootDir)) { + clearDir(tempRootDir); + } } public static void clearDir(Path clearDir) {