cli: update jcommander lib
This commit is contained in:
@@ -5,7 +5,7 @@ applicationName = 'jadx'
|
||||
|
||||
dependencies {
|
||||
compile(project(':jadx-core'))
|
||||
compile 'com.beust:jcommander:1.47'
|
||||
compile 'com.beust:jcommander:1.72'
|
||||
compile 'ch.qos.logback:logback-classic:1.2.3'
|
||||
}
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@ import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import jadx.api.JadxDecompiler;
|
||||
import jadx.core.utils.exceptions.JadxArgsValidateException;
|
||||
|
||||
public class JadxCLI {
|
||||
private static final Logger LOG = LoggerFactory.getLogger(JadxCLI.class);
|
||||
@@ -22,7 +23,12 @@ public class JadxCLI {
|
||||
|
||||
static void processAndSave(JadxCLIArgs inputArgs) {
|
||||
JadxDecompiler jadx = new JadxDecompiler(inputArgs.toJadxArgs());
|
||||
jadx.load();
|
||||
try {
|
||||
jadx.load();
|
||||
} catch (JadxArgsValidateException e) {
|
||||
LOG.error("Incorrect arguments: {}", e.getMessage());
|
||||
System.exit(1);
|
||||
}
|
||||
jadx.save();
|
||||
if (jadx.getErrorsCount() != 0) {
|
||||
jadx.printErrorsReport();
|
||||
|
||||
@@ -10,7 +10,6 @@ import java.util.stream.Collectors;
|
||||
|
||||
import ch.qos.logback.classic.spi.ILoggingEvent;
|
||||
import ch.qos.logback.core.Appender;
|
||||
import com.beust.jcommander.IStringConverter;
|
||||
import com.beust.jcommander.JCommander;
|
||||
import com.beust.jcommander.Parameter;
|
||||
import com.beust.jcommander.ParameterDescription;
|
||||
@@ -25,7 +24,7 @@ import jadx.core.utils.files.FileUtils;
|
||||
|
||||
public class JadxCLIArgs {
|
||||
|
||||
@Parameter(description = "<input file> (.dex, .apk, .jar or .class)")
|
||||
@Parameter(description = "<input file> (.apk, .dex, .jar or .class)")
|
||||
protected List<String> files = new ArrayList<>(1);
|
||||
|
||||
@Parameter(names = {"-d", "--output-dir"}, description = "output directory")
|
||||
@@ -37,9 +36,6 @@ public class JadxCLIArgs {
|
||||
@Parameter(names = {"-dr", "--output-dir-res"}, description = "output directory for resources")
|
||||
protected String outDirRes;
|
||||
|
||||
@Parameter(names = {"-j", "--threads-count"}, description = "processing threads count")
|
||||
protected int threadsCount = JadxArgs.DEFAULT_THREADS_COUNT;
|
||||
|
||||
@Parameter(names = {"-r", "--no-res"}, description = "do not decode resources")
|
||||
protected boolean skipResources = false;
|
||||
|
||||
@@ -49,15 +45,16 @@ public class JadxCLIArgs {
|
||||
@Parameter(names = {"-e", "--export-gradle"}, description = "save as android gradle project")
|
||||
protected boolean exportAsGradleProject = false;
|
||||
|
||||
@Parameter(names = {"-j", "--threads-count"}, description = "processing threads count")
|
||||
protected int threadsCount = JadxArgs.DEFAULT_THREADS_COUNT;
|
||||
|
||||
@Parameter(names = {"--show-bad-code"}, description = "show inconsistent code (incorrectly decompiled)")
|
||||
protected boolean showInconsistentCode = false;
|
||||
|
||||
@Parameter(names = {"--no-imports"}, converter = InvertedBooleanConverter.class,
|
||||
description = "disable use of imports, always write entire package name")
|
||||
@Parameter(names = {"--no-imports"}, description = "disable use of imports, always write entire package name")
|
||||
protected boolean useImports = true;
|
||||
|
||||
@Parameter(names = "--no-replace-consts", converter = InvertedBooleanConverter.class,
|
||||
description = "don't replace constant value with matching constant field")
|
||||
@Parameter(names = "--no-replace-consts", description = "don't replace constant value with matching constant field")
|
||||
protected boolean replaceConsts = true;
|
||||
|
||||
@Parameter(names = {"--escape-unicode"}, description = "escape non latin characters in strings (with \\u)")
|
||||
@@ -90,6 +87,9 @@ public class JadxCLIArgs {
|
||||
@Parameter(names = {"-v", "--verbose"}, description = "verbose output")
|
||||
protected boolean verbose = false;
|
||||
|
||||
@Parameter(names = {"--version"}, description = "print jadx version")
|
||||
protected boolean printVersion = false;
|
||||
|
||||
@Parameter(names = {"-h", "--help"}, description = "print this help", help = true)
|
||||
protected boolean printHelp = false;
|
||||
|
||||
@@ -99,7 +99,7 @@ public class JadxCLIArgs {
|
||||
|
||||
private boolean parse(String[] args) {
|
||||
try {
|
||||
new JCommander(this, args);
|
||||
makeJCommander().parse(args);
|
||||
return true;
|
||||
} catch (ParameterException e) {
|
||||
System.err.println("Arguments parse error: " + e.getMessage());
|
||||
@@ -108,16 +108,24 @@ public class JadxCLIArgs {
|
||||
}
|
||||
}
|
||||
|
||||
private JCommander makeJCommander() {
|
||||
return JCommander.newBuilder().addObject(this).build();
|
||||
}
|
||||
|
||||
private boolean process() {
|
||||
if (isPrintHelp()) {
|
||||
if (printHelp) {
|
||||
printUsage();
|
||||
return false;
|
||||
}
|
||||
if (printVersion) {
|
||||
System.out.println(JadxDecompiler.getVersion());
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
if (threadsCount <= 0) {
|
||||
throw new JadxException("Threads count must be positive, got: " + threadsCount);
|
||||
}
|
||||
if (isVerbose()) {
|
||||
if (verbose) {
|
||||
ch.qos.logback.classic.Logger rootLogger =
|
||||
(ch.qos.logback.classic.Logger) LoggerFactory.getLogger(Logger.ROOT_LOGGER_NAME);
|
||||
// remove INFO ThresholdFilter
|
||||
@@ -135,7 +143,7 @@ public class JadxCLIArgs {
|
||||
}
|
||||
|
||||
public void printUsage() {
|
||||
JCommander jc = new JCommander(this);
|
||||
JCommander jc = makeJCommander();
|
||||
// print usage in not sorted fields order (by default its sorted by description)
|
||||
PrintStream out = System.out;
|
||||
out.println();
|
||||
@@ -162,13 +170,13 @@ public class JadxCLIArgs {
|
||||
continue;
|
||||
}
|
||||
StringBuilder opt = new StringBuilder();
|
||||
opt.append(' ').append(p.getNames());
|
||||
opt.append(" ").append(p.getNames());
|
||||
addSpaces(opt, maxNamesLen - opt.length() + 2);
|
||||
opt.append("- ").append(p.getDescription());
|
||||
out.println(opt);
|
||||
}
|
||||
out.println("Example:");
|
||||
out.println(" jadx -d out classes.dex");
|
||||
out.println(" jadx -d out classes.dex");
|
||||
}
|
||||
|
||||
private static void addSpaces(StringBuilder str, int count) {
|
||||
@@ -202,13 +210,6 @@ public class JadxCLIArgs {
|
||||
return args;
|
||||
}
|
||||
|
||||
public static class InvertedBooleanConverter implements IStringConverter<Boolean> {
|
||||
@Override
|
||||
public Boolean convert(String value) {
|
||||
return "false".equals(value);
|
||||
}
|
||||
}
|
||||
|
||||
public List<String> getFiles() {
|
||||
return files;
|
||||
}
|
||||
@@ -225,10 +226,6 @@ public class JadxCLIArgs {
|
||||
return outDirRes;
|
||||
}
|
||||
|
||||
public boolean isPrintHelp() {
|
||||
return printHelp;
|
||||
}
|
||||
|
||||
public boolean isSkipResources() {
|
||||
return skipResources;
|
||||
}
|
||||
@@ -241,14 +238,6 @@ public class JadxCLIArgs {
|
||||
return threadsCount;
|
||||
}
|
||||
|
||||
public boolean isCFGOutput() {
|
||||
return cfgOutput;
|
||||
}
|
||||
|
||||
public boolean isRawCFGOutput() {
|
||||
return rawCfgOutput;
|
||||
}
|
||||
|
||||
public boolean isFallbackMode() {
|
||||
return fallbackMode;
|
||||
}
|
||||
@@ -261,10 +250,6 @@ public class JadxCLIArgs {
|
||||
return useImports;
|
||||
}
|
||||
|
||||
public boolean isVerbose() {
|
||||
return verbose;
|
||||
}
|
||||
|
||||
public boolean isDeobfuscationOn() {
|
||||
return deobfuscationOn;
|
||||
}
|
||||
@@ -289,6 +274,18 @@ public class JadxCLIArgs {
|
||||
return escapeUnicode;
|
||||
}
|
||||
|
||||
public boolean isEscapeUnicode() {
|
||||
return escapeUnicode;
|
||||
}
|
||||
|
||||
public boolean isCfgOutput() {
|
||||
return cfgOutput;
|
||||
}
|
||||
|
||||
public boolean isRawCfgOutput() {
|
||||
return rawCfgOutput;
|
||||
}
|
||||
|
||||
public boolean isReplaceConsts() {
|
||||
return replaceConsts;
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<level>INFO</level>
|
||||
</filter>
|
||||
<encoder>
|
||||
<pattern>%d{HH:mm:ss} %-5level - %msg%n</pattern>
|
||||
<pattern>%-5level - %msg%n</pattern>
|
||||
</encoder>
|
||||
</appender>
|
||||
|
||||
|
||||
@@ -1,22 +1,40 @@
|
||||
package jadx.cli;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import static org.hamcrest.Matchers.is;
|
||||
import static org.junit.Assert.assertThat;
|
||||
|
||||
public class JadxCLIArgsTest {
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(JadxCLIArgsTest.class);
|
||||
|
||||
@Test
|
||||
public void testInvertedBooleanOption() {
|
||||
assertThat(parse("--no-replace-consts").isReplaceConsts(), is(false));
|
||||
assertThat(parse("").isReplaceConsts(), is(true));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEscapeUnicodeOption() {
|
||||
assertThat(parse("--escape-unicode").isEscapeUnicode(), is(true));
|
||||
assertThat(parse("").isEscapeUnicode(), is(false));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSrcOption() {
|
||||
assertThat(parse("--no-src").isSkipSources(), is(true));
|
||||
assertThat(parse("-s").isSkipSources(), is(true));
|
||||
assertThat(parse("").isSkipSources(), is(false));
|
||||
}
|
||||
|
||||
private JadxCLIArgs parse(String... args) {
|
||||
JadxCLIArgs jadxArgs = new JadxCLIArgs();
|
||||
boolean res = jadxArgs.processArgs(args);
|
||||
assertThat(res, is(true));
|
||||
LOG.info("Jadx args: {}", jadxArgs.toJadxArgs());
|
||||
return jadxArgs;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -211,4 +211,31 @@ public class JadxArgs {
|
||||
public void setExportAsGradleProject(boolean exportAsGradleProject) {
|
||||
this.exportAsGradleProject = exportAsGradleProject;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
final StringBuilder sb = new StringBuilder("JadxArgs{");
|
||||
sb.append("inputFiles=").append(inputFiles);
|
||||
sb.append(", outDir=").append(outDir);
|
||||
sb.append(", outDirSrc=").append(outDirSrc);
|
||||
sb.append(", outDirRes=").append(outDirRes);
|
||||
sb.append(", threadsCount=").append(threadsCount);
|
||||
sb.append(", cfgOutput=").append(cfgOutput);
|
||||
sb.append(", rawCFGOutput=").append(rawCFGOutput);
|
||||
sb.append(", fallbackMode=").append(fallbackMode);
|
||||
sb.append(", showInconsistentCode=").append(showInconsistentCode);
|
||||
sb.append(", useImports=").append(useImports);
|
||||
sb.append(", isSkipResources=").append(isSkipResources);
|
||||
sb.append(", isSkipSources=").append(isSkipSources);
|
||||
sb.append(", isDeobfuscationOn=").append(isDeobfuscationOn);
|
||||
sb.append(", isDeobfuscationForceSave=").append(isDeobfuscationForceSave);
|
||||
sb.append(", useSourceNameAsClassAlias=").append(useSourceNameAsClassAlias);
|
||||
sb.append(", deobfuscationMinLength=").append(deobfuscationMinLength);
|
||||
sb.append(", deobfuscationMaxLength=").append(deobfuscationMaxLength);
|
||||
sb.append(", escapeUnicode=").append(escapeUnicode);
|
||||
sb.append(", replaceConsts=").append(replaceConsts);
|
||||
sb.append(", exportAsGradleProject=").append(exportAsGradleProject);
|
||||
sb.append('}');
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,25 +1,44 @@
|
||||
package jadx.api;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.List;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import jadx.core.utils.exceptions.JadxRuntimeException;
|
||||
import jadx.core.utils.exceptions.JadxArgsValidateException;
|
||||
|
||||
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");
|
||||
checkInputFiles(args);
|
||||
validateOutDirs(args);
|
||||
|
||||
if (LOG.isDebugEnabled()) {
|
||||
LOG.debug("Effective jadx args: {}", args);
|
||||
}
|
||||
for (File file : args.getInputFiles()) {
|
||||
}
|
||||
|
||||
private static void checkInputFiles(JadxArgs args) {
|
||||
List<File> inputFiles = args.getInputFiles();
|
||||
if (inputFiles.isEmpty()) {
|
||||
throw new JadxArgsValidateException("Please specify input file");
|
||||
}
|
||||
if (inputFiles.size() > 1) {
|
||||
for (File inputFile : inputFiles) {
|
||||
String fileName = inputFile.getName();
|
||||
if (fileName.startsWith("--")) {
|
||||
throw new JadxArgsValidateException("Unknown argument: " + fileName);
|
||||
}
|
||||
}
|
||||
throw new JadxArgsValidateException("Only one input file supported");
|
||||
}
|
||||
for (File file : inputFiles) {
|
||||
checkFile(file);
|
||||
}
|
||||
validateOutDirs(args);
|
||||
}
|
||||
|
||||
private static void validateOutDirs(JadxArgs args) {
|
||||
@@ -71,16 +90,16 @@ public class JadxArgsValidator {
|
||||
|
||||
private static void checkFile(File file) {
|
||||
if (!file.exists()) {
|
||||
throw new JadxRuntimeException("File not found " + file.getAbsolutePath());
|
||||
throw new JadxArgsValidateException("File not found " + file.getAbsolutePath());
|
||||
}
|
||||
if (file.isDirectory()) {
|
||||
throw new JadxRuntimeException("Expected file but found directory instead: " + file.getAbsolutePath());
|
||||
throw new JadxArgsValidateException("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);
|
||||
throw new JadxArgsValidateException("Output directory exists as file " + dir);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
package jadx.core.utils.exceptions;
|
||||
|
||||
public class JadxArgsValidateException extends RuntimeException {
|
||||
|
||||
private static final long serialVersionUID = -7457621776087311909L;
|
||||
|
||||
public JadxArgsValidateException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
public JadxArgsValidateException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
}
|
||||
@@ -270,7 +270,7 @@ public class JadxSettingsWindow extends JDialog {
|
||||
});
|
||||
|
||||
JCheckBox cfg = new JCheckBox();
|
||||
cfg.setSelected(settings.isCFGOutput());
|
||||
cfg.setSelected(settings.isCfgOutput());
|
||||
cfg.addItemListener(new ItemListener() {
|
||||
public void itemStateChanged(ItemEvent e) {
|
||||
settings.setCfgOutput(e.getStateChange() == ItemEvent.SELECTED);
|
||||
@@ -279,7 +279,7 @@ public class JadxSettingsWindow extends JDialog {
|
||||
});
|
||||
|
||||
JCheckBox rawCfg = new JCheckBox();
|
||||
rawCfg.setSelected(settings.isRawCFGOutput());
|
||||
rawCfg.setSelected(settings.isRawCfgOutput());
|
||||
rawCfg.addItemListener(new ItemListener() {
|
||||
public void itemStateChanged(ItemEvent e) {
|
||||
settings.setRawCfgOutput(e.getStateChange() == ItemEvent.SELECTED);
|
||||
|
||||
Reference in New Issue
Block a user