feat: add option for hexadecimal integer format globally (PR #1869)

* option for hexadecimal integer format globally

* fix i18n strings, update readme

---------

Co-authored-by: Skylot <skylot@gmail.com>
This commit is contained in:
Krzysztof Iwaniuk 2023-05-15 14:58:13 +02:00 committed by GitHub
parent ccdbb1d62c
commit 63ad7fb128
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
21 changed files with 223 additions and 130 deletions

View File

@ -124,7 +124,6 @@ options:
'overwrite' - don't read, always save
'ignore' - don't read and don't save
--deobf-use-sourcename - use source file name as class name alias
--deobf-parse-kotlin-metadata - parse kotlin metadata to class and package names
--deobf-res-name-source - better name source for resources:
'auto' - automatically select best name (default)
'resources' - use resources names
@ -136,6 +135,10 @@ options:
'printable' - remove non-printable chars from identifiers,
or single 'none' - to disable all renames
or single 'all' - to enable all (default)
--integer-format - how integers are displayed:
'auto' - automatically select (default)
'decimal' - use decimal
'hexadecimal' - use hexadecimal
--fs-case-sensitive - treat filesystem as case sensitive, false by default
--cfg - save methods control flow graph to dot file
--raw-cfg - save methods control flow graph (use raw instructions)

View File

@ -24,6 +24,7 @@ import jadx.api.JadxArgs.RenameEnum;
import jadx.api.JadxArgs.UseKotlinMethodsForVarNames;
import jadx.api.JadxDecompiler;
import jadx.api.args.GeneratedRenamesMappingFileMode;
import jadx.api.args.IntegerFormat;
import jadx.api.args.ResourceNameSource;
import jadx.api.args.UserRenamesMappingsMode;
import jadx.core.utils.exceptions.JadxException;
@ -186,6 +187,16 @@ public class JadxCLIArgs {
)
protected Set<RenameEnum> renameFlags = EnumSet.allOf(RenameEnum.class);
@Parameter(
names = { "--integer-format" },
description = "how integers are displayed:"
+ "\n 'auto' - automatically select (default)"
+ "\n 'decimal' - use decimal"
+ "\n 'hexadecimal' - use hexadecimal",
converter = IntegerFormatConverter.class
)
protected IntegerFormat integerFormat = IntegerFormat.AUTO;
@Parameter(names = { "--fs-case-sensitive" }, description = "treat filesystem as case sensitive, false by default")
protected boolean fsCaseSensitive = false;
@ -318,6 +329,7 @@ public class JadxCLIArgs {
args.setRenameFlags(renameFlags);
args.setFsCaseSensitive(fsCaseSensitive);
args.setCommentsLevel(commentsLevel);
args.setIntegerFormat(integerFormat);
args.setUseDxInput(useDx);
args.setPluginOptions(pluginOptions);
return args;
@ -447,6 +459,10 @@ public class JadxCLIArgs {
return useKotlinMethodsForVarNames;
}
public IntegerFormat getIntegerFormat() {
return integerFormat;
}
public boolean isEscapeUnicode() {
return escapeUnicode;
}
@ -564,6 +580,12 @@ public class JadxCLIArgs {
}
}
public static class IntegerFormatConverter extends BaseEnumConverter<IntegerFormat> {
public IntegerFormatConverter() {
super(IntegerFormat::valueOf, IntegerFormat::values);
}
}
public abstract static class BaseEnumConverter<E extends Enum<E>> implements IStringConverter<E> {
private final Function<String, E> parse;
private final Supplier<E[]> values;

View File

@ -17,6 +17,7 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import jadx.api.args.GeneratedRenamesMappingFileMode;
import jadx.api.args.IntegerFormat;
import jadx.api.args.ResourceNameSource;
import jadx.api.args.UserRenamesMappingsMode;
import jadx.api.data.ICodeData;
@ -132,6 +133,8 @@ public class JadxArgs implements Closeable {
private CommentsLevel commentsLevel = CommentsLevel.INFO;
private IntegerFormat integerFormat = IntegerFormat.AUTO;
private boolean useDxInput = false;
public enum UseKotlinMethodsForVarNames {
@ -591,6 +594,14 @@ public class JadxArgs implements Closeable {
this.commentsLevel = commentsLevel;
}
public IntegerFormat getIntegerFormat() {
return integerFormat;
}
public void setIntegerFormat(IntegerFormat format) {
this.integerFormat = format;
}
public boolean isUseDxInput() {
return useDxInput;
}
@ -635,7 +646,7 @@ public class JadxArgs implements Closeable {
+ insertDebugLines + extractFinally
+ debugInfo + useSourceNameAsClassAlias + escapeUnicode + replaceConsts
+ respectBytecodeAccModifiers + fsCaseSensitive + renameFlags
+ commentsLevel + useDxInput;
+ commentsLevel + useDxInput + integerFormat;
return FileUtils.md5Sum(argStr);
}

View File

@ -0,0 +1,11 @@
package jadx.api.args;
public enum IntegerFormat {
AUTO,
DECIMAL,
HEXADECIMAL;
public boolean isHexadecimal() {
return this == HEXADECIMAL;
}
}

View File

@ -146,6 +146,8 @@ public class AnnotationGen {
code.add("null");
return;
}
StringUtils stringUtils = getStringUtils();
Object value = encodedValue.getValue();
switch (encodedValue.getType()) {
case ENCODED_NULL:
@ -155,28 +157,28 @@ public class AnnotationGen {
code.add(Boolean.TRUE.equals(value) ? "true" : "false");
break;
case ENCODED_BYTE:
code.add(TypeGen.formatByte((Byte) value, false));
code.add(stringUtils.formatByte((Byte) value, false));
break;
case ENCODED_SHORT:
code.add(TypeGen.formatShort((Short) value, false));
code.add(stringUtils.formatShort((Short) value, false));
break;
case ENCODED_CHAR:
code.add(getStringUtils().unescapeChar((Character) value));
code.add(stringUtils.unescapeChar((Character) value));
break;
case ENCODED_INT:
code.add(TypeGen.formatInteger((Integer) value, false));
code.add(stringUtils.formatInteger((Integer) value, false));
break;
case ENCODED_LONG:
code.add(TypeGen.formatLong((Long) value, false));
code.add(stringUtils.formatLong((Long) value, false));
break;
case ENCODED_FLOAT:
code.add(TypeGen.formatFloat((Float) value));
code.add(StringUtils.formatFloat((Float) value));
break;
case ENCODED_DOUBLE:
code.add(TypeGen.formatDouble((Double) value));
code.add(StringUtils.formatDouble((Double) value));
break;
case ENCODED_STRING:
code.add(getStringUtils().unescapeString((String) value));
code.add(stringUtils.unescapeString((String) value));
break;
case ENCODED_TYPE:
classGen.useType(code, ArgType.parse((String) value));

View File

@ -19,6 +19,7 @@ import jadx.api.CommentsLevel;
import jadx.api.ICodeInfo;
import jadx.api.ICodeWriter;
import jadx.api.JadxArgs;
import jadx.api.args.IntegerFormat;
import jadx.api.metadata.annotations.NodeEnd;
import jadx.api.plugins.input.data.AccessFlags;
import jadx.api.plugins.input.data.annotations.EncodedType;
@ -59,6 +60,7 @@ public class ClassGen {
private final boolean fallback;
private final boolean useImports;
private final boolean showInconsistentCode;
private final IntegerFormat integerFormat;
private final Set<ClassInfo> imports = new HashSet<>();
private int clsDeclOffset;
@ -69,19 +71,22 @@ public class ClassGen {
private NameGen outerNameGen;
public ClassGen(ClassNode cls, JadxArgs jadxArgs) {
this(cls, null, jadxArgs.isUseImports(), jadxArgs.isFallbackMode(), jadxArgs.isShowInconsistentCode());
this(cls, null, jadxArgs.isUseImports(), jadxArgs.isFallbackMode(), jadxArgs.isShowInconsistentCode(), jadxArgs.getIntegerFormat());
}
public ClassGen(ClassNode cls, ClassGen parentClsGen) {
this(cls, parentClsGen, parentClsGen.useImports, parentClsGen.fallback, parentClsGen.showInconsistentCode);
this(cls, parentClsGen, parentClsGen.useImports, parentClsGen.fallback, parentClsGen.showInconsistentCode,
parentClsGen.integerFormat);
}
public ClassGen(ClassNode cls, ClassGen parentClsGen, boolean useImports, boolean fallback, boolean showBadCode) {
public ClassGen(ClassNode cls, ClassGen parentClsGen, boolean useImports, boolean fallback, boolean showBadCode,
IntegerFormat integerFormat) {
this.cls = cls;
this.parentGen = parentClsGen;
this.fallback = fallback;
this.useImports = useImports;
this.showInconsistentCode = showBadCode;
this.integerFormat = integerFormat;
this.annotationGen = new AnnotationGen(cls, this);
}
@ -424,10 +429,7 @@ public class ClassGen {
Object val = EncodedValueUtils.convertToConstValue(constVal);
if (val instanceof LiteralArg) {
long lit = ((LiteralArg) val).getLiteral();
if (!AndroidResourcesUtils.handleResourceFieldValue(cls, code, lit, f.getType())) {
// force literal type to be same as field (java bytecode can use different type)
code.add(TypeGen.literalToString(lit, f.getType(), cls, fallback));
}
code.add(getIntegerString(lit, f.getType()));
} else {
annotationGen.encodeValue(cls.root(), code, constVal);
}
@ -437,6 +439,14 @@ public class ClassGen {
code.add(';');
}
private String getIntegerString(long lit, ArgType type) {
if (integerFormat != IntegerFormat.DECIMAL && AndroidResourcesUtils.isResourceFieldValue(cls, type)) {
return String.format("0x%08x", lit);
}
// force literal type to be same as field (java bytecode can use different type)
return TypeGen.literalToString(lit, type, cls, fallback);
}
private boolean isFieldsPresents() {
for (FieldNode field : cls.getFields()) {
if (!field.contains(AFlag.DONT_GENERATE)) {

View File

@ -13,6 +13,7 @@ import org.slf4j.LoggerFactory;
import jadx.api.CommentsLevel;
import jadx.api.ICodeWriter;
import jadx.api.JadxArgs;
import jadx.api.args.IntegerFormat;
import jadx.api.metadata.annotations.InsnCodeOffset;
import jadx.api.metadata.annotations.VarNode;
import jadx.api.plugins.input.data.AccessFlags;
@ -548,7 +549,7 @@ public class MethodGen {
* Return fallback variant of method codegen
*/
public static MethodGen getFallbackMethodGen(MethodNode mth) {
ClassGen clsGen = new ClassGen(mth.getParentClass(), null, false, true, true);
ClassGen clsGen = new ClassGen(mth.getParentClass(), null, false, true, true, IntegerFormat.AUTO);
return new MethodGen(clsGen, mth);
}

View File

@ -73,17 +73,17 @@ public class TypeGen {
case CHAR:
return stringUtils.unescapeChar((char) lit, cast);
case BYTE:
return formatByte(lit, cast);
return stringUtils.formatByte(lit, cast);
case SHORT:
return formatShort(lit, cast);
return stringUtils.formatShort(lit, cast);
case INT:
return formatInteger(lit, cast);
return stringUtils.formatInteger(lit, cast);
case LONG:
return formatLong(lit, cast);
return stringUtils.formatLong(lit, cast);
case FLOAT:
return formatFloat(Float.intBitsToFloat((int) lit));
return StringUtils.formatFloat(Float.intBitsToFloat((int) lit));
case DOUBLE:
return formatDouble(Double.longBitsToDouble(lit));
return StringUtils.formatDouble(Double.longBitsToDouble(lit));
case OBJECT:
case ARRAY:
@ -134,95 +134,4 @@ public class TypeGen {
return null;
}
}
public static String formatShort(long l, boolean cast) {
if (l == Short.MAX_VALUE) {
return "Short.MAX_VALUE";
}
if (l == Short.MIN_VALUE) {
return "Short.MIN_VALUE";
}
String str = Long.toString(l);
return cast ? "(short) " + str : str;
}
public static String formatByte(long l, boolean cast) {
if (l == Byte.MAX_VALUE) {
return "Byte.MAX_VALUE";
}
if (l == Byte.MIN_VALUE) {
return "Byte.MIN_VALUE";
}
String str = Long.toString(l);
return cast ? "(byte) " + str : str;
}
public static String formatInteger(long l, boolean cast) {
if (l == Integer.MAX_VALUE) {
return "Integer.MAX_VALUE";
}
if (l == Integer.MIN_VALUE) {
return "Integer.MIN_VALUE";
}
String str = Long.toString(l);
return cast ? "(int) " + str : str;
}
public static String formatLong(long l, boolean cast) {
if (l == Long.MAX_VALUE) {
return "Long.MAX_VALUE";
}
if (l == Long.MIN_VALUE) {
return "Long.MIN_VALUE";
}
String str = Long.toString(l);
if (cast || Math.abs(l) >= Integer.MAX_VALUE) {
return str + 'L';
}
return str;
}
public static String formatDouble(double d) {
if (Double.isNaN(d)) {
return "Double.NaN";
}
if (d == Double.NEGATIVE_INFINITY) {
return "Double.NEGATIVE_INFINITY";
}
if (d == Double.POSITIVE_INFINITY) {
return "Double.POSITIVE_INFINITY";
}
if (d == Double.MIN_VALUE) {
return "Double.MIN_VALUE";
}
if (d == Double.MAX_VALUE) {
return "Double.MAX_VALUE";
}
if (d == Double.MIN_NORMAL) {
return "Double.MIN_NORMAL";
}
return Double.toString(d) + 'd';
}
public static String formatFloat(float f) {
if (Float.isNaN(f)) {
return "Float.NaN";
}
if (f == Float.NEGATIVE_INFINITY) {
return "Float.NEGATIVE_INFINITY";
}
if (f == Float.POSITIVE_INFINITY) {
return "Float.POSITIVE_INFINITY";
}
if (f == Float.MIN_VALUE) {
return "Float.MIN_VALUE";
}
if (f == Float.MAX_VALUE) {
return "Float.MAX_VALUE";
}
if (f == Float.MIN_NORMAL) {
return "Float.MIN_NORMAL";
}
return Float.toString(f) + 'f';
}
}

View File

@ -7,6 +7,7 @@ import java.util.function.IntConsumer;
import org.jetbrains.annotations.Nullable;
import jadx.api.JadxArgs;
import jadx.api.args.IntegerFormat;
import jadx.core.deobf.NameMapper;
public class StringUtils {
@ -19,9 +20,15 @@ public class StringUtils {
}
private final boolean escapeUnicode;
private final IntegerFormat integerFormat;
public StringUtils(JadxArgs args) {
this.escapeUnicode = args.isEscapeUnicode();
this.integerFormat = args.getIntegerFormat();
}
public IntegerFormat getIntegerFormat() {
return integerFormat;
}
public static void visitCodePoints(String str, IntConsumer visitor) {
@ -370,4 +377,102 @@ public class StringUtils {
public static String getDateText() {
return new SimpleDateFormat("HH:mm:ss").format(new Date());
}
private String toFormatString(long l) {
if (integerFormat.isHexadecimal()) {
return "0x" + Long.toHexString(l);
}
return Long.toString(l);
}
public String formatShort(long l, boolean cast) {
if (l == Short.MAX_VALUE) {
return "Short.MAX_VALUE";
}
if (l == Short.MIN_VALUE) {
return "Short.MIN_VALUE";
}
String str = toFormatString(l);
return cast ? "(short) " + str : str;
}
public String formatByte(long l, boolean cast) {
if (l == Byte.MAX_VALUE) {
return "Byte.MAX_VALUE";
}
if (l == Byte.MIN_VALUE) {
return "Byte.MIN_VALUE";
}
String str = toFormatString(l);
return cast ? "(byte) " + str : str;
}
public String formatInteger(long l, boolean cast) {
if (l == Integer.MAX_VALUE) {
return "Integer.MAX_VALUE";
}
if (l == Integer.MIN_VALUE) {
return "Integer.MIN_VALUE";
}
String str = toFormatString(l);
return cast ? "(int) " + str : str;
}
public String formatLong(long l, boolean cast) {
if (l == Long.MAX_VALUE) {
return "Long.MAX_VALUE";
}
if (l == Long.MIN_VALUE) {
return "Long.MIN_VALUE";
}
String str = toFormatString(l);
if (cast || Math.abs(l) >= Integer.MAX_VALUE) {
return str + 'L';
}
return str;
}
public static String formatDouble(double d) {
if (Double.isNaN(d)) {
return "Double.NaN";
}
if (d == Double.NEGATIVE_INFINITY) {
return "Double.NEGATIVE_INFINITY";
}
if (d == Double.POSITIVE_INFINITY) {
return "Double.POSITIVE_INFINITY";
}
if (d == Double.MIN_VALUE) {
return "Double.MIN_VALUE";
}
if (d == Double.MAX_VALUE) {
return "Double.MAX_VALUE";
}
if (d == Double.MIN_NORMAL) {
return "Double.MIN_NORMAL";
}
return Double.toString(d) + 'd';
}
public static String formatFloat(float f) {
if (Float.isNaN(f)) {
return "Float.NaN";
}
if (f == Float.NEGATIVE_INFINITY) {
return "Float.NEGATIVE_INFINITY";
}
if (f == Float.POSITIVE_INFINITY) {
return "Float.POSITIVE_INFINITY";
}
if (f == Float.MIN_VALUE) {
return "Float.MIN_VALUE";
}
if (f == Float.MAX_VALUE) {
return "Float.MAX_VALUE";
}
if (f == Float.MIN_NORMAL) {
return "Float.MIN_NORMAL";
}
return Float.toString(f) + 'f';
}
}

View File

@ -76,12 +76,8 @@ public class AndroidResourcesUtils {
/**
* Force hex format for Android resources ids
*/
public static boolean handleResourceFieldValue(ClassNode cls, ICodeWriter code, long lit, ArgType type) {
if (type.equals(ArgType.INT) && isResourceClass(cls)) {
code.add(String.format("0x%08x", lit));
return true;
}
return false;
public static boolean isResourceFieldValue(ClassNode cls, ArgType type) {
return type.equals(ArgType.INT) && isResourceClass(cls);
}
public static boolean isResourceClass(ClassNode cls) {

View File

@ -37,7 +37,6 @@ import jadx.api.plugins.input.insns.InsnData;
import jadx.api.plugins.input.insns.InsnIndexType;
import jadx.api.plugins.input.insns.Opcode;
import jadx.api.plugins.input.insns.custom.ISwitchPayload;
import jadx.core.codegen.TypeGen;
import jadx.core.dex.attributes.AttributeStorage;
import jadx.core.dex.instructions.IndexInsnNode;
import jadx.core.dex.instructions.InsnDecoder;
@ -48,6 +47,7 @@ import jadx.core.dex.instructions.args.RegisterArg;
import jadx.core.dex.nodes.ClassNode;
import jadx.core.dex.nodes.InsnNode;
import jadx.core.dex.nodes.MethodNode;
import jadx.core.utils.StringUtils;
import jadx.core.utils.Utils;
import jadx.core.utils.exceptions.JadxRuntimeException;
@ -593,6 +593,7 @@ public class Smali {
}
private void writeEncodedValue(SmaliWriter smali, EncodedValue value, boolean wrapArray) {
StringUtils stringUtils = smali.getClassNode().root().getStringUtils();
switch (value.getType()) {
case ENCODED_ARRAY:
smali.add("{");
@ -624,28 +625,28 @@ public class Smali {
writeAnnotation(smali, (IAnnotation) value.getValue());
break;
case ENCODED_BYTE:
smali.add(TypeGen.formatByte((Byte) value.getValue(), false));
smali.add(stringUtils.formatByte((Byte) value.getValue(), false));
break;
case ENCODED_SHORT:
smali.add(TypeGen.formatShort((Short) value.getValue(), false));
smali.add(stringUtils.formatShort((Short) value.getValue(), false));
break;
case ENCODED_CHAR:
smali.add(smali.getClassNode().root().getStringUtils().unescapeChar((Character) value.getValue()));
smali.add(stringUtils.unescapeChar((Character) value.getValue()));
break;
case ENCODED_INT:
smali.add(TypeGen.formatInteger((Integer) value.getValue(), false));
smali.add(stringUtils.formatInteger((Integer) value.getValue(), false));
break;
case ENCODED_LONG:
smali.add(TypeGen.formatLong((Long) value.getValue(), false));
smali.add(stringUtils.formatLong((Long) value.getValue(), false));
break;
case ENCODED_FLOAT:
smali.add(TypeGen.formatFloat((Float) value.getValue()));
smali.add(StringUtils.formatFloat((Float) value.getValue()));
break;
case ENCODED_DOUBLE:
smali.add(TypeGen.formatDouble((Double) value.getValue()));
smali.add(StringUtils.formatDouble((Double) value.getValue()));
break;
case ENCODED_STRING:
smali.add(smali.getClassNode().root().getStringUtils().unescapeString((String) value.getValue()));
smali.add(stringUtils.unescapeString((String) value.getValue()));
break;
case ENCODED_TYPE:
smali.add(ArgType.parse((String) value.getValue()) + ".class");

View File

@ -26,6 +26,7 @@ import jadx.api.CommentsLevel;
import jadx.api.DecompilationMode;
import jadx.api.JadxArgs;
import jadx.api.args.GeneratedRenamesMappingFileMode;
import jadx.api.args.IntegerFormat;
import jadx.api.args.ResourceNameSource;
import jadx.api.args.UserRenamesMappingsMode;
import jadx.cli.JadxCLIArgs;
@ -652,6 +653,10 @@ public class JadxSettings extends JadxCLIArgs {
return lineNumbersMode;
}
public void setIntegerFormat(IntegerFormat format) {
this.integerFormat = format;
}
public void setLineNumbersMode(LineNumbersMode lineNumbersMode) {
this.lineNumbersMode = lineNumbersMode;
}

View File

@ -63,6 +63,7 @@ import jadx.api.DecompilationMode;
import jadx.api.JadxArgs;
import jadx.api.JadxArgs.UseKotlinMethodsForVarNames;
import jadx.api.args.GeneratedRenamesMappingFileMode;
import jadx.api.args.IntegerFormat;
import jadx.api.args.ResourceNameSource;
import jadx.api.plugins.options.JadxPluginOptions;
import jadx.api.plugins.options.OptionDescription;
@ -758,6 +759,13 @@ public class JadxSettingsWindow extends JDialog {
needReload();
});
JComboBox<IntegerFormat> integerFormat = new JComboBox<>(IntegerFormat.values());
integerFormat.setSelectedItem(settings.getIntegerFormat());
integerFormat.addActionListener(e -> {
settings.setIntegerFormat((IntegerFormat) integerFormat.getSelectedItem());
needReload();
});
SettingsGroup group = new SettingsGroup(NLS.str("preferences.other"));
group.addRow(NLS.str("preferences.language"), languageCbx);
group.addRow(NLS.str("preferences.lineNumbersMode"), lineNumbersMode);
@ -766,6 +774,7 @@ public class JadxSettingsWindow extends JDialog {
group.addRow(NLS.str("preferences.check_for_updates"), update);
group.addRow(NLS.str("preferences.cfg"), cfg);
group.addRow(NLS.str("preferences.raw_cfg"), rawCfg);
group.addRow(NLS.str("preferences.integerFormat"), integerFormat);
return group;
}

View File

@ -192,6 +192,7 @@ preferences.excludedPackages.button=Bearbeiten
preferences.excludedPackages.editDialog=<html>Liste der durch Leerzeichen getrennten Paketnamen, die nicht dekompiliert oder indiziert werden. (spart RAM)<br>z.B. <code>android.support</code></html>
preferences.cfg=CFG-Grafiken für Methoden generieren (im 'dot'-Format)
preferences.raw_cfg=RAW CFG-Grafiken generieren
#preferences.integerFormat=Integer format
preferences.font=Schrift ändern
preferences.smali_font=Schrifteditor
preferences.laf_theme=Thema

View File

@ -192,6 +192,7 @@ preferences.excludedPackages.button=Edit
preferences.excludedPackages.editDialog=<html>List of space separated package names that will not be decompiled or indexed (saves RAM)<br>e.g. <code>android.support</code></html>
preferences.cfg=Generate methods CFG graphs (in 'dot' format)
preferences.raw_cfg=Generate RAW CFG graphs
preferences.integerFormat=Integer format
preferences.font=Editor font
preferences.smali_font=Smali Editor font
preferences.laf_theme=Theme

View File

@ -192,6 +192,7 @@ preferences.threads=Número de hilos a procesar
#preferences.excludedPackages.editDialog=
preferences.cfg=Generar methods CFG graphs (in 'dot' format)
preferences.raw_cfg=Generate RAW CFG graphs
#preferences.integerFormat=Integer format
preferences.font=Fuente del editor
#preferences.smali_font=
#preferences.laf_theme=Theme

View File

@ -192,6 +192,7 @@ preferences.excludedPackages.button=Edit
preferences.excludedPackages.editDialog=<html>RAM 절약을 위해 디컴파일되거나 인덱싱하지 않을 패키지 이름 목록 (공백으로 항목 구분)<br>예: <code>android.support</code></html>
preferences.cfg=메소드 CFG 그래프 생성 ('dot' 포맷)
preferences.raw_cfg=RAW CFG 그래프 생성
#preferences.integerFormat=Integer format
preferences.font=에디터 글씨체
preferences.smali_font=Smali 에디터 글씨체
preferences.laf_theme=테마

View File

@ -192,6 +192,7 @@ preferences.excludedPackages.button=Editar
preferences.excludedPackages.editDialog=<html>Lista espaço de pacotes que não vão ser descompilados ou indexados (economiza RAM)<br>ex: <code>android.support</code></html>
preferences.cfg=Gera gráficos de métodos CFG no formato de pontos ('dot')
preferences.raw_cfg=Gera gráficos CFG no formato RAW
#preferences.integerFormat=Integer format
preferences.font=Fonte do editor
preferences.smali_font=Fonte do editor de smali
preferences.laf_theme=Tema

View File

@ -192,6 +192,7 @@ preferences.excludedPackages.button=Изменить
preferences.excludedPackages.editDialog=<html>Список пакетов, которые не будут декомпилироваться и индексироваться (экономит ОЗУ)<br>например: <code>android.support</code><br>Разделитель - одинарный пробел</html>
preferences.cfg=Методы генерации графиков CFG (в "dot" формате)
preferences.raw_cfg=Генерировать необработанные графики CFG
#preferences.integerFormat=Integer format
preferences.font=Шрифт редактора Java
preferences.smali_font=Шрифт редактора smali
preferences.laf_theme=Тема приложения

View File

@ -192,6 +192,7 @@ preferences.excludedPackages.button=编辑
preferences.excludedPackages.editDialog=<html>排除于反编译或索引的以空格分隔的包名列表(节省 RAM<br>例如<code>android.support</code></html>
preferences.cfg=生成方法的 CFG 图('.dot'
preferences.raw_cfg=生成原始的 CFG 图
#preferences.integerFormat=Integer format
preferences.font=编辑器字体
preferences.smali_font=Smali编辑器字体
preferences.laf_theme=主题

View File

@ -192,6 +192,7 @@ preferences.excludedPackages.button=編輯
preferences.excludedPackages.editDialog=<html>排除於索引或反編譯外的套件列表 (以空格分隔) (節省 RAM) <br>例如 <code>android.support</code></html>
preferences.cfg=產生方法 CFG 圖表 ('dot' 格式)
preferences.raw_cfg=產生 RAW CFG 圖表
#preferences.integerFormat=Integer format
preferences.font=編輯器字型
preferences.smali_font=Smali 編輯器字型
preferences.laf_theme=主題