Commit 948f9456 authored by Skylot's avatar Skylot

core: change jadx args api for easier processing and validation

parent 32f94b46
package jadx.cli; package jadx.cli;
import java.io.File;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import jadx.api.JadxDecompiler; import jadx.api.JadxDecompiler;
import jadx.core.utils.exceptions.JadxException;
public class JadxCLI { public class JadxCLI {
private static final Logger LOG = LoggerFactory.getLogger(JadxCLI.class); private static final Logger LOG = LoggerFactory.getLogger(JadxCLI.class);
...@@ -14,7 +11,7 @@ public class JadxCLI { ...@@ -14,7 +11,7 @@ public class JadxCLI {
public static void main(String[] args) { public static void main(String[] args) {
try { try {
JadxCLIArgs jadxArgs = new JadxCLIArgs(); JadxCLIArgs jadxArgs = new JadxCLIArgs();
if (processArgs(jadxArgs, args)) { if (jadxArgs.processArgs(args)) {
processAndSave(jadxArgs); processAndSave(jadxArgs);
} }
} catch (Exception e) { } catch (Exception e) {
...@@ -23,10 +20,9 @@ public class JadxCLI { ...@@ -23,10 +20,9 @@ public class JadxCLI {
} }
} }
static void processAndSave(JadxCLIArgs jadxArgs) throws JadxException { static void processAndSave(JadxCLIArgs inputArgs) {
JadxDecompiler jadx = new JadxDecompiler(jadxArgs); JadxDecompiler jadx = new JadxDecompiler(inputArgs.toJadxArgs());
jadx.setOutputDir(jadxArgs.getOutDir()); jadx.load();
jadx.loadFiles(jadxArgs.getInput());
jadx.save(); jadx.save();
if (jadx.getErrorsCount() != 0) { if (jadx.getErrorsCount() != 0) {
jadx.printErrorsReport(); jadx.printErrorsReport();
...@@ -35,34 +31,4 @@ public class JadxCLI { ...@@ -35,34 +31,4 @@ public class JadxCLI {
LOG.info("done"); LOG.info("done");
} }
} }
static boolean processArgs(JadxCLIArgs jadxArgs, String[] args) throws JadxException {
if (!jadxArgs.processArgs(args)) {
return false;
}
if (jadxArgs.getInput().isEmpty()) {
LOG.error("Please specify input file");
jadxArgs.printUsage();
return false;
}
File outputDir = jadxArgs.getOutDir();
if (outputDir == null) {
String outDirName;
File file = jadxArgs.getInput().get(0);
String name = file.getName();
int pos = name.lastIndexOf('.');
if (pos != -1) {
outDirName = name.substring(0, pos);
} else {
outDirName = name + "-jadx-out";
}
LOG.info("output directory: {}", outDirName);
outputDir = new File(outDirName);
jadxArgs.setOutputDir(outputDir);
}
if (outputDir.exists() && !outputDir.isDirectory()) {
throw new JadxException("Output directory exists as file " + outputDir);
}
return true;
}
} }
package jadx.cli; package jadx.cli;
import java.io.File;
import java.io.PrintStream; import java.io.PrintStream;
import java.lang.reflect.Field; import java.lang.reflect.Field;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.LinkedHashMap; import java.util.LinkedHashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.stream.Collectors;
import ch.qos.logback.classic.spi.ILoggingEvent; import ch.qos.logback.classic.spi.ILoggingEvent;
import ch.qos.logback.core.Appender; import ch.qos.logback.core.Appender;
...@@ -18,28 +18,27 @@ import com.beust.jcommander.ParameterException; ...@@ -18,28 +18,27 @@ import com.beust.jcommander.ParameterException;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import jadx.api.IJadxArgs; import jadx.api.JadxArgs;
import jadx.api.JadxDecompiler; import jadx.api.JadxDecompiler;
import jadx.core.utils.exceptions.JadxException; import jadx.core.utils.exceptions.JadxException;
import jadx.core.utils.files.FileUtils;
public class JadxCLIArgs implements IJadxArgs { public class JadxCLIArgs {
protected static final int DEFAULT_THREADS_COUNT = Math.max(1, Runtime.getRuntime().availableProcessors() / 2);
@Parameter(description = "<input file> (.dex, .apk, .jar or .class)") @Parameter(description = "<input file> (.dex, .apk, .jar or .class)")
protected List<String> files; protected List<String> files = new ArrayList<>(1);
@Parameter(names = {"-d", "--output-dir"}, description = "output directory") @Parameter(names = {"-d", "--output-dir"}, description = "output directory")
protected String outDirName; protected String outDir;
@Parameter(names = {"-ds", "--output-dir-src"}, description = "output directory for sources") @Parameter(names = {"-ds", "--output-dir-src"}, description = "output directory for sources")
protected String outDirNameSrc; protected String outDirSrc;
@Parameter(names = {"-dr", "--output-dir-res"}, description = "output directory for resources") @Parameter(names = {"-dr", "--output-dir-res"}, description = "output directory for resources")
protected String outDirNameRes; protected String outDirRes;
@Parameter(names = {"-j", "--threads-count"}, description = "processing threads count") @Parameter(names = {"-j", "--threads-count"}, description = "processing threads count")
protected int threadsCount = DEFAULT_THREADS_COUNT; protected int threadsCount = JadxArgs.DEFAULT_THREADS_COUNT;
@Parameter(names = {"-r", "--no-res"}, description = "do not decode resources") @Parameter(names = {"-r", "--no-res"}, description = "do not decode resources")
protected boolean skipResources = false; protected boolean skipResources = false;
...@@ -94,11 +93,6 @@ public class JadxCLIArgs implements IJadxArgs { ...@@ -94,11 +93,6 @@ public class JadxCLIArgs implements IJadxArgs {
@Parameter(names = {"-h", "--help"}, description = "print this help", help = true) @Parameter(names = {"-h", "--help"}, description = "print this help", help = true)
protected boolean printHelp = false; protected boolean printHelp = false;
private final List<File> input = new ArrayList<>(1);
private File outputDir;
private File outputDirSrc;
private File outputDirRes;
public boolean processArgs(String[] args) { public boolean processArgs(String[] args) {
return parse(args) && process(); return parse(args) && process();
} }
...@@ -123,35 +117,6 @@ public class JadxCLIArgs implements IJadxArgs { ...@@ -123,35 +117,6 @@ public class JadxCLIArgs implements IJadxArgs {
if (threadsCount <= 0) { if (threadsCount <= 0) {
throw new JadxException("Threads count must be positive, got: " + threadsCount); throw new JadxException("Threads count must be positive, got: " + threadsCount);
} }
if (files != null) {
for (String fileName : files) {
File file = new File(fileName);
if (file.exists()) {
input.add(file);
} else {
throw new JadxException("File not found: " + file);
}
}
}
if (input.size() > 1) {
throw new JadxException("Only one input file is supported");
}
if(outDirNameSrc != null) {
outputDirSrc = new File(outDirNameSrc);
}
if(outDirNameRes != null) {
outputDirRes = new File(outDirNameRes);
}
if (outDirName != null) {
outputDir = new File(outDirName);
if(outputDirSrc == null) {
outputDirSrc = new File(outputDir, "source");
}
if(outputDirRes == null) {
outputDirRes = new File(outputDir, "res");
}
}
if (isVerbose()) { if (isVerbose()) {
ch.qos.logback.classic.Logger rootLogger = ch.qos.logback.classic.Logger rootLogger =
(ch.qos.logback.classic.Logger) LoggerFactory.getLogger(Logger.ROOT_LOGGER_NAME); (ch.qos.logback.classic.Logger) LoggerFactory.getLogger(Logger.ROOT_LOGGER_NAME);
...@@ -212,6 +177,31 @@ public class JadxCLIArgs implements IJadxArgs { ...@@ -212,6 +177,31 @@ public class JadxCLIArgs implements IJadxArgs {
} }
} }
public JadxArgs toJadxArgs() {
JadxArgs args = new JadxArgs();
args.setInputFiles(files.stream().map(FileUtils::toFile).collect(Collectors.toList()));
args.setOutDir(FileUtils.toFile(outDir));
args.setOutDirSrc(FileUtils.toFile(outDirSrc));
args.setOutDirRes(FileUtils.toFile(outDirRes));
args.setThreadsCount(threadsCount);
args.setSkipSources(skipSources);
args.setSkipResources(skipResources);
args.setFallbackMode(fallbackMode);
args.setShowInconsistentCode(showInconsistentCode);
args.setCfgOutput(cfgOutput);
args.setRawCFGOutput(rawCfgOutput);
args.setReplaceConsts(replaceConsts);
args.setDeobfuscationOn(deobfuscationOn);
args.setDeobfuscationForceSave(deobfuscationForceSave);
args.setDeobfuscationMinLength(deobfuscationMinLength);
args.setDeobfuscationMaxLength(deobfuscationMaxLength);
args.setUseSourceNameAsClassAlias(deobfuscationUseSourceNameAsAlias);
args.setEscapeUnicode(escapeUnicode);
args.setExportAsGradleProject(exportAsGradleProject);
args.setUseImports(useImports);
return args;
}
public static class InvertedBooleanConverter implements IStringConverter<Boolean> { public static class InvertedBooleanConverter implements IStringConverter<Boolean> {
@Override @Override
public Boolean convert(String value) { public Boolean convert(String value) {
...@@ -219,114 +209,90 @@ public class JadxCLIArgs implements IJadxArgs { ...@@ -219,114 +209,90 @@ public class JadxCLIArgs implements IJadxArgs {
} }
} }
public List<File> getInput() { public List<String> getFiles() {
return input; return files;
} }
@Override public String getOutDir() {
public File getOutDir() { return outDir;
return outputDir;
}
@Override
public File getOutDirSrc() {
return outputDirSrc;
} }
@Override public String getOutDirSrc() {
public File getOutDirRes() { return outDirSrc;
return outputDirRes;
} }
public void setOutputDir(File outputDir) { public String getOutDirRes() {
this.outputDir = outputDir; return outDirRes;
} }
public boolean isPrintHelp() { public boolean isPrintHelp() {
return printHelp; return printHelp;
} }
@Override
public boolean isSkipResources() { public boolean isSkipResources() {
return skipResources; return skipResources;
} }
@Override
public boolean isSkipSources() { public boolean isSkipSources() {
return skipSources; return skipSources;
} }
@Override
public int getThreadsCount() { public int getThreadsCount() {
return threadsCount; return threadsCount;
} }
@Override
public boolean isCFGOutput() { public boolean isCFGOutput() {
return cfgOutput; return cfgOutput;
} }
@Override
public boolean isRawCFGOutput() { public boolean isRawCFGOutput() {
return rawCfgOutput; return rawCfgOutput;
} }
@Override
public boolean isFallbackMode() { public boolean isFallbackMode() {
return fallbackMode; return fallbackMode;
} }
@Override
public boolean isShowInconsistentCode() { public boolean isShowInconsistentCode() {
return showInconsistentCode; return showInconsistentCode;
} }
@Override public boolean isUseImports() {
public boolean isUsingImports() {
return useImports; return useImports;
} }
@Override
public boolean isVerbose() { public boolean isVerbose() {
return verbose; return verbose;
} }
@Override
public boolean isDeobfuscationOn() { public boolean isDeobfuscationOn() {
return deobfuscationOn; return deobfuscationOn;
} }
@Override
public int getDeobfuscationMinLength() { public int getDeobfuscationMinLength() {
return deobfuscationMinLength; return deobfuscationMinLength;
} }
@Override
public int getDeobfuscationMaxLength() { public int getDeobfuscationMaxLength() {
return deobfuscationMaxLength; return deobfuscationMaxLength;
} }
@Override
public boolean isDeobfuscationForceSave() { public boolean isDeobfuscationForceSave() {
return deobfuscationForceSave; return deobfuscationForceSave;
} }
@Override public boolean isDeobfuscationUseSourceNameAsAlias() {
public boolean useSourceNameAsClassAlias() {
return deobfuscationUseSourceNameAsAlias; return deobfuscationUseSourceNameAsAlias;
} }
@Override
public boolean escapeUnicode() { public boolean escapeUnicode() {
return escapeUnicode; return escapeUnicode;
} }
@Override
public boolean isReplaceConsts() { public boolean isReplaceConsts() {
return replaceConsts; return replaceConsts;
} }
@Override
public boolean isExportAsGradleProject() { public boolean isExportAsGradleProject() {
return exportAsGradleProject; return exportAsGradleProject;
} }
......
...@@ -8,7 +8,7 @@ import static org.junit.Assert.assertThat; ...@@ -8,7 +8,7 @@ import static org.junit.Assert.assertThat;
public class JadxCLIArgsTest { public class JadxCLIArgsTest {
@Test @Test
public void testInvertedBooleanOption() throws Exception { public void testInvertedBooleanOption() {
assertThat(parse("--no-replace-consts").isReplaceConsts(), is(false)); assertThat(parse("--no-replace-consts").isReplaceConsts(), is(false));
assertThat(parse("").isReplaceConsts(), is(true)); assertThat(parse("").isReplaceConsts(), is(true));
} }
......
package jadx.api;
import java.io.File;
public interface IJadxArgs {
File getOutDir();
File getOutDirSrc();
File getOutDirRes();
int getThreadsCount();
boolean isCFGOutput();
boolean isRawCFGOutput();
boolean isFallbackMode();
boolean isShowInconsistentCode();
boolean isUsingImports();
boolean isVerbose();
boolean isSkipResources();
boolean isSkipSources();
boolean isDeobfuscationOn();
int getDeobfuscationMinLength();
int getDeobfuscationMaxLength();
boolean isDeobfuscationForceSave();
boolean useSourceNameAsClassAlias();
boolean escapeUnicode();
/**
* Replace constant values with static final fields with same value
*/
boolean isReplaceConsts();
/**
* Save as gradle project
*/
boolean isExportAsGradleProject();
}
package jadx.api; package jadx.api;
import java.io.File; import java.io.File;
import java.util.ArrayList;
import java.util.List;
public class JadxArgs implements IJadxArgs { public class JadxArgs {
private File outDir = new File("jadx-output"); public static final int DEFAULT_THREADS_COUNT = Math.max(1, Runtime.getRuntime().availableProcessors() / 2);
private File outDirSrc = new File(outDir, "source");
private File outDirRes = new File(outDir, "res"); public static final String DEFAULT_OUT_DIR = "jadx-output";
private int threadsCount = Math.max(1, Runtime.getRuntime().availableProcessors() - 1); public static final String DEFAULT_SRC_DIR = "sources";
public static final String DEFAULT_RES_DIR = "resources";
private List<File> inputFiles = new ArrayList<>(1);
private File outDir;
private File outDirSrc;
private File outDirRes;
private int threadsCount = DEFAULT_THREADS_COUNT;
private boolean cfgOutput = false; private boolean cfgOutput = false;
private boolean rawCFGOutput = false; private boolean rawCFGOutput = false;
private boolean isVerbose = false;
private boolean fallbackMode = false; private boolean fallbackMode = false;
private boolean showInconsistentCode = false; private boolean showInconsistentCode = false;
...@@ -32,7 +42,24 @@ public class JadxArgs implements IJadxArgs { ...@@ -32,7 +42,24 @@ public class JadxArgs implements IJadxArgs {
private boolean replaceConsts = true; private boolean replaceConsts = true;
private boolean exportAsGradleProject = false; private boolean exportAsGradleProject = false;
@Override public JadxArgs() {
// use default options
}
public void setRootDir(File rootDir) {
setOutDir(rootDir);
setOutDirSrc(new File(rootDir, DEFAULT_SRC_DIR));
setOutDirRes(new File(rootDir, DEFAULT_RES_DIR));
}
public List<File> getInputFiles() {
return inputFiles;
}
public void setInputFiles(List<File> inputFiles) {
this.inputFiles = inputFiles;
}
public File getOutDir() { public File getOutDir() {
return outDir; return outDir;
} }
...@@ -41,7 +68,6 @@ public class JadxArgs implements IJadxArgs { ...@@ -41,7 +68,6 @@ public class JadxArgs implements IJadxArgs {
this.outDir = outDir; this.outDir = outDir;
} }
@Override
public File getOutDirSrc() { public File getOutDirSrc() {
return outDirSrc; return outDirSrc;
} }
...@@ -50,7 +76,6 @@ public class JadxArgs implements IJadxArgs { ...@@ -50,7 +76,6 @@ public class JadxArgs implements IJadxArgs {
this.outDirSrc = outDirSrc; this.outDirSrc = outDirSrc;
} }
@Override
public File getOutDirRes() { public File getOutDirRes() {
return outDirRes; return outDirRes;
} }
...@@ -59,7 +84,6 @@ public class JadxArgs implements IJadxArgs { ...@@ -59,7 +84,6 @@ public class JadxArgs implements IJadxArgs {
this.outDirRes = outDirRes; this.outDirRes = outDirRes;
} }
@Override
public int getThreadsCount() { public int getThreadsCount() {
return threadsCount; return threadsCount;
} }
...@@ -68,8 +92,7 @@ public class JadxArgs implements IJadxArgs { ...@@ -68,8 +92,7 @@ public class JadxArgs implements IJadxArgs {
this.threadsCount = threadsCount; this.threadsCount = threadsCount;
} }
@Override public boolean isCfgOutput() {
public boolean isCFGOutput() {
return cfgOutput; return cfgOutput;
} }
...@@ -77,7 +100,6 @@ public class JadxArgs implements IJadxArgs { ...@@ -77,7 +100,6 @@ public class JadxArgs implements IJadxArgs {
this.cfgOutput = cfgOutput; this.cfgOutput = cfgOutput;
} }
@Override
public boolean isRawCFGOutput() { public boolean isRawCFGOutput() {
return rawCFGOutput; return rawCFGOutput;
} }
...@@ -86,7 +108,6 @@ public class JadxArgs implements IJadxArgs { ...@@ -86,7 +108,6 @@ public class JadxArgs implements IJadxArgs {
this.rawCFGOutput = rawCFGOutput; this.rawCFGOutput = rawCFGOutput;
} }
@Override
public boolean isFallbackMode() { public boolean isFallbackMode() {
return fallbackMode; return fallbackMode;
} }
...@@ -95,7 +116,6 @@ public class JadxArgs implements IJadxArgs { ...@@ -95,7 +116,6 @@ public class JadxArgs implements IJadxArgs {
this.fallbackMode = fallbackMode; this.fallbackMode = fallbackMode;
} }
@Override
public boolean isShowInconsistentCode() { public boolean isShowInconsistentCode() {
return showInconsistentCode; return showInconsistentCode;
} }
...@@ -104,8 +124,7 @@ public class JadxArgs implements IJadxArgs { ...@@ -104,8 +124,7 @@ public class JadxArgs implements IJadxArgs {
this.showInconsistentCode = showInconsistentCode; this.showInconsistentCode = showInconsistentCode;
} }
@Override public boolean isUseImports() {
public boolean isUsingImports() {
return useImports; return useImports;
} }
...@@ -113,16 +132,6 @@ public class JadxArgs implements IJadxArgs { ...@@ -113,16 +132,6 @@ public class JadxArgs implements IJadxArgs {
this.useImports = useImports; this.useImports = useImports;
} }
@Override
public boolean isVerbose() {
return isVerbose;
}
public void setVerbose(boolean verbose) {
isVerbose = verbose;
}
@Override
public boolean isSkipResources() { public boolean isSkipResources() {
return isSkipResources; return isSkipResources;
} }
...@@ -131,7 +140,6 @@ public class JadxArgs implements IJadxArgs { ...@@ -131,7 +140,6 @@ public class JadxArgs implements IJadxArgs {
isSkipResources = skipResources; isSkipResources = skipResources;
} }
@Override
public boolean isSkipSources() { public boolean isSkipSources() {
return isSkipSources; return isSkipSources;
} }
...@@ -140,7 +148,6 @@ public class JadxArgs implements IJadxArgs { ...@@ -140,7 +148,6 @@ public class JadxArgs implements IJadxArgs {
isSkipSources = skipSources; isSkipSources = skipSources;
} }
@Override
public boolean isDeobfuscationOn() { public boolean isDeobfuscationOn() {
return isDeobfuscationOn; return isDeobfuscationOn;
} }
...@@ -149,7 +156,6 @@ public class JadxArgs implements IJadxArgs { ...@@ -149,7 +156,6 @@ public class JadxArgs implements IJadxArgs {
isDeobfuscationOn = deobfuscationOn; isDeobfuscationOn = deobfuscationOn;
} }
@Override
public boolean isDeobfuscationForceSave() { public boolean isDeobfuscationForceSave() {
return isDeobfuscationForceSave; return isDeobfuscationForceSave;
} }
...@@ -158,8 +164,7 @@ public class JadxArgs implements IJadxArgs { ...@@ -158,8 +164,7 @@ public class JadxArgs implements IJadxArgs {
isDeobfuscationForceSave = deobfuscationForceSave; isDeobfuscationForceSave = deobfuscationForceSave;
} }
@Override public boolean isUseSourceNameAsClassAlias() {
public boolean useSourceNameAsClassAlias() {
return useSourceNameAsClassAlias; return useSourceNameAsClassAlias;
} }
...@@ -167,7 +172,6 @@ public class JadxArgs implements IJadxArgs { ...@@ -167,7 +172,6 @@ public class JadxArgs implements IJadxArgs {
this.useSourceNameAsClassAlias = useSourceNameAsClassAlias; this.useSourceNameAsClassAlias = useSourceNameAsClassAlias;
} }
@Override
public int getDeobfuscationMinLength() { public int getDeobfuscationMinLength() {
return deobfuscationMinLength; return deobfuscationMinLength;
} }
...@@ -176,7 +180,6 @@ public class JadxArgs implements IJadxArgs { ...@@ -176,7 +180,6 @@ public class JadxArgs implements IJadxArgs {
this.deobfuscationMinLength = deobfuscationMinLength; this.deobfuscationMinLength = deobfuscationMinLength;
} }
@Override
public int getDeobfuscationMaxLength() { public int getDeobfuscationMaxLength() {
return deobfuscationMaxLength; return deobfuscationMaxLength;
} }
...@@ -185,8 +188,7 @@ public class JadxArgs implements IJadxArgs { ...@@ -185,8 +188,7 @@ public class JadxArgs implements IJadxArgs {
this.deobfuscationMaxLength = deobfuscationMaxLength; this.deobfuscationMaxLength = deobfuscationMaxLength;
} }
@Override public boolean isEscapeUnicode() {
public boolean escapeUnicode() {
return escapeUnicode; return escapeUnicode;
} }
...@@ -194,7 +196,6 @@ public class JadxArgs implements IJadxArgs { ...@@ -194,7 +196,6 @@ public class JadxArgs implements IJadxArgs {
this.escapeUnicode = escapeUnicode; this.escapeUnicode = escapeUnicode;
} }
@Override
public boolean isReplaceConsts() { public boolean isReplaceConsts() {
return replaceConsts; return replaceConsts;
} }
...@@ -203,7 +204,6 @@ public class JadxArgs implements IJadxArgs { ...@@ -203,7 +204,6 @@ public class JadxArgs implements IJadxArgs {
this.replaceConsts = replaceConsts; this.replaceConsts = replaceConsts;
} }
@Override
public boolean isExportAsGradleProject() { public boolean isExportAsGradleProject() {
return exportAsGradleProject; return exportAsGradleProject;
} }
......
package jadx.api;
import java.io.File;
import org.jetbrains.annotations.NotNull;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import jadx.core.utils.exceptions.JadxRuntimeException;
public class JadxArgsValidator {
private static final Logger LOG = LoggerFactory.getLogger(JadxArgsValidator.class);
public static void validate(JadxArgs args) {
if (args.getInputFiles().isEmpty()) {
throw new JadxRuntimeException("Please specify input file");
}
for (File file : args.getInputFiles()) {
checkFile(file);
}
validateOutDirs(args);
}
private static void validateOutDirs(JadxArgs args) {
File outDir = args.getOutDir();
File srcDir = args.getOutDirSrc();
File resDir = args.getOutDirRes();
if (outDir == null) {
if (srcDir != null) {
outDir = srcDir;
} else if (resDir != null) {
outDir = resDir;
} else {
outDir = makeDirFromInput(args);
}
}
args.setOutDir(outDir);
setFromOut(args);
checkDir(args.getOutDir());
checkDir(args.getOutDirSrc());
checkDir(args.getOutDirRes());
}
@NotNull
private static File makeDirFromInput(JadxArgs args) {
File outDir;
String outDirName;
File file = args.getInputFiles().get(0);
String name = file.getName();
int pos = name.lastIndexOf('.');
if (pos != -1) {
outDirName = name.substring(0, pos);
} else {
outDirName = name + "-" + JadxArgs.DEFAULT_OUT_DIR;
}
LOG.info("output directory: {}", outDirName);
outDir = new File(outDirName);
return outDir;
}
private static void setFromOut(JadxArgs args) {
if (args.getOutDirSrc() == null) {
args.setOutDirSrc(new File(args.getOutDir(), JadxArgs.DEFAULT_SRC_DIR));
}
if (args.getOutDirRes() == null) {
args.setOutDirRes(new File(args.getOutDir(), JadxArgs.DEFAULT_RES_DIR));
}
}
private static void checkFile(File file) {
if (!file.exists()) {
throw new JadxRuntimeException("File not found " + file.getAbsolutePath());
}
if (file.isDirectory()) {
throw new JadxRuntimeException("Expected file but found directory instead: " + file.getAbsolutePath());
}
}
private static void checkDir(File dir) {
if (dir != null && dir.exists() && !dir.isDirectory()) {
throw new JadxRuntimeException("Output directory exists as file " + dir);
}
}
private JadxArgsValidator() {
}
}
package jadx.api; package jadx.api;
import java.io.File;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import jadx.core.Jadx; import jadx.core.Jadx;
import jadx.core.ProcessClass; import jadx.core.ProcessClass;
import jadx.core.codegen.CodeGen; import jadx.core.codegen.CodeGen;
...@@ -11,38 +26,24 @@ import jadx.core.dex.nodes.RootNode; ...@@ -11,38 +26,24 @@ import jadx.core.dex.nodes.RootNode;
import jadx.core.dex.visitors.IDexTreeVisitor; import jadx.core.dex.visitors.IDexTreeVisitor;
import jadx.core.dex.visitors.SaveCode; import jadx.core.dex.visitors.SaveCode;
import jadx.core.export.ExportGradleProject; import jadx.core.export.ExportGradleProject;
import jadx.core.utils.exceptions.JadxException;
import jadx.core.utils.exceptions.JadxRuntimeException; import jadx.core.utils.exceptions.JadxRuntimeException;
import jadx.core.utils.files.InputFile; import jadx.core.utils.files.InputFile;
import jadx.core.xmlgen.BinaryXMLParser; import jadx.core.xmlgen.BinaryXMLParser;
import jadx.core.xmlgen.ResourcesSaver; import jadx.core.xmlgen.ResourcesSaver;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/** /**
* Jadx API usage example: * Jadx API usage example:
* <pre><code> * <pre><code>
* JadxDecompiler jadx = new JadxDecompiler(); * JadxArgs args = new JadxArgs();
* jadx.loadFile(new File("classes.dex")); * args.getInputFiles().add(new File("test.apk"));
* jadx.setOutputDir(new File("out")); * args.setOutDir(new File("jadx-test-output"));
*
* JadxDecompiler jadx = new JadxDecompiler(args);
* jadx.load();
* jadx.save(); * jadx.save();
* </code></pre> * </code></pre>
* <p/> * <p/>
* Instead of 'save()' you can get list of decompiled classes: * Instead of 'save()' you can iterate over decompiled classes:
* <pre><code> * <pre><code>
* for(JavaClass cls : jadx.getClasses()) { * for(JavaClass cls : jadx.getClasses()) {
* System.out.println(cls.getCode()); * System.out.println(cls.getCode());
...@@ -52,12 +53,9 @@ import org.slf4j.LoggerFactory; ...@@ -52,12 +53,9 @@ import org.slf4j.LoggerFactory;
public final class JadxDecompiler { public final class JadxDecompiler {
private static final Logger LOG = LoggerFactory.getLogger(JadxDecompiler.class); private static final Logger LOG = LoggerFactory.getLogger(JadxDecompiler.class);
private final IJadxArgs args; private JadxArgs args;
private final List<InputFile> inputFiles = new ArrayList<>();
private File outDir; private final List<InputFile> inputFiles = new ArrayList<>();
private File outDirRes;
private File outDirSrc;
private RootNode root; private RootNode root;
private List<IDexTreeVisitor> passes; private List<IDexTreeVisitor> passes;
...@@ -72,54 +70,35 @@ public final class JadxDecompiler { ...@@ -72,54 +70,35 @@ public final class JadxDecompiler {
private Map<MethodNode, JavaMethod> methodsMap = new ConcurrentHashMap<>(); private Map<MethodNode, JavaMethod> methodsMap = new ConcurrentHashMap<>();
private Map<FieldNode, JavaField> fieldsMap = new ConcurrentHashMap<>(); private Map<FieldNode, JavaField> fieldsMap = new ConcurrentHashMap<>();
public JadxDecompiler() throws JadxException { public JadxDecompiler() {
this(new JadxArgs()); this(new JadxArgs());
} }
public JadxDecompiler(IJadxArgs jadxArgs) throws JadxException { public JadxDecompiler(JadxArgs args) {
this.args = jadxArgs; this.args = args;
this.outDir = jadxArgs.getOutDir();
this.outDirSrc = jadxArgs.getOutDirSrc();
this.outDirRes = jadxArgs.getOutDirRes();
reset();
init();
} }
public void setOutputDir(File outDir) throws JadxException { public void load() {
this.outDir = outDir; reset();
JadxArgsValidator.validate(args);
init(); init();
} LOG.info("loading ...");
public void setOutputDirSrc(File outDirSrc) throws JadxException { loadFiles(args.getInputFiles());
this.outDirSrc = outDirSrc;
init();
}
public void setOutputDirRes(File outDirRes) throws JadxException { root = new RootNode(args);
this.outDirRes = outDirRes; root.load(inputFiles);
init();
}
void init() throws JadxException { root.initClassPath();
if(outDir == null && outDirSrc == null) { root.loadResources(getResources());
outDirSrc = new JadxArgs().getOutDirSrc(); root.initAppResClass();
}
if(outDir == null && outDirRes == null) { initVisitors();
outDirRes = new JadxArgs().getOutDirRes();
}
if (outDir == null) {
outDir = new JadxArgs().getOutDir();
}
else {
if(outDirSrc == null && outDirRes != null && !args.isSkipSources()) {
throw new JadxException("--output-dir-src must be specified");
}
if(outDirSrc != null && outDirRes == null && !args.isSkipResources()) {
throw new JadxException("--output-dir-res must be specified");
}
} }
this.passes = Jadx.getPassesList(args, outDir);
this.codeGen = new CodeGen(args); void init() {
this.passes = Jadx.getPassesList(args);
this.codeGen = new CodeGen();
} }
void reset() { void reset() {
...@@ -135,23 +114,18 @@ public final class JadxDecompiler { ...@@ -135,23 +114,18 @@ public final class JadxDecompiler {
return Jadx.getVersion(); return Jadx.getVersion();
} }
public void loadFile(File file) throws JadxException { private void loadFiles(List<File> files) {
loadFiles(Collections.singletonList(file));
}
public void loadFiles(List<File> files) throws JadxException {
if (files.isEmpty()) { if (files.isEmpty()) {
throw new JadxException("Empty file list"); throw new JadxRuntimeException("Empty file list");
} }
inputFiles.clear(); inputFiles.clear();
for (File file : files) { for (File file : files) {
try { try {
InputFile.addFilesFrom(file, inputFiles, args.isSkipSources()); InputFile.addFilesFrom(file, inputFiles, args.isSkipSources());
} catch (IOException e) { } catch (Exception e) {
throw new JadxException("Error load file: " + file, e); throw new JadxRuntimeException("Error load file: " + file, e);
} }
} }
parse();
} }
public void save() { public void save() {
...@@ -194,13 +168,13 @@ public final class JadxDecompiler { ...@@ -194,13 +168,13 @@ public final class JadxDecompiler {
File sourcesOutDir; File sourcesOutDir;
File resOutDir; File resOutDir;
if (args.isExportAsGradleProject()) { if (args.isExportAsGradleProject()) {
ExportGradleProject export = new ExportGradleProject(root, outDir); ExportGradleProject export = new ExportGradleProject(root, args.getOutDir());
export.init(); export.init();
sourcesOutDir = export.getSrcOutDir(); sourcesOutDir = export.getSrcOutDir();
resOutDir = export.getResOutDir(); resOutDir = export.getResOutDir();
} else { } else {
sourcesOutDir = outDirSrc; sourcesOutDir = args.getOutDirSrc();
resOutDir = outDirRes; resOutDir = args.getOutDirRes();
} }
if (saveSources) { if (saveSources) {
appendSourcesSave(executor, sourcesOutDir); appendSourcesSave(executor, sourcesOutDir);
...@@ -294,21 +268,6 @@ public final class JadxDecompiler { ...@@ -294,21 +268,6 @@ public final class JadxDecompiler {
root.getErrorsCounter().printReport(); root.getErrorsCounter().printReport();
} }
void parse() throws JadxException {
reset();
init();
root = new RootNode(args);
LOG.info("loading ...");
root.load(inputFiles);
root.initClassPath();
root.loadResources(getResources());
root.initAppResClass();
initVisitors();
}
private void initVisitors() { private void initVisitors() {
for (IDexTreeVisitor pass : passes) { for (IDexTreeVisitor pass : passes) {
try { try {
...@@ -346,7 +305,7 @@ public final class JadxDecompiler { ...@@ -346,7 +305,7 @@ public final class JadxDecompiler {
return fieldsMap; return fieldsMap;
} }
public IJadxArgs getArgs() { public JadxArgs getArgs() {
return args; return args;
} }
...@@ -354,5 +313,4 @@ public final class JadxDecompiler { ...@@ -354,5 +313,4 @@ public final class JadxDecompiler {
public String toString() { public String toString() {
return "jadx decompiler " + getVersion(); return "jadx decompiler " + getVersion();
} }
} }
package jadx.core; package jadx.core;
import jadx.api.IJadxArgs; import java.net.URL;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
import java.util.jar.Manifest;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import jadx.api.JadxArgs;
import jadx.core.dex.visitors.ClassModifier; import jadx.core.dex.visitors.ClassModifier;
import jadx.core.dex.visitors.CodeShrinker; import jadx.core.dex.visitors.CodeShrinker;
import jadx.core.dex.visitors.ConstInlineVisitor; import jadx.core.dex.visitors.ConstInlineVisitor;
...@@ -33,16 +42,6 @@ import jadx.core.dex.visitors.ssa.SSATransform; ...@@ -33,16 +42,6 @@ import jadx.core.dex.visitors.ssa.SSATransform;
import jadx.core.dex.visitors.typeinference.FinishTypeInference; import jadx.core.dex.visitors.typeinference.FinishTypeInference;
import jadx.core.dex.visitors.typeinference.TypeInference; import jadx.core.dex.visitors.typeinference.TypeInference;
import java.io.File;
import java.net.URL;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
import java.util.jar.Manifest;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class Jadx { public class Jadx {
private static final Logger LOG = LoggerFactory.getLogger(Jadx.class); private static final Logger LOG = LoggerFactory.getLogger(Jadx.class);
...@@ -55,7 +54,7 @@ public class Jadx { ...@@ -55,7 +54,7 @@ public class Jadx {
} }
} }
public static List<IDexTreeVisitor> getPassesList(IJadxArgs args, File outDir) { public static List<IDexTreeVisitor> getPassesList(JadxArgs args) {
List<IDexTreeVisitor> passes = new ArrayList<>(); List<IDexTreeVisitor> passes = new ArrayList<>();
if (args.isFallbackMode()) { if (args.isFallbackMode()) {
passes.add(new FallbackModeVisitor()); passes.add(new FallbackModeVisitor());
...@@ -71,7 +70,7 @@ public class Jadx { ...@@ -71,7 +70,7 @@ public class Jadx {
passes.add(new TypeInference()); passes.add(new TypeInference());
if (args.isRawCFGOutput()) { if (args.isRawCFGOutput()) {
passes.add(DotGraphVisitor.dumpRaw(outDir)); passes.add(DotGraphVisitor.dumpRaw());
} }
passes.add(new ConstInlineVisitor()); passes.add(new ConstInlineVisitor());
...@@ -83,8 +82,8 @@ public class Jadx { ...@@ -83,8 +82,8 @@ public class Jadx {
passes.add(new CodeShrinker()); passes.add(new CodeShrinker());
passes.add(new ReSugarCode()); passes.add(new ReSugarCode());
if (args.isCFGOutput()) { if (args.isCfgOutput()) {
passes.add(DotGraphVisitor.dump(outDir)); passes.add(DotGraphVisitor.dump());
} }
passes.add(new RegionMakerVisitor()); passes.add(new RegionMakerVisitor());
...@@ -95,8 +94,8 @@ public class Jadx { ...@@ -95,8 +94,8 @@ public class Jadx {
passes.add(new SimplifyVisitor()); passes.add(new SimplifyVisitor());
passes.add(new CheckRegions()); passes.add(new CheckRegions());
if (args.isCFGOutput()) { if (args.isCfgOutput()) {
passes.add(DotGraphVisitor.dumpRegions(outDir)); passes.add(DotGraphVisitor.dumpRegions());
} }
passes.add(new MethodInlineVisitor()); passes.add(new MethodInlineVisitor());
......
...@@ -12,7 +12,7 @@ import java.util.Set; ...@@ -12,7 +12,7 @@ import java.util.Set;
import com.android.dx.rop.code.AccessFlags; import com.android.dx.rop.code.AccessFlags;
import jadx.api.IJadxArgs; import jadx.api.JadxArgs;
import jadx.core.dex.attributes.AFlag; import jadx.core.dex.attributes.AFlag;
import jadx.core.dex.attributes.AType; import jadx.core.dex.attributes.AType;
import jadx.core.dex.attributes.AttrNode; import jadx.core.dex.attributes.AttrNode;
...@@ -48,8 +48,8 @@ public class ClassGen { ...@@ -48,8 +48,8 @@ public class ClassGen {
private final Set<ClassInfo> imports = new HashSet<>(); private final Set<ClassInfo> imports = new HashSet<>();
private int clsDeclLine; private int clsDeclLine;
public ClassGen(ClassNode cls, IJadxArgs jadxArgs) { public ClassGen(ClassNode cls, JadxArgs jadxArgs) {
this(cls, null, jadxArgs.isUsingImports(), jadxArgs.isFallbackMode(), jadxArgs.isShowInconsistentCode()); this(cls, null, jadxArgs.isUseImports(), jadxArgs.isFallbackMode(), jadxArgs.isShowInconsistentCode());
} }
public ClassGen(ClassNode cls, ClassGen parentClsGen) { public ClassGen(ClassNode cls, ClassGen parentClsGen) {
......
package jadx.core.codegen; package jadx.core.codegen;
import jadx.api.IJadxArgs;
import jadx.core.dex.nodes.ClassNode; import jadx.core.dex.nodes.ClassNode;
import jadx.core.dex.visitors.AbstractVisitor; import jadx.core.dex.visitors.AbstractVisitor;
import jadx.core.utils.exceptions.CodegenException; import jadx.core.utils.exceptions.CodegenException;
public class CodeGen extends AbstractVisitor { public class CodeGen extends AbstractVisitor {
private final IJadxArgs args;
public CodeGen(IJadxArgs args) {
this.args = args;
}
@Override @Override
public boolean visit(ClassNode cls) throws CodegenException { public boolean visit(ClassNode cls) throws CodegenException {
ClassGen clsGen = new ClassGen(cls, args); ClassGen clsGen = new ClassGen(cls, cls.root().getArgs());
CodeWriter clsCode = clsGen.makeClass(); CodeWriter clsCode = clsGen.makeClass();
clsCode.finish(); clsCode.finish();
cls.setCode(clsCode); cls.setCode(clsCode);
return false; return false;
} }
} }
package jadx.core.deobf; package jadx.core.deobf;
import jadx.api.IJadxArgs; import jadx.api.JadxArgs;
import jadx.core.dex.attributes.AType; import jadx.core.dex.attributes.AType;
import jadx.core.dex.attributes.nodes.SourceFileAttr; import jadx.core.dex.attributes.nodes.SourceFileAttr;
import jadx.core.dex.info.ClassInfo; import jadx.core.dex.info.ClassInfo;
...@@ -34,7 +34,7 @@ public class Deobfuscator { ...@@ -34,7 +34,7 @@ public class Deobfuscator {
public static final String CLASS_NAME_SEPARATOR = "."; public static final String CLASS_NAME_SEPARATOR = ".";
public static final String INNER_CLASS_SEPARATOR = "$"; public static final String INNER_CLASS_SEPARATOR = "$";
private final IJadxArgs args; private final JadxArgs args;
@NotNull @NotNull
private final List<DexNode> dexNodes; private final List<DexNode> dexNodes;
private final DeobfPresets deobfPresets; private final DeobfPresets deobfPresets;
...@@ -58,13 +58,13 @@ public class Deobfuscator { ...@@ -58,13 +58,13 @@ public class Deobfuscator {
private int fldIndex = 0; private int fldIndex = 0;
private int mthIndex = 0; private int mthIndex = 0;
public Deobfuscator(IJadxArgs args, @NotNull List<DexNode> dexNodes, File deobfMapFile) { public Deobfuscator(JadxArgs args, @NotNull List<DexNode> dexNodes, File deobfMapFile) {
this.args = args; this.args = args;
this.dexNodes = dexNodes; this.dexNodes = dexNodes;
this.minLength = args.getDeobfuscationMinLength(); this.minLength = args.getDeobfuscationMinLength();
this.maxLength = args.getDeobfuscationMaxLength(); this.maxLength = args.getDeobfuscationMaxLength();
this.useSourceNameAsAlias = args.useSourceNameAsClassAlias(); this.useSourceNameAsAlias = args.isUseSourceNameAsClassAlias();
this.deobfPresets = new DeobfPresets(this, deobfMapFile); this.deobfPresets = new DeobfPresets(this, deobfMapFile);
} }
......
...@@ -8,7 +8,7 @@ import java.util.Set; ...@@ -8,7 +8,7 @@ import java.util.Set;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import jadx.api.IJadxArgs; import jadx.api.JadxArgs;
import jadx.core.dex.attributes.AType; import jadx.core.dex.attributes.AType;
import jadx.core.dex.instructions.args.LiteralArg; import jadx.core.dex.instructions.args.LiteralArg;
import jadx.core.dex.instructions.args.PrimitiveType; import jadx.core.dex.instructions.args.PrimitiveType;
...@@ -60,7 +60,7 @@ public class ConstStorage { ...@@ -60,7 +60,7 @@ public class ConstStorage {
private Map<Integer, String> resourcesNames = new HashMap<>(); private Map<Integer, String> resourcesNames = new HashMap<>();
public ConstStorage(IJadxArgs args) { public ConstStorage(JadxArgs args) {
this.replaceEnabled = args.isReplaceConsts(); this.replaceEnabled = args.isReplaceConsts();
} }
......
...@@ -65,7 +65,7 @@ public class ClassNode extends LineAttrNode implements ILoadable, IDexNode { ...@@ -65,7 +65,7 @@ public class ClassNode extends LineAttrNode implements ILoadable, IDexNode {
// cache maps // cache maps
private Map<MethodInfo, MethodNode> mthInfoMap = Collections.emptyMap(); private Map<MethodInfo, MethodNode> mthInfoMap = Collections.emptyMap();
public ClassNode(DexNode dex, ClassDef cls) throws DecodeException { public ClassNode(DexNode dex, ClassDef cls) {
this.dex = dex; this.dex = dex;
this.clsInfo = ClassInfo.fromDex(dex, cls.getTypeIndex()); this.clsInfo = ClassInfo.fromDex(dex, cls.getTypeIndex());
try { try {
...@@ -128,7 +128,7 @@ public class ClassNode extends LineAttrNode implements ILoadable, IDexNode { ...@@ -128,7 +128,7 @@ public class ClassNode extends LineAttrNode implements ILoadable, IDexNode {
buildCache(); buildCache();
} catch (Exception e) { } catch (Exception e) {
throw new DecodeException("Error decode class: " + clsInfo, e); throw new JadxRuntimeException("Error decode class: " + clsInfo, e);
} }
} }
......
...@@ -46,7 +46,7 @@ public class DexNode implements IDexNode { ...@@ -46,7 +46,7 @@ public class DexNode implements IDexNode {
this.dexId = dexId; this.dexId = dexId;
} }
public void loadClasses() throws DecodeException { public void loadClasses() {
for (ClassDef cls : dexBuf.classDefs()) { for (ClassDef cls : dexBuf.classDefs()) {
ClassNode clsNode = new ClassNode(this, cls); ClassNode clsNode = new ClassNode(this, cls);
classes.add(clsNode); classes.add(clsNode);
......
package jadx.core.dex.nodes; package jadx.core.dex.nodes;
import jadx.api.IJadxArgs; import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import org.jetbrains.annotations.Nullable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import jadx.api.JadxArgs;
import jadx.api.ResourceFile; import jadx.api.ResourceFile;
import jadx.api.ResourceType; import jadx.api.ResourceType;
import jadx.api.ResourcesLoader; import jadx.api.ResourcesLoader;
...@@ -11,28 +20,19 @@ import jadx.core.dex.info.InfoStorage; ...@@ -11,28 +20,19 @@ import jadx.core.dex.info.InfoStorage;
import jadx.core.utils.ErrorsCounter; import jadx.core.utils.ErrorsCounter;
import jadx.core.utils.StringUtils; import jadx.core.utils.StringUtils;
import jadx.core.utils.android.AndroidResourcesUtils; import jadx.core.utils.android.AndroidResourcesUtils;
import jadx.core.utils.exceptions.DecodeException;
import jadx.core.utils.exceptions.JadxException; import jadx.core.utils.exceptions.JadxException;
import jadx.core.utils.exceptions.JadxRuntimeException;
import jadx.core.utils.files.DexFile; import jadx.core.utils.files.DexFile;
import jadx.core.utils.files.InputFile; import jadx.core.utils.files.InputFile;
import jadx.core.xmlgen.ResContainer; import jadx.core.xmlgen.ResContainer;
import jadx.core.xmlgen.ResTableParser; import jadx.core.xmlgen.ResTableParser;
import jadx.core.xmlgen.ResourceStorage; import jadx.core.xmlgen.ResourceStorage;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import org.jetbrains.annotations.Nullable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class RootNode { public class RootNode {
private static final Logger LOG = LoggerFactory.getLogger(RootNode.class); private static final Logger LOG = LoggerFactory.getLogger(RootNode.class);
private final ErrorsCounter errorsCounter = new ErrorsCounter(); private final ErrorsCounter errorsCounter = new ErrorsCounter();
private final IJadxArgs args; private final JadxArgs args;
private final StringUtils stringUtils; private final StringUtils stringUtils;
private final ConstStorage constValues; private final ConstStorage constValues;
private final InfoStorage infoStorage = new InfoStorage(); private final InfoStorage infoStorage = new InfoStorage();
...@@ -43,13 +43,13 @@ public class RootNode { ...@@ -43,13 +43,13 @@ public class RootNode {
private ClassNode appResClass; private ClassNode appResClass;
private ClspGraph clsp; private ClspGraph clsp;
public RootNode(IJadxArgs args) { public RootNode(JadxArgs args) {
this.args = args; this.args = args;
this.stringUtils = new StringUtils(args); this.stringUtils = new StringUtils(args);
this.constValues = new ConstStorage(args); this.constValues = new ConstStorage(args);
} }
public void load(List<InputFile> inputFiles) throws DecodeException { public void load(List<InputFile> inputFiles) {
dexNodes = new ArrayList<>(); dexNodes = new ArrayList<>();
for (InputFile input : inputFiles) { for (InputFile input : inputFiles) {
for (DexFile dexFile : input.getDexFiles()) { for (DexFile dexFile : input.getDexFiles()) {
...@@ -58,7 +58,7 @@ public class RootNode { ...@@ -58,7 +58,7 @@ public class RootNode {
DexNode dexNode = new DexNode(this, dexFile, dexNodes.size()); DexNode dexNode = new DexNode(this, dexFile, dexNodes.size());
dexNodes.add(dexNode); dexNodes.add(dexNode);
} catch (Exception e) { } catch (Exception e) {
throw new DecodeException("Error decode file: " + dexFile, e); throw new JadxRuntimeException("Error decode file: " + dexFile, e);
} }
} }
} }
...@@ -103,22 +103,22 @@ public class RootNode { ...@@ -103,22 +103,22 @@ public class RootNode {
appResClass = AndroidResourcesUtils.searchAppResClass(this); appResClass = AndroidResourcesUtils.searchAppResClass(this);
} }
public void initClassPath() throws DecodeException { public void initClassPath() {
try { try {
if (this.clsp == null) { if (this.clsp == null) {
ClspGraph clsp = new ClspGraph(); ClspGraph newClsp = new ClspGraph();
clsp.load(); newClsp.load();
List<ClassNode> classes = new ArrayList<>(); List<ClassNode> classes = new ArrayList<>();
for (DexNode dexNode : dexNodes) { for (DexNode dexNode : dexNodes) {
classes.addAll(dexNode.getClasses()); classes.addAll(dexNode.getClasses());
} }
clsp.addApp(classes); newClsp.addApp(classes);
this.clsp = clsp; this.clsp = newClsp;
} }
} catch (IOException e) { } catch (Exception e) {
throw new DecodeException("Error loading classpath", e); throw new JadxRuntimeException("Error loading classpath", e);
} }
} }
...@@ -188,10 +188,6 @@ public class RootNode { ...@@ -188,10 +188,6 @@ public class RootNode {
return appResClass; return appResClass;
} }
public IJadxArgs getArgs() {
return args;
}
public StringUtils getStringUtils() { public StringUtils getStringUtils() {
return stringUtils; return stringUtils;
} }
...@@ -204,4 +200,7 @@ public class RootNode { ...@@ -204,4 +200,7 @@ public class RootNode {
return infoStorage; return infoStorage;
} }
public JadxArgs getArgs() {
return args;
}
} }
...@@ -23,42 +23,33 @@ import java.util.HashSet; ...@@ -23,42 +23,33 @@ import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Set; import java.util.Set;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class DotGraphVisitor extends AbstractVisitor { public class DotGraphVisitor extends AbstractVisitor {
private static final Logger LOG = LoggerFactory.getLogger(DotGraphVisitor.class);
private static final String NL = "\\l"; private static final String NL = "\\l";
private static final boolean PRINT_DOMINATORS = false; private static final boolean PRINT_DOMINATORS = false;
private final File dir;
private final boolean useRegions; private final boolean useRegions;
private final boolean rawInsn; private final boolean rawInsn;
public static DotGraphVisitor dump(File outDir) { public static DotGraphVisitor dump() {
return new DotGraphVisitor(outDir, false, false); return new DotGraphVisitor(false, false);
} }
public static DotGraphVisitor dumpRaw(File outDir) { public static DotGraphVisitor dumpRaw() {
return new DotGraphVisitor(outDir, false, true); return new DotGraphVisitor(false, true);
} }
public static DotGraphVisitor dumpRegions(File outDir) { public static DotGraphVisitor dumpRegions() {
return new DotGraphVisitor(outDir, true, false); return new DotGraphVisitor(true, false);
} }
public static DotGraphVisitor dumpRawRegions(File outDir) { public static DotGraphVisitor dumpRawRegions() {
return new DotGraphVisitor(outDir, true, true); return new DotGraphVisitor(true, true);
} }
private DotGraphVisitor(File outDir, boolean useRegions, boolean rawInsn) { private DotGraphVisitor(boolean useRegions, boolean rawInsn) {
this.dir = outDir;
this.useRegions = useRegions; this.useRegions = useRegions;
this.rawInsn = rawInsn; this.rawInsn = rawInsn;
LOG.debug("DOT {}{}graph dump dir: {}",
useRegions ? "regions " : "", rawInsn ? "raw " : "", outDir.getAbsolutePath());
} }
@Override @Override
...@@ -66,12 +57,25 @@ public class DotGraphVisitor extends AbstractVisitor { ...@@ -66,12 +57,25 @@ public class DotGraphVisitor extends AbstractVisitor {
if (mth.isNoCode()) { if (mth.isNoCode()) {
return; return;
} }
new DumpDotGraph().process(mth); File outRootDir = mth.root().getArgs().getOutDir();
new DumpDotGraph(outRootDir).process(mth);
}
public void save(File dir, MethodNode mth) {
if (mth.isNoCode()) {
return;
}
new DumpDotGraph(dir).process(mth);
} }
private class DumpDotGraph { private class DumpDotGraph {
private final CodeWriter dot = new CodeWriter(); private final CodeWriter dot = new CodeWriter();
private final CodeWriter conn = new CodeWriter(); private final CodeWriter conn = new CodeWriter();
private final File dir;
public DumpDotGraph(File dir) {
this.dir = dir;
}
public void process(MethodNode mth) { public void process(MethodNode mth) {
dot.startLine("digraph \"CFG for"); dot.startLine("digraph \"CFG for");
......
...@@ -7,7 +7,7 @@ import java.util.Set; ...@@ -7,7 +7,7 @@ import java.util.Set;
import org.apache.commons.io.FilenameUtils; import org.apache.commons.io.FilenameUtils;
import jadx.api.IJadxArgs; import jadx.api.JadxArgs;
import jadx.core.Consts; import jadx.core.Consts;
import jadx.core.codegen.TypeGen; import jadx.core.codegen.TypeGen;
import jadx.core.deobf.Deobfuscator; import jadx.core.deobf.Deobfuscator;
...@@ -31,8 +31,6 @@ public class RenameVisitor extends AbstractVisitor { ...@@ -31,8 +31,6 @@ public class RenameVisitor extends AbstractVisitor {
@Override @Override
public void init(RootNode root) { public void init(RootNode root) {
IJadxArgs args = root.getArgs();
List<DexNode> dexNodes = root.getDexNodes(); List<DexNode> dexNodes = root.getDexNodes();
if (dexNodes.isEmpty()) { if (dexNodes.isEmpty()) {
return; return;
...@@ -43,6 +41,7 @@ public class RenameVisitor extends AbstractVisitor { ...@@ -43,6 +41,7 @@ public class RenameVisitor extends AbstractVisitor {
String inputName = FilenameUtils.getBaseName(firstInputFileName); String inputName = FilenameUtils.getBaseName(firstInputFileName);
File deobfMapFile = new File(inputPath, inputName + ".jobf"); File deobfMapFile = new File(inputPath, inputName + ".jobf");
JadxArgs args = root.getArgs();
deobfuscator = new Deobfuscator(args, dexNodes, deobfMapFile); deobfuscator = new Deobfuscator(args, dexNodes, deobfMapFile);
boolean deobfuscationOn = args.isDeobfuscationOn(); boolean deobfuscationOn = args.isDeobfuscationOn();
if (deobfuscationOn) { if (deobfuscationOn) {
......
...@@ -2,7 +2,7 @@ package jadx.core.dex.visitors; ...@@ -2,7 +2,7 @@ package jadx.core.dex.visitors;
import java.io.File; import java.io.File;
import jadx.api.IJadxArgs; import jadx.api.JadxArgs;
import jadx.core.codegen.CodeWriter; import jadx.core.codegen.CodeWriter;
import jadx.core.dex.nodes.ClassNode; import jadx.core.dex.nodes.ClassNode;
...@@ -10,7 +10,7 @@ public class SaveCode { ...@@ -10,7 +10,7 @@ public class SaveCode {
private SaveCode() {} private SaveCode() {}
public static void save(File dir, IJadxArgs args, ClassNode cls) { public static void save(File dir, JadxArgs args, ClassNode cls) {
CodeWriter clsCode = cls.getCode(); CodeWriter clsCode = cls.getCode();
String fileName = cls.getClassInfo().getFullPath() + ".java"; String fileName = cls.getClassInfo().getFullPath() + ".java";
if (args.isFallbackMode()) { if (args.isFallbackMode()) {
......
...@@ -44,9 +44,9 @@ public class DebugUtils { ...@@ -44,9 +44,9 @@ public class DebugUtils {
public static void dump(MethodNode mth, String desc) { public static void dump(MethodNode mth, String desc) {
File out = new File("test-graph" + desc + "-tmp"); File out = new File("test-graph" + desc + "-tmp");
DotGraphVisitor.dump(out).visit(mth); DotGraphVisitor.dump().save(out, mth);
DotGraphVisitor.dumpRaw(out).visit(mth); DotGraphVisitor.dumpRaw().save(out, mth);
DotGraphVisitor.dumpRegions(out).visit(mth); DotGraphVisitor.dumpRegions().save(out, mth);
} }
public static void printRegionsWithBlock(MethodNode mth, BlockNode block) { public static void printRegionsWithBlock(MethodNode mth, BlockNode block) {
......
package jadx.core.utils; package jadx.core.utils;
import jadx.api.IJadxArgs; import jadx.api.JadxArgs;
public class StringUtils { public class StringUtils {
private final boolean escapeUnicode; private final boolean escapeUnicode;
public StringUtils(IJadxArgs args) { public StringUtils(JadxArgs args) {
this.escapeUnicode = args.escapeUnicode(); this.escapeUnicode = args.isEscapeUnicode();
} }
public String unescapeString(String str) { public String unescapeString(String str) {
......
...@@ -214,4 +214,12 @@ public class FileUtils { ...@@ -214,4 +214,12 @@ public class FileUtils {
} }
return IOCase.SYSTEM.isCaseSensitive(); return IOCase.SYSTEM.isCaseSensitive();
} }
public static File toFile(String path) {
if (path == null) {
return null;
}
return new File(path);
}
} }
package jadx.tests
import jadx.api.IJadxArgs
import jadx.api.JadxDecompiler
import jadx.core.utils.exceptions.JadxException
import jadx.core.utils.exceptions.JadxRuntimeException
import spock.lang.Specification
class TestAPI extends Specification {
def "no loaded files"() {
setup:
def d = new JadxDecompiler()
when:
def classes = d.getClasses()
def packages = d.getPackages()
then:
notThrown(NullPointerException)
classes?.isEmpty()
packages?.isEmpty()
}
def "save with no loaded files"() {
when:
new JadxDecompiler().save()
then:
def e = thrown(JadxRuntimeException)
e.message == "No loaded files"
}
def "load empty files list"() {
when:
new JadxDecompiler().loadFiles(Collections.emptyList())
then:
def e = thrown(JadxException)
e.message == "Empty file list"
}
def "load null"() {
when:
new JadxDecompiler().loadFile(null)
then:
thrown(NullPointerException)
}
def "load missing file"() {
when:
new JadxDecompiler().loadFile(new File("_.dex"))
then:
def e = thrown(JadxException)
e.message == "Error load file: _.dex"
e.cause.class == IOException
}
def "pass decompiler args"() {
setup:
def args = Mock(IJadxArgs)
when:
new JadxDecompiler(args)
then:
noExceptionThrown()
}
def "get errors count for new decompiler"() {
expect:
new JadxDecompiler().getErrorsCount() == 0
}
}
package jadx.api;
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import jadx.core.utils.files.FileUtils;
import static jadx.core.utils.files.FileUtils.toFile;
import static org.hamcrest.Matchers.is;
import static org.junit.Assert.assertThat;
public class JadxArgsValidatorOutDirsTest {
private static final Logger LOG = LoggerFactory.getLogger(JadxArgsValidatorOutDirsTest.class);
public JadxArgs args;
@Test
public void checkAllSet() {
setOutDirs("r", "s", "r");
checkOutDirs("r", "s", "r");
}
@Test
public void checkRootOnly() {
setOutDirs("out", null, null);
checkOutDirs("out", "out/" + JadxArgs.DEFAULT_SRC_DIR, "out/" + JadxArgs.DEFAULT_RES_DIR);
}
@Test
public void checkSrcOnly() {
setOutDirs(null, "src", null);
checkOutDirs("src", "src", "src/" + JadxArgs.DEFAULT_RES_DIR);
}
@Test
public void checkResOnly() {
setOutDirs(null, null, "res");
checkOutDirs("res", "res/" + JadxArgs.DEFAULT_SRC_DIR, "res");
}
@Test
public void checkNone() {
setOutDirs(null, null, null);
String inputFileBase = args.getInputFiles().get(0).getName().replace(".apk", "");
checkOutDirs(inputFileBase,
inputFileBase + "/" + JadxArgs.DEFAULT_SRC_DIR,
inputFileBase + "/" + JadxArgs.DEFAULT_RES_DIR);
}
private void setOutDirs(String outDir, String srcDir, String resDir) {
args = makeArgs();
args.setOutDir(toFile(outDir));
args.setOutDirSrc(toFile(srcDir));
args.setOutDirRes(toFile(resDir));
LOG.debug("Set dirs: out={}, src={}, res={}", outDir, srcDir, resDir);
}
private void checkOutDirs(String outDir, String srcDir, String resDir) {
JadxArgsValidator.validate(args);
LOG.debug("Got dirs: out={}, src={}, res={}", args.getOutDir(), args.getOutDirSrc(), args.getOutDirRes());
assertThat(args.getOutDir(), is(toFile(outDir)));
assertThat(args.getOutDirSrc(), is(toFile(srcDir)));
assertThat(args.getOutDirRes(), is(toFile(resDir)));
}
private JadxArgs makeArgs() {
JadxArgs args = new JadxArgs();
args.getInputFiles().add(FileUtils.createTempFile("some.apk"));
return args;
}
}
package jadx.api;
import java.io.File;
import org.junit.Ignore;
import org.junit.Test;
public class JadxDecompilerTest {
@Test
@Ignore
public void testExampleUsage() {
JadxArgs args = new JadxArgs();
args.getInputFiles().add(new File("test.apk"));
args.setOutDir(new File("jadx-test-output"));
JadxDecompiler jadx = new JadxDecompiler(args);
jadx.load();
jadx.save();
}
// TODO make more tests
}
...@@ -10,7 +10,6 @@ import java.net.URISyntaxException; ...@@ -10,7 +10,6 @@ import java.net.URISyntaxException;
import java.net.URL; import java.net.URL;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.Iterator;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.jar.JarOutputStream; import java.util.jar.JarOutputStream;
...@@ -29,7 +28,6 @@ import jadx.core.dex.nodes.RootNode; ...@@ -29,7 +28,6 @@ import jadx.core.dex.nodes.RootNode;
import jadx.core.dex.visitors.DepthTraversal; import jadx.core.dex.visitors.DepthTraversal;
import jadx.core.dex.visitors.IDexTreeVisitor; import jadx.core.dex.visitors.IDexTreeVisitor;
import jadx.core.utils.exceptions.CodegenException; import jadx.core.utils.exceptions.CodegenException;
import jadx.core.utils.exceptions.JadxException;
import jadx.tests.api.compiler.DynamicCompiler; import jadx.tests.api.compiler.DynamicCompiler;
import jadx.tests.api.compiler.StaticCompiler; import jadx.tests.api.compiler.StaticCompiler;
import jadx.tests.api.utils.TestUtils; import jadx.tests.api.utils.TestUtils;
...@@ -65,6 +63,7 @@ public abstract class IntegrationTest extends TestUtils { ...@@ -65,6 +63,7 @@ public abstract class IntegrationTest extends TestUtils {
public IntegrationTest() { public IntegrationTest() {
args = new JadxArgs(); args = new JadxArgs();
args.setOutDir(new File(outDir));
args.setShowInconsistentCode(true); args.setShowInconsistentCode(true);
args.setThreadsCount(1); args.setThreadsCount(1);
args.setSkipResources(true); args.setSkipResources(true);
...@@ -84,9 +83,10 @@ public abstract class IntegrationTest extends TestUtils { ...@@ -84,9 +83,10 @@ public abstract class IntegrationTest extends TestUtils {
public ClassNode getClassNodeFromFile(File file, String clsName) { public ClassNode getClassNodeFromFile(File file, String clsName) {
JadxDecompiler d = null; JadxDecompiler d = null;
try { try {
args.setInputFiles(Collections.singletonList(file));
d = new JadxDecompiler(args); d = new JadxDecompiler(args);
d.loadFile(file); d.load();
} catch (JadxException e) { } catch (Exception e) {
e.printStackTrace(); e.printStackTrace();
fail(e.getMessage()); fail(e.getMessage());
} }
...@@ -114,18 +114,18 @@ public abstract class IntegrationTest extends TestUtils { ...@@ -114,18 +114,18 @@ public abstract class IntegrationTest extends TestUtils {
} }
private void decompile(JadxDecompiler jadx, ClassNode cls) { private void decompile(JadxDecompiler jadx, ClassNode cls) {
List<IDexTreeVisitor> passes = Jadx.getPassesList(jadx.getArgs(), new File(outDir)); List<IDexTreeVisitor> passes = Jadx.getPassesList(jadx.getArgs());
ProcessClass.process(cls, passes, new CodeGen(jadx.getArgs())); ProcessClass.process(cls, passes, new CodeGen());
} }
private void decompileWithoutUnload(JadxDecompiler d, ClassNode cls) { private void decompileWithoutUnload(JadxDecompiler d, ClassNode cls) {
cls.load(); cls.load();
List<IDexTreeVisitor> passes = Jadx.getPassesList(d.getArgs(), new File(outDir)); List<IDexTreeVisitor> passes = Jadx.getPassesList(d.getArgs());
for (IDexTreeVisitor visitor : passes) { for (IDexTreeVisitor visitor : passes) {
DepthTraversal.visit(visitor, cls); DepthTraversal.visit(visitor, cls);
} }
try { try {
new CodeGen(d.getArgs()).visit(cls); new CodeGen().visit(cls);
} catch (CodegenException e) { } catch (CodegenException e) {
e.printStackTrace(); e.printStackTrace();
fail(e.getMessage()); fail(e.getMessage());
......
package jadx.tests.functional; package jadx.tests.functional;
import java.io.File;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashSet; import java.util.HashSet;
import java.util.List; import java.util.List;
...@@ -24,7 +23,7 @@ public class JadxVisitorsOrderTest { ...@@ -24,7 +23,7 @@ public class JadxVisitorsOrderTest {
@Test @Test
public void testOrder() { public void testOrder() {
List<IDexTreeVisitor> passes = Jadx.getPassesList(new JadxArgs(), new File("out")); List<IDexTreeVisitor> passes = Jadx.getPassesList(new JadxArgs());
List<String> errors = check(passes); List<String> errors = check(passes);
for (String str : errors) { for (String str : errors) {
......
...@@ -5,7 +5,6 @@ import javax.swing.*; ...@@ -5,7 +5,6 @@ import javax.swing.*;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import jadx.core.utils.exceptions.JadxException;
import jadx.gui.settings.JadxSettings; import jadx.gui.settings.JadxSettings;
import jadx.gui.settings.JadxSettingsAdapter; import jadx.gui.settings.JadxSettingsAdapter;
import jadx.gui.ui.MainWindow; import jadx.gui.ui.MainWindow;
...@@ -17,24 +16,17 @@ public class JadxGUI { ...@@ -17,24 +16,17 @@ public class JadxGUI {
public static void main(String[] args) { public static void main(String[] args) {
try { try {
LogCollector.register(); LogCollector.register();
final JadxSettings jadxArgs = JadxSettingsAdapter.load(); final JadxSettings settings = JadxSettingsAdapter.load();
// overwrite loaded settings by command line arguments // overwrite loaded settings by command line arguments
if (!jadxArgs.processArgs(args)) { if (!settings.processArgs(args)) {
return; return;
} }
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
SwingUtilities.invokeLater(new Runnable() { SwingUtilities.invokeLater(() -> {
public void run() { MainWindow window = new MainWindow(settings);
try {
MainWindow window = new MainWindow(jadxArgs);
window.open(); window.open();
}
catch(JadxException e) {
throw new RuntimeException(e);
}
}
}); });
} catch (Throwable e) { } catch (Exception e) {
LOG.error("Error: {}", e.getMessage(), e); LOG.error("Error: {}", e.getMessage(), e);
System.exit(1); System.exit(1);
} }
......
...@@ -2,38 +2,38 @@ package jadx.gui; ...@@ -2,38 +2,38 @@ package jadx.gui;
import javax.swing.*; import javax.swing.*;
import java.io.File; import java.io.File;
import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.ThreadPoolExecutor;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import jadx.api.IJadxArgs;
import jadx.api.JadxDecompiler; import jadx.api.JadxDecompiler;
import jadx.api.JavaClass; import jadx.api.JavaClass;
import jadx.api.JavaPackage; import jadx.api.JavaPackage;
import jadx.api.ResourceFile; import jadx.api.ResourceFile;
import jadx.core.utils.exceptions.DecodeException; import jadx.gui.settings.JadxSettings;
import jadx.core.utils.exceptions.JadxException;
public class JadxWrapper { public class JadxWrapper {
private static final Logger LOG = LoggerFactory.getLogger(JadxWrapper.class); private static final Logger LOG = LoggerFactory.getLogger(JadxWrapper.class);
private final JadxDecompiler decompiler; private final JadxSettings settings;
private JadxDecompiler decompiler;
private File openFile; private File openFile;
public JadxWrapper(IJadxArgs jadxArgs) throws JadxException { public JadxWrapper(JadxSettings settings) {
this.decompiler = new JadxDecompiler(jadxArgs); this.settings = settings;
} }
public void openFile(File file) { public void openFile(File file) {
this.openFile = file; this.openFile = file;
try { try {
this.decompiler.loadFile(file); this.decompiler = new JadxDecompiler(settings.toJadxArgs());
} catch (DecodeException e) { this.decompiler.getArgs().setInputFiles(Collections.singletonList(file));
LOG.error("Error decode file: {}", file, e); this.decompiler.load();
} catch (JadxException e) { } catch (Exception e) {
LOG.error("Error open file: {}", file, e); LOG.error("Error load file: {}", file, e);
} }
} }
...@@ -42,7 +42,7 @@ public class JadxWrapper { ...@@ -42,7 +42,7 @@ public class JadxWrapper {
@Override @Override
public void run() { public void run() {
try { try {
decompiler.setOutputDir(dir); decompiler.getArgs().setRootDir(dir);
ThreadPoolExecutor ex = (ThreadPoolExecutor) decompiler.getSaveExecutor(); ThreadPoolExecutor ex = (ThreadPoolExecutor) decompiler.getSaveExecutor();
ex.shutdown(); ex.shutdown();
while (ex.isTerminating()) { while (ex.isTerminating()) {
...@@ -53,7 +53,7 @@ public class JadxWrapper { ...@@ -53,7 +53,7 @@ public class JadxWrapper {
} }
progressMonitor.close(); progressMonitor.close();
LOG.info("done"); LOG.info("done");
} catch (InterruptedException|JadxException e) { } catch (InterruptedException e) {
LOG.error("Save interrupted", e); LOG.error("Save interrupted", e);
Thread.currentThread().interrupt(); Thread.currentThread().interrupt();
} }
......
...@@ -11,6 +11,7 @@ import java.util.Set; ...@@ -11,6 +11,7 @@ import java.util.Set;
import org.fife.ui.rsyntaxtextarea.RSyntaxTextArea; import org.fife.ui.rsyntaxtextarea.RSyntaxTextArea;
import jadx.api.JadxArgs;
import jadx.cli.JadxCLIArgs; import jadx.cli.JadxCLIArgs;
public class JadxSettings extends JadxCLIArgs { public class JadxSettings extends JadxCLIArgs {
...@@ -44,7 +45,7 @@ public class JadxSettings extends JadxCLIArgs { ...@@ -44,7 +45,7 @@ public class JadxSettings extends JadxCLIArgs {
public void fixOnLoad() { public void fixOnLoad() {
if (threadsCount <= 0) { if (threadsCount <= 0) {
threadsCount = DEFAULT_THREADS_COUNT; threadsCount = JadxArgs.DEFAULT_THREADS_COUNT;
} }
} }
...@@ -165,8 +166,8 @@ public class JadxSettings extends JadxCLIArgs { ...@@ -165,8 +166,8 @@ public class JadxSettings extends JadxCLIArgs {
this.deobfuscationForceSave = deobfuscationForceSave; this.deobfuscationForceSave = deobfuscationForceSave;
} }
public void setUseSourceNameAsClassAlias(boolean useSourceNameAsAlias) { public void setDeobfuscationUseSourceNameAsAlias(boolean deobfuscationUseSourceNameAsAlias) {
this.deobfuscationUseSourceNameAsAlias = useSourceNameAsAlias; this.deobfuscationUseSourceNameAsAlias = deobfuscationUseSourceNameAsAlias;
} }
public void setEscapeUnicode(boolean escapeUnicode) { public void setEscapeUnicode(boolean escapeUnicode) {
......
...@@ -145,10 +145,10 @@ public class JadxSettingsWindow extends JDialog { ...@@ -145,10 +145,10 @@ public class JadxSettingsWindow extends JDialog {
}); });
JCheckBox deobfSourceAlias = new JCheckBox(); JCheckBox deobfSourceAlias = new JCheckBox();
deobfSourceAlias.setSelected(settings.useSourceNameAsClassAlias()); deobfSourceAlias.setSelected(settings.isDeobfuscationUseSourceNameAsAlias());
deobfSourceAlias.addItemListener(new ItemListener() { deobfSourceAlias.addItemListener(new ItemListener() {
public void itemStateChanged(ItemEvent e) { public void itemStateChanged(ItemEvent e) {
settings.setUseSourceNameAsClassAlias(e.getStateChange() == ItemEvent.SELECTED); settings.setDeobfuscationUseSourceNameAsAlias(e.getStateChange() == ItemEvent.SELECTED);
needReload(); needReload();
} }
}); });
...@@ -219,6 +219,7 @@ public class JadxSettingsWindow extends JDialog { ...@@ -219,6 +219,7 @@ public class JadxSettingsWindow extends JDialog {
@Override @Override
public void stateChanged(ChangeEvent e) { public void stateChanged(ChangeEvent e) {
settings.setThreadsCount((Integer) threadsCount.getValue()); settings.setThreadsCount((Integer) threadsCount.getValue());
needReload();
} }
}); });
......
...@@ -27,12 +27,13 @@ import java.util.Arrays; ...@@ -27,12 +27,13 @@ import java.util.Arrays;
import java.util.EnumSet; import java.util.EnumSet;
import java.util.Timer; import java.util.Timer;
import java.util.TimerTask; import java.util.TimerTask;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import jadx.api.ResourceFile; import jadx.api.ResourceFile;
import jadx.core.utils.exceptions.JadxException;
import jadx.gui.JadxWrapper; import jadx.gui.JadxWrapper;
import jadx.gui.jobs.BackgroundWorker; import jadx.gui.jobs.BackgroundWorker;
import jadx.gui.jobs.DecompileJob; import jadx.gui.jobs.DecompileJob;
...@@ -101,7 +102,7 @@ public class MainWindow extends JFrame { ...@@ -101,7 +102,7 @@ public class MainWindow extends JFrame {
private transient ProgressPanel progressPane; private transient ProgressPanel progressPane;
private transient BackgroundWorker backgroundWorker; private transient BackgroundWorker backgroundWorker;
public MainWindow(JadxSettings settings) throws JadxException { public MainWindow(JadxSettings settings) {
this.wrapper = new JadxWrapper(settings); this.wrapper = new JadxWrapper(settings);
this.settings = settings; this.settings = settings;
this.cacheObject = new CacheObject(); this.cacheObject = new CacheObject();
...@@ -119,10 +120,10 @@ public class MainWindow extends JFrame { ...@@ -119,10 +120,10 @@ public class MainWindow extends JFrame {
setLocationRelativeTo(null); setLocationRelativeTo(null);
setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE); setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
if (settings.getInput().isEmpty()) { if (settings.getFiles().isEmpty()) {
openFile(); openFile();
} else { } else {
openFile(settings.getInput().get(0)); openFile(new File(settings.getFiles().get(0)));
} }
} }
...@@ -689,5 +690,4 @@ public class MainWindow extends JFrame { ...@@ -689,5 +690,4 @@ public class MainWindow extends JFrame {
public void menuCanceled(MenuEvent e) { public void menuCanceled(MenuEvent e) {
} }
} }
} }
...@@ -7,7 +7,7 @@ import org.junit.Before; ...@@ -7,7 +7,7 @@ import org.junit.Before;
import org.junit.Test; import org.junit.Test;
import jadx.api.Factory; import jadx.api.Factory;
import jadx.api.IJadxArgs; import jadx.api.JadxArgs;
import jadx.api.JadxDecompiler; import jadx.api.JadxDecompiler;
import jadx.api.JavaClass; import jadx.api.JavaClass;
import jadx.api.JavaPackage; import jadx.api.JavaPackage;
...@@ -30,7 +30,7 @@ public class JSourcesTest { ...@@ -30,7 +30,7 @@ public class JSourcesTest {
when(root.isFlatPackages()).thenReturn(false); when(root.isFlatPackages()).thenReturn(false);
JadxWrapper wrapper = mock(JadxWrapper.class); JadxWrapper wrapper = mock(JadxWrapper.class);
sources = new JSources(root, wrapper); sources = new JSources(root, wrapper);
decompiler = new JadxDecompiler(mock(IJadxArgs.class)); decompiler = new JadxDecompiler(new JadxArgs());
} }
@Test @Test
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment