diff --git a/jadx-cli/src/main/java/jadx/cli/JadxCLI.java b/jadx-cli/src/main/java/jadx/cli/JadxCLI.java index 2959c23ee..ef5465fcb 100644 --- a/jadx-cli/src/main/java/jadx/cli/JadxCLI.java +++ b/jadx-cli/src/main/java/jadx/cli/JadxCLI.java @@ -22,26 +22,28 @@ public class JadxCLI { private static final Logger LOG = LoggerFactory.getLogger(JadxCLI.class); public static void main(String[] args) { - int result = 0; + int result = 1; try { result = execute(args); - } catch (JadxArgsValidateException e) { - LOG.error("Incorrect arguments: {}", e.getMessage()); - result = 1; - } catch (Throwable e) { - LOG.error("Process error:", e); - result = 1; } finally { System.exit(result); } } public static int execute(String[] args) { - JadxCLIArgs jadxArgs = new JadxCLIArgs(); - if (jadxArgs.processArgs(args)) { - return processAndSave(jadxArgs); + try { + JadxCLIArgs jadxArgs = new JadxCLIArgs(); + if (jadxArgs.processArgs(args)) { + return processAndSave(jadxArgs); + } + return 0; + } catch (JadxArgsValidateException e) { + LOG.error("Incorrect arguments: {}", e.getMessage()); + return 1; + } catch (Throwable e) { + LOG.error("Process error:", e); + return 1; } - return 0; } private static int processAndSave(JadxCLIArgs cliArgs) { @@ -66,11 +68,11 @@ public class JadxCLI { if (errorsCount != 0) { jadx.printErrorsReport(); LOG.error("finished with errors, count: {}", errorsCount); - } else { - LOG.info("done"); + return 1; } + LOG.info("done"); + return 0; } - return 0; } private static void initCodeWriterProvider(JadxArgs jadxArgs) { diff --git a/jadx-cli/src/test/java/jadx/cli/TestInput.java b/jadx-cli/src/test/java/jadx/cli/TestInput.java index b8e3adece..b11dfb4cf 100644 --- a/jadx-cli/src/test/java/jadx/cli/TestInput.java +++ b/jadx-cli/src/test/java/jadx/cli/TestInput.java @@ -12,6 +12,7 @@ import java.util.List; import java.util.stream.Collectors; import java.util.stream.Stream; +import org.assertj.core.api.Condition; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.io.TempDir; import org.slf4j.Logger; @@ -36,6 +37,22 @@ public class TestInput { assertThat(result).isEqualTo(0); } + @Test + public void testApkInput() throws Exception { + int result = JadxCLI.execute(buildArgs(List.of(), "samples/small.apk")); + assertThat(result).isEqualTo(0); + List resultFiles = collectAllFilesInDir(testDir); + printFiles(resultFiles); + assertThat(resultFiles) + .describedAs("check output files") + .map(p -> p.getFileName().toString()) + .haveExactly(2, new Condition<>(f -> f.endsWith(".java"), "java classes")) + .haveExactly(9, new Condition<>(f -> f.endsWith(".xml"), "xml resources")) + .haveExactly(1, new Condition<>(f -> f.equals("classes.dex"), "dex")) + .haveExactly(1, new Condition<>(f -> f.equals("AndroidManifest.xml"), "manifest")) + .hasSize(13); + } + @Test public void testDexInput() throws Exception { decompile("samples/hello.dex"); @@ -110,11 +127,26 @@ public class TestInput { return args.toArray(new String[0]); } + private void printFiles(List files) { + LOG.info("Output files (count: {}):", files.size()); + for (Path file : files) { + LOG.info(" {}", testDir.relativize(file)); + } + } + private static List collectJavaFilesInDir(Path dir) throws IOException { PathMatcher javaMatcher = dir.getFileSystem().getPathMatcher("glob:**.java"); return collectFilesInDir(dir, javaMatcher); } + private static List collectAllFilesInDir(Path dir) throws IOException { + try (Stream pathStream = Files.walk(dir)) { + return pathStream + .filter(Files::isRegularFile) + .collect(Collectors.toList()); + } + } + private static List collectFilesInDir(Path dir, PathMatcher matcher) throws IOException { try (Stream pathStream = Files.walk(dir)) { return pathStream diff --git a/jadx-cli/src/test/resources/samples/small.apk b/jadx-cli/src/test/resources/samples/small.apk new file mode 100644 index 000000000..7ad35494a Binary files /dev/null and b/jadx-cli/src/test/resources/samples/small.apk differ diff --git a/jadx-core/src/main/java/jadx/core/codegen/utils/CodeGenUtils.java b/jadx-core/src/main/java/jadx/core/codegen/utils/CodeGenUtils.java index 778cbe668..b703df797 100644 --- a/jadx-core/src/main/java/jadx/core/codegen/utils/CodeGenUtils.java +++ b/jadx-core/src/main/java/jadx/core/codegen/utils/CodeGenUtils.java @@ -140,7 +140,9 @@ public class CodeGenUtils { String inputFileName = cls.getClsData().getInputFileName(); if (inputFileName != null) { ClassNode declCls = cls.getDeclaringClass(); - if (declCls != null && inputFileName.equals(declCls.getClsData().getInputFileName())) { + if (declCls != null + && declCls.getClsData() != null + && inputFileName.equals(declCls.getClsData().getInputFileName())) { // don't add same comment for inner classes return; } diff --git a/jadx-core/src/main/java/jadx/core/dex/nodes/ClassNode.java b/jadx-core/src/main/java/jadx/core/dex/nodes/ClassNode.java index fa97363ba..13d13c43b 100644 --- a/jadx-core/src/main/java/jadx/core/dex/nodes/ClassNode.java +++ b/jadx-core/src/main/java/jadx/core/dex/nodes/ClassNode.java @@ -864,7 +864,12 @@ public class ClassNode extends NotificationAttrNode } } - public IClassData getClsData() { + /** + * Low level class data access. + * + * @return null for classes generated by jadx + */ + public @Nullable IClassData getClsData() { return clsData; }