Commit 218c39b1 authored by Skylot's avatar Skylot

core: option for control escaping of unicode characters (#103)

parent e915f4fc
...@@ -42,20 +42,22 @@ Run **jadx** on itself: ...@@ -42,20 +42,22 @@ Run **jadx** on itself:
``` ```
jadx[-gui] [options] <input file> (.dex, .apk, .jar or .class) jadx[-gui] [options] <input file> (.dex, .apk, .jar or .class)
options: options:
-d, --output-dir - output directory -d, --output-dir - output directory
-j, --threads-count - processing threads count -j, --threads-count - processing threads count
-f, --fallback - make simple dump (using goto instead of 'if', 'for', etc) -f, --fallback - make simple dump (using goto instead of 'if', 'for', etc)
-r, --no-res - do not decode resources -r, --no-res - do not decode resources
-s, --no-src - do not decompile source code -s, --no-src - do not decompile source code
--show-bad-code - show inconsistent code (incorrectly decompiled) --show-bad-code - show inconsistent code (incorrectly decompiled)
--cfg - save methods control flow graph to dot file --cfg - save methods control flow graph to dot file
--raw-cfg - save methods control flow graph (use raw instructions) --raw-cfg - save methods control flow graph (use raw instructions)
-v, --verbose - verbose output -v, --verbose - verbose output
--deobf - activate deobfuscation --deobf - activate deobfuscation
--deobf-min - min length of name --deobf-min - min length of name
--deobf-max - max length of name --deobf-max - max length of name
--deobf-rewrite-cfg - force to save deobfuscation map --deobf-rewrite-cfg - force to save deobfuscation map
-h, --help - print this help --deobf-use-sourcename - use source file name as class name alias
--escape-unicode - escape non latin characters in strings (with \u)
-h, --help - print this help
Example: Example:
jadx -d out classes.dex jadx -d out classes.dex
``` ```
......
package jadx.cli; package jadx.cli;
import ch.qos.logback.classic.spi.ILoggingEvent;
import ch.qos.logback.core.Appender;
import jadx.api.IJadxArgs; import jadx.api.IJadxArgs;
import jadx.api.JadxDecompiler; import jadx.api.JadxDecompiler;
import jadx.core.utils.exceptions.JadxException; import jadx.core.utils.exceptions.JadxException;
...@@ -67,6 +69,9 @@ public class JadxCLIArgs implements IJadxArgs { ...@@ -67,6 +69,9 @@ public class JadxCLIArgs implements IJadxArgs {
@Parameter(names = {"--deobf-use-sourcename"}, description = "use source file name as class name alias") @Parameter(names = {"--deobf-use-sourcename"}, description = "use source file name as class name alias")
protected boolean deobfuscationUseSourceNameAsAlias = false; protected boolean deobfuscationUseSourceNameAsAlias = false;
@Parameter(names = {"--escape-unicode"}, description = "escape non latin characters in strings (with \\u)")
protected boolean escapeUnicode = false;
@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;
...@@ -117,7 +122,10 @@ public class JadxCLIArgs implements IJadxArgs { ...@@ -117,7 +122,10 @@ public class JadxCLIArgs implements IJadxArgs {
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);
// remove INFO ThresholdFilter // remove INFO ThresholdFilter
rootLogger.getAppender("STDOUT").clearAllFilters(); Appender<ILoggingEvent> appender = rootLogger.getAppender("STDOUT");
if (appender != null) {
appender.clearAllFilters();
}
} }
} catch (JadxException e) { } catch (JadxException e) {
System.err.println("ERROR: " + e.getMessage()); System.err.println("ERROR: " + e.getMessage());
...@@ -251,4 +259,9 @@ public class JadxCLIArgs implements IJadxArgs { ...@@ -251,4 +259,9 @@ public class JadxCLIArgs implements IJadxArgs {
public boolean useSourceNameAsClassAlias() { public boolean useSourceNameAsClassAlias() {
return deobfuscationUseSourceNameAsAlias; return deobfuscationUseSourceNameAsAlias;
} }
@Override
public boolean escapeUnicode() {
return escapeUnicode;
}
} }
...@@ -30,4 +30,6 @@ public interface IJadxArgs { ...@@ -30,4 +30,6 @@ public interface IJadxArgs {
boolean isDeobfuscationForceSave(); boolean isDeobfuscationForceSave();
boolean useSourceNameAsClassAlias(); boolean useSourceNameAsClassAlias();
boolean escapeUnicode();
} }
...@@ -24,6 +24,8 @@ public class JadxArgs implements IJadxArgs { ...@@ -24,6 +24,8 @@ public class JadxArgs implements IJadxArgs {
private int deobfuscationMinLength = 0; private int deobfuscationMinLength = 0;
private int deobfuscationMaxLength = Integer.MAX_VALUE; private int deobfuscationMaxLength = Integer.MAX_VALUE;
private boolean escapeUnicode = false;
@Override @Override
public File getOutDir() { public File getOutDir() {
return outDir; return outDir;
...@@ -149,4 +151,13 @@ public class JadxArgs implements IJadxArgs { ...@@ -149,4 +151,13 @@ public class JadxArgs implements IJadxArgs {
public void setDeobfuscationMaxLength(int deobfuscationMaxLength) { public void setDeobfuscationMaxLength(int deobfuscationMaxLength) {
this.deobfuscationMaxLength = deobfuscationMaxLength; this.deobfuscationMaxLength = deobfuscationMaxLength;
} }
@Override
public boolean escapeUnicode() {
return escapeUnicode;
}
public void setEscapeUnicode(boolean escapeUnicode) {
this.escapeUnicode = escapeUnicode;
}
} }
...@@ -130,11 +130,11 @@ public class AnnotationGen { ...@@ -130,11 +130,11 @@ public class AnnotationGen {
return; return;
} }
if (val instanceof String) { if (val instanceof String) {
code.add(StringUtils.unescapeString((String) val)); code.add(getStringUtils().unescapeString((String) val));
} else if (val instanceof Integer) { } else if (val instanceof Integer) {
code.add(TypeGen.formatInteger((Integer) val)); code.add(TypeGen.formatInteger((Integer) val));
} else if (val instanceof Character) { } else if (val instanceof Character) {
code.add(StringUtils.unescapeChar((Character) val)); code.add(getStringUtils().unescapeChar((Character) val));
} else if (val instanceof Boolean) { } else if (val instanceof Boolean) {
code.add(Boolean.TRUE.equals(val) ? "true" : "false"); code.add(Boolean.TRUE.equals(val) ? "true" : "false");
} else if (val instanceof Float) { } else if (val instanceof Float) {
...@@ -172,4 +172,8 @@ public class AnnotationGen { ...@@ -172,4 +172,8 @@ public class AnnotationGen {
throw new JadxRuntimeException("Can't decode value: " + val + " (" + val.getClass() + ")"); throw new JadxRuntimeException("Can't decode value: " + val + " (" + val.getClass() + ")");
} }
} }
private StringUtils getStringUtils() {
return cls.dex().root().getStringUtils();
}
} }
...@@ -348,7 +348,7 @@ public class ClassGen { ...@@ -348,7 +348,7 @@ public class ClassGen {
if (fv != null) { if (fv != null) {
code.add(" = "); code.add(" = ");
if (fv.getValue() == null) { if (fv.getValue() == null) {
code.add(TypeGen.literalToString(0, f.getType())); code.add(TypeGen.literalToString(0, f.getType(), cls));
} else { } else {
if (fv.getValueType() == InitType.CONST) { if (fv.getValueType() == InitType.CONST) {
annotationGen.encodeValue(code, fv.getValue()); annotationGen.encodeValue(code, fv.getValue());
......
...@@ -38,7 +38,6 @@ import jadx.core.dex.nodes.MethodNode; ...@@ -38,7 +38,6 @@ import jadx.core.dex.nodes.MethodNode;
import jadx.core.dex.nodes.RootNode; import jadx.core.dex.nodes.RootNode;
import jadx.core.utils.ErrorsCounter; import jadx.core.utils.ErrorsCounter;
import jadx.core.utils.RegionUtils; import jadx.core.utils.RegionUtils;
import jadx.core.utils.StringUtils;
import jadx.core.utils.exceptions.CodegenException; import jadx.core.utils.exceptions.CodegenException;
import jadx.core.utils.exceptions.JadxRuntimeException; import jadx.core.utils.exceptions.JadxRuntimeException;
...@@ -130,8 +129,8 @@ public class InsnGen { ...@@ -130,8 +129,8 @@ public class InsnGen {
code.add(mgen.getNameGen().assignArg(arg)); code.add(mgen.getNameGen().assignArg(arg));
} }
private static String lit(LiteralArg arg) { private String lit(LiteralArg arg) {
return TypeGen.literalToString(arg.getLiteral(), arg.getType()); return TypeGen.literalToString(arg.getLiteral(), arg.getType(), mth);
} }
private void instanceField(CodeWriter code, FieldInfo field, InsnArg arg) throws CodegenException { private void instanceField(CodeWriter code, FieldInfo field, InsnArg arg) throws CodegenException {
...@@ -236,7 +235,7 @@ public class InsnGen { ...@@ -236,7 +235,7 @@ public class InsnGen {
switch (insn.getType()) { switch (insn.getType()) {
case CONST_STR: case CONST_STR:
String str = ((ConstStringNode) insn).getString(); String str = ((ConstStringNode) insn).getString();
code.add(StringUtils.unescapeString(str)); code.add(mth.dex().root().getStringUtils().unescapeString(str));
break; break;
case CONST_CLASS: case CONST_CLASS:
......
...@@ -255,7 +255,7 @@ public class RegionGen extends InsnGen { ...@@ -255,7 +255,7 @@ public class RegionGen extends InsnGen {
} }
} }
} else if (k instanceof Integer) { } else if (k instanceof Integer) {
code.add(TypeGen.literalToString((Integer) k, arg.getType())); code.add(TypeGen.literalToString((Integer) k, arg.getType(), mth));
} else { } else {
throw new JadxRuntimeException("Unexpected key in switch: " + (k != null ? k.getClass() : null)); throw new JadxRuntimeException("Unexpected key in switch: " + (k != null ? k.getClass() : null));
} }
......
package jadx.core.codegen; package jadx.core.codegen;
import jadx.api.JadxArgs;
import jadx.core.dex.instructions.args.ArgType; import jadx.core.dex.instructions.args.ArgType;
import jadx.core.dex.instructions.args.PrimitiveType; import jadx.core.dex.instructions.args.PrimitiveType;
import jadx.core.dex.nodes.IDexNode;
import jadx.core.utils.StringUtils; import jadx.core.utils.StringUtils;
import jadx.core.utils.Utils; import jadx.core.utils.Utils;
import jadx.core.utils.exceptions.JadxRuntimeException; import jadx.core.utils.exceptions.JadxRuntimeException;
...@@ -31,7 +33,16 @@ public class TypeGen { ...@@ -31,7 +33,16 @@ public class TypeGen {
* *
* @throws JadxRuntimeException for incorrect type or literal value * @throws JadxRuntimeException for incorrect type or literal value
*/ */
public static String literalToString(long lit, ArgType type, IDexNode dexNode) {
return literalToString(lit, type, dexNode.root().getStringUtils());
}
@Deprecated
public static String literalToString(long lit, ArgType type) { public static String literalToString(long lit, ArgType type) {
return literalToString(lit, type, new StringUtils(new JadxArgs()));
}
private static String literalToString(long lit, ArgType type, StringUtils stringUtils) {
if (type == null || !type.isTypeKnown()) { if (type == null || !type.isTypeKnown()) {
String n = Long.toString(lit); String n = Long.toString(lit);
if (Math.abs(lit) > 100) { if (Math.abs(lit) > 100) {
...@@ -46,7 +57,7 @@ public class TypeGen { ...@@ -46,7 +57,7 @@ public class TypeGen {
case BOOLEAN: case BOOLEAN:
return lit == 0 ? "false" : "true"; return lit == 0 ? "false" : "true";
case CHAR: case CHAR:
return StringUtils.unescapeChar((char) lit); return stringUtils.unescapeChar((char) lit);
case BYTE: case BYTE:
return formatByte((byte) lit); return formatByte((byte) lit);
case SHORT: case SHORT:
......
...@@ -43,7 +43,7 @@ import com.android.dex.ClassData.Method; ...@@ -43,7 +43,7 @@ import com.android.dex.ClassData.Method;
import com.android.dex.ClassDef; import com.android.dex.ClassDef;
import com.android.dx.rop.code.AccessFlags; import com.android.dx.rop.code.AccessFlags;
public class ClassNode extends LineAttrNode implements ILoadable { public class ClassNode extends LineAttrNode implements ILoadable, IDexNode {
private static final Logger LOG = LoggerFactory.getLogger(ClassNode.class); private static final Logger LOG = LoggerFactory.getLogger(ClassNode.class);
private final DexNode dex; private final DexNode dex;
...@@ -472,10 +472,16 @@ public class ClassNode extends LineAttrNode implements ILoadable { ...@@ -472,10 +472,16 @@ public class ClassNode extends LineAttrNode implements ILoadable {
return accessFlags; return accessFlags;
} }
@Override
public DexNode dex() { public DexNode dex() {
return dex; return dex;
} }
@Override
public RootNode root() {
return dex.root();
}
public String getRawName() { public String getRawName() {
return clsInfo.getRawName(); return clsInfo.getRawName();
} }
......
...@@ -28,7 +28,7 @@ import com.android.dex.MethodId; ...@@ -28,7 +28,7 @@ import com.android.dex.MethodId;
import com.android.dex.ProtoId; import com.android.dex.ProtoId;
import com.android.dex.TypeList; import com.android.dex.TypeList;
public class DexNode { public class DexNode implements IDexNode {
public static final int NO_INDEX = -1; public static final int NO_INDEX = -1;
...@@ -210,11 +210,17 @@ public class DexNode { ...@@ -210,11 +210,17 @@ public class DexNode {
return dexBuf.open(offset); return dexBuf.open(offset);
} }
@Override
public RootNode root() { public RootNode root() {
return root; return root;
} }
@Override @Override
public DexNode dex() {
return this;
}
@Override
public String toString() { public String toString() {
return "DEX"; return "DEX";
} }
......
package jadx.core.dex.nodes;
public interface IDexNode {
DexNode dex();
RootNode root();
}
...@@ -44,7 +44,7 @@ import com.android.dex.Code; ...@@ -44,7 +44,7 @@ import com.android.dex.Code;
import com.android.dex.Code.CatchHandler; import com.android.dex.Code.CatchHandler;
import com.android.dex.Code.Try; import com.android.dex.Code.Try;
public class MethodNode extends LineAttrNode implements ILoadable { public class MethodNode extends LineAttrNode implements ILoadable, IDexNode {
private static final Logger LOG = LoggerFactory.getLogger(MethodNode.class); private static final Logger LOG = LoggerFactory.getLogger(MethodNode.class);
private final MethodInfo mthInfo; private final MethodInfo mthInfo;
...@@ -594,10 +594,16 @@ public class MethodNode extends LineAttrNode implements ILoadable { ...@@ -594,10 +594,16 @@ public class MethodNode extends LineAttrNode implements ILoadable {
this.region = region; this.region = region;
} }
@Override
public DexNode dex() { public DexNode dex() {
return parentClass.dex(); return parentClass.dex();
} }
@Override
public RootNode root() {
return dex().root();
}
public MethodInfo getMethodInfo() { public MethodInfo getMethodInfo() {
return mthInfo; return mthInfo;
} }
......
...@@ -7,6 +7,7 @@ import jadx.api.ResourcesLoader; ...@@ -7,6 +7,7 @@ import jadx.api.ResourcesLoader;
import jadx.core.clsp.ClspGraph; import jadx.core.clsp.ClspGraph;
import jadx.core.dex.info.ClassInfo; import jadx.core.dex.info.ClassInfo;
import jadx.core.utils.ErrorsCounter; import jadx.core.utils.ErrorsCounter;
import jadx.core.utils.StringUtils;
import jadx.core.utils.exceptions.DecodeException; import jadx.core.utils.exceptions.DecodeException;
import jadx.core.utils.exceptions.JadxException; import jadx.core.utils.exceptions.JadxException;
import jadx.core.utils.files.DexFile; import jadx.core.utils.files.DexFile;
...@@ -31,6 +32,7 @@ public class RootNode { ...@@ -31,6 +32,7 @@ public class RootNode {
private final ErrorsCounter errorsCounter = new ErrorsCounter(); private final ErrorsCounter errorsCounter = new ErrorsCounter();
private final IJadxArgs args; private final IJadxArgs args;
private final StringUtils stringUtils;
private List<DexNode> dexNodes; private List<DexNode> dexNodes;
private Map<Integer, String> resourcesNames = new HashMap<Integer, String>(); private Map<Integer, String> resourcesNames = new HashMap<Integer, String>();
...@@ -41,6 +43,7 @@ public class RootNode { ...@@ -41,6 +43,7 @@ public class RootNode {
public RootNode(IJadxArgs args) { public RootNode(IJadxArgs args) {
this.args = args; this.args = args;
this.stringUtils = new StringUtils(args);
} }
public void load(List<InputFile> inputFiles) throws DecodeException { public void load(List<InputFile> inputFiles) throws DecodeException {
...@@ -194,4 +197,8 @@ public class RootNode { ...@@ -194,4 +197,8 @@ public class RootNode {
public IJadxArgs getArgs() { public IJadxArgs getArgs() {
return args; return args;
} }
public StringUtils getStringUtils() {
return stringUtils;
}
} }
package jadx.core.utils; package jadx.core.utils;
import jadx.api.IJadxArgs;
public class StringUtils { public class StringUtils {
private StringUtils() { private final boolean escapeUnicode;
public StringUtils(IJadxArgs args) {
this.escapeUnicode = args.escapeUnicode();
} }
public static String unescapeString(String str) { public String unescapeString(String str) {
int len = str.length(); int len = str.length();
if (len == 0) {
return "\"\"";
}
StringBuilder res = new StringBuilder(); StringBuilder res = new StringBuilder();
for (int i = 0; i < len; i++) { for (int i = 0; i < len; i++) {
int c = str.charAt(i) & 0xFFFF; int c = str.charAt(i) & 0xFFFF;
processChar(c, res); processChar(c, res);
...@@ -16,7 +23,7 @@ public class StringUtils { ...@@ -16,7 +23,7 @@ public class StringUtils {
return '"' + res.toString() + '"'; return '"' + res.toString() + '"';
} }
public static String unescapeChar(char ch) { public String unescapeChar(char ch) {
if (ch == '\'') { if (ch == '\'') {
return "'\\\''"; return "'\\\''";
} }
...@@ -25,7 +32,7 @@ public class StringUtils { ...@@ -25,7 +32,7 @@ public class StringUtils {
return '\'' + res.toString() + '\''; return '\'' + res.toString() + '\'';
} }
private static void processChar(int c, StringBuilder res) { private void processChar(int c, StringBuilder res) {
switch (c) { switch (c) {
case '\n': res.append("\\n"); break; case '\n': res.append("\\n"); break;
case '\r': res.append("\\r"); break; case '\r': res.append("\\r"); break;
...@@ -37,10 +44,10 @@ public class StringUtils { ...@@ -37,10 +44,10 @@ public class StringUtils {
case '\\': res.append("\\\\"); break; case '\\': res.append("\\\\"); break;
default: default:
if (32 <= c && c <= 126) { if (c < 32 || c >= 127 && escapeUnicode) {
res.append((char) c);
} else {
res.append("\\u").append(String.format("%04x", c)); res.append("\\u").append(String.format("%04x", c));
} else {
res.append((char) c);
} }
break; break;
} }
......
package jadx.tests package jadx.tests
import jadx.api.JadxArgs
import jadx.core.utils.StringUtils import jadx.core.utils.StringUtils
import spock.lang.Specification import spock.lang.Specification
class TestStringUtils extends Specification { class TestStringUtils extends Specification {
def "unescape string"() { def "unescape string"() {
def args = new JadxArgs()
args.setEscapeUnicode(true)
def stringUtils = new StringUtils(args)
expect: expect:
StringUtils.unescapeString(input) == "\"$expected\"" stringUtils.unescapeString(input) == "\"$expected\""
where: where:
input | expected input | expected
...@@ -26,12 +30,14 @@ class TestStringUtils extends Specification { ...@@ -26,12 +30,14 @@ class TestStringUtils extends Specification {
def "unescape char"() { def "unescape char"() {
expect: expect:
StringUtils.unescapeChar(input as char) == "'$expected'" new StringUtils(new JadxArgs()).unescapeChar(input as char) == "'$expected'"
where: where:
input | expected input | expected
'a' | "a" 'a' | "a"
' ' | " "
'\n' | "\\n" '\n' | "\\n"
'\'' | "\\\'" '\'' | "\\\'"
'\0' | "\\u0000"
} }
} }
...@@ -5,7 +5,7 @@ mainClassName = 'jadx.gui.JadxGUI' ...@@ -5,7 +5,7 @@ mainClassName = 'jadx.gui.JadxGUI'
dependencies { dependencies {
compile(project(":jadx-core")) compile(project(":jadx-core"))
compile(project(":jadx-cli")) compile(project(":jadx-cli"))
compile 'com.fifesoft:rsyntaxtextarea:2.5.7' compile 'com.fifesoft:rsyntaxtextarea:2.5.8'
compile 'com.google.code.gson:gson:2.3.1' compile 'com.google.code.gson:gson:2.3.1'
compile files('libs/jfontchooser-1.0.5.jar') compile files('libs/jfontchooser-1.0.5.jar')
compile 'com.googlecode.concurrent-trees:concurrent-trees:2.4.0' compile 'com.googlecode.concurrent-trees:concurrent-trees:2.4.0'
......
...@@ -30,7 +30,7 @@ public class JadxGUI { ...@@ -30,7 +30,7 @@ public class JadxGUI {
} }
}); });
} catch (Throwable e) { } catch (Throwable e) {
LOG.error("Error: {}", e.getMessage()); LOG.error("Error: {}", e.getMessage(), e);
System.exit(1); System.exit(1);
} }
} }
......
...@@ -165,6 +165,10 @@ public class JadxSettings extends JadxCLIArgs { ...@@ -165,6 +165,10 @@ public class JadxSettings extends JadxCLIArgs {
this.deobfuscationUseSourceNameAsAlias = useSourceNameAsAlias; this.deobfuscationUseSourceNameAsAlias = useSourceNameAsAlias;
} }
public void setEscapeUnicode(boolean escapeUnicode) {
this.escapeUnicode = escapeUnicode;
}
public boolean isUseFastSearch() { public boolean isUseFastSearch() {
return false; return false;
// return useFastSearch; // return useFastSearch;
......
...@@ -67,6 +67,8 @@ public class JadxSettingsWindow extends JDialog { ...@@ -67,6 +67,8 @@ public class JadxSettingsWindow extends JDialog {
panel.setLayout(new BoxLayout(panel, BoxLayout.PAGE_AXIS)); panel.setLayout(new BoxLayout(panel, BoxLayout.PAGE_AXIS));
panel.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10)); panel.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10));
panel.add(makeDeobfuscationGroup()); panel.add(makeDeobfuscationGroup());
panel.add(makeDecompilationGroup());
panel.add(makeEditorGroup());
panel.add(makeOtherGroup()); panel.add(makeOtherGroup());
JButton saveBtn = new JButton(NLS.str("preferences.save")); JButton saveBtn = new JButton(NLS.str("preferences.save"));
...@@ -179,15 +181,29 @@ public class JadxSettingsWindow extends JDialog { ...@@ -179,15 +181,29 @@ public class JadxSettingsWindow extends JDialog {
return deobfGroup; return deobfGroup;
} }
private SettingsGroup makeOtherGroup() { private SettingsGroup makeEditorGroup() {
JCheckBox update = new JCheckBox(); JButton fontBtn = new JButton(NLS.str("preferences.select_font"));
update.setSelected(settings.isCheckForUpdates()); fontBtn.addMouseListener(new MouseAdapter() {
update.addItemListener(new ItemListener() { @Override
public void itemStateChanged(ItemEvent e) { public void mouseClicked(MouseEvent e) {
settings.setCheckForUpdates(e.getStateChange() == ItemEvent.SELECTED); JFontChooser fontChooser = new JFontChooser();
fontChooser.setSelectedFont(settings.getFont());
int result = fontChooser.showDialog(JadxSettingsWindow.this);
if (result == JFontChooser.OK_OPTION) {
Font font = fontChooser.getSelectedFont();
LOG.info("Selected Font : {}", font);
settings.setFont(font);
mainWindow.updateFont(font);
}
} }
}); });
SettingsGroup other = new SettingsGroup(NLS.str("preferences.editor"));
other.addRow(NLS.str("preferences.font"), fontBtn);
return other;
}
private SettingsGroup makeDecompilationGroup() {
JCheckBox fallback = new JCheckBox(); JCheckBox fallback = new JCheckBox();
fallback.setSelected(settings.isFallbackMode()); fallback.setSelected(settings.isFallbackMode());
fallback.addItemListener(new ItemListener() { fallback.addItemListener(new ItemListener() {
...@@ -224,6 +240,42 @@ public class JadxSettingsWindow extends JDialog { ...@@ -224,6 +240,42 @@ public class JadxSettingsWindow extends JDialog {
} }
}); });
JCheckBox autoStartJobs = new JCheckBox();
autoStartJobs.setSelected(settings.isAutoStartJobs());
autoStartJobs.addItemListener(new ItemListener() {
public void itemStateChanged(ItemEvent e) {
settings.setAutoStartJobs(e.getStateChange() == ItemEvent.SELECTED);
}
});
JCheckBox escapeUnicode = new JCheckBox();
escapeUnicode.setSelected(settings.escapeUnicode());
escapeUnicode.addItemListener(new ItemListener() {
public void itemStateChanged(ItemEvent e) {
settings.setEscapeUnicode(e.getStateChange() == ItemEvent.SELECTED);
needReload();
}
});
SettingsGroup other = new SettingsGroup(NLS.str("preferences.decompile"));
other.addRow(NLS.str("preferences.threads"), threadsCount);
other.addRow(NLS.str("preferences.start_jobs"), autoStartJobs);
other.addRow(NLS.str("preferences.showInconsistentCode"), showInconsistentCode);
other.addRow(NLS.str("preferences.escapeUnicode"), escapeUnicode);
other.addRow(NLS.str("preferences.fallback"), fallback);
other.addRow(NLS.str("preferences.skipResourcesDecode"), resourceDecode);
return other;
}
private SettingsGroup makeOtherGroup() {
JCheckBox update = new JCheckBox();
update.setSelected(settings.isCheckForUpdates());
update.addItemListener(new ItemListener() {
public void itemStateChanged(ItemEvent e) {
settings.setCheckForUpdates(e.getStateChange() == ItemEvent.SELECTED);
}
});
JCheckBox cfg = new JCheckBox(); JCheckBox cfg = new JCheckBox();
cfg.setSelected(settings.isCFGOutput()); cfg.setSelected(settings.isCFGOutput());
cfg.addItemListener(new ItemListener() { cfg.addItemListener(new ItemListener() {
...@@ -242,30 +294,6 @@ public class JadxSettingsWindow extends JDialog { ...@@ -242,30 +294,6 @@ public class JadxSettingsWindow extends JDialog {
} }
}); });
JButton fontBtn = new JButton(NLS.str("preferences.select_font"));
fontBtn.addMouseListener(new MouseAdapter() {
@Override
public void mouseClicked(MouseEvent e) {
JFontChooser fontChooser = new JFontChooser();
fontChooser.setSelectedFont(settings.getFont());
int result = fontChooser.showDialog(JadxSettingsWindow.this);
if (result == JFontChooser.OK_OPTION) {
Font font = fontChooser.getSelectedFont();
LOG.info("Selected Font : {}", font);
settings.setFont(font);
mainWindow.updateFont(font);
}
}
});
JCheckBox autoStartJobs = new JCheckBox();
autoStartJobs.setSelected(settings.isAutoStartJobs());
autoStartJobs.addItemListener(new ItemListener() {
public void itemStateChanged(ItemEvent e) {
settings.setAutoStartJobs(e.getStateChange() == ItemEvent.SELECTED);
}
});
JCheckBox fastSearch = new JCheckBox(); JCheckBox fastSearch = new JCheckBox();
fastSearch.setEnabled(false); fastSearch.setEnabled(false);
fastSearch.setSelected(settings.isUseFastSearch()); fastSearch.setSelected(settings.isUseFastSearch());
...@@ -277,15 +305,9 @@ public class JadxSettingsWindow extends JDialog { ...@@ -277,15 +305,9 @@ public class JadxSettingsWindow extends JDialog {
SettingsGroup other = new SettingsGroup(NLS.str("preferences.other")); SettingsGroup other = new SettingsGroup(NLS.str("preferences.other"));
other.addRow(NLS.str("preferences.check_for_updates"), update); other.addRow(NLS.str("preferences.check_for_updates"), update);
other.addRow(NLS.str("preferences.threads"), threadsCount);
other.addRow(NLS.str("preferences.fallback"), fallback);
other.addRow(NLS.str("preferences.showInconsistentCode"), showInconsistentCode);
other.addRow(NLS.str("preferences.skipResourcesDecode"), resourceDecode);
other.addRow(NLS.str("preferences.cfg"), cfg); other.addRow(NLS.str("preferences.cfg"), cfg);
other.addRow(NLS.str("preferences.raw_cfg"), rawCfg); other.addRow(NLS.str("preferences.raw_cfg"), rawCfg);
other.addRow(NLS.str("preferences.font"), fontBtn);
other.addRow(NLS.str("preferences.fast_search"), fastSearch); other.addRow(NLS.str("preferences.fast_search"), fastSearch);
other.addRow(NLS.str("preferences.start_jobs"), autoStartJobs);
return other; return other;
} }
......
...@@ -52,10 +52,13 @@ usage_dialog.label=Usage for: ...@@ -52,10 +52,13 @@ usage_dialog.label=Usage for:
preferences.title=Preferences preferences.title=Preferences
preferences.deobfuscation=Deobfuscation preferences.deobfuscation=Deobfuscation
preferences.editor=Editor
preferences.decompile=Decompilation
preferences.other=Other preferences.other=Other
preferences.check_for_updates=Check for updates on startup preferences.check_for_updates=Check for updates on startup
preferences.fallback=Fallback (simple dump) preferences.fallback=Fallback mode (simple dump)
preferences.showInconsistentCode=Show inconsistent code preferences.showInconsistentCode=Show inconsistent code
preferences.escapeUnicode=Escape unicode
preferences.skipResourcesDecode=Don't decode resources preferences.skipResourcesDecode=Don't decode resources
preferences.threads=Processing threads count preferences.threads=Processing threads count
preferences.cfg=Generate methods CFG graphs (in 'dot' format) preferences.cfg=Generate methods CFG graphs (in 'dot' format)
......
package jadx.samples;
import java.util.ArrayList;
import java.util.List;
public class TestUnicode extends AbstractTest {
/**
* Some unicode strings from:
* http://www.ltg.ed.ac.uk/~richard/unicode-sample-3-2.html
*/
public List<String> strings() {
List<String> list = new ArrayList<String>();
list.add("! \" # $ % & ' ( ) * + , - . / 0 1 2 3 4 5 6 7 8 9 : ; < = > ? @ A B C D E F G H I J K L M N O P Q R S T U V W X Y Z [ \\ ] ^ _ ` a b c d e f g h i j k l m n o p q r s t u v w x y z { | } ~");
list.add("¡ ¢ £ ¤ ¥ ¦ § ¨ © ª « ¬ ® ¯ ° ± ² ³ ´ µ ¶ · ¸ ¹ º » ¼ ½ ¾ ¿ À Á Â Ã Ä Å Æ Ç È É Ê Ë Ì Í Î Ï Ð Ñ Ò Ó Ô Õ Ö × Ø Ù Ú Û Ü Ý Þ ß à á â ã ä å æ ç è é ê ë ì í î ï ð ñ ò ó ô õ ö ÷ ø ù ú û ü ý þ ÿ");
list.add("∀ ∁ ∂ ∃ ∄ ∅ ∆ ∇ ∈ ∉ ∊ ∋ ∌ ∍ ∎ ∏ ∐ ∑ − ∓ ∔ ∕ ∖ ∗ ∘ ∙ √ ∛ ∜ ∝ ∞ ∟ ∠ ∡ ∢ ∣ ∤ ∥ ∦ ∧ ∨ ∩ ∪ ∫ ∬ ∭ ∮ ∯ ∰ ∱ ∲ ∳ ∴ ∵ ∶ ∷ ∸ ∹ ∺ ∻ ∼ ∽ ∾ ∿ ≀ ≁ ≂ ≃ ≄ ≅ ≆ ≇ ≈ ≉ ≊ ≋ ≌ ≍ ≎ ≏ ≐ ≑ ≒ ≓ ≔ ≕ ≖ ≗ ≘ ≙ ≚ ≛ ≜ ≝ ≞ ≟ ≠ ≡ ≢ ≣ ≤ ≥ ≦ ≧ ≨ ≩ ≪ ≫ ≬ ≭ ≮ ≯ ≰ ≱ ≲ ≳ ≴ ≵ ≶ ≷ ≸ ≹ ≺ ≻ ≼ ≽ ≾ ≿");
list.add("Ѐ Ё Ђ Ѓ Є Ѕ І Ї Ј Љ Њ Ћ Ќ Ѝ Ў Џ А Б В Г Д Е Ж З И Й К Л М Н О П Р С Т У Ф Х Ц Ч Ш Щ Ъ Ы Ь Э Ю Я а б в г д е ж з и й к л м н о п р с т у ф х ц ч ш щ ъ ы ь э ю я ѐ ё ђ ѓ є ѕ і ї");
list.add("ぁ あ ぃ い ぅ う ぇ え ぉ お か が き ぎ く ぐ け げ こ ご さ ざ し じ す ず せ ぜ そ ぞ た だ ち ぢ っ つ づ て で と ど な に ぬ ね の は ば ぱ ひ び ぴ ふ ぶ ぷ へ べ ぺ ほ ぼ ぽ ま み む め も ゃ や ゅ ゆ ょ よ ら り る れ ろ ゎ わ ゐ ゑ を ん");
list.add("ァ ア ィ イ ゥ ウ ェ エ ォ オ カ ガ キ ギ ク グ ケ ゲ コ ゴ サ ザ シ ジ ス ズ セ ゼ ソ ゾ タ ダ チ ヂ ッ ツ ヅ テ デ ト ド ナ ニ ヌ ネ ノ ハ バ パ ヒ ビ ピ フ ブ プ ヘ ベ ペ ホ ボ ポ マ ミ ム メ モ ャ ヤ ュ ユ ョ ヨ ラ リ ル レ ロ ヮ ワ ヰ ヱ ヲ ン ヴ ヵ ヶ");
list.add("一 丁 丂 七 丄 丅 丆 万 丈 三 上 下 丌 不 与 丏 丐 丑 丒 专 且 丕 世 丗 丘 丙 业 丛 东 丝 丞 丟 丠 両 丢 丣 两 严 並 丧 丨 丩 个 丫 丬 中 丮 丯 丰 丱 串 丳 临 丵 丶 丷 丸 丹 为 主 丼 丽 举 丿 乀 乁 乂 乃 乄 久 乆 乇 么 义 乊 之 乌 乍 乎 乏 乐 乑 乒 乓 乔 乕 乖 乗 乘 乙 乚 乛 乜 九 乞 也 习 乡 乢 乣 乤 乥 书 乧 乨 乩 乪 乫 乬 乭 乮 乯 买 乱 乲 乳 乴 乵 乶 乷 乸 乹 乺 乻 乼 乽 乾 乿");
list.add("豈 更 車 賈 滑 串 句 龜 龜 契 金 喇 奈 懶 癩 羅 蘿 螺 裸 邏 樂 洛 烙 珞 落 酪 駱 亂 卵 欄 爛 蘭 鸞 嵐 濫 藍 襤 拉 臘 蠟 廊 朗 浪 狼 郎 來 冷 勞 擄 櫓 爐 盧 老 蘆 虜 路 露 魯 鷺 碌 祿 綠 菉 錄 鹿 論 壟 弄 籠 聾 牢 磊 賂 雷 壘 屢 樓 淚 漏 累 縷 陋 勒 肋 凜 凌 稜 綾 菱 陵 讀 拏 樂 諾 丹 寧 怒 率 異 北 磻 便 復 不 泌 數 索 參 塞 省 葉 說 殺 辰 沈 拾 若 掠 略 亮 兩 凉 梁 糧 良 諒 量 勵");
list.add("ㄱ ㄲ ㄳ ㄴ ㄵ ㄶ ㄷ ㄸ ㄹ ㄺ ㄻ ㄼ ㄽ ㄾ ㄿ ㅀ ㅁ ㅂ ㅃ ㅄ ㅅ ㅆ ㅇ ㅈ ㅉ ㅊ ㅋ ㅌ ㅍ ㅎ ㅏ ㅐ ㅑ ㅒ ㅓ ㅔ ㅕ ㅖ ㅗ ㅘ ㅙ ㅚ ㅛ ㅜ ㅝ ㅞ ㅟ ㅠ ㅡ ㅢ ㅣ ㅤ ㅥ ㅦ ㅧ ㅨ ㅩ ㅪ ㅫ ㅬ ㅭ ㅮ ㅯ ㅰ ㅱ ㅲ ㅳ ㅴ ㅵ ㅶ ㅷ ㅸ ㅹ ㅺ ㅻ ㅼ ㅽ ㅾ ㅿ ㆀ ㆁ ㆂ ㆃ ㆄ ㆅ ㆆ ㆇ ㆈ ㆉ ㆊ ㆋ ㆌ");
list.add("가 각 갂 갃 간 갅 갆 갇 갈 갉 갊 갋 갌 갍 갎 갏 감 갑 값 갓 갔 강 갖 갗 갘 같 갚 갛 개 객 갞 갟 갠 갡 갢 갣 갤 갥 갦 갧 갨 갩 갪 갫 갬 갭 갮 갯 갰 갱 갲 갳 갴 갵 갶 갷 갸 갹 갺 갻 갼 갽 갾 갿 걀 걁 걂 걃 걄 걅 걆 걇 걈 걉 걊 걋 걌 걍 걎 걏 걐 걑 걒 걓 걔 걕 걖 걗 걘 걙 걚 걛 걜 걝 걞 걟 걠 걡 걢 걣 걤 걥 걦 걧 걨 걩 걪 걫 걬 걭 걮 걯 거 걱 걲 걳 건 걵 걶 걷 걸 걹 걺 걻 걼 걽 걾 걿");
list.add( "؛ ؟ ء آ أ ؤ إ ئ ا ب ة ت ث ج ح خ د ذ ر ز س ش ص ض ط ظ ع غ ـ ف ق ك ل م ن ه و ى ي ً ٌ ٍ َ ُ ِ ّ ْ ٓ ٔ ٕ ٠ ١ ٢ ٣ ٤ ٥ ٦ ٧ ٨ ٩ ٪ ٫ ٬ ٭ ٮ ٯ ٰ ٱ ٲ ٳ ٴ ٵ ٶ ٷ ٸ ٹ ٺ ٻ ټ ٽ پ ٿ ڀ ځ ڂ ڃ ڄ څ چ ڇ ڈ ډ ڊ ڋ ڌ ڍ ڎ ڏ ڐ ڑ ڒ ړ ڔ ڕ ږ ڗ ژ ڙ ښ ڛ ڜ ڝ ڞ ڟ ڠ ڡ ڢ ڣ ڤ ڥ ڦ ڧ ڨ ک ڪ ګ ڬ");
list.add( "ஃ அ ஆ இ ஈ உ ஊ எ ஏ ஐ ஒ ஓ ஔ க ங ச ஜ ஞ ட ண த ந ன ப ம ய ர ற ல ள ழ வ ஷ ஸ ஹ ா ி ீ ு ூ ெ ே ை ொ ோ ௌ ் ௗ ௧ ௨ ௩ ௪ ௫ ௬ ௭ ௮ ௯ ௰ ௱ ௲");
list.add( "\uD800\uDF00 \uD800\uDF01 \uD800\uDF02 \uD800\uDF03 \uD800\uDF04 \uD800\uDF05 \uD800\uDF06 \uD800\uDF07 \uD800\uDF08 \uD800\uDF09 \uD800\uDF0A \uD800\uDF0B \uD800\uDF0C \uD800\uDF0D \uD800\uDF0E \uD800\uDF0F \uD800\uDF10 \uD800\uDF11 \uD800\uDF12 \uD800\uDF13 \uD800\uDF14 \uD800\uDF15 \uD800\uDF16 \uD800\uDF17 \uD800\uDF18 \uD800\uDF19 \uD800\uDF1A \uD800\uDF1B \uD800\uDF1C \uD800\uDF1D \uD800\uDF1E \uD800\uDF20 \uD800\uDF21 \uD800\uDF22 \uD800\uDF23");
list.add("𐌀 𐌁 𐌂 𐌃 𐌄 𐌅 𐌆 𐌇 𐌈 𐌉 𐌊 𐌋 𐌌 𐌍 𐌎 𐌏 𐌐 𐌑 𐌒 𐌓 𐌔 𐌕 𐌖 𐌗 𐌘 𐌙 𐌚 𐌛 𐌜 𐌝 𐌞 𐌠 𐌡 𐌢 𐌣");
return list;
}
@Override
public boolean testRun() throws Exception {
String s = "\uD800\uDF0F"; // 𐌏
int codePoint = s.codePointAt(0);
System.out.println(s + " = " + codePoint);
assertEquals(codePoint, 66319);
return true;
}
public static void main(String[] args) throws Exception {
new TestUnicode().testRun();
}
}
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