From 6e8affcbdc917965379d524f245ba96d107d5be5 Mon Sep 17 00:00:00 2001 From: Skylot Date: Mon, 8 Apr 2024 21:51:24 +0100 Subject: [PATCH] feat: add options to JadxArgs to change code new line and indent (#1945, #1948) --- .../src/main/java/jadx/api/ICodeWriter.java | 2 - .../src/main/java/jadx/api/JadxArgs.java | 23 ++++++++ .../jadx/api/impl/AnnotatedCodeWriter.java | 11 ++-- .../java/jadx/api/impl/SimpleCodeWriter.java | 58 +++++++++---------- .../main/java/jadx/api/utils/CodeUtils.java | 28 ++++++--- .../jadx/core/codegen/json/JsonCodeGen.java | 12 ++-- .../core/dex/attributes/nodes/JadxError.java | 3 +- .../nodes/LocalVarsDebugInfoAttr.java | 3 +- .../nodes/NotificationAttrNode.java | 3 +- .../dex/attributes/nodes/PhiListAttr.java | 3 +- .../core/dex/instructions/SwitchInsn.java | 9 ++- .../java/jadx/core/dex/nodes/ClassNode.java | 26 ++++----- .../java/jadx/core/dex/nodes/InsnNode.java | 5 +- .../jadx/core/dex/regions/SwitchRegion.java | 2 +- .../core/dex/visitors/DotGraphVisitor.java | 3 +- .../dex/visitors/MethodInvokeVisitor.java | 9 ++- .../java/jadx/core/utils/DebugChecks.java | 9 ++- .../main/java/jadx/core/utils/DebugUtils.java | 6 +- .../java/jadx/core/utils/InsnRemover.java | 11 ++-- .../src/main/java/jadx/core/utils/Utils.java | 7 +++ .../java/jadx/core/xmlgen/ResProtoParser.java | 2 +- .../java/jadx/core/xmlgen/ResTableParser.java | 2 +- .../main/java/jadx/core/xmlgen/ResXmlGen.java | 5 +- .../java/jadx/core/xmlgen/ResXmlGenTest.java | 55 ++++++++++-------- .../java/jadx/tests/api/IntegrationTest.java | 14 +++-- .../jadx/tests/api/utils/JadxMatchers.java | 6 +- .../java/jadx/tests/api/utils/TestUtils.java | 12 ++-- .../api/utils/assertj/JadxCodeAssertions.java | 5 +- .../jadx/tests/external/BaseExternalTest.java | 3 +- .../conditions/TestElseIfCodeStyle.java | 3 +- .../debuginfo/TestReturnSourceLine.java | 5 +- .../jadx/gui/device/debugger/smali/Smali.java | 3 +- .../search/providers/CodeSearchProvider.java | 6 +- .../providers/ResourceSearchProvider.java | 6 +- .../java/jadx/gui/treemodel/JResource.java | 3 +- .../java/jadx/gui/ui/panel/ImagePanel.java | 3 +- 36 files changed, 194 insertions(+), 172 deletions(-) diff --git a/jadx-core/src/main/java/jadx/api/ICodeWriter.java b/jadx-core/src/main/java/jadx/api/ICodeWriter.java index fd49ee92eb6..056284d901f 100644 --- a/jadx-core/src/main/java/jadx/api/ICodeWriter.java +++ b/jadx-core/src/main/java/jadx/api/ICodeWriter.java @@ -8,8 +8,6 @@ import jadx.api.metadata.ICodeNodeRef; public interface ICodeWriter { - String NL = System.getProperty("line.separator"); - String INDENT_STR = " "; boolean isMetadataSupported(); diff --git a/jadx-core/src/main/java/jadx/api/JadxArgs.java b/jadx-core/src/main/java/jadx/api/JadxArgs.java index f86e973f441..df7ff1cfdb2 100644 --- a/jadx-core/src/main/java/jadx/api/JadxArgs.java +++ b/jadx-core/src/main/java/jadx/api/JadxArgs.java @@ -42,6 +42,9 @@ public class JadxArgs implements Closeable { public static final int DEFAULT_THREADS_COUNT = Math.max(1, Runtime.getRuntime().availableProcessors() / 2); + public static final String DEFAULT_NEW_LINE_STR = System.lineSeparator(); + public static final String DEFAULT_INDENT_STR = " "; + public static final String DEFAULT_OUT_DIR = "jadx-output"; public static final String DEFAULT_SRC_DIR = "sources"; public static final String DEFAULT_RES_DIR = "resources"; @@ -144,6 +147,10 @@ public enum OutputFormatEnum { private ICodeData codeData; + private String codeNewLineStr = DEFAULT_NEW_LINE_STR; + + private String codeIndentStr = DEFAULT_INDENT_STR; + private CommentsLevel commentsLevel = CommentsLevel.INFO; private IntegerFormat integerFormat = IntegerFormat.AUTO; @@ -622,6 +629,22 @@ public void setCodeData(ICodeData codeData) { this.codeData = codeData; } + public String getCodeIndentStr() { + return codeIndentStr; + } + + public void setCodeIndentStr(String codeIndentStr) { + this.codeIndentStr = codeIndentStr; + } + + public String getCodeNewLineStr() { + return codeNewLineStr; + } + + public void setCodeNewLineStr(String codeNewLineStr) { + this.codeNewLineStr = codeNewLineStr; + } + public CommentsLevel getCommentsLevel() { return commentsLevel; } diff --git a/jadx-core/src/main/java/jadx/api/impl/AnnotatedCodeWriter.java b/jadx-core/src/main/java/jadx/api/impl/AnnotatedCodeWriter.java index 4dc44528235..ca1a6ddad1a 100644 --- a/jadx-core/src/main/java/jadx/api/impl/AnnotatedCodeWriter.java +++ b/jadx-core/src/main/java/jadx/api/impl/AnnotatedCodeWriter.java @@ -21,9 +21,6 @@ public class AnnotatedCodeWriter extends SimpleCodeWriter implements ICodeWriter private Map annotations = Collections.emptyMap(); private Map lineMap = Collections.emptyMap(); - public AnnotatedCodeWriter() { - } - public AnnotatedCodeWriter(JadxArgs args) { super(args); } @@ -35,9 +32,9 @@ public boolean isMetadataSupported() { @Override public AnnotatedCodeWriter addMultiLine(String str) { - if (str.contains(NL)) { - buf.append(str.replace(NL, NL + indentStr)); - line += StringUtils.countMatches(str, NL); + if (str.contains(newLineStr)) { + buf.append(str.replace(newLineStr, newLineStr + indentStr)); + line += StringUtils.countMatches(str, newLineStr); offset = 0; } else { buf.append(str); @@ -84,7 +81,7 @@ public ICodeWriter add(ICodeWriter cw) { @Override protected void addLine() { - buf.append(NL); + buf.append(newLineStr); line++; offset = 0; } diff --git a/jadx-core/src/main/java/jadx/api/impl/SimpleCodeWriter.java b/jadx-core/src/main/java/jadx/api/impl/SimpleCodeWriter.java index ed9a0e2fafc..4b955673f0d 100644 --- a/jadx-core/src/main/java/jadx/api/impl/SimpleCodeWriter.java +++ b/jadx-core/src/main/java/jadx/api/impl/SimpleCodeWriter.java @@ -14,38 +14,39 @@ import jadx.core.utils.Utils; /** - * CodeWriter implementation without meta information support (only strings builder) + * CodeWriter implementation without meta information support */ public class SimpleCodeWriter implements ICodeWriter { private static final Logger LOG = LoggerFactory.getLogger(SimpleCodeWriter.class); - private static final String[] INDENT_CACHE = { - "", - INDENT_STR, - INDENT_STR + INDENT_STR, - INDENT_STR + INDENT_STR + INDENT_STR, - INDENT_STR + INDENT_STR + INDENT_STR + INDENT_STR, - INDENT_STR + INDENT_STR + INDENT_STR + INDENT_STR + INDENT_STR, - }; - protected StringBuilder buf = new StringBuilder(); protected String indentStr = ""; protected int indent = 0; - private final boolean insertLineNumbers; - - public SimpleCodeWriter() { - this.insertLineNumbers = false; - } + protected final boolean insertLineNumbers; + protected final String singleIndentStr; + protected final String newLineStr; public SimpleCodeWriter(JadxArgs args) { this.insertLineNumbers = args.isInsertDebugLines(); + this.singleIndentStr = args.getCodeIndentStr(); + this.newLineStr = args.getCodeNewLineStr(); if (insertLineNumbers) { incIndent(3); add(indentStr); } } + /** + * Constructor with JadxArgs should be used. + */ + @Deprecated + public SimpleCodeWriter() { + this.insertLineNumbers = false; + this.singleIndentStr = JadxArgs.DEFAULT_INDENT_STR; + this.newLineStr = JadxArgs.DEFAULT_INDENT_STR; + } + @Override public boolean isMetadataSupported() { return false; @@ -96,8 +97,8 @@ public SimpleCodeWriter startLineWithNum(int sourceLine) { @Override public SimpleCodeWriter addMultiLine(String str) { - if (str.contains(NL)) { - buf.append(str.replace(NL, NL + indentStr)); + if (str.contains(newLineStr)) { + buf.append(str.replace(newLineStr, newLineStr + indentStr)); } else { buf.append(str); } @@ -130,12 +131,12 @@ public SimpleCodeWriter newLine() { @Override public SimpleCodeWriter addIndent() { - add(INDENT_STR); + add(singleIndentStr); return this; } protected void addLine() { - buf.append(NL); + buf.append(newLineStr); } protected SimpleCodeWriter addLineIndent() { @@ -144,12 +145,7 @@ protected SimpleCodeWriter addLineIndent() { } private void updateIndent() { - int curIndent = indent; - if (curIndent < INDENT_CACHE.length) { - this.indentStr = INDENT_CACHE[curIndent]; - } else { - this.indentStr = Utils.strRepeat(INDENT_STR, curIndent); - } + this.indentStr = Utils.strRepeat(singleIndentStr, indent); } @Override @@ -219,17 +215,17 @@ public void attachSourceLine(int sourceLine) { @Override public ICodeInfo finish() { - removeFirstEmptyLine(); - String code = buf.toString(); + String code = getStringWithoutFirstEmptyLine(); buf = null; return new SimpleCodeInfo(code); } - protected void removeFirstEmptyLine() { - int len = NL.length(); - if (buf.length() > len && buf.substring(0, len).equals(NL)) { - buf.delete(0, len); + private String getStringWithoutFirstEmptyLine() { + int len = newLineStr.length(); + if (buf.length() > len && buf.substring(0, len).equals(newLineStr)) { + return buf.substring(len); } + return buf.toString(); } @Override diff --git a/jadx-core/src/main/java/jadx/api/utils/CodeUtils.java b/jadx-core/src/main/java/jadx/api/utils/CodeUtils.java index 66ef4b2dd33..9b7730303a7 100644 --- a/jadx-core/src/main/java/jadx/api/utils/CodeUtils.java +++ b/jadx-core/src/main/java/jadx/api/utils/CodeUtils.java @@ -1,7 +1,5 @@ package jadx.api.utils; -import jadx.api.ICodeWriter; - public class CodeUtils { public static String getLineForPos(String code, int pos) { @@ -11,18 +9,32 @@ public static String getLineForPos(String code, int pos) { } public static int getLineStartForPos(String code, int pos) { - String newLine = ICodeWriter.NL; - int start = code.lastIndexOf(newLine, pos); - return start == -1 ? 0 : start + newLine.length(); + int start = getNewLinePosBefore(code, pos); + return start == -1 ? 0 : start + 1; } public static int getLineEndForPos(String code, int pos) { - int end = code.indexOf(ICodeWriter.NL, pos); + int end = getNewLinePosAfter(code, pos); return end == -1 ? code.length() : end; } - public static int getLineNumForPos(String code, int pos) { - String newLine = ICodeWriter.NL; + public static int getNewLinePosAfter(String code, int startPos) { + int pos = code.indexOf('\n', startPos); + if (pos != -1) { + // check for '\r\n' + int prev = pos - 1; + if (code.charAt(prev) == '\r') { + return prev; + } + } + return pos; + } + + public static int getNewLinePosBefore(String code, int startPos) { + return code.lastIndexOf('\n', startPos); + } + + public static int getLineNumForPos(String code, int pos, String newLine) { int newLineLen = newLine.length(); int line = 1; int prev = 0; diff --git a/jadx-core/src/main/java/jadx/core/codegen/json/JsonCodeGen.java b/jadx-core/src/main/java/jadx/core/codegen/json/JsonCodeGen.java index 110f084ad00..63f3645e781 100644 --- a/jadx-core/src/main/java/jadx/core/codegen/json/JsonCodeGen.java +++ b/jadx-core/src/main/java/jadx/core/codegen/json/JsonCodeGen.java @@ -86,7 +86,7 @@ private JsonClass processCls(ClassNode cls, @Nullable ClassGen parentCodeGen) { jsonCls.setInterfaces(Utils.collectionMap(cls.getInterfaces(), clsType -> getTypeAlias(classGen, clsType))); } - ICodeWriter cw = new SimpleCodeWriter(); + ICodeWriter cw = new SimpleCodeWriter(args); CodeGenUtils.addErrorsAndComments(cw, cls); classGen.addClassDeclaration(cw); jsonCls.setDeclaration(cw.getCodeStr()); @@ -130,7 +130,7 @@ private void addFields(ClassNode cls, JsonClass jsonCls, ClassGen classGen) { jsonField.setAlias(field.getAlias()); } - ICodeWriter cw = new SimpleCodeWriter(); + ICodeWriter cw = new SimpleCodeWriter(args); classGen.addField(cw, field); jsonField.setDeclaration(cw.getCodeStr()); jsonField.setAccessFlags(field.getAccessFlags().rawValue()); @@ -154,7 +154,7 @@ private void addMethods(ClassNode cls, JsonClass jsonCls, ClassGen classGen) { jsonMth.setArguments(Utils.collectionMap(mth.getMethodInfo().getArgumentsTypes(), clsType -> getTypeAlias(classGen, clsType))); MethodGen mthGen = new MethodGen(classGen, mth); - ICodeWriter cw = new AnnotatedCodeWriter(); + ICodeWriter cw = new AnnotatedCodeWriter(args); mthGen.addDefinition(cw); jsonMth.setDeclaration(cw.getCodeStr()); jsonMth.setAccessFlags(mth.getAccessFlags().rawValue()); @@ -181,7 +181,7 @@ private List fillMthCode(MethodNode mth, MethodGen mthGen) { return Collections.emptyList(); } - String[] lines = codeStr.split(ICodeWriter.NL); + String[] lines = codeStr.split(args.getCodeNewLineStr()); Map lineMapping = code.getCodeMetadata().getLineMapping(); ICodeMetadata metadata = code.getCodeMetadata(); long mthCodeOffset = mth.getMethodCodeOffset() + 16; @@ -189,7 +189,7 @@ private List fillMthCode(MethodNode mth, MethodGen mthGen) { int linesCount = lines.length; List codeLines = new ArrayList<>(linesCount); int lineStartPos = 0; - int newLineLen = ICodeWriter.NL.length(); + int newLineLen = args.getCodeNewLineStr().length(); for (int i = 0; i < linesCount; i++) { String codeLine = lines[i]; int line = i + 2; @@ -208,7 +208,7 @@ private List fillMthCode(MethodNode mth, MethodGen mthGen) { } private String getTypeAlias(ClassGen classGen, ArgType clsType) { - ICodeWriter code = new SimpleCodeWriter(); + ICodeWriter code = new SimpleCodeWriter(args); classGen.useType(code, clsType); return code.getCodeStr(); } diff --git a/jadx-core/src/main/java/jadx/core/dex/attributes/nodes/JadxError.java b/jadx-core/src/main/java/jadx/core/dex/attributes/nodes/JadxError.java index f644e9ca57b..46c1f16fdae 100644 --- a/jadx-core/src/main/java/jadx/core/dex/attributes/nodes/JadxError.java +++ b/jadx-core/src/main/java/jadx/core/dex/attributes/nodes/JadxError.java @@ -4,7 +4,6 @@ import org.jetbrains.annotations.NotNull; -import jadx.api.ICodeWriter; import jadx.core.utils.Utils; public class JadxError implements Comparable { @@ -55,7 +54,7 @@ public String toString() { str.append(cause.getClass()); str.append(':'); str.append(cause.getMessage()); - str.append(ICodeWriter.NL); + str.append('\n'); str.append(Utils.getStackTrace(cause)); } return str.toString(); diff --git a/jadx-core/src/main/java/jadx/core/dex/attributes/nodes/LocalVarsDebugInfoAttr.java b/jadx-core/src/main/java/jadx/core/dex/attributes/nodes/LocalVarsDebugInfoAttr.java index 1645cfc41ab..3fd7cc60c80 100644 --- a/jadx-core/src/main/java/jadx/core/dex/attributes/nodes/LocalVarsDebugInfoAttr.java +++ b/jadx-core/src/main/java/jadx/core/dex/attributes/nodes/LocalVarsDebugInfoAttr.java @@ -2,7 +2,6 @@ import java.util.List; -import jadx.api.ICodeWriter; import jadx.api.plugins.input.data.ILocalVar; import jadx.api.plugins.input.data.attributes.IJadxAttribute; import jadx.core.dex.attributes.AType; @@ -26,6 +25,6 @@ public AType getAttrType() { @Override public String toString() { - return "Debug Info:" + ICodeWriter.NL + " " + Utils.listToString(localVars, ICodeWriter.NL + " "); + return "Debug Info:\n " + Utils.listToString(localVars, "\n "); } } diff --git a/jadx-core/src/main/java/jadx/core/dex/attributes/nodes/NotificationAttrNode.java b/jadx-core/src/main/java/jadx/core/dex/attributes/nodes/NotificationAttrNode.java index e50c3d43ad0..3eed35c8f11 100644 --- a/jadx-core/src/main/java/jadx/core/dex/attributes/nodes/NotificationAttrNode.java +++ b/jadx-core/src/main/java/jadx/core/dex/attributes/nodes/NotificationAttrNode.java @@ -1,7 +1,6 @@ package jadx.core.dex.attributes.nodes; import jadx.api.CommentsLevel; -import jadx.api.ICodeWriter; import jadx.api.data.CommentStyle; import jadx.core.codegen.utils.CodeComment; import jadx.core.dex.attributes.AFlag; @@ -39,7 +38,7 @@ public void addWarnComment(String warn) { } public void addWarnComment(String warn, Throwable exc) { - String commentStr = warn + ICodeWriter.NL + Utils.getStackTrace(exc); + String commentStr = warn + root().getArgs().getCodeNewLineStr() + Utils.getStackTrace(exc); JadxCommentsAttr.add(this, CommentsLevel.WARN, commentStr); } diff --git a/jadx-core/src/main/java/jadx/core/dex/attributes/nodes/PhiListAttr.java b/jadx-core/src/main/java/jadx/core/dex/attributes/nodes/PhiListAttr.java index d495d30a7e8..2e0c2e8077e 100644 --- a/jadx-core/src/main/java/jadx/core/dex/attributes/nodes/PhiListAttr.java +++ b/jadx-core/src/main/java/jadx/core/dex/attributes/nodes/PhiListAttr.java @@ -3,7 +3,6 @@ import java.util.ArrayList; import java.util.List; -import jadx.api.ICodeWriter; import jadx.api.plugins.input.data.attributes.IJadxAttribute; import jadx.core.dex.attributes.AType; import jadx.core.dex.instructions.PhiInsn; @@ -33,7 +32,7 @@ public String toString() { } } for (PhiInsn phiInsn : list) { - sb.append(ICodeWriter.NL).append(" ").append(phiInsn); + sb.append('\n').append(" ").append(phiInsn); } return sb.toString(); } diff --git a/jadx-core/src/main/java/jadx/core/dex/instructions/SwitchInsn.java b/jadx-core/src/main/java/jadx/core/dex/instructions/SwitchInsn.java index 4d773d6f3a4..5ede68a41b3 100644 --- a/jadx-core/src/main/java/jadx/core/dex/instructions/SwitchInsn.java +++ b/jadx-core/src/main/java/jadx/core/dex/instructions/SwitchInsn.java @@ -5,7 +5,6 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import jadx.api.ICodeWriter; import jadx.core.dex.instructions.args.InsnArg; import jadx.core.dex.nodes.BlockNode; import jadx.core.dex.nodes.InsnNode; @@ -111,20 +110,20 @@ public String toString() { int[] keys = switchData.getKeys(); if (targetBlocks != null) { for (int i = 0; i < size; i++) { - sb.append(ICodeWriter.NL); + sb.append('\n'); sb.append(" case ").append(keys[i]).append(": goto ").append(targetBlocks[i]); } if (def != -1) { - sb.append(ICodeWriter.NL).append(" default: goto ").append(defTargetBlock); + sb.append('\n').append(" default: goto ").append(defTargetBlock); } } else { int[] targets = switchData.getTargets(); for (int i = 0; i < size; i++) { - sb.append(ICodeWriter.NL); + sb.append('\n'); sb.append(" case ").append(keys[i]).append(": goto ").append(InsnUtils.formatOffset(targets[i])); } if (def != -1) { - sb.append(ICodeWriter.NL); + sb.append('\n'); sb.append(" default: goto ").append(InsnUtils.formatOffset(def)); } } diff --git a/jadx-core/src/main/java/jadx/core/dex/nodes/ClassNode.java b/jadx-core/src/main/java/jadx/core/dex/nodes/ClassNode.java index c6a9e01c801..c6f6d92e04c 100644 --- a/jadx-core/src/main/java/jadx/core/dex/nodes/ClassNode.java +++ b/jadx-core/src/main/java/jadx/core/dex/nodes/ClassNode.java @@ -18,10 +18,10 @@ import jadx.api.DecompilationMode; import jadx.api.ICodeCache; import jadx.api.ICodeInfo; -import jadx.api.ICodeWriter; import jadx.api.JadxArgs; import jadx.api.JavaClass; import jadx.api.impl.SimpleCodeInfo; +import jadx.api.impl.SimpleCodeWriter; import jadx.api.metadata.ICodeAnnotation; import jadx.api.metadata.annotations.NodeDeclareRef; import jadx.api.plugins.input.data.IClassData; @@ -831,33 +831,29 @@ public String getPackage() { public String getDisassembledCode() { if (smali == null) { - StringBuilder sb = new StringBuilder(); - getDisassembledCode(sb); - sb.append(ICodeWriter.NL); + SimpleCodeWriter code = new SimpleCodeWriter(root.getArgs()); + getDisassembledCode(code); Set allInlinedClasses = new LinkedHashSet<>(); getInnerAndInlinedClassesRecursive(allInlinedClasses); for (ClassNode innerClass : allInlinedClasses) { - innerClass.getDisassembledCode(sb); - sb.append(ICodeWriter.NL); + innerClass.getDisassembledCode(code); } - smali = sb.toString(); + smali = code.finish().getCodeStr(); } return smali; } - protected void getDisassembledCode(StringBuilder sb) { + protected void getDisassembledCode(SimpleCodeWriter code) { if (clsData == null) { - sb.append(String.format("###### Class %s is created by jadx", getFullName())); + code.startLine(String.format("###### Class %s is created by jadx", getFullName())); return; } - sb.append(String.format("###### Class %s (%s)", getFullName(), getRawName())); - sb.append(ICodeWriter.NL); + code.startLine(String.format("###### Class %s (%s)", getFullName(), getRawName())); try { - sb.append(clsData.getDisassembledCode()); + code.startLine(clsData.getDisassembledCode()); } catch (Throwable e) { - sb.append("Failed to disassemble class:"); - sb.append(ICodeWriter.NL); - sb.append(Utils.getStackTrace(e)); + code.startLine("Failed to disassemble class:"); + code.startLine(Utils.getStackTrace(e)); } } diff --git a/jadx-core/src/main/java/jadx/core/dex/nodes/InsnNode.java b/jadx-core/src/main/java/jadx/core/dex/nodes/InsnNode.java index b9a292ca6c8..ba5a49fc832 100644 --- a/jadx-core/src/main/java/jadx/core/dex/nodes/InsnNode.java +++ b/jadx-core/src/main/java/jadx/core/dex/nodes/InsnNode.java @@ -10,7 +10,6 @@ import org.jetbrains.annotations.Nullable; -import jadx.api.ICodeWriter; import jadx.api.plugins.input.insns.InsnData; import jadx.core.dex.attributes.AFlag; import jadx.core.dex.attributes.AType; @@ -563,9 +562,9 @@ protected boolean appendArgs(StringBuilder sb) { return false; } // wrap args - String separator = ICodeWriter.NL + " "; + String separator = "\n "; sb.append(separator).append(Utils.listToString(arguments, separator)); - sb.append(ICodeWriter.NL); + sb.append('\n'); return true; } diff --git a/jadx-core/src/main/java/jadx/core/dex/regions/SwitchRegion.java b/jadx-core/src/main/java/jadx/core/dex/regions/SwitchRegion.java index eb4f8deeca2..045457df9c2 100644 --- a/jadx-core/src/main/java/jadx/core/dex/regions/SwitchRegion.java +++ b/jadx-core/src/main/java/jadx/core/dex/regions/SwitchRegion.java @@ -96,7 +96,7 @@ public String toString() { for (CaseInfo caseInfo : cases) { List keyStrings = Utils.collectionMap(caseInfo.getKeys(), k -> k == DEFAULT_CASE_KEY ? "default" : k.toString()); - sb.append(ICodeWriter.NL).append(" case ") + sb.append("\n case ") .append(Utils.listToString(keyStrings)) .append(" -> ").append(caseInfo.getContainer()); } diff --git a/jadx-core/src/main/java/jadx/core/dex/visitors/DotGraphVisitor.java b/jadx-core/src/main/java/jadx/core/dex/visitors/DotGraphVisitor.java index 105ca93f2cd..184ab3c2f57 100644 --- a/jadx-core/src/main/java/jadx/core/dex/visitors/DotGraphVisitor.java +++ b/jadx-core/src/main/java/jadx/core/dex/visitors/DotGraphVisitor.java @@ -319,8 +319,7 @@ private String escape(String string) { .replace("\"", "\\\"") .replace("-", "\\-") .replace("|", "\\|") - .replace(ICodeWriter.NL, NL) - .replace("\n", NL); + .replaceAll("\\R", NL); } } } diff --git a/jadx-core/src/main/java/jadx/core/dex/visitors/MethodInvokeVisitor.java b/jadx-core/src/main/java/jadx/core/dex/visitors/MethodInvokeVisitor.java index a5cbff756cc..9ac0ed9f269 100644 --- a/jadx-core/src/main/java/jadx/core/dex/visitors/MethodInvokeVisitor.java +++ b/jadx-core/src/main/java/jadx/core/dex/visitors/MethodInvokeVisitor.java @@ -8,7 +8,6 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import jadx.api.ICodeWriter; import jadx.core.Consts; import jadx.core.dex.attributes.AFlag; import jadx.core.dex.info.MethodInfo; @@ -290,10 +289,10 @@ private List searchCastTypes(MethodNode parentMth, IMethodDetails mthDe if (Consts.DEBUG_OVERLOADED_CASTS) { // TODO: try to minimize casts count parentMth.addDebugComment("Failed to find minimal casts for resolve overloaded methods, cast all args instead" - + ICodeWriter.NL + " method: " + mthDetails - + ICodeWriter.NL + " arg types: " + compilerVarTypes - + ICodeWriter.NL + " candidates:" - + ICodeWriter.NL + " " + Utils.listToString(overloadedMethods, ICodeWriter.NL + " ")); + + "\n method: " + mthDetails + + "\n arg types: " + compilerVarTypes + + "\n candidates:" + + "\n " + Utils.listToString(overloadedMethods, "\n ")); } // not resolved -> cast all args return mthDetails.getArgTypes(); diff --git a/jadx-core/src/main/java/jadx/core/utils/DebugChecks.java b/jadx-core/src/main/java/jadx/core/utils/DebugChecks.java index 7614723bfd3..53f6ffca2cd 100644 --- a/jadx-core/src/main/java/jadx/core/utils/DebugChecks.java +++ b/jadx-core/src/main/java/jadx/core/utils/DebugChecks.java @@ -3,7 +3,6 @@ import java.util.ArrayList; import java.util.List; -import jadx.api.ICodeWriter; import jadx.core.dex.attributes.AFlag; import jadx.core.dex.attributes.AType; import jadx.core.dex.attributes.nodes.PhiListAttr; @@ -96,13 +95,13 @@ private static void checkVar(MethodNode mth, InsnNode insn, RegisterArg reg) { if (resArg == reg) { if (sVar.getAssignInsn() != insn) { throw new JadxRuntimeException("Incorrect assign in ssa var: " + sVar - + ICodeWriter.NL + " expected: " + sVar.getAssignInsn() - + ICodeWriter.NL + " got: " + insn); + + "\n expected: " + sVar.getAssignInsn() + + "\n got: " + insn); } } else { if (!Utils.containsInListByRef(useList, reg)) { throw new JadxRuntimeException("Incorrect use list in ssa var: " + sVar + ", register not listed." - + ICodeWriter.NL + " insn: " + insn); + + "\n insn: " + insn); } } for (RegisterArg useArg : useList) { @@ -177,7 +176,7 @@ private static void checkRegisterArg(MethodNode mth, RegisterArg reg) { BlockNode parentInsnBlock = BlockUtils.getBlockByInsn(mth, parentInsn); if (parentInsnBlock == null) { throw new JadxRuntimeException("Parent insn not found in blocks tree for: " + reg - + ICodeWriter.NL + " insn: " + parentInsn); + + "\n insn: " + parentInsn); } } } diff --git a/jadx-core/src/main/java/jadx/core/utils/DebugUtils.java b/jadx-core/src/main/java/jadx/core/utils/DebugUtils.java index 22877be2019..530a4ed2935 100644 --- a/jadx-core/src/main/java/jadx/core/utils/DebugUtils.java +++ b/jadx-core/src/main/java/jadx/core/utils/DebugUtils.java @@ -136,7 +136,7 @@ public static void printRegion(MethodNode mth, IRegion region, boolean printInsn ICodeWriter cw = new SimpleCodeWriter(); cw.startLine('|').add(mth.toString()); printRegion(mth, region, cw, "| ", printInsns); - LOG.debug("{}{}", ICodeWriter.NL, cw.finish().getCodeStr()); + LOG.debug("{}{}", '\n', cw.finish().getCodeStr()); } private static void printRegion(MethodNode mth, IRegion region, ICodeWriter cw, String indent, boolean printInsns) { @@ -182,7 +182,7 @@ private static void printInsns(MethodNode mth, ICodeWriter cw, String indent, IB ig.makeInsn(insn, code); String codeStr = code.getCodeStr(); - List insnStrings = Stream.of(codeStr.split(ICodeWriter.NL)) + List insnStrings = Stream.of(codeStr.split("\\R")) .filter(StringUtils::notBlank) .map(s -> "|> " + s) .collect(Collectors.toList()); @@ -204,7 +204,7 @@ private static void printInsns(MethodNode mth, ICodeWriter cw, String indent, IB private static void printWithAttributes(ICodeWriter cw, String indent, String codeStr, IAttributeNode attrNode) { String str = attrNode.isAttrStorageEmpty() ? codeStr : codeStr + ' ' + attrNode.getAttributesString(); - List attrStrings = Stream.of(str.split(ICodeWriter.NL)) + List attrStrings = Stream.of(str.split("\\R")) .filter(StringUtils::notBlank) .collect(Collectors.toList()); Iterator it = attrStrings.iterator(); diff --git a/jadx-core/src/main/java/jadx/core/utils/InsnRemover.java b/jadx-core/src/main/java/jadx/core/utils/InsnRemover.java index 4e1627b9eda..e6ff2f461fc 100644 --- a/jadx-core/src/main/java/jadx/core/utils/InsnRemover.java +++ b/jadx-core/src/main/java/jadx/core/utils/InsnRemover.java @@ -7,7 +7,6 @@ import org.jetbrains.annotations.Nullable; -import jadx.api.ICodeWriter; import jadx.core.Consts; import jadx.core.dex.attributes.AFlag; import jadx.core.dex.instructions.InsnType; @@ -147,9 +146,9 @@ private static void removeSsaVar(MethodNode mth, SSAVar ssaVar) { return; } throw new JadxRuntimeException("Can't remove SSA var: " + ssaVar + ", still in use, count: " + useCount - + ", list:" + ICodeWriter.NL + " " + ssaVar.getUseList().stream() + + ", list:\n " + ssaVar.getUseList().stream() .map(arg -> arg + " from " + arg.getParentInsn()) - .collect(Collectors.joining(ICodeWriter.NL + " "))); + .collect(Collectors.joining("\n "))); } public static void unbindArgUsage(@Nullable MethodNode mth, InsnArg arg) { @@ -183,9 +182,9 @@ private static void removeAll(List insns, List toRemove) { } if (!found && Consts.DEBUG_WITH_ERRORS) { throw new JadxRuntimeException("Can't remove insn:" - + ICodeWriter.NL + " " + rem - + ICodeWriter.NL + " not found in list:" - + ICodeWriter.NL + " " + Utils.listToString(insns, ICodeWriter.NL + " ")); + + "\n " + rem + + "\n not found in list:" + + "\n " + Utils.listToString(insns, "\n ")); } } } diff --git a/jadx-core/src/main/java/jadx/core/utils/Utils.java b/jadx-core/src/main/java/jadx/core/utils/Utils.java index 2bfe4053439..acdb1ada0e2 100644 --- a/jadx-core/src/main/java/jadx/core/utils/Utils.java +++ b/jadx-core/src/main/java/jadx/core/utils/Utils.java @@ -55,7 +55,14 @@ public static String makeQualifiedObjectName(String obj) { return 'L' + obj.replace('.', '/') + ';'; } + @SuppressWarnings("StringRepeatCanBeUsed") public static String strRepeat(String str, int count) { + if (count < 1) { + return ""; + } + if (count == 1) { + return str; + } StringBuilder sb = new StringBuilder(str.length() * count); for (int i = 0; i < count; i++) { sb.append(str); diff --git a/jadx-core/src/main/java/jadx/core/xmlgen/ResProtoParser.java b/jadx-core/src/main/java/jadx/core/xmlgen/ResProtoParser.java index 8cb60c2955d..0496d122a3c 100644 --- a/jadx-core/src/main/java/jadx/core/xmlgen/ResProtoParser.java +++ b/jadx-core/src/main/java/jadx/core/xmlgen/ResProtoParser.java @@ -31,7 +31,7 @@ public ResContainer decodeFiles(InputStream inputStream) throws IOException { ValuesParser vp = new ValuesParser(new BinaryXMLStrings(), resStorage.getResourcesNames()); ResXmlGen resGen = new ResXmlGen(resStorage, vp); ICodeInfo content = XmlGenUtils.makeXmlDump(root.makeCodeWriter(), resStorage); - List xmlFiles = resGen.makeResourcesXml(); + List xmlFiles = resGen.makeResourcesXml(root.getArgs()); return ResContainer.resourceTable("res", xmlFiles, content); } diff --git a/jadx-core/src/main/java/jadx/core/xmlgen/ResTableParser.java b/jadx-core/src/main/java/jadx/core/xmlgen/ResTableParser.java index 7a0e2cbd2f1..a37bf7b797d 100644 --- a/jadx-core/src/main/java/jadx/core/xmlgen/ResTableParser.java +++ b/jadx-core/src/main/java/jadx/core/xmlgen/ResTableParser.java @@ -103,7 +103,7 @@ public ResContainer decodeFiles(InputStream inputStream) throws IOException { ResXmlGen resGen = new ResXmlGen(resStorage, vp); ICodeInfo content = XmlGenUtils.makeXmlDump(root.makeCodeWriter(), resStorage); - List xmlFiles = resGen.makeResourcesXml(); + List xmlFiles = resGen.makeResourcesXml(root.getArgs()); return ResContainer.resourceTable("res", xmlFiles, content); } diff --git a/jadx-core/src/main/java/jadx/core/xmlgen/ResXmlGen.java b/jadx-core/src/main/java/jadx/core/xmlgen/ResXmlGen.java index a5816ac980f..fbc2006b707 100644 --- a/jadx-core/src/main/java/jadx/core/xmlgen/ResXmlGen.java +++ b/jadx-core/src/main/java/jadx/core/xmlgen/ResXmlGen.java @@ -11,6 +11,7 @@ import jadx.api.ICodeInfo; import jadx.api.ICodeWriter; +import jadx.api.JadxArgs; import jadx.api.impl.SimpleCodeWriter; import jadx.core.utils.StringUtils; import jadx.core.xmlgen.entry.ProtoValue; @@ -48,7 +49,7 @@ public ResXmlGen(ResourceStorage resStorage, ValuesParser vp) { this.vp = vp; } - public List makeResourcesXml() { + public List makeResourcesXml(JadxArgs args) { Map contMap = new HashMap<>(); for (ResourceEntry ri : resStorage.getResources()) { if (SKIP_RES_TYPES.contains(ri.getTypeName())) { @@ -57,7 +58,7 @@ public List makeResourcesXml() { String fn = getFileName(ri); ICodeWriter cw = contMap.get(fn); if (cw == null) { - cw = new SimpleCodeWriter(); + cw = new SimpleCodeWriter(args); cw.add(""); cw.startLine(""); cw.incIndent(); diff --git a/jadx-core/src/test/java/jadx/core/xmlgen/ResXmlGenTest.java b/jadx-core/src/test/java/jadx/core/xmlgen/ResXmlGenTest.java index 90cbdfd4e79..778139fb347 100644 --- a/jadx-core/src/test/java/jadx/core/xmlgen/ResXmlGenTest.java +++ b/jadx-core/src/test/java/jadx/core/xmlgen/ResXmlGenTest.java @@ -4,8 +4,10 @@ import java.util.List; import org.assertj.core.util.Lists; +import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +import jadx.api.JadxArgs; import jadx.core.xmlgen.entry.RawNamedValue; import jadx.core.xmlgen.entry.RawValue; import jadx.core.xmlgen.entry.ResourceEntry; @@ -14,6 +16,12 @@ import static org.junit.jupiter.api.Assertions.assertEquals; class ResXmlGenTest { + private final JadxArgs args = new JadxArgs(); + + @BeforeEach + void init() { + args.setCodeNewLineStr("\n"); + } @Test void testSimpleAttr() { @@ -24,15 +32,16 @@ void testSimpleAttr() { ValuesParser vp = new ValuesParser(null, resStorage.getResourcesNames()); ResXmlGen resXmlGen = new ResXmlGen(resStorage, vp); - List files = resXmlGen.makeResourcesXml(); + List files = resXmlGen.makeResourcesXml(args); assertEquals(1, files.size()); assertEquals("res/values/attrs.xml", files.get(0).getName()); + String input = files.get(0).getText().toString(); assertEquals("\n" + "\n" + " \n" + " \n" - + "", adaptLineEndings(files.get(0).getText().toString())); + + "", input); } @Test @@ -45,16 +54,17 @@ void testAttrEnum() { ValuesParser vp = new ValuesParser(null, resStorage.getResourcesNames()); ResXmlGen resXmlGen = new ResXmlGen(resStorage, vp); - List files = resXmlGen.makeResourcesXml(); + List files = resXmlGen.makeResourcesXml(args); assertEquals(1, files.size()); assertEquals("res/values/attrs.xml", files.get(0).getName()); + String input = files.get(0).getText().toString(); assertEquals("\n" + "\n" + " \n" + " \n" + " \n" - + "", adaptLineEndings(files.get(0).getText().toString())); + + "", input); } @Test @@ -67,16 +77,17 @@ void testAttrFlag() { ValuesParser vp = new ValuesParser(null, resStorage.getResourcesNames()); ResXmlGen resXmlGen = new ResXmlGen(resStorage, vp); - List files = resXmlGen.makeResourcesXml(); + List files = resXmlGen.makeResourcesXml(args); assertEquals(1, files.size()); assertEquals("res/values/attrs.xml", files.get(0).getName()); + String input = files.get(0).getText().toString(); assertEquals("\n" + "\n" + " \n" + " \n" + " \n" - + "", adaptLineEndings(files.get(0).getText().toString())); + + "", input); } @Test @@ -89,15 +100,16 @@ void testAttrMin() { ValuesParser vp = new ValuesParser(null, resStorage.getResourcesNames()); ResXmlGen resXmlGen = new ResXmlGen(resStorage, vp); - List files = resXmlGen.makeResourcesXml(); + List files = resXmlGen.makeResourcesXml(args); assertEquals(1, files.size()); assertEquals("res/values/attrs.xml", files.get(0).getName()); + String input = files.get(0).getText().toString(); assertEquals("\n" + "\n" + " \n" + " \n" - + "", adaptLineEndings(files.get(0).getText().toString())); + + "", input); } @Test @@ -113,10 +125,11 @@ void testStyle() { resStorage.add(re); ValuesParser vp = new ValuesParser(null, resStorage.getResourcesNames()); ResXmlGen resXmlGen = new ResXmlGen(resStorage, vp); - List files = resXmlGen.makeResourcesXml(); + List files = resXmlGen.makeResourcesXml(args); assertEquals(1, files.size()); assertEquals("res/values/styles.xml", files.get(0).getName()); + String input = files.get(0).getText().toString(); assertEquals("\n" + "\n" + " \n" + " \n" - + "", adaptLineEndings(files.get(0).getText().toString())); + + "", input); } @Test @@ -139,14 +152,15 @@ void testString() { strings.put(0, "Jadx Decompiler App"); ValuesParser vp = new ValuesParser(strings, resStorage.getResourcesNames()); ResXmlGen resXmlGen = new ResXmlGen(resStorage, vp); - List files = resXmlGen.makeResourcesXml(); + List files = resXmlGen.makeResourcesXml(args); assertEquals(1, files.size()); assertEquals("res/values/strings.xml", files.get(0).getName()); + String input = files.get(0).getText().toString(); assertEquals("\n" + "\n" + " Jadx Decompiler App\n" - + "", adaptLineEndings(files.get(0).getText().toString())); + + "", input); } @Test @@ -161,14 +175,15 @@ void testStringFormattedFalse() { strings.put(0, "%s at %s"); ValuesParser vp = new ValuesParser(strings, resStorage.getResourcesNames()); ResXmlGen resXmlGen = new ResXmlGen(resStorage, vp); - List files = resXmlGen.makeResourcesXml(); + List files = resXmlGen.makeResourcesXml(args); assertEquals(1, files.size()); assertEquals("res/values/strings.xml", files.get(0).getName()); + String input = files.get(0).getText().toString(); assertEquals("\n" + "\n" + " %s at %s\n" - + "", adaptLineEndings(files.get(0).getText().toString())); + + "", input); } @Test @@ -183,22 +198,16 @@ void testArrayEscape() { strings.put(0, "Let's go"); ValuesParser vp = new ValuesParser(strings, resStorage.getResourcesNames()); ResXmlGen resXmlGen = new ResXmlGen(resStorage, vp); - List files = resXmlGen.makeResourcesXml(); + List files = resXmlGen.makeResourcesXml(args); assertEquals(1, files.size()); assertEquals("res/values/arrays.xml", files.get(0).getName()); + String input = files.get(0).getText().toString(); assertEquals("\n" + "\n" + " \n" + " Let\\'s go\n" + " \n" - + "", adaptLineEndings(files.get(0).getText().toString())); - } - - private static String adaptLineEndings(String input) { - if (System.lineSeparator().equals("\n")) { - return input; // no adaption necessary - } - return input.replaceAll(System.lineSeparator(), "\n"); + + "", input); } } diff --git a/jadx-core/src/test/java/jadx/tests/api/IntegrationTest.java b/jadx-core/src/test/java/jadx/tests/api/IntegrationTest.java index 1c168195c5c..3f44b75c1a9 100644 --- a/jadx-core/src/test/java/jadx/tests/api/IntegrationTest.java +++ b/jadx-core/src/test/java/jadx/tests/api/IntegrationTest.java @@ -36,7 +36,6 @@ import jadx.api.CommentsLevel; import jadx.api.DecompilationMode; import jadx.api.ICodeInfo; -import jadx.api.ICodeWriter; import jadx.api.JadxArgs; import jadx.api.JadxDecompiler; import jadx.api.JadxInternalAccess; @@ -141,10 +140,14 @@ public void init() { args.setShowInconsistentCode(true); args.setThreadsCount(1); args.setSkipResources(true); - args.setFsCaseSensitive(false); // use same value on all systems args.setCommentsLevel(CommentsLevel.DEBUG); args.setDeobfuscationOn(false); args.setGeneratedRenamesMappingFileMode(GeneratedRenamesMappingFileMode.IGNORE); + + // use the same values on all systems + args.setFsCaseSensitive(false); + args.setCodeNewLineStr("\n"); + args.setCodeIndentStr(JadxArgs.DEFAULT_INDENT_STR); } @AfterEach @@ -315,7 +318,7 @@ private void printDisasm(ClassNode cls) { private void printCodeWithLineNumbers(ICodeInfo code) { String codeStr = code.getCodeStr(); Map lineMapping = code.getCodeMetadata().getLineMapping(); - String[] lines = codeStr.split(ICodeWriter.NL); + String[] lines = codeStr.split("\\R"); for (int i = 0; i < lines.length; i++) { String line = lines[i]; int curLine = i + 1; @@ -332,8 +335,9 @@ private void printCodeWithOffsets(ICodeInfo code) { String codeStr = code.getCodeStr(); ICodeMetadata metadata = code.getCodeMetadata(); int lineStartPos = 0; - int newLineLen = ICodeWriter.NL.length(); - for (String line : codeStr.split(ICodeWriter.NL)) { + String newLineStr = args.getCodeNewLineStr(); + int newLineLen = newLineStr.length(); + for (String line : codeStr.split(newLineStr)) { Object ann = metadata.getAt(lineStartPos); String offsetStr = ""; if (ann instanceof InsnCodeOffset) { diff --git a/jadx-core/src/test/java/jadx/tests/api/utils/JadxMatchers.java b/jadx-core/src/test/java/jadx/tests/api/utils/JadxMatchers.java index c5e7409fb83..2ce7f8ec4df 100644 --- a/jadx-core/src/test/java/jadx/tests/api/utils/JadxMatchers.java +++ b/jadx-core/src/test/java/jadx/tests/api/utils/JadxMatchers.java @@ -2,8 +2,6 @@ import org.hamcrest.Matcher; -import jadx.api.ICodeWriter; - public class JadxMatchers { public static Matcher countString(int count, String substring) { @@ -17,7 +15,7 @@ public static Matcher containsOne(String substring) { public static Matcher containsLines(String... lines) { StringBuilder sb = new StringBuilder(); for (String line : lines) { - sb.append(line).append(ICodeWriter.NL); + sb.append(line).append('\n'); } return countString(1, sb.toString()); } @@ -30,7 +28,7 @@ public static Matcher containsLines(int commonIndent, String... lines) { sb.append(indent); sb.append(line); } - sb.append(ICodeWriter.NL); + sb.append('\n'); } return countString(1, sb.toString()); } diff --git a/jadx-core/src/test/java/jadx/tests/api/utils/TestUtils.java b/jadx-core/src/test/java/jadx/tests/api/utils/TestUtils.java index bd966a1cf31..45f1460eaa8 100644 --- a/jadx-core/src/test/java/jadx/tests/api/utils/TestUtils.java +++ b/jadx-core/src/test/java/jadx/tests/api/utils/TestUtils.java @@ -4,7 +4,7 @@ import jadx.NotYetImplementedExtension; import jadx.api.CommentsLevel; -import jadx.api.ICodeWriter; +import jadx.api.JadxArgs; import jadx.core.dex.attributes.AFlag; import jadx.core.dex.attributes.AType; import jadx.core.dex.attributes.IAttributeNode; @@ -23,18 +23,14 @@ public class TestUtils { public static String indent() { - return ICodeWriter.INDENT_STR; + return JadxArgs.DEFAULT_INDENT_STR; } public static String indent(int indent) { if (indent == 1) { - return ICodeWriter.INDENT_STR; + return JadxArgs.DEFAULT_INDENT_STR; } - StringBuilder sb = new StringBuilder(indent * ICodeWriter.INDENT_STR.length()); - for (int i = 0; i < indent; i++) { - sb.append(ICodeWriter.INDENT_STR); - } - return sb.toString(); + return Utils.strRepeat(JadxArgs.DEFAULT_INDENT_STR, indent); } public static int count(String string, String substring) { diff --git a/jadx-core/src/test/java/jadx/tests/api/utils/assertj/JadxCodeAssertions.java b/jadx-core/src/test/java/jadx/tests/api/utils/assertj/JadxCodeAssertions.java index 044b2724684..03fe347f28d 100644 --- a/jadx-core/src/test/java/jadx/tests/api/utils/assertj/JadxCodeAssertions.java +++ b/jadx-core/src/test/java/jadx/tests/api/utils/assertj/JadxCodeAssertions.java @@ -8,7 +8,6 @@ import org.assertj.core.api.AbstractStringAssert; -import jadx.api.ICodeWriter; import jadx.tests.api.utils.TestUtils; public class JadxCodeAssertions extends AbstractStringAssert { @@ -53,7 +52,7 @@ public JadxCodeAssertions containsLines(int commonIndent, String... lines) { String indent = TestUtils.indent(commonIndent); StringBuilder sb = new StringBuilder(); for (String line : lines) { - sb.append(ICodeWriter.NL); + sb.append('\n'); if (line.isEmpty()) { // don't add common indent to empty lines continue; @@ -63,7 +62,7 @@ public JadxCodeAssertions containsLines(int commonIndent, String... lines) { // check every line for easier debugging contains(searchLine); } - return containsOnlyOnce(sb.substring(ICodeWriter.NL.length())); + return containsOnlyOnce(sb.substring(1)); } public JadxCodeAssertions removeBlockComments() { diff --git a/jadx-core/src/test/java/jadx/tests/external/BaseExternalTest.java b/jadx-core/src/test/java/jadx/tests/external/BaseExternalTest.java index 54d35dd3dac..d9b9aec0976 100644 --- a/jadx-core/src/test/java/jadx/tests/external/BaseExternalTest.java +++ b/jadx-core/src/test/java/jadx/tests/external/BaseExternalTest.java @@ -10,7 +10,6 @@ import jadx.api.CommentsLevel; import jadx.api.ICodeInfo; -import jadx.api.ICodeWriter; import jadx.api.JadxArgs; import jadx.api.JadxDecompiler; import jadx.api.JadxInternalAccess; @@ -186,7 +185,7 @@ public Integer apply(Integer pos, ICodeAnnotation ann) { } protected int getCommentStartPos(ICodeInfo codeInfo, int pos) { - String emptyLine = ICodeWriter.NL + ICodeWriter.NL; + String emptyLine = "\n\n"; int emptyLinePos = codeInfo.getCodeStr().lastIndexOf(emptyLine, pos); return emptyLinePos == -1 ? pos : emptyLinePos + emptyLine.length(); } diff --git a/jadx-core/src/test/java/jadx/tests/integration/conditions/TestElseIfCodeStyle.java b/jadx-core/src/test/java/jadx/tests/integration/conditions/TestElseIfCodeStyle.java index e1133cc7a98..122f723c531 100644 --- a/jadx-core/src/test/java/jadx/tests/integration/conditions/TestElseIfCodeStyle.java +++ b/jadx-core/src/test/java/jadx/tests/integration/conditions/TestElseIfCodeStyle.java @@ -2,7 +2,6 @@ import org.junit.jupiter.api.Test; -import jadx.api.ICodeWriter; import jadx.tests.api.IntegrationTest; import static jadx.tests.api.utils.assertj.JadxAssertions.assertThat; @@ -32,6 +31,6 @@ public void test() { assertThat(getClassNode(TestCls.class)) .code() .doesNotContain("!\"c\".equals(str)") - .doesNotContain("{" + ICodeWriter.NL + indent(2) + "} else {"); // no empty `then` block + .doesNotContain("{\n" + indent(2) + "} else {"); // no empty `then` block } } diff --git a/jadx-core/src/test/java/jadx/tests/integration/debuginfo/TestReturnSourceLine.java b/jadx-core/src/test/java/jadx/tests/integration/debuginfo/TestReturnSourceLine.java index 84207f74c34..5cec034766b 100644 --- a/jadx-core/src/test/java/jadx/tests/integration/debuginfo/TestReturnSourceLine.java +++ b/jadx-core/src/test/java/jadx/tests/integration/debuginfo/TestReturnSourceLine.java @@ -3,7 +3,6 @@ import org.junit.jupiter.api.Test; import jadx.api.ICodeInfo; -import jadx.api.ICodeWriter; import jadx.api.utils.CodeUtils; import jadx.core.dex.attributes.nodes.LineAttrNode; import jadx.core.dex.nodes.ClassNode; @@ -55,7 +54,7 @@ public void test() { ClassNode cls = getClassNode(TestCls.class); ICodeInfo codeInfo = cls.getCode(); - String[] lines = codeInfo.getCodeStr().split(ICodeWriter.NL); + String[] lines = codeInfo.getCodeStr().split("\\R"); MethodNode test1 = cls.searchMethodByShortId("test1(Z)I"); checkLine(lines, codeInfo, test1, 3, "return 1;"); @@ -72,7 +71,7 @@ public void test() { } private static void checkLine(String[] lines, ICodeInfo cw, LineAttrNode node, int offset, String str) { - int nodeDefLine = CodeUtils.getLineNumForPos(cw.getCodeStr(), node.getDefPosition()); + int nodeDefLine = CodeUtils.getLineNumForPos(cw.getCodeStr(), node.getDefPosition(), "\n"); int decompiledLine = nodeDefLine + offset; assertThat(lines[decompiledLine - 1], containsOne(str)); Integer sourceLine = cw.getCodeMetadata().getLineMapping().get(decompiledLine); diff --git a/jadx-gui/src/main/java/jadx/gui/device/debugger/smali/Smali.java b/jadx-gui/src/main/java/jadx/gui/device/debugger/smali/Smali.java index 4a45eb66e22..cee169bffdd 100644 --- a/jadx-gui/src/main/java/jadx/gui/device/debugger/smali/Smali.java +++ b/jadx-gui/src/main/java/jadx/gui/device/debugger/smali/Smali.java @@ -17,6 +17,7 @@ import org.slf4j.LoggerFactory; import jadx.api.ICodeInfo; +import jadx.api.JadxArgs; import jadx.api.plugins.input.data.AccessFlags; import jadx.api.plugins.input.data.AccessFlagsScope; import jadx.api.plugins.input.data.ICatch; @@ -787,7 +788,7 @@ private void fmtSwitchPayload(InsnData insn, String fmtTarget, String fmtTag, Li int lineStart = getInsnColStart(); lineStart += CODE_OFFSET_COLUMN_WIDTH + 1 + 1; // plus 1s for space and the ':' String basicIndent = new String(new byte[lineStart]).replace("\0", " "); - String indent = SmaliWriter.INDENT_STR + basicIndent; + String indent = JadxArgs.DEFAULT_INDENT_STR + basicIndent; int[] keys = payload.getKeys(); int[] targets = payload.getTargets(); Integer switchOffset = line.payloadOffsetMap.get(insn.getOffset()); diff --git a/jadx-gui/src/main/java/jadx/gui/search/providers/CodeSearchProvider.java b/jadx-gui/src/main/java/jadx/gui/search/providers/CodeSearchProvider.java index aa96c51fbab..96e15805d5a 100644 --- a/jadx-gui/src/main/java/jadx/gui/search/providers/CodeSearchProvider.java +++ b/jadx-gui/src/main/java/jadx/gui/search/providers/CodeSearchProvider.java @@ -7,11 +7,11 @@ import org.slf4j.LoggerFactory; import jadx.api.ICodeCache; -import jadx.api.ICodeWriter; import jadx.api.JavaClass; import jadx.api.JavaNode; import jadx.api.metadata.ICodeMetadata; import jadx.api.metadata.ICodeNodeRef; +import jadx.api.utils.CodeUtils; import jadx.gui.JadxWrapper; import jadx.gui.jobs.Cancelable; import jadx.gui.search.SearchSettings; @@ -68,8 +68,8 @@ private JNode searchNext(JavaClass javaClass, String clsCode) { if (newPos == -1) { return null; } - int lineStart = 1 + clsCode.lastIndexOf(ICodeWriter.NL, newPos); - int lineEnd = clsCode.indexOf(ICodeWriter.NL, newPos); + int lineStart = 1 + CodeUtils.getNewLinePosBefore(clsCode, newPos); + int lineEnd = CodeUtils.getNewLinePosAfter(clsCode, newPos); int end = lineEnd == -1 ? clsCode.length() : lineEnd; String line = clsCode.substring(lineStart, end); this.pos = end; diff --git a/jadx-gui/src/main/java/jadx/gui/search/providers/ResourceSearchProvider.java b/jadx-gui/src/main/java/jadx/gui/search/providers/ResourceSearchProvider.java index c9b311561f3..9ef3c77108f 100644 --- a/jadx-gui/src/main/java/jadx/gui/search/providers/ResourceSearchProvider.java +++ b/jadx-gui/src/main/java/jadx/gui/search/providers/ResourceSearchProvider.java @@ -13,10 +13,10 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import jadx.api.ICodeWriter; import jadx.api.ResourceFile; import jadx.api.ResourceType; import jadx.api.plugins.utils.CommonFileUtils; +import jadx.api.utils.CodeUtils; import jadx.gui.jobs.Cancelable; import jadx.gui.search.ISearchProvider; import jadx.gui.search.SearchSettings; @@ -95,8 +95,8 @@ private JNode search(JResource resNode) { if (newPos == -1) { return null; } - int lineStart = content.lastIndexOf(ICodeWriter.NL, newPos) + ICodeWriter.NL.length(); - int lineEnd = content.indexOf(ICodeWriter.NL, newPos + searchString.length()); + int lineStart = 1 + CodeUtils.getNewLinePosBefore(content, newPos); + int lineEnd = CodeUtils.getNewLinePosAfter(content, newPos); int end = lineEnd == -1 ? content.length() : lineEnd; String line = content.substring(lineStart, end); this.pos = end; diff --git a/jadx-gui/src/main/java/jadx/gui/treemodel/JResource.java b/jadx-gui/src/main/java/jadx/gui/treemodel/JResource.java index f918b5504bd..2db2ed119c3 100644 --- a/jadx-gui/src/main/java/jadx/gui/treemodel/JResource.java +++ b/jadx-gui/src/main/java/jadx/gui/treemodel/JResource.java @@ -12,7 +12,6 @@ import org.jetbrains.annotations.Nullable; import jadx.api.ICodeInfo; -import jadx.api.ICodeWriter; import jadx.api.ResourceFile; import jadx.api.ResourceType; import jadx.api.ResourcesLoader; @@ -189,7 +188,7 @@ private ICodeInfo loadCurrentSingleRes(ResContainer rc) { return ResourcesLoader.loadToCodeWriter(is); }); } catch (Exception e) { - return new SimpleCodeInfo("Failed to load resource file:" + ICodeWriter.NL + Utils.getStackTrace(e)); + return new SimpleCodeInfo("Failed to load resource file:\n" + Utils.getStackTrace(e)); } case DECODED_DATA: diff --git a/jadx-gui/src/main/java/jadx/gui/ui/panel/ImagePanel.java b/jadx-gui/src/main/java/jadx/gui/ui/panel/ImagePanel.java index e1c332474c1..89c26df39bd 100644 --- a/jadx-gui/src/main/java/jadx/gui/ui/panel/ImagePanel.java +++ b/jadx-gui/src/main/java/jadx/gui/ui/panel/ImagePanel.java @@ -10,7 +10,6 @@ import hu.kazocsaba.imageviewer.ImageViewer; -import jadx.api.ICodeWriter; import jadx.api.ResourceFile; import jadx.api.ResourcesLoader; import jadx.core.utils.Utils; @@ -32,7 +31,7 @@ public ImagePanel(TabbedPane panel, JResource res) { add(imageViewer.getComponent()); } catch (Exception e) { RSyntaxTextArea textArea = AbstractCodeArea.getDefaultArea(panel.getMainWindow()); - textArea.setText("Image load error:" + ICodeWriter.NL + Utils.getStackTrace(e)); + textArea.setText("Image load error:\n" + Utils.getStackTrace(e)); add(textArea); } }