package eu.bibl.cfide.engine.decompiler;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.tree.AnnotationNode;
import org.objectweb.asm.tree.LocalVariableNode;
import org.objectweb.asm.tree.MethodNode;
import org.objectweb.asm.tree.TryCatchBlockNode;
import eu.bibl.cfide.context.CFIDEContext;
public class MethodNodeDecompilationUnit implements DecompilationUnit<MethodNode> {
protected CFIDEContext context;
public MethodNodeDecompilationUnit(CFIDEContext context) {
this.context = context;
}
@Override
public PrefixedStringBuilder decompile(PrefixedStringBuilder sb, MethodNode m) {
String s = getAccessString(m.access);
sb.append(" ");
sb.append("method: ");
sb.append(s);
if (s.length() > 0)
sb.append(" ");
sb.append(m.name);
sb.append(" ");
sb.append(m.desc);
int amountOfThrows = m.exceptions.size();
if (amountOfThrows > 0) {
sb.append(" throws ");
sb.append(m.exceptions.get(0));// exceptions is list<string>
for (int i = 1; i < amountOfThrows; i++) {
sb.append(", ");
sb.append(m.exceptions.get(i));
}
}
if (s.contains("abstract")) {
sb.append(" {}\n");
} else {
sb.append(" {\n");
if (m.annotationDefault != null) {
sb.append(m.annotationDefault);
sb.append("\n");
}
if (m.signature != null) {
sb.append(" <sig:").append(m.signature).append(">\n");
}
AdvancedInstructionPrinter insnPrinter = new AdvancedInstructionPrinter(context, m);
List<String> print = insnPrinter.createPrint();
addAttrList(m.attrs, "attr", sb, insnPrinter);
addAttrList(m.invisibleAnnotations, "invisAnno", sb, insnPrinter);
addAttrList(m.invisibleAnnotations, "invisLocalVarAnno", sb, insnPrinter);
addAttrList(m.invisibleTypeAnnotations, "invisTypeAnno", sb, insnPrinter);
addAttrList(m.localVariables, "localVar", sb, insnPrinter);
addAttrList(m.visibleAnnotations, "visAnno", sb, insnPrinter);
addAttrList(m.visibleLocalVariableAnnotations, "visLocalVarAnno", sb, insnPrinter);
addAttrList(m.visibleTypeAnnotations, "visTypeAnno", sb, insnPrinter);
for (String insn : print) {
sb.append(" ");
sb.append(insn);
sb.append("\n");
}
for (Object o : m.tryCatchBlocks) {
TryCatchBlockNode tcbn = (TryCatchBlockNode) o;
sb.append(" ");
sb.append("<TryCatch: L");
sb.append(insnPrinter.resolveLabel(tcbn.start));
sb.append(" L");
sb.append(insnPrinter.resolveLabel(tcbn.end));
sb.append(" L");
sb.append(insnPrinter.resolveLabel(tcbn.handler));
sb.append(" ");
sb.append(tcbn.type);
sb.append(">\n");
}
sb.append(" } //end of ");
sb.append(m.name);
sb.append(" ");
sb.append(m.desc);
sb.append("\n");
}
return sb;
}
private void addAttrList(List<?> list, String name, PrefixedStringBuilder sb, AdvancedInstructionPrinter insnPrinter) {
if (list == null)
return;
if (list.size() > 0) {
for (Object o : list) {
sb.append(" <");
sb.append(name);
sb.append(":");
sb.append(printAttr(o, insnPrinter));
sb.append(">");
sb.append("\n");
}
sb.append("\n");
}
}
private String printAttr(Object o, AdvancedInstructionPrinter insnPrinter) {
if (o instanceof LocalVariableNode) {
LocalVariableNode lvn = (LocalVariableNode) o;
return "index=" + lvn.index + " , name=" + lvn.name + " , desc=" + lvn.desc + ", sig=" + lvn.signature + ", start=L" + insnPrinter.resolveLabel(lvn.start) + ", end=L" + insnPrinter.resolveLabel(lvn.end);
} else if (o instanceof AnnotationNode) {
AnnotationNode an = (AnnotationNode) o;
StringBuilder sb = new StringBuilder();
sb.append("desc = ");
sb.append(an.desc);
sb.append(" , values = ");
if (an.values != null) {
sb.append(Arrays.toString(an.values.toArray()));
} else {
sb.append("[]");
}
return sb.toString();
}
if (o == null)
return "";
return o.toString();
}
public static String getAccessString(int access) {
// public, protected, private, abstract, static,
// final, synchronized, native & strictfp are permitted
List<String> tokens = new ArrayList<String>();
if ((access & Opcodes.ACC_PUBLIC) != 0)
tokens.add("public");
if ((access & Opcodes.ACC_PRIVATE) != 0)
tokens.add("private");
if ((access & Opcodes.ACC_PROTECTED) != 0)
tokens.add("protected");
if ((access & Opcodes.ACC_STATIC) != 0)
tokens.add("static");
if ((access & Opcodes.ACC_ABSTRACT) != 0)
tokens.add("abstract");
if ((access & Opcodes.ACC_FINAL) != 0)
tokens.add("final");
if ((access & Opcodes.ACC_SYNCHRONIZED) != 0)
tokens.add("synchronized");
if ((access & Opcodes.ACC_NATIVE) != 0)
tokens.add("native");
if ((access & Opcodes.ACC_STRICT) != 0)
tokens.add("strictfp");
if ((access & Opcodes.ACC_BRIDGE) != 0)
tokens.add("bridge");
if ((access & Opcodes.ACC_VARARGS) != 0)
tokens.add("varargs");
if (tokens.size() == 0)
return "";
// hackery delimeters
StringBuilder sb = new StringBuilder(tokens.get(0));
for (int i = 1; i < tokens.size(); i++) {
sb.append(" ");
sb.append(tokens.get(i));
}
return sb.toString();
}
}