diff --git a/README.md b/README.md
index e408e9d88..99b8aa46a 100644
--- a/README.md
+++ b/README.md
@@ -44,19 +44,20 @@ jadx[-gui] [options] (.dex, .apk, .jar or .class)
options:
-d, --output-dir - output directory
-j, --threads-count - processing threads count
- -f, --fallback - make simple dump (using goto instead of 'if', 'for', etc)
-r, --no-res - do not decode resources
-s, --no-src - do not decompile source code
--show-bad-code - show inconsistent code (incorrectly decompiled)
- --cfg - save methods control flow graph to dot file
- --raw-cfg - save methods control flow graph (use raw instructions)
- -v, --verbose - verbose output
+ --no-replace-consts - don't replace constant value with matching constant field
+ --escape-unicode - escape non latin characters in strings (with \u)
--deobf - activate deobfuscation
--deobf-min - min length of name
--deobf-max - max length of name
--deobf-rewrite-cfg - force to save deobfuscation map
--deobf-use-sourcename - use source file name as class name alias
- --escape-unicode - escape non latin characters in strings (with \u)
+ --cfg - save methods control flow graph to dot file
+ --raw-cfg - save methods control flow graph (use raw instructions)
+ -f, --fallback - make simple dump (using goto instead of 'if', 'for', etc)
+ -v, --verbose - verbose output
-h, --help - print this help
Example:
jadx -d out classes.dex
diff --git a/jadx-cli/src/main/java/jadx/cli/JadxCLIArgs.java b/jadx-cli/src/main/java/jadx/cli/JadxCLIArgs.java
index b1add245c..632adb33a 100644
--- a/jadx-cli/src/main/java/jadx/cli/JadxCLIArgs.java
+++ b/jadx-cli/src/main/java/jadx/cli/JadxCLIArgs.java
@@ -17,6 +17,7 @@ import java.util.Map;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import com.beust.jcommander.IStringConverter;
import com.beust.jcommander.JCommander;
import com.beust.jcommander.Parameter;
import com.beust.jcommander.ParameterDescription;
@@ -33,9 +34,6 @@ public class JadxCLIArgs implements IJadxArgs {
@Parameter(names = {"-j", "--threads-count"}, description = "processing threads count")
protected int threadsCount = Math.max(1, Runtime.getRuntime().availableProcessors() / 2);
- @Parameter(names = {"-f", "--fallback"}, description = "make simple dump (using goto instead of 'if', 'for', etc)")
- protected boolean fallbackMode = false;
-
@Parameter(names = {"-r", "--no-res"}, description = "do not decode resources")
protected boolean skipResources = false;
@@ -45,14 +43,12 @@ public class JadxCLIArgs implements IJadxArgs {
@Parameter(names = {"--show-bad-code"}, description = "show inconsistent code (incorrectly decompiled)")
protected boolean showInconsistentCode = false;
- @Parameter(names = {"--cfg"}, description = "save methods control flow graph to dot file")
- protected boolean cfgOutput = false;
+ @Parameter(names = "--no-replace-consts", converter = InvertedBooleanConverter.class,
+ description = "don't replace constant value with matching constant field")
+ protected boolean replaceConsts = true;
- @Parameter(names = {"--raw-cfg"}, description = "save methods control flow graph (use raw instructions)")
- protected boolean rawCfgOutput = false;
-
- @Parameter(names = {"-v", "--verbose"}, description = "verbose output")
- protected boolean verbose = false;
+ @Parameter(names = {"--escape-unicode"}, description = "escape non latin characters in strings (with \\u)")
+ protected boolean escapeUnicode = false;
@Parameter(names = {"--deobf"}, description = "activate deobfuscation")
protected boolean deobfuscationOn = false;
@@ -69,8 +65,17 @@ public class JadxCLIArgs implements IJadxArgs {
@Parameter(names = {"--deobf-use-sourcename"}, description = "use source file name as class name alias")
protected boolean deobfuscationUseSourceNameAsAlias = false;
- @Parameter(names = {"--escape-unicode"}, description = "escape non latin characters in strings (with \\u)")
- protected boolean escapeUnicode = false;
+ @Parameter(names = {"--cfg"}, description = "save methods control flow graph to dot file")
+ protected boolean cfgOutput = false;
+
+ @Parameter(names = {"--raw-cfg"}, description = "save methods control flow graph (use raw instructions)")
+ protected boolean rawCfgOutput = false;
+
+ @Parameter(names = {"-f", "--fallback"}, description = "make simple dump (using goto instead of 'if', 'for', etc)")
+ protected boolean fallbackMode = false;
+
+ @Parameter(names = {"-v", "--verbose"}, description = "verbose output")
+ protected boolean verbose = false;
@Parameter(names = {"-h", "--help"}, description = "print this help", help = true)
protected boolean printHelp = false;
@@ -178,6 +183,13 @@ public class JadxCLIArgs implements IJadxArgs {
}
}
+ public static class InvertedBooleanConverter implements IStringConverter {
+ @Override
+ public Boolean convert(String value) {
+ return "false".equals(value);
+ }
+ }
+
public List getInput() {
return input;
}
@@ -264,4 +276,9 @@ public class JadxCLIArgs implements IJadxArgs {
public boolean escapeUnicode() {
return escapeUnicode;
}
+
+ @Override
+ public boolean isReplaceConsts() {
+ return replaceConsts;
+ }
}
diff --git a/jadx-cli/src/test/java/jadx/cli/JadxCLIArgsTest.java b/jadx-cli/src/test/java/jadx/cli/JadxCLIArgsTest.java
new file mode 100644
index 000000000..428efccfa
--- /dev/null
+++ b/jadx-cli/src/test/java/jadx/cli/JadxCLIArgsTest.java
@@ -0,0 +1,22 @@
+package jadx.cli;
+
+import org.junit.Test;
+
+import static org.hamcrest.Matchers.is;
+import static org.junit.Assert.assertThat;
+
+public class JadxCLIArgsTest {
+
+ @Test
+ public void testInvertedBooleanOption() throws Exception {
+ assertThat(parse("--no-replace-consts").isReplaceConsts(), is(false));
+ assertThat(parse("").isReplaceConsts(), is(true));
+ }
+
+ private JadxCLIArgs parse(String... args) {
+ JadxCLIArgs jadxArgs = new JadxCLIArgs();
+ boolean res = jadxArgs.processArgs(args);
+ assertThat(res, is(true));
+ return jadxArgs;
+ }
+}
diff --git a/jadx-core/src/main/java/jadx/api/IJadxArgs.java b/jadx-core/src/main/java/jadx/api/IJadxArgs.java
index 2c5034d63..212ae6199 100644
--- a/jadx-core/src/main/java/jadx/api/IJadxArgs.java
+++ b/jadx-core/src/main/java/jadx/api/IJadxArgs.java
@@ -32,4 +32,9 @@ public interface IJadxArgs {
boolean useSourceNameAsClassAlias();
boolean escapeUnicode();
+
+ /**
+ * Replace constant values with static final fields with same value
+ */
+ boolean isReplaceConsts();
}
diff --git a/jadx-core/src/main/java/jadx/api/JadxArgs.java b/jadx-core/src/main/java/jadx/api/JadxArgs.java
index 7d789f1ef..81c3746c4 100644
--- a/jadx-core/src/main/java/jadx/api/JadxArgs.java
+++ b/jadx-core/src/main/java/jadx/api/JadxArgs.java
@@ -25,6 +25,7 @@ public class JadxArgs implements IJadxArgs {
private int deobfuscationMaxLength = Integer.MAX_VALUE;
private boolean escapeUnicode = false;
+ private boolean replaceConsts = true;
@Override
public File getOutDir() {
@@ -160,4 +161,13 @@ public class JadxArgs implements IJadxArgs {
public void setEscapeUnicode(boolean escapeUnicode) {
this.escapeUnicode = escapeUnicode;
}
+
+ @Override
+ public boolean isReplaceConsts() {
+ return replaceConsts;
+ }
+
+ public void setReplaceConsts(boolean replaceConsts) {
+ this.replaceConsts = replaceConsts;
+ }
}
diff --git a/jadx-core/src/main/java/jadx/core/dex/info/ClassInfo.java b/jadx-core/src/main/java/jadx/core/dex/info/ClassInfo.java
index 0f6a9e89e..53b04c03f 100644
--- a/jadx-core/src/main/java/jadx/core/dex/info/ClassInfo.java
+++ b/jadx-core/src/main/java/jadx/core/dex/info/ClassInfo.java
@@ -167,7 +167,7 @@ public final class ClassInfo {
@Override
public int hashCode() {
- return fullName.hashCode();
+ return type.hashCode();
}
@Override
diff --git a/jadx-core/src/main/java/jadx/core/dex/info/ConstStorage.java b/jadx-core/src/main/java/jadx/core/dex/info/ConstStorage.java
new file mode 100644
index 000000000..9697c4248
--- /dev/null
+++ b/jadx-core/src/main/java/jadx/core/dex/info/ConstStorage.java
@@ -0,0 +1,187 @@
+package jadx.core.dex.info;
+
+import jadx.api.IJadxArgs;
+import jadx.core.dex.attributes.AType;
+import jadx.core.dex.instructions.args.LiteralArg;
+import jadx.core.dex.instructions.args.PrimitiveType;
+import jadx.core.dex.nodes.ClassNode;
+import jadx.core.dex.nodes.DexNode;
+import jadx.core.dex.nodes.FieldNode;
+import jadx.core.dex.nodes.ResRefField;
+import jadx.core.dex.nodes.parser.FieldInitAttr;
+
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.jetbrains.annotations.Nullable;
+
+public class ConstStorage {
+
+ private static final class Values {
+ private final Map