|
|
|
@ -5,9 +5,13 @@ import java.util.Arrays;
|
|
|
|
|
import java.util.Collection;
|
|
|
|
|
import java.util.HashMap;
|
|
|
|
|
import java.util.List;
|
|
|
|
|
import java.util.Map;
|
|
|
|
|
import java.util.Map.Entry;
|
|
|
|
|
import java.util.NavigableMap;
|
|
|
|
|
|
|
|
|
|
import org.benf.cfr.reader.api.CfrDriver;
|
|
|
|
|
import org.benf.cfr.reader.api.OutputSinkFactory;
|
|
|
|
|
import org.benf.cfr.reader.api.SinkReturns.LineNumberMapping;
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
*
|
|
|
|
@ -20,24 +24,31 @@ public class Decompiler {
|
|
|
|
|
return decompile(classFilePath, methodName, false);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static String decompile(String classFilePath, String methodName, boolean hideUnicode) {
|
|
|
|
|
return decompile(classFilePath, methodName, hideUnicode, true);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @param classFilePath
|
|
|
|
|
* @param methodName
|
|
|
|
|
* @param hideUnicode
|
|
|
|
|
* @return
|
|
|
|
|
*/
|
|
|
|
|
public static String decompile(String classFilePath, String methodName, boolean hideUnicode) {
|
|
|
|
|
final StringBuilder result = new StringBuilder(8192);
|
|
|
|
|
public static String decompile(String classFilePath, String methodName, boolean hideUnicode,
|
|
|
|
|
boolean printLineNumber) {
|
|
|
|
|
final StringBuilder sb = new StringBuilder(8192);
|
|
|
|
|
|
|
|
|
|
final Map<Integer, Integer> lineMapping = new HashMap<Integer, Integer>();
|
|
|
|
|
|
|
|
|
|
OutputSinkFactory mySink = new OutputSinkFactory() {
|
|
|
|
|
@Override
|
|
|
|
|
public List<SinkClass> getSupportedSinks(SinkType sinkType, Collection<SinkClass> collection) {
|
|
|
|
|
return Arrays.asList(SinkClass.STRING, SinkClass.DECOMPILED, SinkClass.DECOMPILED_MULTIVER,
|
|
|
|
|
SinkClass.EXCEPTION_MESSAGE);
|
|
|
|
|
SinkClass.EXCEPTION_MESSAGE, SinkClass.LINE_NUMBER_MAPPING);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public <T> Sink<T> getSink(final SinkType sinkType, SinkClass sinkClass) {
|
|
|
|
|
public <T> Sink<T> getSink(final SinkType sinkType, final SinkClass sinkClass) {
|
|
|
|
|
return new Sink<T>() {
|
|
|
|
|
@Override
|
|
|
|
|
public void write(T sinkable) {
|
|
|
|
@ -45,7 +56,19 @@ public class Decompiler {
|
|
|
|
|
if (sinkType == SinkType.PROGRESS) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
result.append(sinkable);
|
|
|
|
|
if (sinkType == SinkType.LINENUMBER) {
|
|
|
|
|
LineNumberMapping mapping = (LineNumberMapping) sinkable;
|
|
|
|
|
NavigableMap<Integer, Integer> classFileMappings = mapping.getClassFileMappings();
|
|
|
|
|
NavigableMap<Integer,Integer> mappings = mapping.getMappings();
|
|
|
|
|
if (classFileMappings != null && mappings != null) {
|
|
|
|
|
for (Entry<Integer, Integer> entry : mappings.entrySet()) {
|
|
|
|
|
Integer srcLineNumber = classFileMappings.get(entry.getKey());
|
|
|
|
|
lineMapping.put(entry.getValue(), srcLineNumber);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
sb.append(sinkable);
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
@ -58,6 +81,7 @@ public class Decompiler {
|
|
|
|
|
*/
|
|
|
|
|
options.put("showversion", "false");
|
|
|
|
|
options.put("hideutf", String.valueOf(hideUnicode));
|
|
|
|
|
options.put("trackbytecodeloc", "true");
|
|
|
|
|
if (!StringUtils.isBlank(methodName)) {
|
|
|
|
|
options.put("methodname", methodName);
|
|
|
|
|
}
|
|
|
|
@ -67,7 +91,45 @@ public class Decompiler {
|
|
|
|
|
toAnalyse.add(classFilePath);
|
|
|
|
|
driver.analyse(toAnalyse);
|
|
|
|
|
|
|
|
|
|
return result.toString();
|
|
|
|
|
String result = sb.toString();
|
|
|
|
|
if (printLineNumber && !lineMapping.isEmpty()) {
|
|
|
|
|
result = addLineNumber(result, lineMapping);
|
|
|
|
|
}
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private static String addLineNumber(String src, Map<Integer, Integer> lineMapping) {
|
|
|
|
|
int maxLineNumber = 0;
|
|
|
|
|
for (Integer value : lineMapping.values()) {
|
|
|
|
|
if (value != null && value > maxLineNumber) {
|
|
|
|
|
maxLineNumber = value;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
String formatStr = "/*%2d*/ ";
|
|
|
|
|
String emptyStr = " ";
|
|
|
|
|
|
|
|
|
|
StringBuilder sb = new StringBuilder();
|
|
|
|
|
String[] lines = src.split("\\R");
|
|
|
|
|
|
|
|
|
|
if (maxLineNumber >= 100) {
|
|
|
|
|
formatStr = "/*%3d*/ ";
|
|
|
|
|
emptyStr = " ";
|
|
|
|
|
} else if (maxLineNumber >= 1000) {
|
|
|
|
|
formatStr = "/*%4d*/ ";
|
|
|
|
|
emptyStr = " ";
|
|
|
|
|
}
|
|
|
|
|
for (int i = 0; i < lines.length; ++i) {
|
|
|
|
|
Integer srcLineNumber = lineMapping.get(i + 1);
|
|
|
|
|
if (srcLineNumber != null) {
|
|
|
|
|
sb.append(String.format(formatStr, srcLineNumber));
|
|
|
|
|
} else {
|
|
|
|
|
sb.append(emptyStr);
|
|
|
|
|
}
|
|
|
|
|
sb.append(lines[i]).append("\n");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return sb.toString();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|