refactor: use interface for CodeWriter
Details: - add simple and annotated code writers to allow skip code annotations processing in jadx-cli and other places - add annotated code info to use only than needed - allow to set provider for codewriter in JadxArgs - add JadxArgs argument to constructor to allow change output - add cli option to insert debug line numbers as code comments (example for previous change)
This commit is contained in:
@@ -6,6 +6,7 @@ import org.slf4j.LoggerFactory;
|
||||
import jadx.api.JadxArgs;
|
||||
import jadx.api.JadxDecompiler;
|
||||
import jadx.api.impl.NoOpCodeCache;
|
||||
import jadx.api.impl.SimpleCodeWriter;
|
||||
import jadx.core.utils.exceptions.JadxArgsValidateException;
|
||||
import jadx.core.utils.files.FileUtils;
|
||||
|
||||
@@ -38,6 +39,7 @@ public class JadxCLI {
|
||||
|
||||
private static int processAndSave(JadxArgs jadxArgs) {
|
||||
jadxArgs.setCodeCache(new NoOpCodeCache());
|
||||
jadxArgs.setCodeWriterProvider(SimpleCodeWriter::new);
|
||||
try (JadxDecompiler jadx = new JadxDecompiler(jadxArgs)) {
|
||||
jadx.load();
|
||||
jadx.save();
|
||||
|
||||
@@ -58,6 +58,9 @@ public class JadxCLIArgs {
|
||||
@Parameter(names = { "--no-debug-info" }, description = "disable debug info")
|
||||
protected boolean debugInfo = true;
|
||||
|
||||
@Parameter(names = { "--add-debug-lines" }, description = "add comments with debug line numbers if available")
|
||||
protected boolean addDebugLines = false;
|
||||
|
||||
@Parameter(names = { "--no-inline-anonymous" }, description = "disable anonymous classes inline")
|
||||
protected boolean inlineAnonymousClasses = true;
|
||||
|
||||
@@ -210,6 +213,7 @@ public class JadxCLIArgs {
|
||||
args.setExportAsGradleProject(exportAsGradleProject);
|
||||
args.setUseImports(useImports);
|
||||
args.setDebugInfo(debugInfo);
|
||||
args.setInsertDebugLines(addDebugLines);
|
||||
args.setInlineAnonymousClasses(inlineAnonymousClasses);
|
||||
args.setRenameCaseSensitive(isRenameCaseSensitive());
|
||||
args.setRenameValid(isRenameValid());
|
||||
@@ -262,6 +266,10 @@ public class JadxCLIArgs {
|
||||
return debugInfo;
|
||||
}
|
||||
|
||||
public boolean isAddDebugLines() {
|
||||
return addDebugLines;
|
||||
}
|
||||
|
||||
public boolean isInlineAnonymousClasses() {
|
||||
return inlineAnonymousClasses;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
package jadx.api;
|
||||
|
||||
import jadx.core.dex.attributes.nodes.LineAttrNode;
|
||||
|
||||
public interface ICodeWriter {
|
||||
String NL = System.getProperty("line.separator");
|
||||
String INDENT_STR = " ";
|
||||
|
||||
boolean isMetadataSupported();
|
||||
|
||||
ICodeWriter startLine();
|
||||
|
||||
ICodeWriter startLine(char c);
|
||||
|
||||
ICodeWriter startLine(String str);
|
||||
|
||||
ICodeWriter startLineWithNum(int sourceLine);
|
||||
|
||||
ICodeWriter addMultiLine(String str);
|
||||
|
||||
ICodeWriter add(String str);
|
||||
|
||||
ICodeWriter add(char c);
|
||||
|
||||
ICodeWriter add(ICodeWriter code);
|
||||
|
||||
ICodeWriter newLine();
|
||||
|
||||
ICodeWriter addIndent();
|
||||
|
||||
void incIndent();
|
||||
|
||||
void decIndent();
|
||||
|
||||
int getIndent();
|
||||
|
||||
void setIndent(int indent);
|
||||
|
||||
int getLine();
|
||||
|
||||
void attachDefinition(LineAttrNode obj);
|
||||
|
||||
void attachAnnotation(Object obj);
|
||||
|
||||
void attachLineAnnotation(Object obj);
|
||||
|
||||
void attachSourceLine(int sourceLine);
|
||||
|
||||
ICodeInfo finish();
|
||||
|
||||
String getCodeStr();
|
||||
|
||||
int getLength();
|
||||
}
|
||||
@@ -6,8 +6,10 @@ import java.util.Collections;
|
||||
import java.util.EnumSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
import jadx.api.impl.AnnotatedCodeWriter;
|
||||
import jadx.api.impl.InMemoryCodeCache;
|
||||
|
||||
public class JadxArgs {
|
||||
@@ -25,6 +27,7 @@ public class JadxArgs {
|
||||
private File outDirRes;
|
||||
|
||||
private ICodeCache codeCache = new InMemoryCodeCache();
|
||||
private Function<JadxArgs, ICodeWriter> codeWriterProvider = AnnotatedCodeWriter::new;
|
||||
|
||||
private int threadsCount = DEFAULT_THREADS_COUNT;
|
||||
|
||||
@@ -36,6 +39,7 @@ public class JadxArgs {
|
||||
|
||||
private boolean useImports = true;
|
||||
private boolean debugInfo = true;
|
||||
private boolean insertDebugLines = false;
|
||||
private boolean inlineAnonymousClasses = true;
|
||||
|
||||
private boolean skipResources = false;
|
||||
@@ -176,6 +180,14 @@ public class JadxArgs {
|
||||
this.debugInfo = debugInfo;
|
||||
}
|
||||
|
||||
public boolean isInsertDebugLines() {
|
||||
return insertDebugLines;
|
||||
}
|
||||
|
||||
public void setInsertDebugLines(boolean insertDebugLines) {
|
||||
this.insertDebugLines = insertDebugLines;
|
||||
}
|
||||
|
||||
public boolean isInlineAnonymousClasses() {
|
||||
return inlineAnonymousClasses;
|
||||
}
|
||||
@@ -364,6 +376,14 @@ public class JadxArgs {
|
||||
this.codeCache = codeCache;
|
||||
}
|
||||
|
||||
public Function<JadxArgs, ICodeWriter> getCodeWriterProvider() {
|
||||
return codeWriterProvider;
|
||||
}
|
||||
|
||||
public void setCodeWriterProvider(Function<JadxArgs, ICodeWriter> codeWriterProvider) {
|
||||
this.codeWriterProvider = codeWriterProvider;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "JadxArgs{" + "inputFiles=" + inputFiles
|
||||
@@ -393,6 +413,7 @@ public class JadxArgs {
|
||||
+ ", renameFlags=" + renameFlags
|
||||
+ ", outputFormat=" + outputFormat
|
||||
+ ", codeCache=" + codeCache
|
||||
+ ", codeWriter=" + codeWriterProvider.apply(this).getClass().getSimpleName()
|
||||
+ '}';
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,7 +17,6 @@ import org.slf4j.LoggerFactory;
|
||||
import jadx.api.ResourceFile.ZipRef;
|
||||
import jadx.api.impl.SimpleCodeInfo;
|
||||
import jadx.api.plugins.utils.ZipSecurity;
|
||||
import jadx.core.codegen.CodeWriter;
|
||||
import jadx.core.utils.Utils;
|
||||
import jadx.core.utils.android.Res9patchStreamDecoder;
|
||||
import jadx.core.utils.exceptions.JadxException;
|
||||
@@ -83,7 +82,7 @@ public final class ResourcesLoader {
|
||||
return decodeStream(rf, (size, is) -> loadContent(jadxRef, rf, is));
|
||||
} catch (JadxException e) {
|
||||
LOG.error("Decode error", e);
|
||||
CodeWriter cw = new CodeWriter();
|
||||
ICodeWriter cw = jadxRef.getRoot().makeCodeWriter();
|
||||
cw.add("Error decode ").add(rf.getType().toString().toLowerCase());
|
||||
Utils.appendStackTrace(cw, e.getCause());
|
||||
return ResContainer.textResource(rf.getDeobfName(), cw.finish());
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
package jadx.api.impl;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import jadx.api.CodePosition;
|
||||
import jadx.api.ICodeInfo;
|
||||
|
||||
public class AnnotatedCodeInfo implements ICodeInfo {
|
||||
|
||||
private final String code;
|
||||
private final Map<Integer, Integer> lineMapping;
|
||||
private final Map<CodePosition, Object> annotations;
|
||||
|
||||
public AnnotatedCodeInfo(ICodeInfo codeInfo) {
|
||||
this(codeInfo.getCodeStr(), codeInfo.getLineMapping(), codeInfo.getAnnotations());
|
||||
}
|
||||
|
||||
public AnnotatedCodeInfo(String code, Map<Integer, Integer> lineMapping, Map<CodePosition, Object> annotations) {
|
||||
this.code = code;
|
||||
this.lineMapping = lineMapping;
|
||||
this.annotations = annotations;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getCodeStr() {
|
||||
return code;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<Integer, Integer> getLineMapping() {
|
||||
return lineMapping;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<CodePosition, Object> getAnnotations() {
|
||||
return annotations;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return code;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,181 @@
|
||||
package jadx.api.impl;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.TreeMap;
|
||||
|
||||
import jadx.api.CodePosition;
|
||||
import jadx.api.ICodeInfo;
|
||||
import jadx.api.ICodeWriter;
|
||||
import jadx.api.JadxArgs;
|
||||
import jadx.core.dex.attributes.nodes.LineAttrNode;
|
||||
import jadx.core.utils.StringUtils;
|
||||
|
||||
public class AnnotatedCodeWriter extends SimpleCodeWriter implements ICodeWriter {
|
||||
|
||||
private int line = 1;
|
||||
private int offset;
|
||||
private Map<CodePosition, Object> annotations = Collections.emptyMap();
|
||||
private Map<Integer, Integer> lineMap = Collections.emptyMap();
|
||||
|
||||
public AnnotatedCodeWriter() {
|
||||
}
|
||||
|
||||
public AnnotatedCodeWriter(JadxArgs args) {
|
||||
super(args);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isMetadataSupported() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public AnnotatedCodeWriter addMultiLine(String str) {
|
||||
if (str.contains(NL)) {
|
||||
buf.append(str.replace(NL, NL + indentStr));
|
||||
line += StringUtils.countMatches(str, NL);
|
||||
offset = 0;
|
||||
} else {
|
||||
buf.append(str);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public AnnotatedCodeWriter add(String str) {
|
||||
buf.append(str);
|
||||
offset += str.length();
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public AnnotatedCodeWriter add(char c) {
|
||||
buf.append(c);
|
||||
offset++;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ICodeWriter add(ICodeWriter cw) {
|
||||
if ((!(cw instanceof AnnotatedCodeWriter))) {
|
||||
buf.append(cw.getCodeStr());
|
||||
return this;
|
||||
}
|
||||
AnnotatedCodeWriter code = ((AnnotatedCodeWriter) cw);
|
||||
line--;
|
||||
for (Map.Entry<CodePosition, Object> entry : code.annotations.entrySet()) {
|
||||
Object val = entry.getValue();
|
||||
if (val instanceof DefinitionWrapper) {
|
||||
LineAttrNode node = ((DefinitionWrapper) val).getNode();
|
||||
node.setDefPosition(node.getDefPosition() + this.buf.length());
|
||||
}
|
||||
CodePosition pos = entry.getKey();
|
||||
int usagePos = pos.getUsagePosition() + getLength();
|
||||
attachAnnotation(val,
|
||||
new CodePosition(line + pos.getLine(), pos.getOffset())
|
||||
.setUsagePosition(usagePos));
|
||||
}
|
||||
for (Map.Entry<Integer, Integer> entry : code.lineMap.entrySet()) {
|
||||
attachSourceLine(line + entry.getKey(), entry.getValue());
|
||||
}
|
||||
line += code.line;
|
||||
offset = code.offset;
|
||||
buf.append(code.buf);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void addLine() {
|
||||
buf.append(NL);
|
||||
line++;
|
||||
offset = 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected AnnotatedCodeWriter addLineIndent() {
|
||||
buf.append(indentStr);
|
||||
offset += indentStr.length();
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getLine() {
|
||||
return line;
|
||||
}
|
||||
|
||||
private static final class DefinitionWrapper {
|
||||
private final LineAttrNode node;
|
||||
|
||||
private DefinitionWrapper(LineAttrNode node) {
|
||||
this.node = node;
|
||||
}
|
||||
|
||||
public LineAttrNode getNode() {
|
||||
return node;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void attachDefinition(LineAttrNode obj) {
|
||||
obj.setDefPosition(buf.length());
|
||||
attachAnnotation(obj);
|
||||
attachAnnotation(new DefinitionWrapper(obj), new CodePosition(line, offset));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void attachAnnotation(Object obj) {
|
||||
attachAnnotation(obj, new CodePosition(line, offset + 1).setUsagePosition(getLength()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void attachLineAnnotation(Object obj) {
|
||||
attachAnnotation(obj, new CodePosition(line, 0));
|
||||
}
|
||||
|
||||
private void attachAnnotation(Object obj, CodePosition pos) {
|
||||
if (annotations.isEmpty()) {
|
||||
annotations = new HashMap<>();
|
||||
}
|
||||
annotations.put(pos, obj);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void attachSourceLine(int sourceLine) {
|
||||
if (sourceLine == 0) {
|
||||
return;
|
||||
}
|
||||
attachSourceLine(line, sourceLine);
|
||||
}
|
||||
|
||||
private void attachSourceLine(int decompiledLine, int sourceLine) {
|
||||
if (lineMap.isEmpty()) {
|
||||
lineMap = new TreeMap<>();
|
||||
}
|
||||
lineMap.put(decompiledLine, sourceLine);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ICodeInfo finish() {
|
||||
removeFirstEmptyLine();
|
||||
processDefinitionAnnotations();
|
||||
String code = buf.toString();
|
||||
buf = null;
|
||||
return new AnnotatedCodeInfo(code, lineMap, annotations);
|
||||
}
|
||||
|
||||
private void processDefinitionAnnotations() {
|
||||
if (!annotations.isEmpty()) {
|
||||
annotations.entrySet().removeIf(entry -> {
|
||||
Object v = entry.getValue();
|
||||
if (v instanceof DefinitionWrapper) {
|
||||
LineAttrNode l = ((DefinitionWrapper) v).getNode();
|
||||
l.setDecompiledLine(entry.getKey().getLine());
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -9,21 +9,9 @@ import jadx.api.ICodeInfo;
|
||||
public class SimpleCodeInfo implements ICodeInfo {
|
||||
|
||||
private final String code;
|
||||
private final Map<Integer, Integer> lineMapping;
|
||||
private final Map<CodePosition, Object> annotations;
|
||||
|
||||
public SimpleCodeInfo(String code) {
|
||||
this(code, Collections.emptyMap(), Collections.emptyMap());
|
||||
}
|
||||
|
||||
public SimpleCodeInfo(ICodeInfo codeInfo) {
|
||||
this(codeInfo.getCodeStr(), codeInfo.getLineMapping(), codeInfo.getAnnotations());
|
||||
}
|
||||
|
||||
public SimpleCodeInfo(String code, Map<Integer, Integer> lineMapping, Map<CodePosition, Object> annotations) {
|
||||
this.code = code;
|
||||
this.lineMapping = lineMapping;
|
||||
this.annotations = annotations;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -33,12 +21,12 @@ public class SimpleCodeInfo implements ICodeInfo {
|
||||
|
||||
@Override
|
||||
public Map<Integer, Integer> getLineMapping() {
|
||||
return lineMapping;
|
||||
return Collections.emptyMap();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<CodePosition, Object> getAnnotations() {
|
||||
return annotations;
|
||||
return Collections.emptyMap();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -0,0 +1,241 @@
|
||||
package jadx.api.impl;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import jadx.api.ICodeInfo;
|
||||
import jadx.api.ICodeWriter;
|
||||
import jadx.api.JadxArgs;
|
||||
import jadx.core.dex.attributes.nodes.LineAttrNode;
|
||||
import jadx.core.utils.Utils;
|
||||
|
||||
/**
|
||||
* CodeWriter implementation without meta information support (only strings builder)
|
||||
*/
|
||||
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;
|
||||
}
|
||||
|
||||
public SimpleCodeWriter(JadxArgs args) {
|
||||
this.insertLineNumbers = args.isInsertDebugLines();
|
||||
if (insertLineNumbers) {
|
||||
incIndent(3);
|
||||
add(indentStr);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isMetadataSupported() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SimpleCodeWriter startLine() {
|
||||
addLine();
|
||||
addLineIndent();
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SimpleCodeWriter startLine(char c) {
|
||||
startLine();
|
||||
add(c);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SimpleCodeWriter startLine(String str) {
|
||||
startLine();
|
||||
add(str);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SimpleCodeWriter startLineWithNum(int sourceLine) {
|
||||
if (sourceLine == 0) {
|
||||
startLine();
|
||||
return this;
|
||||
}
|
||||
if (this.insertLineNumbers) {
|
||||
newLine();
|
||||
attachSourceLine(sourceLine);
|
||||
int start = getLength();
|
||||
add("/* ").add(Integer.toString(sourceLine)).add(" */ ");
|
||||
int len = getLength() - start;
|
||||
if (indentStr.length() > len) {
|
||||
add(indentStr.substring(len));
|
||||
}
|
||||
} else {
|
||||
startLine();
|
||||
attachSourceLine(sourceLine);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SimpleCodeWriter addMultiLine(String str) {
|
||||
if (str.contains(NL)) {
|
||||
buf.append(str.replace(NL, NL + indentStr));
|
||||
} else {
|
||||
buf.append(str);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SimpleCodeWriter add(String str) {
|
||||
buf.append(str);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SimpleCodeWriter add(char c) {
|
||||
buf.append(c);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ICodeWriter add(ICodeWriter cw) {
|
||||
buf.append(cw.getCodeStr());
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SimpleCodeWriter newLine() {
|
||||
addLine();
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SimpleCodeWriter addIndent() {
|
||||
add(INDENT_STR);
|
||||
return this;
|
||||
}
|
||||
|
||||
protected void addLine() {
|
||||
buf.append(NL);
|
||||
}
|
||||
|
||||
protected SimpleCodeWriter addLineIndent() {
|
||||
buf.append(indentStr);
|
||||
return this;
|
||||
}
|
||||
|
||||
private void updateIndent() {
|
||||
int curIndent = indent;
|
||||
if (curIndent < INDENT_CACHE.length) {
|
||||
this.indentStr = INDENT_CACHE[curIndent];
|
||||
} else {
|
||||
this.indentStr = Utils.strRepeat(INDENT_STR, curIndent);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void incIndent() {
|
||||
incIndent(1);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void decIndent() {
|
||||
decIndent(1);
|
||||
}
|
||||
|
||||
private void incIndent(int c) {
|
||||
this.indent += c;
|
||||
updateIndent();
|
||||
}
|
||||
|
||||
private void decIndent(int c) {
|
||||
this.indent -= c;
|
||||
if (this.indent < 0) {
|
||||
LOG.warn("Indent < 0");
|
||||
this.indent = 0;
|
||||
}
|
||||
updateIndent();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getIndent() {
|
||||
return indent;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setIndent(int indent) {
|
||||
this.indent = indent;
|
||||
updateIndent();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getLine() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void attachDefinition(LineAttrNode obj) {
|
||||
// no op
|
||||
}
|
||||
|
||||
@Override
|
||||
public void attachAnnotation(Object obj) {
|
||||
// no op
|
||||
}
|
||||
|
||||
@Override
|
||||
public void attachLineAnnotation(Object obj) {
|
||||
// no op
|
||||
}
|
||||
|
||||
@Override
|
||||
public void attachSourceLine(int sourceLine) {
|
||||
// no op
|
||||
}
|
||||
|
||||
@Override
|
||||
public ICodeInfo finish() {
|
||||
removeFirstEmptyLine();
|
||||
String code = buf.toString();
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getLength() {
|
||||
return buf.length();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getCodeStr() {
|
||||
removeFirstEmptyLine();
|
||||
return buf.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return getCodeStr();
|
||||
}
|
||||
}
|
||||
@@ -7,6 +7,7 @@ import java.util.Map.Entry;
|
||||
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import jadx.api.ICodeWriter;
|
||||
import jadx.api.plugins.input.data.IFieldData;
|
||||
import jadx.api.plugins.input.data.annotations.EncodedValue;
|
||||
import jadx.api.plugins.input.data.annotations.IAnnotation;
|
||||
@@ -34,19 +35,19 @@ public class AnnotationGen {
|
||||
this.classGen = classGen;
|
||||
}
|
||||
|
||||
public void addForClass(CodeWriter code) {
|
||||
public void addForClass(ICodeWriter code) {
|
||||
add(cls, code);
|
||||
}
|
||||
|
||||
public void addForMethod(CodeWriter code, MethodNode mth) {
|
||||
public void addForMethod(ICodeWriter code, MethodNode mth) {
|
||||
add(mth, code);
|
||||
}
|
||||
|
||||
public void addForField(CodeWriter code, FieldNode field) {
|
||||
public void addForField(ICodeWriter code, FieldNode field) {
|
||||
add(field, code);
|
||||
}
|
||||
|
||||
public void addForParameter(CodeWriter code, MethodParameters paramsAnnotations, int n) {
|
||||
public void addForParameter(ICodeWriter code, MethodParameters paramsAnnotations, int n) {
|
||||
List<AnnotationsList> paramList = paramsAnnotations.getParamList();
|
||||
if (n >= paramList.size()) {
|
||||
return;
|
||||
@@ -61,7 +62,7 @@ public class AnnotationGen {
|
||||
}
|
||||
}
|
||||
|
||||
private void add(IAttributeNode node, CodeWriter code) {
|
||||
private void add(IAttributeNode node, ICodeWriter code) {
|
||||
AnnotationsList aList = node.get(AType.ANNOTATION_LIST);
|
||||
if (aList == null || aList.isEmpty()) {
|
||||
return;
|
||||
@@ -75,7 +76,7 @@ public class AnnotationGen {
|
||||
}
|
||||
}
|
||||
|
||||
private void formatAnnotation(CodeWriter code, IAnnotation a) {
|
||||
private void formatAnnotation(ICodeWriter code, IAnnotation a) {
|
||||
code.add('@');
|
||||
ClassNode annCls = cls.root().resolveClass(a.getAnnotationClass());
|
||||
if (annCls != null) {
|
||||
@@ -116,7 +117,7 @@ public class AnnotationGen {
|
||||
return paramName;
|
||||
}
|
||||
|
||||
public void addThrows(MethodNode mth, CodeWriter code) {
|
||||
public void addThrows(MethodNode mth, ICodeWriter code) {
|
||||
List<ArgType> throwList = mth.getThrows();
|
||||
if (!throwList.isEmpty()) {
|
||||
code.add(" throws ");
|
||||
@@ -143,7 +144,7 @@ public class AnnotationGen {
|
||||
}
|
||||
|
||||
// TODO: refactor this boilerplate code
|
||||
public void encodeValue(RootNode root, CodeWriter code, EncodedValue encodedValue) {
|
||||
public void encodeValue(RootNode root, ICodeWriter code, EncodedValue encodedValue) {
|
||||
if (encodedValue == null) {
|
||||
code.add("null");
|
||||
return;
|
||||
|
||||
@@ -14,6 +14,7 @@ import java.util.stream.Stream;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import jadx.api.ICodeInfo;
|
||||
import jadx.api.ICodeWriter;
|
||||
import jadx.api.JadxArgs;
|
||||
import jadx.api.plugins.input.data.AccessFlags;
|
||||
import jadx.api.plugins.input.data.annotations.EncodedType;
|
||||
@@ -54,7 +55,7 @@ public class ClassGen {
|
||||
private final boolean showInconsistentCode;
|
||||
|
||||
private final Set<ClassInfo> imports = new HashSet<>();
|
||||
private int clsDeclLine;
|
||||
private int clsDeclOffset;
|
||||
|
||||
private boolean bodyGenStarted;
|
||||
|
||||
@@ -81,10 +82,10 @@ public class ClassGen {
|
||||
}
|
||||
|
||||
public ICodeInfo makeClass() throws CodegenException {
|
||||
CodeWriter clsBody = new CodeWriter();
|
||||
ICodeWriter clsBody = cls.root().makeCodeWriter();
|
||||
addClassCode(clsBody);
|
||||
|
||||
CodeWriter clsCode = new CodeWriter();
|
||||
ICodeWriter clsCode = cls.root().makeCodeWriter();
|
||||
if (!"".equals(cls.getPackage())) {
|
||||
clsCode.add("package ").add(cls.getPackage()).add(';');
|
||||
clsCode.newLine();
|
||||
@@ -109,7 +110,7 @@ public class ClassGen {
|
||||
return clsCode.finish();
|
||||
}
|
||||
|
||||
public void addClassCode(CodeWriter code) throws CodegenException {
|
||||
public void addClassCode(ICodeWriter code) throws CodegenException {
|
||||
if (cls.contains(AFlag.DONT_GENERATE)) {
|
||||
return;
|
||||
}
|
||||
@@ -122,7 +123,7 @@ public class ClassGen {
|
||||
addClassBody(code);
|
||||
}
|
||||
|
||||
public void addClassDeclaration(CodeWriter clsCode) {
|
||||
public void addClassDeclaration(ICodeWriter clsCode) {
|
||||
AccessInfo af = cls.getAccessFlags();
|
||||
if (af.isInterface()) {
|
||||
af = af.remove(AccessFlags.ABSTRACT)
|
||||
@@ -141,8 +142,7 @@ public class ClassGen {
|
||||
annotationGen.addForClass(clsCode);
|
||||
insertRenameInfo(clsCode, cls);
|
||||
CodeGenUtils.addSourceFileInfo(clsCode, cls);
|
||||
clsCode.startLineWithNum(cls.getSourceLine());
|
||||
clsCode.add(af.makeString());
|
||||
clsCode.startLineWithNum(cls.getSourceLine()).add(af.makeString());
|
||||
if (af.isInterface()) {
|
||||
if (af.isAnnotation()) {
|
||||
clsCode.add('@');
|
||||
@@ -187,7 +187,7 @@ public class ClassGen {
|
||||
}
|
||||
}
|
||||
|
||||
public boolean addGenericTypeParameters(CodeWriter code, List<ArgType> generics, boolean classDeclaration) {
|
||||
public boolean addGenericTypeParameters(ICodeWriter code, List<ArgType> generics, boolean classDeclaration) {
|
||||
if (generics == null || generics.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
@@ -228,7 +228,7 @@ public class ClassGen {
|
||||
return true;
|
||||
}
|
||||
|
||||
public void addClassBody(CodeWriter clsCode) throws CodegenException {
|
||||
public void addClassBody(ICodeWriter clsCode) throws CodegenException {
|
||||
addClassBody(clsCode, false);
|
||||
}
|
||||
|
||||
@@ -236,10 +236,10 @@ public class ClassGen {
|
||||
* @param printClassName allows to print the original class name as comment (e.g. for inlined
|
||||
* classes)
|
||||
*/
|
||||
public void addClassBody(CodeWriter clsCode, boolean printClassName) throws CodegenException {
|
||||
public void addClassBody(ICodeWriter clsCode, boolean printClassName) throws CodegenException {
|
||||
clsCode.add('{');
|
||||
setBodyGenStarted(true);
|
||||
clsDeclLine = clsCode.getLine();
|
||||
clsDeclOffset = clsCode.getLength();
|
||||
clsCode.incIndent();
|
||||
if (printClassName) {
|
||||
clsCode.startLine();
|
||||
@@ -251,7 +251,7 @@ public class ClassGen {
|
||||
clsCode.startLine('}');
|
||||
}
|
||||
|
||||
private void addInnerClsAndMethods(CodeWriter clsCode) {
|
||||
private void addInnerClsAndMethods(ICodeWriter clsCode) {
|
||||
Stream.of(cls.getInnerClasses(), cls.getMethods())
|
||||
.flatMap(Collection::stream)
|
||||
.filter(node -> !node.contains(AFlag.DONT_GENERATE) || fallback)
|
||||
@@ -265,7 +265,7 @@ public class ClassGen {
|
||||
});
|
||||
}
|
||||
|
||||
private void addInnerClass(CodeWriter code, ClassNode innerCls) {
|
||||
private void addInnerClass(ICodeWriter code, ClassNode innerCls) {
|
||||
try {
|
||||
ClassGen inClGen = new ClassGen(innerCls, getParentGen());
|
||||
code.newLine();
|
||||
@@ -285,8 +285,8 @@ public class ClassGen {
|
||||
return false;
|
||||
}
|
||||
|
||||
private void addMethod(CodeWriter code, MethodNode mth) {
|
||||
if (code.getLine() != clsDeclLine) {
|
||||
private void addMethod(ICodeWriter code, MethodNode mth) {
|
||||
if (code.getLength() != clsDeclOffset) {
|
||||
code.newLine();
|
||||
}
|
||||
int savedIndent = code.getIndent();
|
||||
@@ -314,7 +314,7 @@ public class ClassGen {
|
||||
return false;
|
||||
}
|
||||
|
||||
public void addMethodCode(CodeWriter code, MethodNode mth) throws CodegenException {
|
||||
public void addMethodCode(ICodeWriter code, MethodNode mth) throws CodegenException {
|
||||
CodeGenUtils.addComments(code, mth);
|
||||
if (mth.isNoCode()) {
|
||||
MethodGen mthGen = new MethodGen(this, mth);
|
||||
@@ -344,7 +344,7 @@ public class ClassGen {
|
||||
}
|
||||
}
|
||||
|
||||
public void insertDecompilationProblems(CodeWriter code, AttrNode node) {
|
||||
public void insertDecompilationProblems(ICodeWriter code, AttrNode node) {
|
||||
List<JadxError> errors = node.getAll(AType.JADX_ERROR);
|
||||
if (!errors.isEmpty()) {
|
||||
errors.stream().distinct().sorted().forEach(err -> {
|
||||
@@ -365,14 +365,14 @@ public class ClassGen {
|
||||
}
|
||||
}
|
||||
|
||||
private void addFields(CodeWriter code) throws CodegenException {
|
||||
private void addFields(ICodeWriter code) throws CodegenException {
|
||||
addEnumFields(code);
|
||||
for (FieldNode f : cls.getFields()) {
|
||||
addField(code, f);
|
||||
}
|
||||
}
|
||||
|
||||
public void addField(CodeWriter code, FieldNode f) {
|
||||
public void addField(ICodeWriter code, FieldNode f) {
|
||||
if (f.contains(AFlag.DONT_GENERATE)) {
|
||||
return;
|
||||
}
|
||||
@@ -418,7 +418,7 @@ public class ClassGen {
|
||||
return false;
|
||||
}
|
||||
|
||||
private void addEnumFields(CodeWriter code) throws CodegenException {
|
||||
private void addEnumFields(ICodeWriter code) throws CodegenException {
|
||||
EnumClassAttr enumFields = cls.get(AType.ENUM_CLASS);
|
||||
if (enumFields == null) {
|
||||
return;
|
||||
@@ -470,7 +470,7 @@ public class ClassGen {
|
||||
return new InsnGen(mthGen, false);
|
||||
}
|
||||
|
||||
private void addInsnBody(InsnGen insnGen, CodeWriter code, InsnNode insn) {
|
||||
private void addInsnBody(InsnGen insnGen, ICodeWriter code, InsnNode insn) {
|
||||
try {
|
||||
insnGen.makeInsn(insn, code, InsnGen.Flags.BODY_ONLY_NOWRAP);
|
||||
} catch (Exception e) {
|
||||
@@ -478,7 +478,7 @@ public class ClassGen {
|
||||
}
|
||||
}
|
||||
|
||||
public void useType(CodeWriter code, ArgType type) {
|
||||
public void useType(ICodeWriter code, ArgType type) {
|
||||
PrimitiveType stype = type.getPrimitiveType();
|
||||
if (stype == null) {
|
||||
code.add(type.toString());
|
||||
@@ -496,11 +496,11 @@ public class ClassGen {
|
||||
}
|
||||
}
|
||||
|
||||
public void useClass(CodeWriter code, String rawCls) {
|
||||
public void useClass(ICodeWriter code, String rawCls) {
|
||||
useClass(code, ArgType.object(rawCls));
|
||||
}
|
||||
|
||||
public void useClass(CodeWriter code, ArgType type) {
|
||||
public void useClass(ICodeWriter code, ArgType type) {
|
||||
ArgType outerType = type.getOuterType();
|
||||
if (outerType != null) {
|
||||
useClass(code, outerType);
|
||||
@@ -535,7 +535,7 @@ public class ClassGen {
|
||||
}
|
||||
}
|
||||
|
||||
private void useClassShortName(CodeWriter code, String object) {
|
||||
private void useClassShortName(ICodeWriter code, String object) {
|
||||
ClassInfo classInfo = ClassInfo.fromName(cls.root(), object);
|
||||
ClassNode classNode = cls.root().resolveClass(classInfo);
|
||||
if (classNode != null) {
|
||||
@@ -544,7 +544,7 @@ public class ClassGen {
|
||||
code.add(classInfo.getAliasShortName());
|
||||
}
|
||||
|
||||
public void useClass(CodeWriter code, ClassInfo classInfo) {
|
||||
public void useClass(ICodeWriter code, ClassInfo classInfo) {
|
||||
ClassNode classNode = cls.root().resolveClass(classInfo);
|
||||
if (classNode != null) {
|
||||
useClass(code, classNode);
|
||||
@@ -553,12 +553,12 @@ public class ClassGen {
|
||||
}
|
||||
}
|
||||
|
||||
public void useClass(CodeWriter code, ClassNode classNode) {
|
||||
public void useClass(ICodeWriter code, ClassNode classNode) {
|
||||
code.attachAnnotation(classNode);
|
||||
addClsName(code, classNode.getClassInfo());
|
||||
}
|
||||
|
||||
private void addClsName(CodeWriter code, ClassInfo classInfo) {
|
||||
private void addClsName(ICodeWriter code, ClassInfo classInfo) {
|
||||
String clsName = useClassInternal(cls.getClassInfo(), classInfo);
|
||||
code.add(clsName);
|
||||
}
|
||||
@@ -684,14 +684,14 @@ public class ClassGen {
|
||||
return searchCollision(root, useCls.getParentClass(), searchCls);
|
||||
}
|
||||
|
||||
private void insertRenameInfo(CodeWriter code, ClassNode cls) {
|
||||
private void insertRenameInfo(ICodeWriter code, ClassNode cls) {
|
||||
ClassInfo classInfo = cls.getClassInfo();
|
||||
if (classInfo.hasAlias()) {
|
||||
CodeGenUtils.addRenamedComment(code, cls, classInfo.getType().getObject());
|
||||
}
|
||||
}
|
||||
|
||||
private static void addClassUsageInfo(CodeWriter code, ClassNode cls) {
|
||||
private static void addClassUsageInfo(ICodeWriter code, ClassNode cls) {
|
||||
List<ClassNode> deps = cls.getDependencies();
|
||||
code.startLine("// deps - ").add(Integer.toString(deps.size()));
|
||||
for (ClassNode depCls : deps) {
|
||||
@@ -709,7 +709,7 @@ public class ClassGen {
|
||||
}
|
||||
}
|
||||
|
||||
static void addMthUsageInfo(CodeWriter code, MethodNode mth) {
|
||||
static void addMthUsageInfo(ICodeWriter code, MethodNode mth) {
|
||||
List<MethodNode> useInMths = mth.getUseIn();
|
||||
code.startLine("// use in methods - ").add(Integer.toString(useInMths.size()));
|
||||
for (MethodNode useMth : useInMths) {
|
||||
@@ -717,7 +717,7 @@ public class ClassGen {
|
||||
}
|
||||
}
|
||||
|
||||
private static void addFieldUsageInfo(CodeWriter code, FieldNode fieldNode) {
|
||||
private static void addFieldUsageInfo(ICodeWriter code, FieldNode fieldNode) {
|
||||
List<MethodNode> useInMths = fieldNode.getUseIn();
|
||||
code.startLine("// use in methods - ").add(Integer.toString(useInMths.size()));
|
||||
for (MethodNode useMth : useInMths) {
|
||||
|
||||
@@ -1,301 +0,0 @@
|
||||
package jadx.core.codegen;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.TreeMap;
|
||||
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import jadx.api.CodePosition;
|
||||
import jadx.api.ICodeInfo;
|
||||
import jadx.api.impl.SimpleCodeInfo;
|
||||
import jadx.core.dex.attributes.nodes.LineAttrNode;
|
||||
import jadx.core.utils.StringUtils;
|
||||
import jadx.core.utils.Utils;
|
||||
|
||||
public class CodeWriter {
|
||||
private static final Logger LOG = LoggerFactory.getLogger(CodeWriter.class);
|
||||
|
||||
public static final String NL = System.getProperty("line.separator");
|
||||
public static final String INDENT_STR = " ";
|
||||
|
||||
private static final boolean ADD_LINE_NUMBERS = false;
|
||||
|
||||
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,
|
||||
};
|
||||
|
||||
private StringBuilder buf;
|
||||
@Nullable
|
||||
private String code;
|
||||
private String indentStr;
|
||||
private int indent;
|
||||
|
||||
private int line = 1;
|
||||
private int offset = 0;
|
||||
private Map<CodePosition, Object> annotations = Collections.emptyMap();
|
||||
private Map<Integer, Integer> lineMap = Collections.emptyMap();
|
||||
|
||||
public CodeWriter() {
|
||||
this.buf = new StringBuilder();
|
||||
this.indent = 0;
|
||||
this.indentStr = "";
|
||||
if (ADD_LINE_NUMBERS) {
|
||||
incIndent(3);
|
||||
add(indentStr);
|
||||
}
|
||||
}
|
||||
|
||||
public CodeWriter startLine() {
|
||||
addLine();
|
||||
addLineIndent();
|
||||
return this;
|
||||
}
|
||||
|
||||
public CodeWriter startLine(char c) {
|
||||
addLine();
|
||||
addLineIndent();
|
||||
add(c);
|
||||
return this;
|
||||
}
|
||||
|
||||
public CodeWriter startLine(String str) {
|
||||
addLine();
|
||||
addLineIndent();
|
||||
add(str);
|
||||
return this;
|
||||
}
|
||||
|
||||
public CodeWriter startLineWithNum(int sourceLine) {
|
||||
if (sourceLine == 0) {
|
||||
startLine();
|
||||
return this;
|
||||
}
|
||||
if (ADD_LINE_NUMBERS) {
|
||||
newLine();
|
||||
attachSourceLine(sourceLine);
|
||||
String ln = "/* " + sourceLine + " */ ";
|
||||
add(ln);
|
||||
if (indentStr.length() > ln.length()) {
|
||||
add(indentStr.substring(ln.length()));
|
||||
}
|
||||
} else {
|
||||
startLine();
|
||||
attachSourceLine(sourceLine);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public CodeWriter addMultiLine(String str) {
|
||||
if (str.contains(NL)) {
|
||||
buf.append(str.replace(NL, NL + indentStr));
|
||||
line += StringUtils.countMatches(str, NL);
|
||||
offset = 0;
|
||||
} else {
|
||||
buf.append(str);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public CodeWriter add(String str) {
|
||||
buf.append(str);
|
||||
offset += str.length();
|
||||
return this;
|
||||
}
|
||||
|
||||
public CodeWriter add(char c) {
|
||||
buf.append(c);
|
||||
offset++;
|
||||
return this;
|
||||
}
|
||||
|
||||
CodeWriter add(CodeWriter code) {
|
||||
line--;
|
||||
for (Map.Entry<CodePosition, Object> entry : code.annotations.entrySet()) {
|
||||
Object val = entry.getValue();
|
||||
if (val instanceof DefinitionWrapper) {
|
||||
LineAttrNode node = ((DefinitionWrapper) val).getNode();
|
||||
node.setDefPosition(node.getDefPosition() + this.buf.length());
|
||||
}
|
||||
CodePosition pos = entry.getKey();
|
||||
int usagePos = pos.getUsagePosition() + bufLength();
|
||||
attachAnnotation(val,
|
||||
new CodePosition(line + pos.getLine(), pos.getOffset())
|
||||
.setUsagePosition(usagePos));
|
||||
}
|
||||
for (Map.Entry<Integer, Integer> entry : code.lineMap.entrySet()) {
|
||||
attachSourceLine(line + entry.getKey(), entry.getValue());
|
||||
}
|
||||
line += code.line;
|
||||
offset = code.offset;
|
||||
buf.append(code.buf);
|
||||
return this;
|
||||
}
|
||||
|
||||
public CodeWriter newLine() {
|
||||
addLine();
|
||||
return this;
|
||||
}
|
||||
|
||||
public CodeWriter addIndent() {
|
||||
add(INDENT_STR);
|
||||
return this;
|
||||
}
|
||||
|
||||
private void addLine() {
|
||||
buf.append(NL);
|
||||
line++;
|
||||
offset = 0;
|
||||
}
|
||||
|
||||
private CodeWriter addLineIndent() {
|
||||
buf.append(indentStr);
|
||||
offset += indentStr.length();
|
||||
return this;
|
||||
}
|
||||
|
||||
private void updateIndent() {
|
||||
int curIndent = indent;
|
||||
if (curIndent < INDENT_CACHE.length) {
|
||||
this.indentStr = INDENT_CACHE[curIndent];
|
||||
} else {
|
||||
this.indentStr = Utils.strRepeat(INDENT_STR, curIndent);
|
||||
}
|
||||
}
|
||||
|
||||
public void incIndent() {
|
||||
incIndent(1);
|
||||
}
|
||||
|
||||
public void decIndent() {
|
||||
decIndent(1);
|
||||
}
|
||||
|
||||
public void incIndent(int c) {
|
||||
this.indent += c;
|
||||
updateIndent();
|
||||
}
|
||||
|
||||
public void decIndent(int c) {
|
||||
this.indent -= c;
|
||||
if (this.indent < 0) {
|
||||
LOG.warn("Indent < 0");
|
||||
this.indent = 0;
|
||||
}
|
||||
updateIndent();
|
||||
}
|
||||
|
||||
public int getIndent() {
|
||||
return indent;
|
||||
}
|
||||
|
||||
public void setIndent(int indent) {
|
||||
this.indent = indent;
|
||||
updateIndent();
|
||||
}
|
||||
|
||||
public int getLine() {
|
||||
return line;
|
||||
}
|
||||
|
||||
private static class DefinitionWrapper {
|
||||
private final LineAttrNode node;
|
||||
|
||||
private DefinitionWrapper(LineAttrNode node) {
|
||||
this.node = node;
|
||||
}
|
||||
|
||||
public LineAttrNode getNode() {
|
||||
return node;
|
||||
}
|
||||
}
|
||||
|
||||
public void attachDefinition(LineAttrNode obj) {
|
||||
obj.setDefPosition(buf.length());
|
||||
attachAnnotation(obj);
|
||||
attachAnnotation(new DefinitionWrapper(obj), new CodePosition(line, offset));
|
||||
}
|
||||
|
||||
public void attachAnnotation(Object obj) {
|
||||
attachAnnotation(obj,
|
||||
new CodePosition(line, offset + 1).setUsagePosition(bufLength()));
|
||||
}
|
||||
|
||||
public void attachLineAnnotation(Object obj) {
|
||||
attachAnnotation(obj, new CodePosition(line, 0));
|
||||
}
|
||||
|
||||
private Object attachAnnotation(Object obj, CodePosition pos) {
|
||||
if (annotations.isEmpty()) {
|
||||
annotations = new HashMap<>();
|
||||
}
|
||||
return annotations.put(pos, obj);
|
||||
}
|
||||
|
||||
public void attachSourceLine(int sourceLine) {
|
||||
if (sourceLine == 0) {
|
||||
return;
|
||||
}
|
||||
attachSourceLine(line, sourceLine);
|
||||
}
|
||||
|
||||
private void attachSourceLine(int decompiledLine, int sourceLine) {
|
||||
if (lineMap.isEmpty()) {
|
||||
lineMap = new TreeMap<>();
|
||||
}
|
||||
lineMap.put(decompiledLine, sourceLine);
|
||||
}
|
||||
|
||||
public ICodeInfo finish() {
|
||||
removeFirstEmptyLine();
|
||||
processDefinitionAnnotations();
|
||||
code = buf.toString();
|
||||
buf = null;
|
||||
return new SimpleCodeInfo(code, lineMap, annotations);
|
||||
}
|
||||
|
||||
private void removeFirstEmptyLine() {
|
||||
int len = NL.length();
|
||||
if (buf.length() > len && buf.substring(0, len).equals(NL)) {
|
||||
buf.delete(0, len);
|
||||
}
|
||||
}
|
||||
|
||||
private void processDefinitionAnnotations() {
|
||||
if (!annotations.isEmpty()) {
|
||||
annotations.entrySet().removeIf(entry -> {
|
||||
Object v = entry.getValue();
|
||||
if (v instanceof DefinitionWrapper) {
|
||||
LineAttrNode l = ((DefinitionWrapper) v).getNode();
|
||||
l.setDecompiledLine(entry.getKey().getLine());
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public int bufLength() {
|
||||
return buf.length();
|
||||
}
|
||||
|
||||
public String getCodeStr() {
|
||||
if (code == null) {
|
||||
finish();
|
||||
}
|
||||
return code;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return code != null ? code : buf.toString();
|
||||
}
|
||||
}
|
||||
@@ -4,6 +4,7 @@ import java.util.Iterator;
|
||||
import java.util.LinkedList;
|
||||
import java.util.Queue;
|
||||
|
||||
import jadx.api.ICodeWriter;
|
||||
import jadx.core.dex.attributes.AFlag;
|
||||
import jadx.core.dex.instructions.ArithNode;
|
||||
import jadx.core.dex.instructions.IfOp;
|
||||
@@ -41,15 +42,15 @@ public class ConditionGen extends InsnGen {
|
||||
super(insnGen.mgen, insnGen.fallback);
|
||||
}
|
||||
|
||||
void add(CodeWriter code, IfCondition condition) throws CodegenException {
|
||||
void add(ICodeWriter code, IfCondition condition) throws CodegenException {
|
||||
add(code, new CondStack(), condition);
|
||||
}
|
||||
|
||||
void wrap(CodeWriter code, IfCondition condition) throws CodegenException {
|
||||
void wrap(ICodeWriter code, IfCondition condition) throws CodegenException {
|
||||
wrap(code, new CondStack(), condition);
|
||||
}
|
||||
|
||||
private void add(CodeWriter code, CondStack stack, IfCondition condition) throws CodegenException {
|
||||
private void add(ICodeWriter code, CondStack stack, IfCondition condition) throws CodegenException {
|
||||
stack.push(condition);
|
||||
switch (condition.getMode()) {
|
||||
case COMPARE:
|
||||
@@ -75,7 +76,7 @@ public class ConditionGen extends InsnGen {
|
||||
stack.pop();
|
||||
}
|
||||
|
||||
private void wrap(CodeWriter code, CondStack stack, IfCondition cond) throws CodegenException {
|
||||
private void wrap(ICodeWriter code, CondStack stack, IfCondition cond) throws CodegenException {
|
||||
boolean wrap = isWrapNeeded(cond);
|
||||
if (wrap) {
|
||||
code.add('(');
|
||||
@@ -86,7 +87,7 @@ public class ConditionGen extends InsnGen {
|
||||
}
|
||||
}
|
||||
|
||||
private void wrap(CodeWriter code, InsnArg firstArg) throws CodegenException {
|
||||
private void wrap(ICodeWriter code, InsnArg firstArg) throws CodegenException {
|
||||
boolean wrap = isArgWrapNeeded(firstArg);
|
||||
if (wrap) {
|
||||
code.add('(');
|
||||
@@ -97,7 +98,7 @@ public class ConditionGen extends InsnGen {
|
||||
}
|
||||
}
|
||||
|
||||
private void addCompare(CodeWriter code, CondStack stack, Compare compare) throws CodegenException {
|
||||
private void addCompare(ICodeWriter code, CondStack stack, Compare compare) throws CodegenException {
|
||||
IfOp op = compare.getOp();
|
||||
InsnArg firstArg = compare.getA();
|
||||
InsnArg secondArg = compare.getB();
|
||||
@@ -130,7 +131,7 @@ public class ConditionGen extends InsnGen {
|
||||
addArg(code, secondArg, isArgWrapNeeded(secondArg));
|
||||
}
|
||||
|
||||
private void addTernary(CodeWriter code, CondStack stack, IfCondition condition) throws CodegenException {
|
||||
private void addTernary(ICodeWriter code, CondStack stack, IfCondition condition) throws CodegenException {
|
||||
add(code, stack, condition.first());
|
||||
code.add(" ? ");
|
||||
add(code, stack, condition.second());
|
||||
@@ -138,12 +139,12 @@ public class ConditionGen extends InsnGen {
|
||||
add(code, stack, condition.third());
|
||||
}
|
||||
|
||||
private void addNot(CodeWriter code, CondStack stack, IfCondition condition) throws CodegenException {
|
||||
private void addNot(ICodeWriter code, CondStack stack, IfCondition condition) throws CodegenException {
|
||||
code.add('!');
|
||||
wrap(code, stack, condition.getArgs().get(0));
|
||||
}
|
||||
|
||||
private void addAndOr(CodeWriter code, CondStack stack, IfCondition condition) throws CodegenException {
|
||||
private void addAndOr(ICodeWriter code, CondStack stack, IfCondition condition) throws CodegenException {
|
||||
String mode = condition.getMode() == Mode.AND ? " && " : " || ";
|
||||
Iterator<IfCondition> it = condition.getArgs().iterator();
|
||||
while (it.hasNext()) {
|
||||
|
||||
@@ -9,6 +9,7 @@ import org.jetbrains.annotations.Nullable;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import jadx.api.ICodeWriter;
|
||||
import jadx.api.plugins.input.data.MethodHandleType;
|
||||
import jadx.core.deobf.NameMapper;
|
||||
import jadx.core.dex.attributes.AFlag;
|
||||
@@ -88,19 +89,19 @@ public class InsnGen {
|
||||
return fallback;
|
||||
}
|
||||
|
||||
public void addArgDot(CodeWriter code, InsnArg arg) throws CodegenException {
|
||||
int len = code.bufLength();
|
||||
public void addArgDot(ICodeWriter code, InsnArg arg) throws CodegenException {
|
||||
int len = code.getLength();
|
||||
addArg(code, arg, true);
|
||||
if (len != code.bufLength()) {
|
||||
if (len != code.getLength()) {
|
||||
code.add('.');
|
||||
}
|
||||
}
|
||||
|
||||
public void addArg(CodeWriter code, InsnArg arg) throws CodegenException {
|
||||
public void addArg(ICodeWriter code, InsnArg arg) throws CodegenException {
|
||||
addArg(code, arg, true);
|
||||
}
|
||||
|
||||
public void addArg(CodeWriter code, InsnArg arg, boolean wrap) throws CodegenException {
|
||||
public void addArg(ICodeWriter code, InsnArg arg, boolean wrap) throws CodegenException {
|
||||
if (arg.isRegister()) {
|
||||
CodeVar codeVar = CodeGenUtils.getCodeVar((RegisterArg) arg);
|
||||
if (codeVar != null) {
|
||||
@@ -127,7 +128,7 @@ public class InsnGen {
|
||||
}
|
||||
}
|
||||
|
||||
private void addWrappedArg(CodeWriter code, InsnWrapArg arg, boolean wrap) throws CodegenException {
|
||||
private void addWrappedArg(ICodeWriter code, InsnWrapArg arg, boolean wrap) throws CodegenException {
|
||||
InsnNode wrapInsn = arg.getWrapInsn();
|
||||
if (wrapInsn.contains(AFlag.FORCE_ASSIGN_INLINE)) {
|
||||
code.add('(');
|
||||
@@ -139,7 +140,7 @@ public class InsnGen {
|
||||
}
|
||||
}
|
||||
|
||||
public void assignVar(CodeWriter code, InsnNode insn) throws CodegenException {
|
||||
public void assignVar(ICodeWriter code, InsnNode insn) throws CodegenException {
|
||||
RegisterArg arg = insn.getResult();
|
||||
if (insn.contains(AFlag.DECLARE_VAR)) {
|
||||
declareVar(code, arg);
|
||||
@@ -148,11 +149,11 @@ public class InsnGen {
|
||||
}
|
||||
}
|
||||
|
||||
public void declareVar(CodeWriter code, RegisterArg arg) {
|
||||
public void declareVar(ICodeWriter code, RegisterArg arg) {
|
||||
declareVar(code, arg.getSVar().getCodeVar());
|
||||
}
|
||||
|
||||
public void declareVar(CodeWriter code, CodeVar codeVar) {
|
||||
public void declareVar(ICodeWriter code, CodeVar codeVar) {
|
||||
if (codeVar.isFinal()) {
|
||||
code.add("final ");
|
||||
}
|
||||
@@ -174,7 +175,7 @@ public class InsnGen {
|
||||
return TypeGen.literalToString(arg, mth, fallback);
|
||||
}
|
||||
|
||||
private void instanceField(CodeWriter code, FieldInfo field, InsnArg arg) throws CodegenException {
|
||||
private void instanceField(ICodeWriter code, FieldInfo field, InsnArg arg) throws CodegenException {
|
||||
ClassNode pCls = mth.getParentClass();
|
||||
FieldNode fieldNode = pCls.root().deepResolveField(field);
|
||||
if (fieldNode != null) {
|
||||
@@ -203,7 +204,7 @@ public class InsnGen {
|
||||
}
|
||||
}
|
||||
|
||||
public static void makeStaticFieldAccess(CodeWriter code, FieldInfo field, ClassGen clsGen) {
|
||||
public static void makeStaticFieldAccess(ICodeWriter code, FieldInfo field, ClassGen clsGen) {
|
||||
ClassInfo declClass = field.getDeclClass();
|
||||
// TODO
|
||||
boolean fieldFromThisClass = clsGen.getClassNode().getClassInfo().equals(declClass);
|
||||
@@ -225,23 +226,23 @@ public class InsnGen {
|
||||
}
|
||||
}
|
||||
|
||||
protected void staticField(CodeWriter code, FieldInfo field) {
|
||||
protected void staticField(ICodeWriter code, FieldInfo field) {
|
||||
makeStaticFieldAccess(code, field, mgen.getClassGen());
|
||||
}
|
||||
|
||||
public void useClass(CodeWriter code, ArgType type) {
|
||||
public void useClass(ICodeWriter code, ArgType type) {
|
||||
mgen.getClassGen().useClass(code, type);
|
||||
}
|
||||
|
||||
public void useClass(CodeWriter code, ClassInfo cls) {
|
||||
public void useClass(ICodeWriter code, ClassInfo cls) {
|
||||
mgen.getClassGen().useClass(code, cls);
|
||||
}
|
||||
|
||||
protected void useType(CodeWriter code, ArgType type) {
|
||||
protected void useType(ICodeWriter code, ArgType type) {
|
||||
mgen.getClassGen().useType(code, type);
|
||||
}
|
||||
|
||||
public void makeInsn(InsnNode insn, CodeWriter code) throws CodegenException {
|
||||
public void makeInsn(InsnNode insn, ICodeWriter code) throws CodegenException {
|
||||
makeInsn(insn, code, null);
|
||||
}
|
||||
|
||||
@@ -249,7 +250,7 @@ public class InsnGen {
|
||||
private static final Set<Flags> BODY_ONLY_FLAG = EnumSet.of(Flags.BODY_ONLY);
|
||||
private static final Set<Flags> BODY_ONLY_NOWRAP_FLAGS = EnumSet.of(Flags.BODY_ONLY_NOWRAP);
|
||||
|
||||
protected void makeInsn(InsnNode insn, CodeWriter code, Flags flag) throws CodegenException {
|
||||
protected void makeInsn(InsnNode insn, ICodeWriter code, Flags flag) throws CodegenException {
|
||||
if (insn.getType() == InsnType.REGION_ARG) {
|
||||
return;
|
||||
}
|
||||
@@ -284,7 +285,7 @@ public class InsnGen {
|
||||
}
|
||||
}
|
||||
|
||||
private void makeInsnBody(CodeWriter code, InsnNode insn, Set<Flags> state) throws CodegenException {
|
||||
private void makeInsnBody(ICodeWriter code, InsnNode insn, Set<Flags> state) throws CodegenException {
|
||||
switch (insn.getType()) {
|
||||
case CONST_STR:
|
||||
String str = ((ConstStringNode) insn).getString();
|
||||
@@ -590,7 +591,7 @@ public class InsnGen {
|
||||
* In most cases must be combined with new array instructions.
|
||||
* Use one by one array fill (can be replaced with System.arrayCopy)
|
||||
*/
|
||||
private void fillArray(CodeWriter code, FillArrayInsn arrayNode) throws CodegenException {
|
||||
private void fillArray(ICodeWriter code, FillArrayInsn arrayNode) throws CodegenException {
|
||||
code.add("// fill-array-data instruction");
|
||||
code.startLine();
|
||||
InsnArg arrArg = arrayNode.getArg(0);
|
||||
@@ -614,7 +615,7 @@ public class InsnGen {
|
||||
}
|
||||
}
|
||||
|
||||
private void oneArgInsn(CodeWriter code, InsnNode insn, Set<Flags> state, char op) throws CodegenException {
|
||||
private void oneArgInsn(ICodeWriter code, InsnNode insn, Set<Flags> state, char op) throws CodegenException {
|
||||
boolean wrap = state.contains(Flags.BODY_ONLY);
|
||||
if (wrap) {
|
||||
code.add('(');
|
||||
@@ -636,7 +637,7 @@ public class InsnGen {
|
||||
}
|
||||
}
|
||||
|
||||
private void filledNewArray(FilledNewArrayNode insn, CodeWriter code) throws CodegenException {
|
||||
private void filledNewArray(FilledNewArrayNode insn, ICodeWriter code) throws CodegenException {
|
||||
if (!insn.contains(AFlag.DECLARE_VAR)) {
|
||||
code.add("new ");
|
||||
useType(code, insn.getArrayType());
|
||||
@@ -652,7 +653,7 @@ public class InsnGen {
|
||||
code.add('}');
|
||||
}
|
||||
|
||||
private void makeConstructor(ConstructorInsn insn, CodeWriter code) throws CodegenException {
|
||||
private void makeConstructor(ConstructorInsn insn, ICodeWriter code) throws CodegenException {
|
||||
ClassNode cls = mth.root().resolveClass(insn.getClassType());
|
||||
if (cls != null && cls.isAnonymous() && !fallback) {
|
||||
cls.ensureProcessed();
|
||||
@@ -691,7 +692,7 @@ public class InsnGen {
|
||||
generateMethodArguments(code, insn, 0, callMth);
|
||||
}
|
||||
|
||||
private void inlineAnonymousConstructor(CodeWriter code, ClassNode cls, ConstructorInsn insn) throws CodegenException {
|
||||
private void inlineAnonymousConstructor(ICodeWriter code, ClassNode cls, ConstructorInsn insn) throws CodegenException {
|
||||
if (this.mth.getParentClass() == cls) {
|
||||
cls.remove(AFlag.ANONYMOUS_CLASS);
|
||||
cls.remove(AFlag.DONT_GENERATE);
|
||||
@@ -727,7 +728,7 @@ public class InsnGen {
|
||||
new ClassGen(cls, mgen.getClassGen().getParentGen()).addClassBody(code, true);
|
||||
}
|
||||
|
||||
private void makeInvoke(InvokeNode insn, CodeWriter code) throws CodegenException {
|
||||
private void makeInvoke(InvokeNode insn, ICodeWriter code) throws CodegenException {
|
||||
InvokeType type = insn.getInvokeType();
|
||||
if (type == InvokeType.CUSTOM) {
|
||||
makeInvokeLambda(code, (InvokeCustomNode) insn);
|
||||
@@ -778,7 +779,7 @@ public class InsnGen {
|
||||
generateMethodArguments(code, insn, k, callMthNode);
|
||||
}
|
||||
|
||||
private void makeInvokeLambda(CodeWriter code, InvokeCustomNode customNode) throws CodegenException {
|
||||
private void makeInvokeLambda(ICodeWriter code, InvokeCustomNode customNode) throws CodegenException {
|
||||
if (customNode.isUseRef()) {
|
||||
makeRefLambda(code, customNode);
|
||||
return;
|
||||
@@ -791,7 +792,7 @@ public class InsnGen {
|
||||
makeInlinedLambdaMethod(code, customNode, callMth);
|
||||
}
|
||||
|
||||
private void makeRefLambda(CodeWriter code, InvokeCustomNode customNode) {
|
||||
private void makeRefLambda(ICodeWriter code, InvokeCustomNode customNode) {
|
||||
InsnNode callInsn = customNode.getCallInsn();
|
||||
if (callInsn instanceof ConstructorInsn) {
|
||||
MethodInfo callMth = ((ConstructorInsn) callInsn).getCallMth();
|
||||
@@ -811,7 +812,7 @@ public class InsnGen {
|
||||
}
|
||||
}
|
||||
|
||||
private void makeSimpleLambda(CodeWriter code, InvokeCustomNode customNode) {
|
||||
private void makeSimpleLambda(ICodeWriter code, InvokeCustomNode customNode) {
|
||||
try {
|
||||
InsnNode callInsn = customNode.getCallInsn();
|
||||
MethodInfo implMthInfo = customNode.getImplMthInfo();
|
||||
@@ -858,7 +859,7 @@ public class InsnGen {
|
||||
}
|
||||
}
|
||||
|
||||
private void makeInlinedLambdaMethod(CodeWriter code, InvokeCustomNode customNode, MethodNode callMth) throws CodegenException {
|
||||
private void makeInlinedLambdaMethod(ICodeWriter code, InvokeCustomNode customNode, MethodNode callMth) throws CodegenException {
|
||||
MethodGen callMthGen = new MethodGen(mgen.getClassGen(), callMth);
|
||||
NameGen nameGen = callMthGen.getNameGen();
|
||||
nameGen.inheritUsedNames(this.mgen.getNameGen());
|
||||
@@ -894,7 +895,7 @@ public class InsnGen {
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private ClassInfo getClassForSuperCall(CodeWriter code, MethodInfo callMth) {
|
||||
private ClassInfo getClassForSuperCall(ICodeWriter code, MethodInfo callMth) {
|
||||
ClassNode useCls = mth.getParentClass();
|
||||
ClassInfo insnCls = useCls.getClassInfo();
|
||||
ClassInfo declClass = callMth.getDeclClass();
|
||||
@@ -923,7 +924,7 @@ public class InsnGen {
|
||||
return useCls.getParentClass().getClassInfo();
|
||||
}
|
||||
|
||||
void generateMethodArguments(CodeWriter code, BaseInvokeNode insn, int startArgNum,
|
||||
void generateMethodArguments(ICodeWriter code, BaseInvokeNode insn, int startArgNum,
|
||||
@Nullable MethodNode mthNode) throws CodegenException {
|
||||
int k = startArgNum;
|
||||
if (mthNode != null && mthNode.contains(AFlag.SKIP_FIRST_ARG)) {
|
||||
@@ -960,7 +961,7 @@ public class InsnGen {
|
||||
/**
|
||||
* Expand varArgs from filled array.
|
||||
*/
|
||||
private boolean processVarArg(CodeWriter code, BaseInvokeNode invokeInsn, InsnArg lastArg) throws CodegenException {
|
||||
private boolean processVarArg(ICodeWriter code, BaseInvokeNode invokeInsn, InsnArg lastArg) throws CodegenException {
|
||||
if (!invokeInsn.contains(AFlag.VARARG_CALL)) {
|
||||
return false;
|
||||
}
|
||||
@@ -982,7 +983,7 @@ public class InsnGen {
|
||||
return true;
|
||||
}
|
||||
|
||||
private void makeTernary(TernaryInsn insn, CodeWriter code, Set<Flags> state) throws CodegenException {
|
||||
private void makeTernary(TernaryInsn insn, ICodeWriter code, Set<Flags> state) throws CodegenException {
|
||||
boolean wrap = state.contains(Flags.BODY_ONLY);
|
||||
if (wrap) {
|
||||
code.add('(');
|
||||
@@ -1005,7 +1006,7 @@ public class InsnGen {
|
||||
}
|
||||
}
|
||||
|
||||
private void addCastIfNeeded(CodeWriter code, InsnArg first, InsnArg second) {
|
||||
private void addCastIfNeeded(ICodeWriter code, InsnArg first, InsnArg second) {
|
||||
if (first.isLiteral() && second.isLiteral()) {
|
||||
if (first.getType() == ArgType.BYTE) {
|
||||
long lit1 = ((LiteralArg) first).getLiteral();
|
||||
@@ -1032,7 +1033,7 @@ public class InsnGen {
|
||||
}
|
||||
}
|
||||
|
||||
private void makeArith(ArithNode insn, CodeWriter code, Set<Flags> state) throws CodegenException {
|
||||
private void makeArith(ArithNode insn, ICodeWriter code, Set<Flags> state) throws CodegenException {
|
||||
if (insn.contains(AFlag.ARITH_ONEARG)) {
|
||||
makeArithOneArg(insn, code);
|
||||
return;
|
||||
@@ -1052,7 +1053,7 @@ public class InsnGen {
|
||||
}
|
||||
}
|
||||
|
||||
private void makeArithOneArg(ArithNode insn, CodeWriter code) throws CodegenException {
|
||||
private void makeArithOneArg(ArithNode insn, ICodeWriter code) throws CodegenException {
|
||||
ArithOp op = insn.getOp();
|
||||
InsnArg resArg = insn.getArg(0);
|
||||
InsnArg arg = insn.getArg(1);
|
||||
|
||||
@@ -9,6 +9,7 @@ import java.util.stream.Stream;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import jadx.api.ICodeWriter;
|
||||
import jadx.api.plugins.input.data.AccessFlags;
|
||||
import jadx.api.plugins.input.data.annotations.EncodedValue;
|
||||
import jadx.core.Consts;
|
||||
@@ -72,7 +73,7 @@ public class MethodGen {
|
||||
return mth;
|
||||
}
|
||||
|
||||
public boolean addDefinition(CodeWriter code) {
|
||||
public boolean addDefinition(ICodeWriter code) {
|
||||
if (mth.getMethodInfo().isClassInit()) {
|
||||
code.attachDefinition(mth);
|
||||
code.startLine("static");
|
||||
@@ -162,7 +163,7 @@ public class MethodGen {
|
||||
return true;
|
||||
}
|
||||
|
||||
private void addOverrideAnnotation(CodeWriter code, MethodNode mth) {
|
||||
private void addOverrideAnnotation(ICodeWriter code, MethodNode mth) {
|
||||
MethodOverrideAttr overrideAttr = mth.get(AType.METHOD_OVERRIDE);
|
||||
if (overrideAttr == null) {
|
||||
return;
|
||||
@@ -178,7 +179,7 @@ public class MethodGen {
|
||||
}
|
||||
}
|
||||
|
||||
private void addMethodArguments(CodeWriter code, List<RegisterArg> args) {
|
||||
private void addMethodArguments(ICodeWriter code, List<RegisterArg> args) {
|
||||
MethodParameters paramsAnnotation = mth.get(AType.ANNOTATION_MTH_PARAMETERS);
|
||||
int i = 0;
|
||||
Iterator<RegisterArg> it = args.iterator();
|
||||
@@ -243,7 +244,7 @@ public class MethodGen {
|
||||
}
|
||||
}
|
||||
|
||||
public void addInstructions(CodeWriter code) throws CodegenException {
|
||||
public void addInstructions(ICodeWriter code) throws CodegenException {
|
||||
if (mth.root().getArgs().isFallbackMode()) {
|
||||
addFallbackMethodCode(code, FALLBACK_MODE);
|
||||
} else if (classGen.isFallbackMode()) {
|
||||
@@ -253,7 +254,7 @@ public class MethodGen {
|
||||
}
|
||||
}
|
||||
|
||||
public void addRegionInsns(CodeWriter code) throws CodegenException {
|
||||
public void addRegionInsns(ICodeWriter code) throws CodegenException {
|
||||
try {
|
||||
RegionGen regionGen = new RegionGen(this);
|
||||
regionGen.makeRegion(code, mth.getRegion());
|
||||
@@ -271,7 +272,7 @@ public class MethodGen {
|
||||
}
|
||||
}
|
||||
|
||||
public void dumpInstructions(CodeWriter code) {
|
||||
public void dumpInstructions(ICodeWriter code) {
|
||||
code.startLine("/*");
|
||||
addFallbackMethodCode(code, COMMENTED_DUMP);
|
||||
code.startLine("*/");
|
||||
@@ -287,7 +288,7 @@ public class MethodGen {
|
||||
.add("\");");
|
||||
}
|
||||
|
||||
public void addFallbackMethodCode(CodeWriter code, FallbackOption fallbackOption) {
|
||||
public void addFallbackMethodCode(ICodeWriter code, FallbackOption fallbackOption) {
|
||||
// load original instructions
|
||||
try {
|
||||
mth.unload();
|
||||
@@ -329,7 +330,7 @@ public class MethodGen {
|
||||
COMMENTED_DUMP
|
||||
}
|
||||
|
||||
public static void addFallbackInsns(CodeWriter code, MethodNode mth, InsnNode[] insnArr, FallbackOption option) {
|
||||
public static void addFallbackInsns(ICodeWriter code, MethodNode mth, InsnNode[] insnArr, FallbackOption option) {
|
||||
int startIndent = code.getIndent();
|
||||
InsnGen insnGen = new InsnGen(getFallbackMethodGen(mth), true);
|
||||
boolean attachInsns = mth.root().getArgs().isJsonOutput();
|
||||
|
||||
@@ -8,6 +8,7 @@ import java.util.Objects;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import jadx.api.ICodeWriter;
|
||||
import jadx.core.dex.attributes.AFlag;
|
||||
import jadx.core.dex.attributes.AType;
|
||||
import jadx.core.dex.attributes.fldinit.FieldInitAttr;
|
||||
@@ -21,7 +22,13 @@ import jadx.core.dex.instructions.args.CodeVar;
|
||||
import jadx.core.dex.instructions.args.InsnArg;
|
||||
import jadx.core.dex.instructions.args.NamedArg;
|
||||
import jadx.core.dex.instructions.args.RegisterArg;
|
||||
import jadx.core.dex.nodes.*;
|
||||
import jadx.core.dex.nodes.BlockNode;
|
||||
import jadx.core.dex.nodes.FieldNode;
|
||||
import jadx.core.dex.nodes.IBlock;
|
||||
import jadx.core.dex.nodes.IContainer;
|
||||
import jadx.core.dex.nodes.IRegion;
|
||||
import jadx.core.dex.nodes.InsnNode;
|
||||
import jadx.core.dex.nodes.VariableNode;
|
||||
import jadx.core.dex.regions.Region;
|
||||
import jadx.core.dex.regions.SwitchRegion;
|
||||
import jadx.core.dex.regions.SwitchRegion.CaseInfo;
|
||||
@@ -40,7 +47,7 @@ import jadx.core.utils.RegionUtils;
|
||||
import jadx.core.utils.exceptions.CodegenException;
|
||||
import jadx.core.utils.exceptions.JadxRuntimeException;
|
||||
|
||||
import static jadx.core.dex.nodes.VariableNode.*;
|
||||
import static jadx.core.dex.nodes.VariableNode.VarKind;
|
||||
|
||||
public class RegionGen extends InsnGen {
|
||||
private static final Logger LOG = LoggerFactory.getLogger(RegionGen.class);
|
||||
@@ -49,7 +56,7 @@ public class RegionGen extends InsnGen {
|
||||
super(mgen, false);
|
||||
}
|
||||
|
||||
public void makeRegion(CodeWriter code, IContainer cont) throws CodegenException {
|
||||
public void makeRegion(ICodeWriter code, IContainer cont) throws CodegenException {
|
||||
if (cont instanceof IBlock) {
|
||||
makeSimpleBlock((IBlock) cont, code);
|
||||
} else if (cont instanceof IRegion) {
|
||||
@@ -74,7 +81,7 @@ public class RegionGen extends InsnGen {
|
||||
}
|
||||
}
|
||||
|
||||
private void declareVars(CodeWriter code, IContainer cont) {
|
||||
private void declareVars(ICodeWriter code, IContainer cont) {
|
||||
DeclareVariablesAttr declVars = cont.get(AType.DECLARE_VARIABLES);
|
||||
if (declVars != null) {
|
||||
for (CodeVar v : declVars.getVars()) {
|
||||
@@ -85,20 +92,20 @@ public class RegionGen extends InsnGen {
|
||||
}
|
||||
}
|
||||
|
||||
private void makeSimpleRegion(CodeWriter code, Region region) throws CodegenException {
|
||||
private void makeSimpleRegion(ICodeWriter code, Region region) throws CodegenException {
|
||||
declareVars(code, region);
|
||||
for (IContainer c : region.getSubBlocks()) {
|
||||
makeRegion(code, c);
|
||||
}
|
||||
}
|
||||
|
||||
public void makeRegionIndent(CodeWriter code, IContainer region) throws CodegenException {
|
||||
public void makeRegionIndent(ICodeWriter code, IContainer region) throws CodegenException {
|
||||
code.incIndent();
|
||||
makeRegion(code, region);
|
||||
code.decIndent();
|
||||
}
|
||||
|
||||
private void makeSimpleBlock(IBlock block, CodeWriter code) throws CodegenException {
|
||||
private void makeSimpleBlock(IBlock block, ICodeWriter code) throws CodegenException {
|
||||
if (block.contains(AFlag.DONT_GENERATE)) {
|
||||
return;
|
||||
}
|
||||
@@ -114,7 +121,7 @@ public class RegionGen extends InsnGen {
|
||||
}
|
||||
}
|
||||
|
||||
private void makeIf(IfRegion region, CodeWriter code, boolean newLine) throws CodegenException {
|
||||
private void makeIf(IfRegion region, ICodeWriter code, boolean newLine) throws CodegenException {
|
||||
if (newLine) {
|
||||
code.startLineWithNum(region.getSourceLine());
|
||||
} else {
|
||||
@@ -164,7 +171,7 @@ public class RegionGen extends InsnGen {
|
||||
/**
|
||||
* Connect if-else-if block
|
||||
*/
|
||||
private boolean connectElseIf(CodeWriter code, IContainer els) throws CodegenException {
|
||||
private boolean connectElseIf(ICodeWriter code, IContainer els) throws CodegenException {
|
||||
if (els.contains(AFlag.ELSE_IF_CHAIN) && els instanceof Region) {
|
||||
List<IContainer> subBlocks = ((Region) els).getSubBlocks();
|
||||
if (subBlocks.size() == 1) {
|
||||
@@ -179,7 +186,7 @@ public class RegionGen extends InsnGen {
|
||||
return false;
|
||||
}
|
||||
|
||||
private CodeWriter makeLoop(LoopRegion region, CodeWriter code) throws CodegenException {
|
||||
private void makeLoop(LoopRegion region, ICodeWriter code) throws CodegenException {
|
||||
LoopLabelAttr labelAttr = region.getInfo().getStart().get(AType.LOOP_LABEL);
|
||||
if (labelAttr != null) {
|
||||
code.startLine(mgen.getNameGen().getLoopLabel(labelAttr)).add(':');
|
||||
@@ -191,7 +198,7 @@ public class RegionGen extends InsnGen {
|
||||
code.startLine("while (true) {");
|
||||
makeRegionIndent(code, region.getBody());
|
||||
code.startLine('}');
|
||||
return code;
|
||||
return;
|
||||
}
|
||||
ConditionGen conditionGen = new ConditionGen(this);
|
||||
LoopType type = region.getType();
|
||||
@@ -207,7 +214,7 @@ public class RegionGen extends InsnGen {
|
||||
code.add(") {");
|
||||
makeRegionIndent(code, region.getBody());
|
||||
code.startLine('}');
|
||||
return code;
|
||||
return;
|
||||
}
|
||||
if (type instanceof ForEachLoop) {
|
||||
ForEachLoop forEachLoop = (ForEachLoop) type;
|
||||
@@ -218,7 +225,7 @@ public class RegionGen extends InsnGen {
|
||||
code.add(") {");
|
||||
makeRegionIndent(code, region.getBody());
|
||||
code.startLine('}');
|
||||
return code;
|
||||
return;
|
||||
}
|
||||
throw new JadxRuntimeException("Unknown loop type: " + type.getClass());
|
||||
}
|
||||
@@ -237,10 +244,9 @@ public class RegionGen extends InsnGen {
|
||||
makeRegionIndent(code, region.getBody());
|
||||
code.startLine('}');
|
||||
}
|
||||
return code;
|
||||
}
|
||||
|
||||
private void makeSynchronizedRegion(SynchronizedRegion cont, CodeWriter code) throws CodegenException {
|
||||
private void makeSynchronizedRegion(SynchronizedRegion cont, ICodeWriter code) throws CodegenException {
|
||||
code.startLine("synchronized (");
|
||||
addArg(code, cont.getEnterInsn().getArg(0));
|
||||
code.add(") {");
|
||||
@@ -248,7 +254,7 @@ public class RegionGen extends InsnGen {
|
||||
code.startLine('}');
|
||||
}
|
||||
|
||||
private CodeWriter makeSwitch(SwitchRegion sw, CodeWriter code) throws CodegenException {
|
||||
private void makeSwitch(SwitchRegion sw, ICodeWriter code) throws CodegenException {
|
||||
SwitchInsn insn = (SwitchInsn) BlockUtils.getLastInsn(sw.getHeader());
|
||||
Objects.requireNonNull(insn, "Switch insn not found in header");
|
||||
InsnArg arg = insn.getArg(0);
|
||||
@@ -273,10 +279,9 @@ public class RegionGen extends InsnGen {
|
||||
}
|
||||
code.decIndent();
|
||||
code.startLine('}');
|
||||
return code;
|
||||
}
|
||||
|
||||
private void addCaseKey(CodeWriter code, InsnArg arg, Object k) {
|
||||
private void addCaseKey(ICodeWriter code, InsnArg arg, Object k) {
|
||||
if (k instanceof FieldNode) {
|
||||
FieldNode fn = (FieldNode) k;
|
||||
if (fn.getParentClass().isEnum()) {
|
||||
@@ -299,7 +304,7 @@ public class RegionGen extends InsnGen {
|
||||
}
|
||||
}
|
||||
|
||||
private void makeTryCatch(TryCatchRegion region, CodeWriter code) throws CodegenException {
|
||||
private void makeTryCatch(TryCatchRegion region, ICodeWriter code) throws CodegenException {
|
||||
code.startLine("try {");
|
||||
makeRegionIndent(code, region.getTryRegion());
|
||||
// TODO: move search of 'allHandler' to 'TryCatchRegion'
|
||||
@@ -326,7 +331,7 @@ public class RegionGen extends InsnGen {
|
||||
code.startLine('}');
|
||||
}
|
||||
|
||||
private void makeCatchBlock(CodeWriter code, ExceptionHandler handler) throws CodegenException {
|
||||
private void makeCatchBlock(ICodeWriter code, ExceptionHandler handler) throws CodegenException {
|
||||
IContainer region = handler.getHandlerRegion();
|
||||
if (region == null) {
|
||||
return;
|
||||
|
||||
@@ -14,9 +14,11 @@ import com.google.gson.GsonBuilder;
|
||||
|
||||
import jadx.api.CodePosition;
|
||||
import jadx.api.ICodeInfo;
|
||||
import jadx.api.ICodeWriter;
|
||||
import jadx.api.JadxArgs;
|
||||
import jadx.api.impl.AnnotatedCodeWriter;
|
||||
import jadx.api.impl.SimpleCodeWriter;
|
||||
import jadx.core.codegen.ClassGen;
|
||||
import jadx.core.codegen.CodeWriter;
|
||||
import jadx.core.codegen.MethodGen;
|
||||
import jadx.core.codegen.json.cls.JsonClass;
|
||||
import jadx.core.codegen.json.cls.JsonCodeLine;
|
||||
@@ -82,7 +84,7 @@ public class JsonCodeGen {
|
||||
jsonCls.setInterfaces(Utils.collectionMap(cls.getInterfaces(), this::getTypeAlias));
|
||||
}
|
||||
|
||||
CodeWriter cw = new CodeWriter();
|
||||
ICodeWriter cw = new SimpleCodeWriter();
|
||||
CodeGenUtils.addComments(cw, cls);
|
||||
classGen.insertDecompilationProblems(cw, cls);
|
||||
classGen.addClassDeclaration(cw);
|
||||
@@ -127,11 +129,10 @@ public class JsonCodeGen {
|
||||
jsonField.setAlias(field.getAlias());
|
||||
}
|
||||
|
||||
CodeWriter cw = new CodeWriter();
|
||||
ICodeWriter cw = new SimpleCodeWriter();
|
||||
classGen.addField(cw, field);
|
||||
jsonField.setDeclaration(cw.getCodeStr());
|
||||
jsonField.setAccessFlags(field.getAccessFlags().rawValue());
|
||||
|
||||
jsonCls.getFields().add(jsonField);
|
||||
}
|
||||
}
|
||||
@@ -152,7 +153,7 @@ public class JsonCodeGen {
|
||||
jsonMth.setArguments(Utils.collectionMap(mth.getMethodInfo().getArgumentsTypes(), this::getTypeAlias));
|
||||
|
||||
MethodGen mthGen = new MethodGen(classGen, mth);
|
||||
CodeWriter cw = new CodeWriter();
|
||||
ICodeWriter cw = new AnnotatedCodeWriter();
|
||||
mthGen.addDefinition(cw);
|
||||
jsonMth.setDeclaration(cw.getCodeStr());
|
||||
jsonMth.setAccessFlags(mth.getAccessFlags().rawValue());
|
||||
@@ -167,7 +168,7 @@ public class JsonCodeGen {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
CodeWriter cw = new CodeWriter();
|
||||
ICodeWriter cw = mth.root().makeCodeWriter();
|
||||
try {
|
||||
mthGen.addInstructions(cw);
|
||||
} catch (Exception e) {
|
||||
@@ -179,7 +180,7 @@ public class JsonCodeGen {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
String[] lines = codeStr.split(CodeWriter.NL);
|
||||
String[] lines = codeStr.split(ICodeWriter.NL);
|
||||
Map<Integer, Integer> lineMapping = code.getLineMapping();
|
||||
Map<CodePosition, Object> annotations = code.getAnnotations();
|
||||
long mthCodeOffset = mth.getMethodCodeOffset() + 16;
|
||||
|
||||
@@ -3,7 +3,7 @@ package jadx.core.dex.attributes;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import jadx.core.codegen.CodeWriter;
|
||||
import jadx.api.ICodeWriter;
|
||||
import jadx.core.utils.Utils;
|
||||
|
||||
public class AttrList<T> implements IAttribute {
|
||||
@@ -26,6 +26,6 @@ public class AttrList<T> implements IAttribute {
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return Utils.listToString(list, CodeWriter.NL);
|
||||
return Utils.listToString(list, ICodeWriter.NL);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@ import java.util.Objects;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import jadx.core.codegen.CodeWriter;
|
||||
import jadx.api.ICodeWriter;
|
||||
import jadx.core.utils.Utils;
|
||||
|
||||
public class JadxError implements Comparable<JadxError> {
|
||||
@@ -59,7 +59,7 @@ public class JadxError implements Comparable<JadxError> {
|
||||
str.append(cause.getClass());
|
||||
str.append(':');
|
||||
str.append(cause.getMessage());
|
||||
str.append(CodeWriter.NL);
|
||||
str.append(ICodeWriter.NL);
|
||||
str.append(Utils.getStackTrace(cause));
|
||||
}
|
||||
return str.toString();
|
||||
|
||||
@@ -2,13 +2,12 @@ package jadx.core.dex.attributes.nodes;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import jadx.api.ICodeWriter;
|
||||
import jadx.api.plugins.input.data.ILocalVar;
|
||||
import jadx.core.dex.attributes.AType;
|
||||
import jadx.core.dex.attributes.IAttribute;
|
||||
import jadx.core.utils.Utils;
|
||||
|
||||
import static jadx.core.codegen.CodeWriter.NL;
|
||||
|
||||
public class LocalVarsDebugInfoAttr implements IAttribute {
|
||||
private final List<ILocalVar> localVars;
|
||||
|
||||
@@ -27,6 +26,6 @@ public class LocalVarsDebugInfoAttr implements IAttribute {
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Debug Info:" + NL + " " + Utils.listToString(localVars, NL + " ");
|
||||
return "Debug Info:" + ICodeWriter.NL + " " + Utils.listToString(localVars, ICodeWriter.NL + " ");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@ package jadx.core.dex.attributes.nodes;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
import jadx.core.codegen.CodeWriter;
|
||||
import jadx.api.ICodeWriter;
|
||||
import jadx.core.dex.attributes.AType;
|
||||
import jadx.core.dex.attributes.IAttribute;
|
||||
import jadx.core.dex.instructions.PhiInsn;
|
||||
@@ -29,7 +29,7 @@ public class PhiListAttr implements IAttribute {
|
||||
sb.append('r').append(phiInsn.getResult().getRegNum()).append(' ');
|
||||
}
|
||||
for (PhiInsn phiInsn : list) {
|
||||
sb.append(CodeWriter.NL).append(" ").append(phiInsn).append(' ').append(phiInsn.getAttributesString());
|
||||
sb.append(ICodeWriter.NL).append(" ").append(phiInsn).append(' ').append(phiInsn.getAttributesString());
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@ import java.util.List;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import jadx.core.codegen.CodeWriter;
|
||||
import jadx.api.ICodeWriter;
|
||||
import jadx.core.dex.instructions.args.InsnArg;
|
||||
import jadx.core.dex.nodes.BlockNode;
|
||||
import jadx.core.dex.nodes.InsnNode;
|
||||
@@ -114,20 +114,20 @@ public class SwitchInsn extends TargetInsnNode {
|
||||
int[] keys = switchData.getKeys();
|
||||
if (targetBlocks != null) {
|
||||
for (int i = 0; i < size; i++) {
|
||||
sb.append(CodeWriter.NL);
|
||||
sb.append(ICodeWriter.NL);
|
||||
sb.append(" case ").append(keys[i]).append(": goto ").append(targetBlocks[i]);
|
||||
}
|
||||
if (def != -1) {
|
||||
sb.append(CodeWriter.NL).append(" default: goto ").append(defTargetBlock);
|
||||
sb.append(ICodeWriter.NL).append(" default: goto ").append(defTargetBlock);
|
||||
}
|
||||
} else {
|
||||
int[] targets = switchData.getTargets();
|
||||
for (int i = 0; i < size; i++) {
|
||||
sb.append(CodeWriter.NL);
|
||||
sb.append(ICodeWriter.NL);
|
||||
sb.append(" case ").append(keys[i]).append(": goto ").append(InsnUtils.formatOffset(targets[i]));
|
||||
}
|
||||
if (def != -1) {
|
||||
sb.append(CodeWriter.NL);
|
||||
sb.append(ICodeWriter.NL);
|
||||
sb.append(" default: goto ").append(InsnUtils.formatOffset(def));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,8 +8,8 @@ import java.util.Objects;
|
||||
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import jadx.api.ICodeWriter;
|
||||
import jadx.api.plugins.input.insns.InsnData;
|
||||
import jadx.core.codegen.CodeWriter;
|
||||
import jadx.core.dex.attributes.AFlag;
|
||||
import jadx.core.dex.attributes.nodes.LineAttrNode;
|
||||
import jadx.core.dex.instructions.InsnType;
|
||||
@@ -477,9 +477,9 @@ public class InsnNode extends LineAttrNode {
|
||||
sb.append(argsStr);
|
||||
} else {
|
||||
// wrap args
|
||||
String separator = CodeWriter.NL + " ";
|
||||
String separator = ICodeWriter.NL + " ";
|
||||
sb.append(separator).append(Utils.listToString(arguments, separator));
|
||||
sb.append(CodeWriter.NL);
|
||||
sb.append(ICodeWriter.NL);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -13,6 +13,7 @@ import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import jadx.api.ICodeCache;
|
||||
import jadx.api.ICodeWriter;
|
||||
import jadx.api.JadxArgs;
|
||||
import jadx.api.ResourceFile;
|
||||
import jadx.api.ResourceType;
|
||||
@@ -435,6 +436,11 @@ public class RootNode {
|
||||
}
|
||||
}
|
||||
|
||||
public ICodeWriter makeCodeWriter() {
|
||||
JadxArgs jadxArgs = this.args;
|
||||
return jadxArgs.getCodeWriterProvider().apply(jadxArgs);
|
||||
}
|
||||
|
||||
public ClspGraph getClsp() {
|
||||
return clsp;
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@ import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import jadx.core.codegen.CodeWriter;
|
||||
import jadx.api.ICodeWriter;
|
||||
import jadx.core.dex.nodes.BlockNode;
|
||||
import jadx.core.dex.nodes.IBranchRegion;
|
||||
import jadx.core.dex.nodes.IContainer;
|
||||
@@ -84,7 +84,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(CodeWriter.NL).append(" case ")
|
||||
sb.append(ICodeWriter.NL).append(" case ")
|
||||
.append(Utils.listToString(keyStrings))
|
||||
.append(" -> ").append(caseInfo.getContainer());
|
||||
}
|
||||
|
||||
@@ -5,7 +5,8 @@ import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import jadx.core.codegen.CodeWriter;
|
||||
import jadx.api.ICodeWriter;
|
||||
import jadx.api.impl.SimpleCodeWriter;
|
||||
import jadx.core.codegen.MethodGen;
|
||||
import jadx.core.dex.attributes.IAttributeNode;
|
||||
import jadx.core.dex.instructions.IfNode;
|
||||
@@ -72,8 +73,8 @@ public class DotGraphVisitor extends AbstractVisitor {
|
||||
}
|
||||
|
||||
private class DumpDotGraph {
|
||||
private final CodeWriter dot = new CodeWriter();
|
||||
private final CodeWriter conn = new CodeWriter();
|
||||
private final ICodeWriter dot = new SimpleCodeWriter();
|
||||
private final ICodeWriter conn = new SimpleCodeWriter();
|
||||
private final File dir;
|
||||
|
||||
public DumpDotGraph(File dir) {
|
||||
@@ -272,7 +273,7 @@ public class DotGraphVisitor extends AbstractVisitor {
|
||||
}
|
||||
return str.toString();
|
||||
} else {
|
||||
CodeWriter code = new CodeWriter();
|
||||
ICodeWriter code = new SimpleCodeWriter();
|
||||
List<InsnNode> instructions = block.getInstructions();
|
||||
MethodGen.addFallbackInsns(code, mth, instructions.toArray(new InsnNode[0]), BLOCK_DUMP);
|
||||
String str = escape(code.newLine().toString());
|
||||
@@ -299,7 +300,7 @@ public class DotGraphVisitor extends AbstractVisitor {
|
||||
.replace("\"", "\\\"")
|
||||
.replace("-", "\\-")
|
||||
.replace("|", "\\|")
|
||||
.replace(CodeWriter.NL, NL)
|
||||
.replace(ICodeWriter.NL, NL)
|
||||
.replace("\n", NL);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.function.Function;
|
||||
|
||||
import jadx.api.ICodeWriter;
|
||||
import jadx.core.Consts;
|
||||
import jadx.core.dex.attributes.AFlag;
|
||||
import jadx.core.dex.info.MethodInfo;
|
||||
@@ -30,8 +31,6 @@ import jadx.core.dex.visitors.typeinference.TypeCompareEnum;
|
||||
import jadx.core.utils.Utils;
|
||||
import jadx.core.utils.exceptions.JadxRuntimeException;
|
||||
|
||||
import static jadx.core.codegen.CodeWriter.NL;
|
||||
|
||||
@JadxVisitor(
|
||||
name = "MethodInvokeVisitor",
|
||||
desc = "Process additional info for method invocation (overload, vararg)",
|
||||
@@ -287,10 +286,10 @@ public class MethodInvokeVisitor extends AbstractVisitor {
|
||||
if (Consts.DEBUG_OVERLOADED_CASTS) {
|
||||
// TODO: try to minimize casts count
|
||||
parentMth.addComment("JADX DEBUG: Failed to find minimal casts for resolve overloaded methods, cast all args instead"
|
||||
+ NL + " method: " + mthDetails
|
||||
+ NL + " arg types: " + compilerVarTypes
|
||||
+ NL + " candidates:"
|
||||
+ NL + " " + Utils.listToString(overloadedMethods, NL + " "));
|
||||
+ ICodeWriter.NL + " method: " + mthDetails
|
||||
+ ICodeWriter.NL + " arg types: " + compilerVarTypes
|
||||
+ ICodeWriter.NL + " candidates:"
|
||||
+ ICodeWriter.NL + " " + Utils.listToString(overloadedMethods, ICodeWriter.NL + " "));
|
||||
}
|
||||
// not resolved -> cast all args
|
||||
return mthDetails.getArgTypes();
|
||||
|
||||
+2
-3
@@ -6,6 +6,7 @@ import java.util.Map;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import jadx.api.ICodeWriter;
|
||||
import jadx.api.plugins.input.data.IDebugInfo;
|
||||
import jadx.api.plugins.input.data.ILocalVar;
|
||||
import jadx.core.dex.attributes.nodes.LocalVarsDebugInfoAttr;
|
||||
@@ -24,8 +25,6 @@ import jadx.core.utils.ErrorsCounter;
|
||||
import jadx.core.utils.Utils;
|
||||
import jadx.core.utils.exceptions.JadxException;
|
||||
|
||||
import static jadx.core.codegen.CodeWriter.NL;
|
||||
|
||||
@JadxVisitor(
|
||||
name = "Debug Info Parser",
|
||||
desc = "Attach debug information (variable names and types, instruction lines)",
|
||||
@@ -48,7 +47,7 @@ public class DebugInfoAttachVisitor extends AbstractVisitor {
|
||||
} catch (Exception e) {
|
||||
mth.addComment("JADX WARNING: Error to parse debug info: "
|
||||
+ ErrorsCounter.formatMsg(mth, e.getMessage())
|
||||
+ NL + Utils.getStackTrace(e));
|
||||
+ ICodeWriter.NL + Utils.getStackTrace(e));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -6,7 +6,8 @@ import java.util.Set;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import jadx.core.codegen.CodeWriter;
|
||||
import jadx.api.ICodeWriter;
|
||||
import jadx.api.impl.SimpleCodeWriter;
|
||||
import jadx.core.codegen.InsnGen;
|
||||
import jadx.core.codegen.MethodGen;
|
||||
import jadx.core.dex.attributes.AFlag;
|
||||
@@ -83,7 +84,7 @@ public class CheckRegions extends AbstractVisitor {
|
||||
}
|
||||
|
||||
private static String getBlockInsnStr(MethodNode mth, IBlock block) {
|
||||
CodeWriter code = new CodeWriter();
|
||||
ICodeWriter code = new SimpleCodeWriter();
|
||||
code.incIndent();
|
||||
code.newLine();
|
||||
MethodGen mg = MethodGen.getFallbackMethodGen(mth);
|
||||
@@ -96,7 +97,6 @@ public class CheckRegions extends AbstractVisitor {
|
||||
}
|
||||
}
|
||||
code.newLine();
|
||||
code.finish();
|
||||
return code.toString();
|
||||
return code.getCodeStr();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@ package jadx.core.utils;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import jadx.core.codegen.CodeWriter;
|
||||
import jadx.api.ICodeWriter;
|
||||
import jadx.core.dex.attributes.AType;
|
||||
import jadx.core.dex.attributes.AttrNode;
|
||||
import jadx.core.dex.attributes.nodes.RenameReasonAttr;
|
||||
@@ -14,7 +14,7 @@ import jadx.core.dex.nodes.ClassNode;
|
||||
|
||||
public class CodeGenUtils {
|
||||
|
||||
public static void addComments(CodeWriter code, AttrNode node) {
|
||||
public static void addComments(ICodeWriter code, AttrNode node) {
|
||||
List<String> comments = node.getAll(AType.COMMENTS);
|
||||
if (!comments.isEmpty()) {
|
||||
comments.stream().distinct()
|
||||
@@ -22,7 +22,7 @@ public class CodeGenUtils {
|
||||
}
|
||||
}
|
||||
|
||||
public static void addRenamedComment(CodeWriter code, AttrNode node, String origName) {
|
||||
public static void addRenamedComment(ICodeWriter code, AttrNode node, String origName) {
|
||||
code.startLine("/* renamed from: ").add(origName);
|
||||
RenameReasonAttr renameReasonAttr = node.get(AType.RENAME_REASON);
|
||||
if (renameReasonAttr != null) {
|
||||
@@ -32,7 +32,7 @@ public class CodeGenUtils {
|
||||
code.add(" */");
|
||||
}
|
||||
|
||||
public static void addSourceFileInfo(CodeWriter code, ClassNode node) {
|
||||
public static void addSourceFileInfo(ICodeWriter code, ClassNode node) {
|
||||
SourceFileAttr sourceFileAttr = node.get(AType.SOURCE_FILE);
|
||||
if (sourceFileAttr != null) {
|
||||
code.startLine("/* compiled from: ").add(sourceFileAttr.getFileName()).add(" */");
|
||||
|
||||
@@ -3,6 +3,7 @@ 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;
|
||||
@@ -21,8 +22,6 @@ import jadx.core.dex.visitors.PrepareForCodeGen;
|
||||
import jadx.core.dex.visitors.RenameVisitor;
|
||||
import jadx.core.utils.exceptions.JadxRuntimeException;
|
||||
|
||||
import static jadx.core.codegen.CodeWriter.NL;
|
||||
|
||||
/**
|
||||
* Check invariants and information consistency for registers and SSA variables
|
||||
*/
|
||||
@@ -89,7 +88,7 @@ public class DebugChecks {
|
||||
boolean assignReg = insn.getResult() == reg;
|
||||
if (!assignReg && !Utils.containsInListByRef(useList, reg)) {
|
||||
throw new JadxRuntimeException("Incorrect use list in ssa var: " + sVar + ", register not listed."
|
||||
+ NL + " insn: " + insn);
|
||||
+ ICodeWriter.NL + " insn: " + insn);
|
||||
}
|
||||
for (RegisterArg useArg : useList) {
|
||||
checkRegisterArg(mth, useArg);
|
||||
@@ -111,7 +110,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
|
||||
+ NL + " insn: " + parentInsn);
|
||||
+ ICodeWriter.NL + " insn: " + parentInsn);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,7 +14,8 @@ import org.jetbrains.annotations.TestOnly;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import jadx.core.codegen.CodeWriter;
|
||||
import jadx.api.ICodeWriter;
|
||||
import jadx.api.impl.SimpleCodeWriter;
|
||||
import jadx.core.codegen.InsnGen;
|
||||
import jadx.core.codegen.MethodGen;
|
||||
import jadx.core.dex.attributes.IAttributeNode;
|
||||
@@ -32,8 +33,6 @@ import jadx.core.dex.visitors.regions.TracedRegionVisitor;
|
||||
import jadx.core.utils.exceptions.CodegenException;
|
||||
import jadx.core.utils.exceptions.JadxException;
|
||||
|
||||
import static jadx.core.codegen.CodeWriter.NL;
|
||||
|
||||
@Deprecated
|
||||
@TestOnly
|
||||
public class DebugUtils {
|
||||
@@ -109,13 +108,13 @@ public class DebugUtils {
|
||||
}
|
||||
|
||||
public static void printRegion(MethodNode mth, IRegion region, boolean printInsns) {
|
||||
CodeWriter cw = new CodeWriter();
|
||||
ICodeWriter cw = new SimpleCodeWriter();
|
||||
cw.startLine('|').add(mth.toString());
|
||||
printRegion(mth, region, cw, "| ", printInsns);
|
||||
LOG.debug("{}{}", NL, cw.finish().getCodeStr());
|
||||
LOG.debug("{}{}", ICodeWriter.NL, cw.finish().getCodeStr());
|
||||
}
|
||||
|
||||
private static void printRegion(MethodNode mth, IRegion region, CodeWriter cw, String indent, boolean printInsns) {
|
||||
private static void printRegion(MethodNode mth, IRegion region, ICodeWriter cw, String indent, boolean printInsns) {
|
||||
printWithAttributes(cw, indent, region.toString(), region);
|
||||
indent += "| ";
|
||||
for (IContainer container : region.getSubBlocks()) {
|
||||
@@ -131,16 +130,16 @@ public class DebugUtils {
|
||||
}
|
||||
}
|
||||
|
||||
private static void printInsns(MethodNode mth, CodeWriter cw, String indent, IBlock block) {
|
||||
private static void printInsns(MethodNode mth, ICodeWriter cw, String indent, IBlock block) {
|
||||
for (InsnNode insn : block.getInstructions()) {
|
||||
try {
|
||||
MethodGen mg = MethodGen.getFallbackMethodGen(mth);
|
||||
InsnGen ig = new InsnGen(mg, true);
|
||||
CodeWriter code = new CodeWriter();
|
||||
ICodeWriter code = new SimpleCodeWriter();
|
||||
ig.makeInsn(insn, code);
|
||||
String codeStr = code.finish().getCodeStr();
|
||||
String codeStr = code.getCodeStr();
|
||||
|
||||
List<String> insnStrings = Stream.of(codeStr.split(NL))
|
||||
List<String> insnStrings = Stream.of(codeStr.split(ICodeWriter.NL))
|
||||
.filter(StringUtils::notBlank)
|
||||
.map(s -> "|> " + s)
|
||||
.collect(Collectors.toList());
|
||||
@@ -160,9 +159,9 @@ public class DebugUtils {
|
||||
}
|
||||
}
|
||||
|
||||
private static void printWithAttributes(CodeWriter cw, String indent, String codeStr, IAttributeNode attrNode) {
|
||||
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(NL))
|
||||
List<String> attrStrings = Stream.of(str.split(ICodeWriter.NL))
|
||||
.filter(StringUtils::notBlank)
|
||||
.collect(Collectors.toList());
|
||||
Iterator<String> it = attrStrings.iterator();
|
||||
|
||||
@@ -7,6 +7,7 @@ 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;
|
||||
@@ -20,8 +21,6 @@ import jadx.core.dex.nodes.InsnNode;
|
||||
import jadx.core.dex.nodes.MethodNode;
|
||||
import jadx.core.utils.exceptions.JadxRuntimeException;
|
||||
|
||||
import static jadx.core.codegen.CodeWriter.NL;
|
||||
|
||||
/**
|
||||
* Helper class for correct instructions removing,
|
||||
* can be used while iterating over instructions list
|
||||
@@ -137,9 +136,9 @@ public class InsnRemover {
|
||||
}
|
||||
if (Consts.DEBUG_WITH_ERRORS) {
|
||||
throw new JadxRuntimeException("Can't remove SSA var, still in use, count: " + useCount + ", list:"
|
||||
+ NL + " " + ssaVar.getUseList().stream()
|
||||
+ ICodeWriter.NL + " " + ssaVar.getUseList().stream()
|
||||
.map(arg -> arg + " from " + arg.getParentInsn())
|
||||
.collect(Collectors.joining(NL + " ")));
|
||||
.collect(Collectors.joining(ICodeWriter.NL + " ")));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -174,9 +173,9 @@ public class InsnRemover {
|
||||
}
|
||||
if (!found && Consts.DEBUG_WITH_ERRORS) {
|
||||
throw new JadxRuntimeException("Can't remove insn:"
|
||||
+ NL + " " + rem
|
||||
+ NL + " not found in list:"
|
||||
+ NL + " " + Utils.listToString(insns, NL + " "));
|
||||
+ ICodeWriter.NL + " " + rem
|
||||
+ ICodeWriter.NL + " not found in list:"
|
||||
+ ICodeWriter.NL + " " + Utils.listToString(insns, ICodeWriter.NL + " "));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,8 +16,8 @@ import java.util.function.Function;
|
||||
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import jadx.api.ICodeWriter;
|
||||
import jadx.api.JadxDecompiler;
|
||||
import jadx.core.codegen.CodeWriter;
|
||||
import jadx.core.dex.visitors.DepthTraversal;
|
||||
|
||||
public class Utils {
|
||||
@@ -124,7 +124,7 @@ public class Utils {
|
||||
return sw.getBuffer().toString();
|
||||
}
|
||||
|
||||
public static void appendStackTrace(CodeWriter code, Throwable throwable) {
|
||||
public static void appendStackTrace(ICodeWriter code, Throwable throwable) {
|
||||
if (throwable == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -9,11 +9,11 @@ import org.jetbrains.annotations.NotNull;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import jadx.api.ICodeWriter;
|
||||
import jadx.api.plugins.input.data.AccessFlags;
|
||||
import jadx.api.plugins.input.data.annotations.EncodedType;
|
||||
import jadx.api.plugins.input.data.annotations.EncodedValue;
|
||||
import jadx.core.codegen.ClassGen;
|
||||
import jadx.core.codegen.CodeWriter;
|
||||
import jadx.core.deobf.NameMapper;
|
||||
import jadx.core.dex.attributes.AFlag;
|
||||
import jadx.core.dex.attributes.AType;
|
||||
@@ -63,7 +63,7 @@ public class AndroidResourcesUtils {
|
||||
return newResCls;
|
||||
}
|
||||
|
||||
public static boolean handleAppResField(CodeWriter code, ClassGen clsGen, ClassInfo declClass) {
|
||||
public static boolean handleAppResField(ICodeWriter code, ClassGen clsGen, ClassInfo declClass) {
|
||||
ClassInfo parentClass = declClass.getParentClass();
|
||||
if (parentClass != null && parentClass.getShortName().equals("R")) {
|
||||
clsGen.useClass(code, parentClass);
|
||||
|
||||
@@ -2,10 +2,9 @@ package jadx.core.utils.exceptions;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
import jadx.api.ICodeWriter;
|
||||
import jadx.core.utils.Utils;
|
||||
|
||||
import static jadx.core.codegen.CodeWriter.NL;
|
||||
|
||||
public class JadxRuntimeException extends RuntimeException {
|
||||
|
||||
private static final long serialVersionUID = -7410848445429898248L;
|
||||
@@ -15,7 +14,7 @@ public class JadxRuntimeException extends RuntimeException {
|
||||
}
|
||||
|
||||
public JadxRuntimeException(String... lines) {
|
||||
super(Utils.listToString(Arrays.asList(lines), NL + " "));
|
||||
super(Utils.listToString(Arrays.asList(lines), ICodeWriter.NL + " "));
|
||||
}
|
||||
|
||||
public JadxRuntimeException(String message, Throwable cause) {
|
||||
|
||||
@@ -12,8 +12,8 @@ import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import jadx.api.ICodeInfo;
|
||||
import jadx.api.ICodeWriter;
|
||||
import jadx.api.ResourcesLoader;
|
||||
import jadx.core.codegen.CodeWriter;
|
||||
import jadx.core.dex.info.ConstStorage;
|
||||
import jadx.core.dex.nodes.ClassNode;
|
||||
import jadx.core.dex.nodes.RootNode;
|
||||
@@ -43,7 +43,7 @@ public class BinaryXMLParser extends CommonBinaryParser {
|
||||
private Set<String> nsMapGenerated;
|
||||
private final Map<String, String> tagAttrDeobfNames = new HashMap<>();
|
||||
|
||||
private CodeWriter writer;
|
||||
private ICodeWriter writer;
|
||||
private String[] strings;
|
||||
private String currentTag = "ERROR";
|
||||
private boolean firstElement;
|
||||
@@ -73,7 +73,7 @@ public class BinaryXMLParser extends CommonBinaryParser {
|
||||
}
|
||||
nsMapGenerated = new HashSet<>();
|
||||
nsMap = new HashMap<>();
|
||||
writer = new CodeWriter();
|
||||
writer = rootNode.makeCodeWriter();
|
||||
writer.add("<?xml version=\"1.0\" encoding=\"utf-8\"?>");
|
||||
firstElement = true;
|
||||
decode();
|
||||
@@ -443,7 +443,7 @@ public class BinaryXMLParser extends CommonBinaryParser {
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
private void attachClassNode(CodeWriter writer, String attrName, String clsName) {
|
||||
private void attachClassNode(ICodeWriter writer, String attrName, String clsName) {
|
||||
if (clsName == null || !attrName.equals("name")) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@ import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import jadx.api.ICodeInfo;
|
||||
import jadx.core.codegen.CodeWriter;
|
||||
import jadx.api.ICodeWriter;
|
||||
import jadx.core.deobf.NameMapper;
|
||||
import jadx.core.dex.attributes.AFlag;
|
||||
import jadx.core.dex.nodes.FieldNode;
|
||||
@@ -95,7 +95,7 @@ public class ResTableParser extends CommonBinaryParser {
|
||||
}
|
||||
|
||||
public ICodeInfo makeXmlDump() {
|
||||
CodeWriter writer = new CodeWriter();
|
||||
ICodeWriter writer = root.makeCodeWriter();
|
||||
writer.startLine("<?xml version=\"1.0\" encoding=\"utf-8\"?>");
|
||||
writer.startLine("<resources>");
|
||||
writer.incIndent();
|
||||
|
||||
@@ -10,7 +10,8 @@ import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import jadx.api.ICodeInfo;
|
||||
import jadx.core.codegen.CodeWriter;
|
||||
import jadx.api.ICodeWriter;
|
||||
import jadx.api.impl.SimpleCodeWriter;
|
||||
import jadx.core.utils.StringUtils;
|
||||
import jadx.core.xmlgen.entry.RawNamedValue;
|
||||
import jadx.core.xmlgen.entry.ResourceEntry;
|
||||
@@ -35,15 +36,15 @@ public class ResXmlGen {
|
||||
}
|
||||
|
||||
public List<ResContainer> makeResourcesXml() {
|
||||
Map<String, CodeWriter> contMap = new HashMap<>();
|
||||
Map<String, ICodeWriter> contMap = new HashMap<>();
|
||||
for (ResourceEntry ri : resStorage.getResources()) {
|
||||
if (SKIP_RES_TYPES.contains(ri.getTypeName())) {
|
||||
continue;
|
||||
}
|
||||
String fn = getFileName(ri);
|
||||
CodeWriter cw = contMap.get(fn);
|
||||
ICodeWriter cw = contMap.get(fn);
|
||||
if (cw == null) {
|
||||
cw = new CodeWriter();
|
||||
cw = new SimpleCodeWriter();
|
||||
cw.add("<?xml version=\"1.0\" encoding=\"utf-8\"?>");
|
||||
cw.startLine("<resources>");
|
||||
cw.incIndent();
|
||||
@@ -53,10 +54,9 @@ public class ResXmlGen {
|
||||
}
|
||||
|
||||
List<ResContainer> files = new ArrayList<>(contMap.size());
|
||||
for (Map.Entry<String, CodeWriter> entry : contMap.entrySet()) {
|
||||
for (Map.Entry<String, ICodeWriter> entry : contMap.entrySet()) {
|
||||
String fileName = entry.getKey();
|
||||
CodeWriter content = entry.getValue();
|
||||
|
||||
ICodeWriter content = entry.getValue();
|
||||
content.decIndent();
|
||||
content.startLine("</resources>");
|
||||
ICodeInfo codeInfo = content.finish();
|
||||
@@ -66,7 +66,7 @@ public class ResXmlGen {
|
||||
return files;
|
||||
}
|
||||
|
||||
private void addValue(CodeWriter cw, ResourceEntry ri) {
|
||||
private void addValue(ICodeWriter cw, ResourceEntry ri) {
|
||||
if (ri.getSimpleValue() != null) {
|
||||
String valueStr = vp.decodeValue(ri.getSimpleValue());
|
||||
addSimpleValue(cw, ri.getTypeName(), ri.getTypeName(), "name", ri.getKeyName(), valueStr);
|
||||
@@ -137,7 +137,7 @@ public class ResXmlGen {
|
||||
return s.substring(1);
|
||||
}
|
||||
|
||||
private void addItem(CodeWriter cw, String itemTag, String typeName, RawNamedValue value) {
|
||||
private void addItem(ICodeWriter cw, String itemTag, String typeName, RawNamedValue value) {
|
||||
String nameStr = vp.decodeNameRef(value.getNameRef());
|
||||
String valueStr = vp.decodeValue(value.getRawValue());
|
||||
if (!typeName.equals("attr")) {
|
||||
@@ -177,7 +177,7 @@ public class ResXmlGen {
|
||||
}
|
||||
}
|
||||
|
||||
private void addSimpleValue(CodeWriter cw, String typeName, String itemTag, String attrName, String attrValue, String valueStr) {
|
||||
private void addSimpleValue(ICodeWriter cw, String typeName, String itemTag, String attrName, String attrValue, String valueStr) {
|
||||
if (valueStr == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -26,10 +26,10 @@ import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
|
||||
import jadx.api.ICodeInfo;
|
||||
import jadx.api.ICodeWriter;
|
||||
import jadx.api.JadxArgs;
|
||||
import jadx.api.JadxDecompiler;
|
||||
import jadx.api.JadxInternalAccess;
|
||||
import jadx.core.codegen.CodeWriter;
|
||||
import jadx.core.dex.attributes.AFlag;
|
||||
import jadx.core.dex.attributes.AType;
|
||||
import jadx.core.dex.attributes.AttrList;
|
||||
@@ -240,7 +240,7 @@ public abstract class IntegrationTest extends TestUtils {
|
||||
private void printCodeWithLineNumbers(ICodeInfo code) {
|
||||
String codeStr = code.getCodeStr();
|
||||
Map<Integer, Integer> lineMapping = code.getLineMapping();
|
||||
String[] lines = codeStr.split(CodeWriter.NL);
|
||||
String[] lines = codeStr.split(ICodeWriter.NL);
|
||||
for (int i = 0; i < lines.length; i++) {
|
||||
String line = lines[i];
|
||||
int curLine = i + 1;
|
||||
|
||||
@@ -2,7 +2,7 @@ package jadx.tests.api.utils;
|
||||
|
||||
import org.hamcrest.Matcher;
|
||||
|
||||
import jadx.core.codegen.CodeWriter;
|
||||
import jadx.api.ICodeWriter;
|
||||
|
||||
public class JadxMatchers {
|
||||
|
||||
@@ -17,7 +17,7 @@ public class JadxMatchers {
|
||||
public static Matcher<String> containsLines(String... lines) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (String line : lines) {
|
||||
sb.append(line).append(CodeWriter.NL);
|
||||
sb.append(line).append(ICodeWriter.NL);
|
||||
}
|
||||
return countString(1, sb.toString());
|
||||
}
|
||||
@@ -30,7 +30,7 @@ public class JadxMatchers {
|
||||
sb.append(indent);
|
||||
sb.append(line);
|
||||
}
|
||||
sb.append(CodeWriter.NL);
|
||||
sb.append(ICodeWriter.NL);
|
||||
}
|
||||
return countString(1, sb.toString());
|
||||
}
|
||||
|
||||
@@ -3,22 +3,22 @@ package jadx.tests.api.utils;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
|
||||
import jadx.NotYetImplementedExtension;
|
||||
import jadx.core.codegen.CodeWriter;
|
||||
import jadx.api.ICodeWriter;
|
||||
|
||||
@ExtendWith(NotYetImplementedExtension.class)
|
||||
public class TestUtils {
|
||||
|
||||
public static String indent() {
|
||||
return CodeWriter.INDENT_STR;
|
||||
return ICodeWriter.INDENT_STR;
|
||||
}
|
||||
|
||||
public static String indent(int indent) {
|
||||
if (indent == 1) {
|
||||
return CodeWriter.INDENT_STR;
|
||||
return ICodeWriter.INDENT_STR;
|
||||
}
|
||||
StringBuilder sb = new StringBuilder(indent * CodeWriter.INDENT_STR.length());
|
||||
StringBuilder sb = new StringBuilder(indent * ICodeWriter.INDENT_STR.length());
|
||||
for (int i = 0; i < indent; i++) {
|
||||
sb.append(CodeWriter.INDENT_STR);
|
||||
sb.append(ICodeWriter.INDENT_STR);
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@ package jadx.tests.api.utils.assertj;
|
||||
|
||||
import org.assertj.core.api.AbstractStringAssert;
|
||||
|
||||
import jadx.core.codegen.CodeWriter;
|
||||
import jadx.api.ICodeWriter;
|
||||
import jadx.tests.api.utils.TestUtils;
|
||||
|
||||
public class JadxCodeAssertions extends AbstractStringAssert<JadxCodeAssertions> {
|
||||
@@ -52,7 +52,7 @@ public class JadxCodeAssertions extends AbstractStringAssert<JadxCodeAssertions>
|
||||
if (first) {
|
||||
first = false;
|
||||
} else {
|
||||
sb.append(CodeWriter.NL);
|
||||
sb.append(ICodeWriter.NL);
|
||||
}
|
||||
sb.append(indent);
|
||||
sb.append(line);
|
||||
|
||||
@@ -10,11 +10,11 @@ import org.jetbrains.annotations.Nullable;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import jadx.api.ICodeWriter;
|
||||
import jadx.api.JadxArgs;
|
||||
import jadx.api.JadxDecompiler;
|
||||
import jadx.api.JadxInternalAccess;
|
||||
import jadx.api.JavaClass;
|
||||
import jadx.core.codegen.CodeWriter;
|
||||
import jadx.core.dex.nodes.ClassNode;
|
||||
import jadx.core.dex.nodes.MethodNode;
|
||||
import jadx.core.dex.nodes.RootNode;
|
||||
@@ -130,7 +130,7 @@ public abstract class BaseExternalTest extends IntegrationTest {
|
||||
|
||||
String dashLine = "======================================================================================";
|
||||
Map<Integer, MethodNode> methodsMap = getMethodsMap(classNode);
|
||||
String[] lines = code.split(CodeWriter.NL);
|
||||
String[] lines = code.split(ICodeWriter.NL);
|
||||
for (MethodNode mth : classNode.getMethods()) {
|
||||
if (isMthMatch(mth, mthPattern)) {
|
||||
int decompiledLine = mth.getDecompiledLine() - 1;
|
||||
@@ -144,7 +144,7 @@ public abstract class BaseExternalTest extends IntegrationTest {
|
||||
break;
|
||||
}
|
||||
String line = lines[i];
|
||||
mthCode.append(line).append(CodeWriter.NL);
|
||||
mthCode.append(line).append(ICodeWriter.NL);
|
||||
// also count brackets for detect method end
|
||||
if (i >= decompiledLine) {
|
||||
brackets += StringUtils.countMatches(line, '{');
|
||||
@@ -173,7 +173,7 @@ public abstract class BaseExternalTest extends IntegrationTest {
|
||||
protected int getCommentLinesCount(String[] lines, int line) {
|
||||
for (int i = line - 1; i > 0 && i < lines.length; i--) {
|
||||
String str = lines[i];
|
||||
if (str.isEmpty() || str.equals(CodeWriter.NL)) {
|
||||
if (str.isEmpty() || str.equals(ICodeWriter.NL)) {
|
||||
return i + 1;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@ package jadx.tests.integration.debuginfo;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import jadx.core.codegen.CodeWriter;
|
||||
import jadx.api.ICodeWriter;
|
||||
import jadx.core.dex.attributes.nodes.LineAttrNode;
|
||||
import jadx.core.dex.nodes.ClassNode;
|
||||
import jadx.core.dex.nodes.FieldNode;
|
||||
@@ -61,7 +61,7 @@ public class TestLineNumbers extends IntegrationTest {
|
||||
assertEquals(testClassLine + 20, innerFunc3.getSourceLine());
|
||||
|
||||
// check decompiled lines
|
||||
String[] lines = code.split(CodeWriter.NL);
|
||||
String[] lines = code.split(ICodeWriter.NL);
|
||||
checkLine(lines, field, "int field;");
|
||||
checkLine(lines, func, "public void func() {");
|
||||
checkLine(lines, inner, "public static class Inner {");
|
||||
|
||||
@@ -4,7 +4,7 @@ import org.junit.jupiter.api.Test;
|
||||
|
||||
import jadx.NotYetImplemented;
|
||||
import jadx.api.ICodeInfo;
|
||||
import jadx.core.codegen.CodeWriter;
|
||||
import jadx.api.ICodeWriter;
|
||||
import jadx.core.dex.attributes.nodes.LineAttrNode;
|
||||
import jadx.core.dex.nodes.ClassNode;
|
||||
import jadx.core.dex.nodes.MethodNode;
|
||||
@@ -54,7 +54,7 @@ public class TestReturnSourceLine extends IntegrationTest {
|
||||
ClassNode cls = getClassNode(TestCls.class);
|
||||
ICodeInfo codeInfo = cls.getCode();
|
||||
String code = codeInfo.toString();
|
||||
String[] lines = code.split(CodeWriter.NL);
|
||||
String[] lines = code.split(ICodeWriter.NL);
|
||||
|
||||
MethodNode test1 = cls.searchMethodByShortId("test1(Z)I");
|
||||
checkLine(lines, codeInfo, test1, 3, "return 1;");
|
||||
@@ -69,7 +69,7 @@ public class TestReturnSourceLine extends IntegrationTest {
|
||||
ClassNode cls = getClassNode(TestCls.class);
|
||||
ICodeInfo codeInfo = cls.getCode();
|
||||
String code = codeInfo.toString();
|
||||
String[] lines = code.split(CodeWriter.NL);
|
||||
String[] lines = code.split(ICodeWriter.NL);
|
||||
|
||||
MethodNode test3 = cls.searchMethodByShortId("test3(I)I");
|
||||
checkLine(lines, codeInfo, test3, 3, "return v;");
|
||||
|
||||
@@ -9,7 +9,7 @@ import java.util.List;
|
||||
import java.util.concurrent.ThreadPoolExecutor;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import javax.swing.*;
|
||||
import javax.swing.ProgressMonitor;
|
||||
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.slf4j.Logger;
|
||||
|
||||
@@ -6,8 +6,8 @@ import org.jetbrains.annotations.NotNull;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import jadx.api.ICodeWriter;
|
||||
import jadx.api.JavaClass;
|
||||
import jadx.core.codegen.CodeWriter;
|
||||
import jadx.gui.JadxWrapper;
|
||||
import jadx.gui.utils.CacheObject;
|
||||
import jadx.gui.utils.CodeLinesInfo;
|
||||
@@ -77,7 +77,7 @@ public class IndexJob extends BackgroundJob {
|
||||
|
||||
@NotNull
|
||||
protected static List<StringRef> splitLines(JavaClass cls) {
|
||||
List<StringRef> lines = StringRef.split(cls.getCode(), CodeWriter.NL);
|
||||
List<StringRef> lines = StringRef.split(cls.getCode(), ICodeWriter.NL);
|
||||
int size = lines.size();
|
||||
for (int i = 0; i < size; i++) {
|
||||
lines.set(i, lines.get(i).trim());
|
||||
|
||||
@@ -12,6 +12,7 @@ import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import jadx.api.ICodeInfo;
|
||||
import jadx.api.ICodeWriter;
|
||||
import jadx.api.ResourceFile;
|
||||
import jadx.api.ResourceFileContent;
|
||||
import jadx.api.ResourceType;
|
||||
@@ -23,8 +24,6 @@ import jadx.gui.utils.NLS;
|
||||
import jadx.gui.utils.OverlayIcon;
|
||||
import jadx.gui.utils.UiUtils;
|
||||
|
||||
import static jadx.core.codegen.CodeWriter.NL;
|
||||
|
||||
public class JResource extends JLoadableNode implements Comparable<JResource> {
|
||||
private static final long serialVersionUID = -201018424302612434L;
|
||||
|
||||
@@ -154,7 +153,7 @@ public class JResource extends JLoadableNode implements Comparable<JResource> {
|
||||
return ResourcesLoader.loadToCodeWriter(is);
|
||||
});
|
||||
} catch (Exception e) {
|
||||
return new SimpleCodeInfo("Failed to load resource file:" + NL + Utils.getStackTrace(e));
|
||||
return new SimpleCodeInfo("Failed to load resource file:" + ICodeWriter.NL + Utils.getStackTrace(e));
|
||||
}
|
||||
|
||||
case DECODED_DATA:
|
||||
|
||||
@@ -10,6 +10,7 @@ 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;
|
||||
@@ -18,8 +19,6 @@ import jadx.core.xmlgen.ResContainer;
|
||||
import jadx.gui.treemodel.JResource;
|
||||
import jadx.gui.ui.codearea.AbstractCodeArea;
|
||||
|
||||
import static jadx.core.codegen.CodeWriter.NL;
|
||||
|
||||
public class ImagePanel extends ContentPanel {
|
||||
private static final long serialVersionUID = 4071356367073142688L;
|
||||
|
||||
@@ -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:" + NL + Utils.getStackTrace(e));
|
||||
textArea.setText("Image load error:" + ICodeWriter.NL + Utils.getStackTrace(e));
|
||||
add(textArea);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,7 +24,6 @@ import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import jadx.api.*;
|
||||
import jadx.core.codegen.CodeWriter;
|
||||
import jadx.core.deobf.DeobfPresets;
|
||||
import jadx.core.dex.attributes.AType;
|
||||
import jadx.core.dex.attributes.nodes.MethodOverrideAttr;
|
||||
@@ -70,16 +69,16 @@ public class RenameDialog extends JDialog {
|
||||
|
||||
public static boolean checkSettings(MainWindow mainWindow) {
|
||||
StringBuilder errorMessage = new StringBuilder();
|
||||
errorMessage.append(NLS.str("msg.rename_disabled")).append(CodeWriter.NL);
|
||||
errorMessage.append(NLS.str("msg.rename_disabled")).append(ICodeWriter.NL);
|
||||
|
||||
JadxSettings settings = mainWindow.getSettings();
|
||||
boolean valid = true;
|
||||
if (!settings.isDeobfuscationOn()) {
|
||||
errorMessage.append(" - ").append(NLS.str("msg.rename_disabled_deobfuscation_disabled")).append(CodeWriter.NL);
|
||||
errorMessage.append(" - ").append(NLS.str("msg.rename_disabled_deobfuscation_disabled")).append(ICodeWriter.NL);
|
||||
valid = false;
|
||||
}
|
||||
if (settings.isDeobfuscationForceSave()) {
|
||||
errorMessage.append(" - ").append(NLS.str("msg.rename_disabled_force_rewrite_enabled")).append(CodeWriter.NL);
|
||||
errorMessage.append(" - ").append(NLS.str("msg.rename_disabled_force_rewrite_enabled")).append(ICodeWriter.NL);
|
||||
valid = false;
|
||||
}
|
||||
if (valid) {
|
||||
|
||||
@@ -212,13 +212,13 @@ public class ResourceIndex {
|
||||
extSet.add(ext);
|
||||
}
|
||||
}
|
||||
ZipFile zipFile = getZipFile(cache.getJRoot());
|
||||
traverseTree(cache.getJRoot(), zipFile); // reindex
|
||||
try {
|
||||
ZipFile zipFile = getZipFile(cache.getJRoot());
|
||||
traverseTree(cache.getJRoot(), zipFile); // reindex
|
||||
if (zipFile != null) {
|
||||
zipFile.close();
|
||||
}
|
||||
} catch (IOException e) {
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,11 +11,11 @@ import io.reactivex.BackpressureStrategy;
|
||||
import io.reactivex.Flowable;
|
||||
import io.reactivex.FlowableEmitter;
|
||||
|
||||
import jadx.api.ICodeWriter;
|
||||
import jadx.api.JavaClass;
|
||||
import jadx.api.JavaField;
|
||||
import jadx.api.JavaMethod;
|
||||
import jadx.api.JavaNode;
|
||||
import jadx.core.codegen.CodeWriter;
|
||||
import jadx.gui.treemodel.CodeNode;
|
||||
import jadx.gui.treemodel.JNode;
|
||||
import jadx.gui.ui.SearchDialog;
|
||||
@@ -161,13 +161,12 @@ public class TextSearchIndex {
|
||||
}
|
||||
|
||||
private int searchNext(FlowableEmitter<CodeNode> emitter, JavaNode javaClass, String code, final SearchSettings searchSettings) {
|
||||
int pos;
|
||||
pos = searchSettings.find(code);
|
||||
int pos = searchSettings.find(code);
|
||||
if (pos == -1) {
|
||||
return -1;
|
||||
}
|
||||
int lineStart = 1 + code.lastIndexOf(CodeWriter.NL, pos);
|
||||
int lineEnd = code.indexOf(CodeWriter.NL, pos + searchSettings.getSearchString().length());
|
||||
int lineStart = 1 + code.lastIndexOf(ICodeWriter.NL, pos);
|
||||
int lineEnd = code.indexOf(ICodeWriter.NL, pos + searchSettings.getSearchString().length());
|
||||
StringRef line = StringRef.subString(code, lineStart, lineEnd == -1 ? code.length() : lineEnd);
|
||||
emitter.onNext(new CodeNode(nodeCache.makeFrom(javaClass), -pos, line.trim()).setPos(pos));
|
||||
return lineEnd;
|
||||
|
||||
Reference in New Issue
Block a user