This commit is contained in:
@@ -8,8 +8,6 @@ import jadx.api.metadata.ICodeAnnotation;
|
||||
import jadx.api.metadata.ICodeNodeRef;
|
||||
|
||||
public interface ICodeWriter {
|
||||
String NL = System.getProperty("line.separator");
|
||||
String INDENT_STR = " ";
|
||||
|
||||
boolean isMetadataSupported();
|
||||
|
||||
|
||||
@@ -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 class JadxArgs implements Closeable {
|
||||
|
||||
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 class JadxArgs implements Closeable {
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -21,9 +21,6 @@ public class AnnotatedCodeWriter extends SimpleCodeWriter implements ICodeWriter
|
||||
private Map<Integer, ICodeAnnotation> annotations = Collections.emptyMap();
|
||||
private Map<Integer, Integer> lineMap = Collections.emptyMap();
|
||||
|
||||
public AnnotatedCodeWriter() {
|
||||
}
|
||||
|
||||
public AnnotatedCodeWriter(JadxArgs args) {
|
||||
super(args);
|
||||
}
|
||||
@@ -35,9 +32,9 @@ public class AnnotatedCodeWriter extends SimpleCodeWriter implements ICodeWriter
|
||||
|
||||
@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 class AnnotatedCodeWriter extends SimpleCodeWriter implements ICodeWriter
|
||||
|
||||
@Override
|
||||
protected void addLine() {
|
||||
buf.append(NL);
|
||||
buf.append(newLineStr);
|
||||
line++;
|
||||
offset = 0;
|
||||
}
|
||||
|
||||
@@ -14,38 +14,39 @@ import jadx.api.metadata.ICodeNodeRef;
|
||||
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 class SimpleCodeWriter implements ICodeWriter {
|
||||
|
||||
@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 class SimpleCodeWriter implements ICodeWriter {
|
||||
|
||||
@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 @@ public class SimpleCodeWriter implements ICodeWriter {
|
||||
}
|
||||
|
||||
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 class SimpleCodeWriter implements ICodeWriter {
|
||||
|
||||
@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
|
||||
|
||||
@@ -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 class CodeUtils {
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
@@ -86,7 +86,7 @@ public class JsonCodeGen {
|
||||
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 @@ public class JsonCodeGen {
|
||||
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 @@ public class JsonCodeGen {
|
||||
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 @@ public class JsonCodeGen {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
String[] lines = codeStr.split(ICodeWriter.NL);
|
||||
String[] lines = codeStr.split(args.getCodeNewLineStr());
|
||||
Map<Integer, Integer> lineMapping = code.getCodeMetadata().getLineMapping();
|
||||
ICodeMetadata metadata = code.getCodeMetadata();
|
||||
long mthCodeOffset = mth.getMethodCodeOffset() + 16;
|
||||
@@ -189,7 +189,7 @@ public class JsonCodeGen {
|
||||
int linesCount = lines.length;
|
||||
List<JsonCodeLine> 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 @@ public class JsonCodeGen {
|
||||
}
|
||||
|
||||
private String getTypeAlias(ClassGen classGen, ArgType clsType) {
|
||||
ICodeWriter code = new SimpleCodeWriter();
|
||||
ICodeWriter code = new SimpleCodeWriter(args);
|
||||
classGen.useType(code, clsType);
|
||||
return code.getCodeStr();
|
||||
}
|
||||
|
||||
@@ -4,7 +4,6 @@ import java.util.Objects;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import jadx.api.ICodeWriter;
|
||||
import jadx.core.utils.Utils;
|
||||
|
||||
public class JadxError implements Comparable<JadxError> {
|
||||
@@ -55,7 +54,7 @@ public class JadxError implements Comparable<JadxError> {
|
||||
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();
|
||||
|
||||
@@ -2,7 +2,6 @@ package jadx.core.dex.attributes.nodes;
|
||||
|
||||
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 class LocalVarsDebugInfoAttr implements IJadxAttribute {
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Debug Info:" + ICodeWriter.NL + " " + Utils.listToString(localVars, ICodeWriter.NL + " ");
|
||||
return "Debug Info:\n " + Utils.listToString(localVars, "\n ");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 abstract class NotificationAttrNode extends LineAttrNode implements ICode
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
@@ -3,7 +3,6 @@ package jadx.core.dex.attributes.nodes;
|
||||
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 class PhiListAttr implements IJadxAttribute {
|
||||
}
|
||||
}
|
||||
for (PhiInsn phiInsn : list) {
|
||||
sb.append(ICodeWriter.NL).append(" ").append(phiInsn);
|
||||
sb.append('\n').append(" ").append(phiInsn);
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
@@ -5,7 +5,6 @@ import java.util.List;
|
||||
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 class SwitchInsn extends TargetInsnNode {
|
||||
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));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,10 +18,10 @@ import org.slf4j.LoggerFactory;
|
||||
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 class ClassNode extends NotificationAttrNode
|
||||
|
||||
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<ClassNode> 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));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -10,7 +10,6 @@ import java.util.function.Function;
|
||||
|
||||
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 @@ public class InsnNode extends LineAttrNode {
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
@@ -96,7 +96,7 @@ public final class SwitchRegion extends AbstractRegion implements IBranchRegion
|
||||
for (CaseInfo caseInfo : cases) {
|
||||
List<String> 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());
|
||||
}
|
||||
|
||||
@@ -319,8 +319,7 @@ public class DotGraphVisitor extends AbstractVisitor {
|
||||
.replace("\"", "\\\"")
|
||||
.replace("-", "\\-")
|
||||
.replace("|", "\\|")
|
||||
.replace(ICodeWriter.NL, NL)
|
||||
.replace("\n", NL);
|
||||
.replaceAll("\\R", NL);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,7 +8,6 @@ import java.util.function.Function;
|
||||
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 @@ public class MethodInvokeVisitor extends AbstractVisitor {
|
||||
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();
|
||||
|
||||
@@ -3,7 +3,6 @@ package jadx.core.utils;
|
||||
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 @@ public class DebugChecks {
|
||||
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 @@ public class DebugChecks {
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -136,7 +136,7 @@ public class DebugUtils {
|
||||
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 @@ public class DebugUtils {
|
||||
ig.makeInsn(insn, code);
|
||||
String codeStr = code.getCodeStr();
|
||||
|
||||
List<String> insnStrings = Stream.of(codeStr.split(ICodeWriter.NL))
|
||||
List<String> insnStrings = Stream.of(codeStr.split("\\R"))
|
||||
.filter(StringUtils::notBlank)
|
||||
.map(s -> "|> " + s)
|
||||
.collect(Collectors.toList());
|
||||
@@ -204,7 +204,7 @@ public class DebugUtils {
|
||||
|
||||
private static void printWithAttributes(ICodeWriter cw, String indent, String codeStr, IAttributeNode attrNode) {
|
||||
String str = attrNode.isAttrStorageEmpty() ? codeStr : codeStr + ' ' + attrNode.getAttributesString();
|
||||
List<String> attrStrings = Stream.of(str.split(ICodeWriter.NL))
|
||||
List<String> attrStrings = Stream.of(str.split("\\R"))
|
||||
.filter(StringUtils::notBlank)
|
||||
.collect(Collectors.toList());
|
||||
Iterator<String> it = attrStrings.iterator();
|
||||
|
||||
@@ -7,7 +7,6 @@ import java.util.stream.Collectors;
|
||||
|
||||
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 @@ public class InsnRemover {
|
||||
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 @@ public class InsnRemover {
|
||||
}
|
||||
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 "));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -55,7 +55,14 @@ public class Utils {
|
||||
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);
|
||||
|
||||
@@ -31,7 +31,7 @@ public class ResProtoParser extends CommonProtoParser implements IResParser {
|
||||
ValuesParser vp = new ValuesParser(new BinaryXMLStrings(), resStorage.getResourcesNames());
|
||||
ResXmlGen resGen = new ResXmlGen(resStorage, vp);
|
||||
ICodeInfo content = XmlGenUtils.makeXmlDump(root.makeCodeWriter(), resStorage);
|
||||
List<ResContainer> xmlFiles = resGen.makeResourcesXml();
|
||||
List<ResContainer> xmlFiles = resGen.makeResourcesXml(root.getArgs());
|
||||
return ResContainer.resourceTable("res", xmlFiles, content);
|
||||
}
|
||||
|
||||
|
||||
@@ -103,7 +103,7 @@ public class ResTableParser extends CommonBinaryParser implements IResParser {
|
||||
ResXmlGen resGen = new ResXmlGen(resStorage, vp);
|
||||
|
||||
ICodeInfo content = XmlGenUtils.makeXmlDump(root.makeCodeWriter(), resStorage);
|
||||
List<ResContainer> xmlFiles = resGen.makeResourcesXml();
|
||||
List<ResContainer> xmlFiles = resGen.makeResourcesXml(root.getArgs());
|
||||
return ResContainer.resourceTable("res", xmlFiles, content);
|
||||
}
|
||||
|
||||
|
||||
@@ -11,6 +11,7 @@ import java.util.Set;
|
||||
|
||||
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 class ResXmlGen {
|
||||
this.vp = vp;
|
||||
}
|
||||
|
||||
public List<ResContainer> makeResourcesXml() {
|
||||
public List<ResContainer> makeResourcesXml(JadxArgs args) {
|
||||
Map<String, ICodeWriter> contMap = new HashMap<>();
|
||||
for (ResourceEntry ri : resStorage.getResources()) {
|
||||
if (SKIP_RES_TYPES.contains(ri.getTypeName())) {
|
||||
@@ -57,7 +58,7 @@ public class ResXmlGen {
|
||||
String fn = getFileName(ri);
|
||||
ICodeWriter cw = contMap.get(fn);
|
||||
if (cw == null) {
|
||||
cw = new SimpleCodeWriter();
|
||||
cw = new SimpleCodeWriter(args);
|
||||
cw.add("<?xml version=\"1.0\" encoding=\"utf-8\"?>");
|
||||
cw.startLine("<resources>");
|
||||
cw.incIndent();
|
||||
|
||||
@@ -4,8 +4,10 @@ import java.util.ArrayList;
|
||||
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 jadx.core.xmlgen.entry.ValuesParser;
|
||||
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 @@ class ResXmlGenTest {
|
||||
|
||||
ValuesParser vp = new ValuesParser(null, resStorage.getResourcesNames());
|
||||
ResXmlGen resXmlGen = new ResXmlGen(resStorage, vp);
|
||||
List<ResContainer> files = resXmlGen.makeResourcesXml();
|
||||
List<ResContainer> 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("<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"
|
||||
+ "<resources>\n"
|
||||
+ " <attr name=\"size\" format=\"dimension\">\n"
|
||||
+ " </attr>\n"
|
||||
+ "</resources>", adaptLineEndings(files.get(0).getText().toString()));
|
||||
+ "</resources>", input);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -45,16 +54,17 @@ class ResXmlGenTest {
|
||||
|
||||
ValuesParser vp = new ValuesParser(null, resStorage.getResourcesNames());
|
||||
ResXmlGen resXmlGen = new ResXmlGen(resStorage, vp);
|
||||
List<ResContainer> files = resXmlGen.makeResourcesXml();
|
||||
List<ResContainer> 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("<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"
|
||||
+ "<resources>\n"
|
||||
+ " <attr name=\"size\">\n"
|
||||
+ " <enum name=\"android:string.aerr_wait\" value=\"1\" />\n"
|
||||
+ " </attr>\n"
|
||||
+ "</resources>", adaptLineEndings(files.get(0).getText().toString()));
|
||||
+ "</resources>", input);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -67,16 +77,17 @@ class ResXmlGenTest {
|
||||
|
||||
ValuesParser vp = new ValuesParser(null, resStorage.getResourcesNames());
|
||||
ResXmlGen resXmlGen = new ResXmlGen(resStorage, vp);
|
||||
List<ResContainer> files = resXmlGen.makeResourcesXml();
|
||||
List<ResContainer> 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("<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"
|
||||
+ "<resources>\n"
|
||||
+ " <attr name=\"size\">\n"
|
||||
+ " <flag name=\"android:string.aerr_wait\" value=\"1\" />\n"
|
||||
+ " </attr>\n"
|
||||
+ "</resources>", adaptLineEndings(files.get(0).getText().toString()));
|
||||
+ "</resources>", input);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -89,15 +100,16 @@ class ResXmlGenTest {
|
||||
|
||||
ValuesParser vp = new ValuesParser(null, resStorage.getResourcesNames());
|
||||
ResXmlGen resXmlGen = new ResXmlGen(resStorage, vp);
|
||||
List<ResContainer> files = resXmlGen.makeResourcesXml();
|
||||
List<ResContainer> 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("<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"
|
||||
+ "<resources>\n"
|
||||
+ " <attr name=\"size\" format=\"integer\" min=\"1\">\n"
|
||||
+ " </attr>\n"
|
||||
+ "</resources>", adaptLineEndings(files.get(0).getText().toString()));
|
||||
+ "</resources>", input);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -113,10 +125,11 @@ class ResXmlGenTest {
|
||||
resStorage.add(re);
|
||||
ValuesParser vp = new ValuesParser(null, resStorage.getResourcesNames());
|
||||
ResXmlGen resXmlGen = new ResXmlGen(resStorage, vp);
|
||||
List<ResContainer> files = resXmlGen.makeResourcesXml();
|
||||
List<ResContainer> 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("<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"
|
||||
+ "<resources>\n"
|
||||
+ " <style name=\"JadxGui\" parent=\"\">\n"
|
||||
@@ -124,7 +137,7 @@ class ResXmlGenTest {
|
||||
+ " </style>\n"
|
||||
+ " <style name=\"JadxGui.Dialog\" parent=\"@style/JadxGui\">\n"
|
||||
+ " </style>\n"
|
||||
+ "</resources>", adaptLineEndings(files.get(0).getText().toString()));
|
||||
+ "</resources>", input);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -139,14 +152,15 @@ class ResXmlGenTest {
|
||||
strings.put(0, "Jadx Decompiler App");
|
||||
ValuesParser vp = new ValuesParser(strings, resStorage.getResourcesNames());
|
||||
ResXmlGen resXmlGen = new ResXmlGen(resStorage, vp);
|
||||
List<ResContainer> files = resXmlGen.makeResourcesXml();
|
||||
List<ResContainer> 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("<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"
|
||||
+ "<resources>\n"
|
||||
+ " <string name=\"app_name\">Jadx Decompiler App</string>\n"
|
||||
+ "</resources>", adaptLineEndings(files.get(0).getText().toString()));
|
||||
+ "</resources>", input);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -161,14 +175,15 @@ class ResXmlGenTest {
|
||||
strings.put(0, "%s at %s");
|
||||
ValuesParser vp = new ValuesParser(strings, resStorage.getResourcesNames());
|
||||
ResXmlGen resXmlGen = new ResXmlGen(resStorage, vp);
|
||||
List<ResContainer> files = resXmlGen.makeResourcesXml();
|
||||
List<ResContainer> 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("<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"
|
||||
+ "<resources>\n"
|
||||
+ " <string name=\"app_name\" formatted=\"false\">%s at %s</string>\n"
|
||||
+ "</resources>", adaptLineEndings(files.get(0).getText().toString()));
|
||||
+ "</resources>", input);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -183,22 +198,16 @@ class ResXmlGenTest {
|
||||
strings.put(0, "Let's go");
|
||||
ValuesParser vp = new ValuesParser(strings, resStorage.getResourcesNames());
|
||||
ResXmlGen resXmlGen = new ResXmlGen(resStorage, vp);
|
||||
List<ResContainer> files = resXmlGen.makeResourcesXml();
|
||||
List<ResContainer> 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("<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"
|
||||
+ "<resources>\n"
|
||||
+ " <array name=\"single_quote_escape_sample\">\n"
|
||||
+ " <item>Let\\'s go</item>\n"
|
||||
+ " </array>\n"
|
||||
+ "</resources>", 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");
|
||||
+ "</resources>", input);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -36,7 +36,6 @@ import org.slf4j.LoggerFactory;
|
||||
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 abstract class IntegrationTest extends TestUtils {
|
||||
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 @@ public abstract class IntegrationTest extends TestUtils {
|
||||
private void printCodeWithLineNumbers(ICodeInfo code) {
|
||||
String codeStr = code.getCodeStr();
|
||||
Map<Integer, Integer> 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 @@ public abstract class IntegrationTest extends TestUtils {
|
||||
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) {
|
||||
|
||||
@@ -2,8 +2,6 @@ package jadx.tests.api.utils;
|
||||
|
||||
import org.hamcrest.Matcher;
|
||||
|
||||
import jadx.api.ICodeWriter;
|
||||
|
||||
public class JadxMatchers {
|
||||
|
||||
public static Matcher<String> countString(int count, String substring) {
|
||||
@@ -17,7 +15,7 @@ public class JadxMatchers {
|
||||
public static Matcher<String> 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 class JadxMatchers {
|
||||
sb.append(indent);
|
||||
sb.append(line);
|
||||
}
|
||||
sb.append(ICodeWriter.NL);
|
||||
sb.append('\n');
|
||||
}
|
||||
return countString(1, sb.toString());
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@ import org.junit.jupiter.api.extension.ExtendWith;
|
||||
|
||||
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 @@ import static org.junit.jupiter.api.Assertions.fail;
|
||||
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) {
|
||||
|
||||
@@ -8,7 +8,6 @@ import java.util.stream.Collectors;
|
||||
|
||||
import org.assertj.core.api.AbstractStringAssert;
|
||||
|
||||
import jadx.api.ICodeWriter;
|
||||
import jadx.tests.api.utils.TestUtils;
|
||||
|
||||
public class JadxCodeAssertions extends AbstractStringAssert<JadxCodeAssertions> {
|
||||
@@ -53,7 +52,7 @@ public class JadxCodeAssertions extends AbstractStringAssert<JadxCodeAssertions>
|
||||
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 class JadxCodeAssertions extends AbstractStringAssert<JadxCodeAssertions>
|
||||
// check every line for easier debugging
|
||||
contains(searchLine);
|
||||
}
|
||||
return containsOnlyOnce(sb.substring(ICodeWriter.NL.length()));
|
||||
return containsOnlyOnce(sb.substring(1));
|
||||
}
|
||||
|
||||
public JadxCodeAssertions removeBlockComments() {
|
||||
|
||||
@@ -10,7 +10,6 @@ import org.slf4j.LoggerFactory;
|
||||
|
||||
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 abstract class BaseExternalTest extends TestUtils {
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
@@ -2,7 +2,6 @@ package jadx.tests.integration.conditions;
|
||||
|
||||
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 class TestElseIfCodeStyle extends IntegrationTest {
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,7 +3,6 @@ package jadx.tests.integration.debuginfo;
|
||||
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 class TestReturnSourceLine extends IntegrationTest {
|
||||
|
||||
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 class TestReturnSourceLine extends IntegrationTest {
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
@@ -17,6 +17,7 @@ import org.slf4j.Logger;
|
||||
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 @@ public class Smali {
|
||||
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());
|
||||
|
||||
@@ -7,11 +7,11 @@ import org.slf4j.Logger;
|
||||
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 @@ public final class CodeSearchProvider extends BaseSearchProvider {
|
||||
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;
|
||||
|
||||
@@ -13,10 +13,10 @@ import org.jetbrains.annotations.Nullable;
|
||||
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 @@ public class ResourceSearchProvider implements ISearchProvider {
|
||||
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;
|
||||
|
||||
@@ -12,7 +12,6 @@ import org.fife.ui.rsyntaxtextarea.SyntaxConstants;
|
||||
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 @@ public class JResource extends JLoadableNode {
|
||||
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:
|
||||
|
||||
@@ -10,7 +10,6 @@ import org.fife.ui.rsyntaxtextarea.RSyntaxTextArea;
|
||||
|
||||
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 class ImagePanel extends ContentPanel {
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user