From 53f214b7b0bfb22537dd96df363bc09aa69e9ead Mon Sep 17 00:00:00 2001 From: SuspiciousActivity <38253929+SuspiciousActivity@users.noreply.github.com> Date: Wed, 25 Nov 2020 14:18:11 +0100 Subject: [PATCH] Performance improvements --- src/me/ByteEdit/edit/Assembler.java | 282 ++++---- src/me/ByteEdit/edit/Disassembler.java | 604 ++++++++++-------- .../ByteEdit/edit/JavaAssemblyTokenMaker.java | 11 +- src/me/ByteEdit/edit/StringContext.java | 40 ++ src/me/ByteEdit/main/Main.java | 6 +- src/me/ByteEdit/utils/ClassUtil.java | 38 +- src/me/ByteEdit/utils/UnicodeUtils.java | 172 +++-- 7 files changed, 660 insertions(+), 493 deletions(-) create mode 100644 src/me/ByteEdit/edit/StringContext.java diff --git a/src/me/ByteEdit/edit/Assembler.java b/src/me/ByteEdit/edit/Assembler.java index 37d67d6..e608a7e 100644 --- a/src/me/ByteEdit/edit/Assembler.java +++ b/src/me/ByteEdit/edit/Assembler.java @@ -292,7 +292,7 @@ public class Assembler { } } } - HashMap methodLabelMap = new HashMap(); + HashMap methodLabelMap = new HashMap(); annotationsForNext.clear(); MethodNode node = null; String temp = ""; @@ -348,12 +348,12 @@ public class Assembler { String signat = sp[5].equals("null") ? null : UnicodeUtils.unescape(sp[5]); LabelNode _start = null; LabelNode _end = null; - for (Entry entry : methodLabelMap.entrySet()) { - if (entry.getValue() == start) { - _start = new LabelNode(entry.getKey()); + for (Entry entry : methodLabelMap.entrySet()) { + if (entry.getValue().intValue() == start) { + _start = entry.getKey(); } - if (entry.getValue() == end) { - _end = new LabelNode(entry.getKey()); + if (entry.getValue().intValue() == end) { + _end = entry.getKey(); } } node.localVariables.add(new LocalVariableNode(UnicodeUtils.unescape(sp[0]), @@ -368,15 +368,15 @@ public class Assembler { LabelNode _start = null; LabelNode _end = null; LabelNode _handler = null; - for (Entry entry : methodLabelMap.entrySet()) { - if (entry.getValue() == start) { - _start = new LabelNode(entry.getKey()); + for (Entry entry : methodLabelMap.entrySet()) { + if (entry.getValue().intValue() == start) { + _start = entry.getKey(); } - if (entry.getValue() == end) { - _end = new LabelNode(entry.getKey()); + if (entry.getValue().intValue() == end) { + _end = entry.getKey(); } - if (entry.getValue() == handler) { - _handler = new LabelNode(entry.getKey()); + if (entry.getValue().intValue() == handler) { + _handler = entry.getKey(); } } node.tryCatchBlocks.add(new TryCatchBlockNode(_start, _end, _handler, @@ -625,28 +625,28 @@ public class Assembler { } } - private static AbstractInsnNode getNode(String s, HashMap labels) throws Exception { + private static AbstractInsnNode getNode(String s, HashMap labels) throws Exception { if (s.startsWith("// label ")) { int labelNr = Integer.parseInt(s.substring(9)); - for (Map.Entry entry : labels.entrySet()) { + for (Map.Entry entry : labels.entrySet()) { if (entry.getValue() == labelNr) { - return new LabelNode(entry.getKey()); + return entry.getKey(); } } - Label l = new Label(); - labels.put(l, labelNr); - return new LabelNode(l); + LabelNode ln = new LabelNode(new Label()); + labels.put(ln, labelNr); + return ln; } else if (s.startsWith("// line ")) { s = s.substring(8); int labelNr = Integer.parseInt(s.split(" ")[1]); - for (Map.Entry entry : labels.entrySet()) { + for (Map.Entry entry : labels.entrySet()) { if (entry.getValue() == labelNr) { - return new LineNumberNode(Integer.parseInt(s.split(" ")[0]), new LabelNode(entry.getKey())); + return new LineNumberNode(Integer.parseInt(s.split(" ")[0]), entry.getKey()); } } - Label l = new Label(); - labels.put(l, labelNr); - return new LineNumberNode(Integer.parseInt(s.split(" ")[0]), new LabelNode(l)); + LabelNode ln = new LabelNode(new Label()); + labels.put(ln, labelNr); + return new LineNumberNode(Integer.parseInt(s.split(" ")[0]), ln); } else if (s.startsWith("// frame ")) { String str1 = s.substring(7); String str = str1.substring(str1.indexOf(' ', 3) + 1); @@ -674,16 +674,16 @@ public class Assembler { if (asd.startsWith("(label) ")) { int labelNr = Integer.parseInt(asd.split(" ")[1]); boolean found = false; - for (Map.Entry entry : labels.entrySet()) { + for (Map.Entry entry : labels.entrySet()) { if (entry.getValue() == labelNr) { - arr.add(new LabelNode(entry.getKey())); + arr.add(entry.getKey()); found = true; } } if (!found) { - Label lb = new Label(); - labels.put(lb, labelNr); - arr.add(new LabelNode(lb)); + LabelNode ln = new LabelNode(new Label()); + labels.put(ln, labelNr); + arr.add(ln); } } else { arr.add(ClassUtil.getCastedValue(asd.split(" ")[1], asd.split("\\) ")[0].substring(1))); @@ -720,16 +720,16 @@ public class Assembler { if (asd.startsWith("(label) ")) { int labelNr = Integer.parseInt(asd.split(" ")[1]); boolean found = false; - for (Map.Entry entry : labels.entrySet()) { + for (Map.Entry entry : labels.entrySet()) { if (entry.getValue() == labelNr) { - arr.add(new LabelNode(entry.getKey())); + arr.add(entry.getKey()); found = true; } } if (!found) { - Label l = new Label(); - labels.put(l, labelNr); - arr.add(new LabelNode(l)); + LabelNode ln = new LabelNode(new Label()); + labels.put(ln, labelNr); + arr.add(ln); } } else { arr.add(ClassUtil.getCastedValue(asd.split(" ")[1], asd.split("\\) ")[0].substring(1))); @@ -1115,179 +1115,179 @@ public class Assembler { } case "ifeq": { int labelNr = Integer.parseInt(s.split(" ")[1]); - for (Map.Entry entry : labels.entrySet()) { + for (Map.Entry entry : labels.entrySet()) { if (entry.getValue() == labelNr) { - return new JumpInsnNode(153, new LabelNode(entry.getKey())); + return new JumpInsnNode(153, entry.getKey()); } } - Label l = new Label(); - labels.put(l, labelNr); - return new JumpInsnNode(153, new LabelNode(l)); + LabelNode ln = new LabelNode(new Label()); + labels.put(ln, labelNr); + return new JumpInsnNode(153, ln); } case "ifne": { int labelNr = Integer.parseInt(s.split(" ")[1]); - for (Map.Entry entry : labels.entrySet()) { + for (Map.Entry entry : labels.entrySet()) { if (entry.getValue() == labelNr) { - return new JumpInsnNode(154, new LabelNode(entry.getKey())); + return new JumpInsnNode(154, entry.getKey()); } } - Label l = new Label(); - labels.put(l, labelNr); - return new JumpInsnNode(154, new LabelNode(l)); + LabelNode ln = new LabelNode(new Label()); + labels.put(ln, labelNr); + return new JumpInsnNode(154, ln); } case "iflt": { int labelNr = Integer.parseInt(s.split(" ")[1]); - for (Map.Entry entry : labels.entrySet()) { + for (Map.Entry entry : labels.entrySet()) { if (entry.getValue() == labelNr) { - return new JumpInsnNode(155, new LabelNode(entry.getKey())); + return new JumpInsnNode(155, entry.getKey()); } } - Label l = new Label(); - labels.put(l, labelNr); - return new JumpInsnNode(155, new LabelNode(l)); + LabelNode ln = new LabelNode(new Label()); + labels.put(ln, labelNr); + return new JumpInsnNode(155, ln); } case "ifge": { int labelNr = Integer.parseInt(s.split(" ")[1]); - for (Map.Entry entry : labels.entrySet()) { + for (Map.Entry entry : labels.entrySet()) { if (entry.getValue() == labelNr) { - return new JumpInsnNode(156, new LabelNode(entry.getKey())); + return new JumpInsnNode(156, entry.getKey()); } } - Label l = new Label(); - labels.put(l, labelNr); - return new JumpInsnNode(156, new LabelNode(l)); + LabelNode ln = new LabelNode(new Label()); + labels.put(ln, labelNr); + return new JumpInsnNode(156, ln); } case "ifgt": { int labelNr = Integer.parseInt(s.split(" ")[1]); - for (Map.Entry entry : labels.entrySet()) { + for (Map.Entry entry : labels.entrySet()) { if (entry.getValue() == labelNr) { - return new JumpInsnNode(157, new LabelNode(entry.getKey())); + return new JumpInsnNode(157, entry.getKey()); } } - Label l = new Label(); - labels.put(l, labelNr); - return new JumpInsnNode(157, new LabelNode(l)); + LabelNode ln = new LabelNode(new Label()); + labels.put(ln, labelNr); + return new JumpInsnNode(157, ln); } case "ifle": { int labelNr = Integer.parseInt(s.split(" ")[1]); - for (Map.Entry entry : labels.entrySet()) { + for (Map.Entry entry : labels.entrySet()) { if (entry.getValue() == labelNr) { - return new JumpInsnNode(158, new LabelNode(entry.getKey())); + return new JumpInsnNode(158, entry.getKey()); } } - Label l = new Label(); - labels.put(l, labelNr); - return new JumpInsnNode(158, new LabelNode(l)); + LabelNode ln = new LabelNode(new Label()); + labels.put(ln, labelNr); + return new JumpInsnNode(158, ln); } case "if_icmpeq": { int labelNr = Integer.parseInt(s.split(" ")[1]); - for (Map.Entry entry : labels.entrySet()) { + for (Map.Entry entry : labels.entrySet()) { if (entry.getValue() == labelNr) { - return new JumpInsnNode(159, new LabelNode(entry.getKey())); + return new JumpInsnNode(159, entry.getKey()); } } - Label l = new Label(); - labels.put(l, labelNr); - return new JumpInsnNode(159, new LabelNode(l)); + LabelNode ln = new LabelNode(new Label()); + labels.put(ln, labelNr); + return new JumpInsnNode(159, ln); } case "if_icmpne": { int labelNr = Integer.parseInt(s.split(" ")[1]); - for (Map.Entry entry : labels.entrySet()) { + for (Map.Entry entry : labels.entrySet()) { if (entry.getValue() == labelNr) { - return new JumpInsnNode(160, new LabelNode(entry.getKey())); + return new JumpInsnNode(160, entry.getKey()); } } - Label l = new Label(); - labels.put(l, labelNr); - return new JumpInsnNode(160, new LabelNode(l)); + LabelNode ln = new LabelNode(new Label()); + labels.put(ln, labelNr); + return new JumpInsnNode(160, ln); } case "if_icmplt": { int labelNr = Integer.parseInt(s.split(" ")[1]); - for (Map.Entry entry : labels.entrySet()) { + for (Map.Entry entry : labels.entrySet()) { if (entry.getValue() == labelNr) { - return new JumpInsnNode(161, new LabelNode(entry.getKey())); + return new JumpInsnNode(161, entry.getKey()); } } - Label l = new Label(); - labels.put(l, labelNr); - return new JumpInsnNode(161, new LabelNode(l)); + LabelNode ln = new LabelNode(new Label()); + labels.put(ln, labelNr); + return new JumpInsnNode(161, ln); } case "if_icmpge": { int labelNr = Integer.parseInt(s.split(" ")[1]); - for (Map.Entry entry : labels.entrySet()) { + for (Map.Entry entry : labels.entrySet()) { if (entry.getValue() == labelNr) { - return new JumpInsnNode(162, new LabelNode(entry.getKey())); + return new JumpInsnNode(162, entry.getKey()); } } - Label l = new Label(); - labels.put(l, labelNr); - return new JumpInsnNode(162, new LabelNode(l)); + LabelNode ln = new LabelNode(new Label()); + labels.put(ln, labelNr); + return new JumpInsnNode(162, ln); } case "if_icmpgt": { int labelNr = Integer.parseInt(s.split(" ")[1]); - for (Map.Entry entry : labels.entrySet()) { + for (Map.Entry entry : labels.entrySet()) { if (entry.getValue() == labelNr) { - return new JumpInsnNode(163, new LabelNode(entry.getKey())); + return new JumpInsnNode(163, entry.getKey()); } } - Label l = new Label(); - labels.put(l, labelNr); - return new JumpInsnNode(163, new LabelNode(l)); + LabelNode ln = new LabelNode(new Label()); + labels.put(ln, labelNr); + return new JumpInsnNode(163, ln); } case "if_icmple": { int labelNr = Integer.parseInt(s.split(" ")[1]); - for (Map.Entry entry : labels.entrySet()) { + for (Map.Entry entry : labels.entrySet()) { if (entry.getValue() == labelNr) { - return new JumpInsnNode(164, new LabelNode(entry.getKey())); + return new JumpInsnNode(164, entry.getKey()); } } - Label l = new Label(); - labels.put(l, labelNr); - return new JumpInsnNode(164, new LabelNode(l)); + LabelNode ln = new LabelNode(new Label()); + labels.put(ln, labelNr); + return new JumpInsnNode(164, ln); } case "if_acmpeq": { int labelNr = Integer.parseInt(s.split(" ")[1]); - for (Map.Entry entry : labels.entrySet()) { + for (Map.Entry entry : labels.entrySet()) { if (entry.getValue() == labelNr) { - return new JumpInsnNode(165, new LabelNode(entry.getKey())); + return new JumpInsnNode(165, entry.getKey()); } } - Label l = new Label(); - labels.put(l, labelNr); - return new JumpInsnNode(165, new LabelNode(l)); + LabelNode ln = new LabelNode(new Label()); + labels.put(ln, labelNr); + return new JumpInsnNode(165, ln); } case "if_acmpne": { int labelNr = Integer.parseInt(s.split(" ")[1]); - for (Map.Entry entry : labels.entrySet()) { + for (Map.Entry entry : labels.entrySet()) { if (entry.getValue() == labelNr) { - return new JumpInsnNode(166, new LabelNode(entry.getKey())); + return new JumpInsnNode(166, entry.getKey()); } } - Label l = new Label(); - labels.put(l, labelNr); - return new JumpInsnNode(166, new LabelNode(l)); + LabelNode ln = new LabelNode(new Label()); + labels.put(ln, labelNr); + return new JumpInsnNode(166, ln); } case "goto": { int labelNr = Integer.parseInt(s.split(" ")[1]); - for (Map.Entry entry : labels.entrySet()) { + for (Map.Entry entry : labels.entrySet()) { if (entry.getValue() == labelNr) { - return new JumpInsnNode(167, new LabelNode(entry.getKey())); + return new JumpInsnNode(167, entry.getKey()); } } - Label l = new Label(); - labels.put(l, labelNr); - return new JumpInsnNode(167, new LabelNode(l)); + LabelNode ln = new LabelNode(new Label()); + labels.put(ln, labelNr); + return new JumpInsnNode(167, ln); } case "jsr": { int labelNr = Integer.parseInt(s.split(" ")[1]); - for (Map.Entry entry : labels.entrySet()) { + for (Map.Entry entry : labels.entrySet()) { if (entry.getValue() == labelNr) { - return new JumpInsnNode(168, new LabelNode(entry.getKey())); + return new JumpInsnNode(168, entry.getKey()); } } - Label l = new Label(); - labels.put(l, labelNr); - return new JumpInsnNode(168, new LabelNode(l)); + LabelNode ln = new LabelNode(new Label()); + labels.put(ln, labelNr); + return new JumpInsnNode(168, ln); } case "ret": { return new VarInsnNode(169, Integer.parseInt(s.split(" ")[1])); @@ -1307,9 +1307,9 @@ public class Assembler { LabelNode dflt = null; if (!split2[2].substring(9).equals("null")) { int dfltLabelNr = Integer.parseInt(split2[2].substring(9)); - for (Entry entry : labels.entrySet()) { + for (Entry entry : labels.entrySet()) { if (entry.getValue() == dfltLabelNr) { - dflt = new LabelNode(entry.getKey()); + dflt = entry.getKey(); labelIDs.put(BigInteger.valueOf(dfltLabelNr), dflt); } labelMap.replaceAll(new BiFunction() { @@ -1317,7 +1317,7 @@ public class Assembler { @Override public LabelNode apply(SwitchIntContainer t, LabelNode u) { if (entry.getValue().intValue() == t.getId()) { - return new LabelNode(entry.getKey()); + return entry.getKey(); } return u; } @@ -1325,9 +1325,9 @@ public class Assembler { }); } if (dflt == null) { - Label l = new Label(); - labels.put(l, dfltLabelNr); - dflt = new LabelNode(l); + LabelNode ln = new LabelNode(new Label()); + labels.put(ln, dfltLabelNr); + dflt = ln; labelIDs.put(BigInteger.valueOf(dfltLabelNr), dflt); } } else { @@ -1338,9 +1338,8 @@ public class Assembler { for (Entry entry : labelMap.entrySet()) { LabelNode ln; if (((ln = labelIDs.get(BigInteger.valueOf(entry.getKey().getId()))) == null)) { - Label l = new Label(); - labels.put(l, entry.getKey().getId()); - ln = new LabelNode(l); + ln = new LabelNode(new Label()); + labels.put(ln, entry.getKey().getId()); labelIDs.put(BigInteger.valueOf(entry.getKey().getId()), ln); } arr[counter] = ln; @@ -1374,9 +1373,9 @@ public class Assembler { } LabelNode dflt = null; int labelNr = Integer.parseInt(split2[0].substring(9)); - for (Entry entry : labels.entrySet()) { + for (Entry entry : labels.entrySet()) { if (entry.getValue() == labelNr) { - dflt = new LabelNode(entry.getKey()); + dflt = entry.getKey(); labelIDs.put(BigInteger.valueOf(labelNr), dflt); } labelMap.replaceAll(new BiFunction() { @@ -1384,7 +1383,7 @@ public class Assembler { @Override public LabelNode apply(SwitchIntContainer t, LabelNode u) { if (entry.getValue().intValue() == t.getId()) { - return new LabelNode(entry.getKey()); + return entry.getKey(); } return u; } @@ -1392,9 +1391,9 @@ public class Assembler { }); } if (dflt == null) { - Label l = new Label(); - labels.put(l, labelNr); - dflt = new LabelNode(l); + LabelNode ln = new LabelNode(new Label()); + labels.put(ln, labelNr); + dflt = ln; labelIDs.put(BigInteger.valueOf(labelNr), dflt); } LabelNode[] arr = new LabelNode[labelMap.size()]; @@ -1402,9 +1401,8 @@ public class Assembler { for (Entry entry : labelMap.entrySet()) { LabelNode ln; if (((ln = labelIDs.get(BigInteger.valueOf(entry.getKey().getId()))) == null)) { - Label l = new Label(); - labels.put(l, entry.getKey().getId()); - ln = new LabelNode(l); + ln = new LabelNode(new Label()); + labels.put(ln, entry.getKey().getId()); labelIDs.put(BigInteger.valueOf(entry.getKey().getId()), ln); } arr[counter] = ln; @@ -1582,25 +1580,25 @@ public class Assembler { } case "ifnull": { int labelNr = Integer.parseInt(s.split(" ")[1]); - for (Map.Entry entry : labels.entrySet()) { + for (Map.Entry entry : labels.entrySet()) { if (entry.getValue() == labelNr) { - return new JumpInsnNode(198, new LabelNode(entry.getKey())); + return new JumpInsnNode(198, entry.getKey()); } } - Label l = new Label(); - labels.put(l, labelNr); - return new JumpInsnNode(198, new LabelNode(l)); + LabelNode ln = new LabelNode(new Label()); + labels.put(ln, labelNr); + return new JumpInsnNode(198, ln); } case "ifnonnull": { int labelNr = Integer.parseInt(s.split(" ")[1]); - for (Map.Entry entry : labels.entrySet()) { + for (Map.Entry entry : labels.entrySet()) { if (entry.getValue() == labelNr) { - return new JumpInsnNode(199, new LabelNode(entry.getKey())); + return new JumpInsnNode(199, entry.getKey()); } } - Label l = new Label(); - labels.put(l, labelNr); - return new JumpInsnNode(199, new LabelNode(l)); + LabelNode ln = new LabelNode(new Label()); + labels.put(ln, labelNr); + return new JumpInsnNode(199, ln); } default: throw new IllegalArgumentException("Illegal Instruction: " + s); diff --git a/src/me/ByteEdit/edit/Disassembler.java b/src/me/ByteEdit/edit/Disassembler.java index d26d3d3..6e776e2 100644 --- a/src/me/ByteEdit/edit/Disassembler.java +++ b/src/me/ByteEdit/edit/Disassembler.java @@ -4,6 +4,12 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; import java.util.List; +import java.util.concurrent.Callable; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.Future; +import java.util.concurrent.atomic.AtomicInteger; import org.objectweb.asm.Handle; import org.objectweb.asm.Label; @@ -40,6 +46,9 @@ import me.ByteEdit.utils.UnicodeUtils; public class Disassembler { + private static final ExecutorService exec = Executors + .newFixedThreadPool((Runtime.getRuntime().availableProcessors() + 1) / 2); + public static String disassemble(ClassNode classNode) { return disassemble(classNode, null).getDisassembly(); } @@ -74,12 +83,250 @@ public class Disassembler { return new DisassembleTuple("ClassNode is null! This is not a valid java class file!"); } try { - int lineFound = -1; + AtomicInteger lineFound = new AtomicInteger(-1); + StringContext ctx = new StringContext(16); + ctx.next("// #Annotations:\n"); + ctx.next(doAnnotations(classNode.visibleAnnotations)); + ctx.next("// #Class v:" + classNode.version + "\n"); + if (classNode.signature != null) + ctx.next("// #Signature: " + UnicodeUtils.escapeWithSpaces(classNode.signature) + "\n"); + if (classNode.outerMethod != null) + ctx.next("// #OuterMethod: " + (classNode.outerMethod == null ? "null" + : (UnicodeUtils.escapeWithSpaces(classNode.outerMethod) + " " + + UnicodeUtils.escapeWithSpaces(classNode.outerMethodDesc))) + + "\n"); + if (classNode.outerClass != null) + ctx.next("// #OuterClass: " + UnicodeUtils.escapeWithSpaces(classNode.outerClass) + "\n"); + ctx.next("// #InnerClasses:\n"); + if (classNode.innerClasses != null) { + String ics = ""; + for (InnerClassNode icn : classNode.innerClasses) { + ics += "// " + UnicodeUtils.escapeWithSpaces(icn.name) + " " + + UnicodeUtils.escapeWithSpaces(icn.outerName) + " " + + UnicodeUtils.escapeWithSpaces(icn.innerName) + + (icn.access == 0 ? "" : " " + ClassUtil.getAccessFlagsFull(icn.access).trim()) + "\n"; + } + ctx.next(ics); + } + ctx.next(ClassUtil.getAccessFlagsClass(classNode.access) + UnicodeUtils.escapeWithSpaces(classNode.name) + + " "); + ctx.next("extends " + UnicodeUtils.escapeWithSpaces(classNode.superName) + " "); + if (classNode.interfaces != null && !classNode.interfaces.isEmpty()) { + String interfaceStr = ""; + for (String interfc : classNode.interfaces) { + if (interfaceStr.isEmpty()) { + interfaceStr += UnicodeUtils.escapeWithSpaces(interfc); + } else { + interfaceStr += ", " + UnicodeUtils.escapeWithSpaces(interfc); + } + } + if (!interfaceStr.isEmpty()) + ctx.next("implements " + interfaceStr + " "); + } + ctx.next("{\n// #SourceFile: " + + (classNode.sourceFile == null ? "null" : UnicodeUtils.escape(classNode.sourceFile)) + + "\n\n// #Fields\n"); + ctx.next(doFields(classNode.fields, nodeToFind, lineFound)); + ctx.next("\n// #Methods\n"); + ctx.next(doMethods(classNode.methods, classNode.name, nodeToFind, lineFound)); + ctx.next("}\n"); + return new DisassembleTuple(ctx.finish(), lineFound.get()); + } catch (Throwable e) { + return new DisassembleTuple("Class couldn't be decompiled:\n" + e.getClass().getName() + ": " + + e.getMessage() + "\n" + + Arrays.toString(e.getStackTrace()).replace(", ", "\n\tat ").replace("[", "\tat ").replace("]", "") + + "\n"); + } + } + + private static String doAnnotations(List annotations) { + if (annotations == null) + return ""; + StringContext ctx = new StringContext(annotations.size()); + for (AnnotationNode annotationNode : annotations) { + String s = "@" + UnicodeUtils.escapeWithSpaces(annotationNode.desc); + if (annotationNode.values != null && !annotationNode.values.isEmpty()) { + s += " ("; + boolean valBefore = true; + for (Object o : annotationNode.values) { + if (valBefore) { + s += o + " = ["; + valBefore = false; + continue; + } else { + if (o instanceof String[]) { + String[] arr = (String[]) o; + boolean w8ing = false; + for (String rofl : arr) { + if (!w8ing) { + s += UnicodeUtils.escapeWithSpaces(rofl) + "/"; + w8ing = true; + } else { + s += UnicodeUtils.escapeWithSpaces(rofl) + "]"; + } + } + s += ", "; + } else if (o instanceof List) { + List list = (List) o; + s += "{ "; + for (Object obj : list) { + if (obj instanceof String[]) { + String[] arr = (String[]) obj; + boolean w8ing = false; + for (String rofl : arr) { + if (!w8ing) { + s += UnicodeUtils.escapeWithSpaces(rofl) + "/"; + w8ing = true; + } else { + s += UnicodeUtils.escapeWithSpaces(rofl); + } + } + } else { + s += "\"" + UnicodeUtils.escape(String.valueOf(obj)) + "\""; + } + s += ", "; + } + s = s.substring(0, s.length() - 2); + s += " }]"; + } else if (o instanceof String) { + s += "\"" + UnicodeUtils.escapeWithSpaces((String) o) + "\"], "; + } else { + s += "(" + o.getClass().getName().replace(".", "/") + ") " + o + "], "; + } + valBefore = true; + } + } + if (s.endsWith(", ")) + s = s.substring(0, s.length() - 2); + s += ")"; + } + s += "\n"; + ctx.next(s); + } + return ctx.finish(); + } + + private static String doMethods(List methods, String className, Object nodeToFind, + AtomicInteger lineFound) throws InterruptedException, ExecutionException { + Future[] futures = new Future[methods.size()]; + for (int i = 0; i < futures.length; i++) { + MethodNode mn = methods.get(i); + futures[i] = exec.submit(new Callable() { + @Override + public String call() throws Exception { + String ms = ""; + try { + ms += "\t// #Max: l:" + mn.maxLocals + " s:" + mn.maxStack + "\n"; + if (mn.signature != null) + ms += "\t// #Signature: " + UnicodeUtils.escapeWithSpaces(mn.signature) + "\n"; + String[] dis = disassembleMethod(className, mn); + ms += dis[2]; + ms += dis[1]; + if (mn.visibleAnnotations != null && !mn.visibleAnnotations.isEmpty()) { + for (AnnotationNode annotationNode : mn.visibleAnnotations) { + ms += "\t@" + annotationNode.desc; + if (annotationNode.values != null && !annotationNode.values.isEmpty()) { + ms += " ("; + boolean valBefore = true; + for (Object o : annotationNode.values) { + if (valBefore) { + ms += o + " = ["; + valBefore = false; + continue; + } else { + if (o instanceof String[]) { + String[] arr = (String[]) o; + boolean w8ing = false; + for (String rofl : arr) { + if (!w8ing) { + ms += UnicodeUtils.escapeWithSpaces(rofl) + "/"; + w8ing = true; + } else { + ms += UnicodeUtils.escapeWithSpaces(rofl) + "]"; + } + } + ms += ", "; + } else if (o instanceof List) { + List list = (List) o; + ms += "{ "; + for (Object obj : list) { + if (obj instanceof String[]) { + String[] arr = (String[]) obj; + boolean w8ing = false; + for (String rofl : arr) { + if (!w8ing) { + ms += UnicodeUtils.escapeWithSpaces(rofl) + "/"; + w8ing = true; + } else { + ms += UnicodeUtils.escapeWithSpaces(rofl); + } + } + } else { + ms += "\"" + UnicodeUtils.escape(String.valueOf(obj)) + "\""; + } + ms += ", "; + } + ms = ms.substring(0, ms.length() - 2); + ms += " }]"; + } else { + ms += "(" + o.getClass().getName().replace(".", "/") + ") " + o + "], "; + } + valBefore = true; + } + } + if (ms.endsWith(", ")) + ms = ms.substring(0, ms.length() - 2); + ms += ")"; + } + ms += "\n"; + } + } + if (mn.equals(nodeToFind)) { + lineFound.set(ms.split("\\n").length); + } + ms += "\t" + ClassUtil.getAccessFlagsFull(mn.access) + UnicodeUtils.escapeWithSpaces(mn.name) + + " " + UnicodeUtils.escapeWithSpaces(mn.desc) + " "; + if (mn.exceptions != null && !mn.exceptions.isEmpty()) { + String exceptionStr = ""; + for (String exc : mn.exceptions) { + if (exceptionStr.isEmpty()) { + exceptionStr += UnicodeUtils.escapeWithSpaces(exc); + } else { + exceptionStr += ", " + UnicodeUtils.escapeWithSpaces(exc); + } + } + if (!exceptionStr.isEmpty()) + ms += "throws " + exceptionStr + " "; + } + ms += "{\n"; + ms += dis[0]; + ms += "\t}\n\n"; + } catch (Exception e) { + ms += "\t\t// Method couldn't be disassembled:\n\t\t// " + e.getClass().getName() + ": " + + e.getMessage() + "\n" + Arrays.toString(e.getStackTrace()) + .replace(", ", "\n\t\t// \tat ").replace("[", "\t\t// \tat ").replace("]", "") + + "\n\t}\n\n"; + } + return ms; + } + }); + } + StringContext ctx = new StringContext(futures.length); + for (Future f : futures) { + ctx.next(f.get()); + } + return ctx.finish(); + } + + private static String doFields(List fields, Object nodeToFind, AtomicInteger lineFound) { + StringContext ctx = new StringContext(fields.size()); + for (FieldNode fn : fields) { String s = ""; - s += "// #Annotations:\n"; - if (classNode.visibleAnnotations != null && !classNode.visibleAnnotations.isEmpty()) { - for (AnnotationNode annotationNode : classNode.visibleAnnotations) { - s += "@" + UnicodeUtils.escapeWithSpaces(annotationNode.desc); + if (fn.signature != null) + s += "\t// #Signature: " + UnicodeUtils.escapeWithSpaces(fn.signature) + "\n"; + if (fn.visibleAnnotations != null && !fn.visibleAnnotations.isEmpty()) { + for (AnnotationNode annotationNode : fn.visibleAnnotations) { + s += "\t@" + UnicodeUtils.escapeWithSpaces(annotationNode.desc); if (annotationNode.values != null && !annotationNode.values.isEmpty()) { s += " ("; boolean valBefore = true; @@ -123,8 +370,6 @@ public class Disassembler { } s = s.substring(0, s.length() - 2); s += " }]"; - } else if (o instanceof String) { - s += "\"" + UnicodeUtils.escapeWithSpaces((String) o) + "\"], "; } else { s += "(" + o.getClass().getName().replace(".", "/") + ") " + o + "], "; } @@ -138,262 +383,75 @@ public class Disassembler { s += "\n"; } } - s += "// #Class v:" + classNode.version + "\n"; - if (classNode.signature != null) - s += "// #Signature: " + UnicodeUtils.escapeWithSpaces(classNode.signature) + "\n"; - if (classNode.outerMethod != null) - s += "// #OuterMethod: " + (classNode.outerMethod == null ? "null" - : (UnicodeUtils.escapeWithSpaces(classNode.outerMethod) + " " - + UnicodeUtils.escapeWithSpaces(classNode.outerMethodDesc))) - + "\n"; - if (classNode.outerClass != null) - s += "// #OuterClass: " + UnicodeUtils.escapeWithSpaces(classNode.outerClass) + "\n"; - s += "// #InnerClasses:\n"; - if (classNode.innerClasses != null) { - for (InnerClassNode icn : classNode.innerClasses) { - s += "// " + UnicodeUtils.escapeWithSpaces(icn.name) + " " - + UnicodeUtils.escapeWithSpaces(icn.outerName) + " " - + UnicodeUtils.escapeWithSpaces(icn.innerName) - + (icn.access == 0 ? "" : " " + ClassUtil.getAccessFlagsFull(icn.access).trim()) + "\n"; - } + if (fn.equals(nodeToFind)) { + lineFound.set(s.split("\\n").length); } - s += ClassUtil.getAccessFlagsClass(classNode.access) + UnicodeUtils.escapeWithSpaces(classNode.name) + " "; - s += "extends " + UnicodeUtils.escapeWithSpaces(classNode.superName) + " "; - if (classNode.interfaces != null && !classNode.interfaces.isEmpty()) { - String interfaceStr = ""; - for (String interfc : classNode.interfaces) { - if (interfaceStr.isEmpty()) { - interfaceStr += UnicodeUtils.escapeWithSpaces(interfc); - } else { - interfaceStr += ", " + UnicodeUtils.escapeWithSpaces(interfc); - } - } - if (!interfaceStr.isEmpty()) - s += "implements " + interfaceStr + " "; + s += "\t" + ClassUtil.getAccessFlagsFull(fn.access).replace("varargs", "transient") + + UnicodeUtils.escapeWithSpaces(fn.desc) + " " + UnicodeUtils.escapeWithSpaces(fn.name); + if (fn.value != null) { + s += " = " + ClassUtil.getDecompiledValue(fn.value, fn.desc, true); } - s += "{\n// #SourceFile: " - + (classNode.sourceFile == null ? "null" : UnicodeUtils.escape(classNode.sourceFile)) - + "\n\n// #Fields\n"; - for (FieldNode fn : classNode.fields) { - if (fn.signature != null) - s += "\t// #Signature: " + UnicodeUtils.escapeWithSpaces(fn.signature) + "\n"; - if (fn.visibleAnnotations != null && !fn.visibleAnnotations.isEmpty()) { - for (AnnotationNode annotationNode : fn.visibleAnnotations) { - s += "\t@" + UnicodeUtils.escapeWithSpaces(annotationNode.desc); - if (annotationNode.values != null && !annotationNode.values.isEmpty()) { - s += " ("; - boolean valBefore = true; - for (Object o : annotationNode.values) { - if (valBefore) { - s += o + " = ["; - valBefore = false; - continue; - } else { - if (o instanceof String[]) { - String[] arr = (String[]) o; - boolean w8ing = false; - for (String rofl : arr) { - if (!w8ing) { - s += UnicodeUtils.escapeWithSpaces(rofl) + "/"; - w8ing = true; - } else { - s += UnicodeUtils.escapeWithSpaces(rofl) + "]"; - } - } - s += ", "; - } else if (o instanceof List) { - List list = (List) o; - s += "{ "; - for (Object obj : list) { - if (obj instanceof String[]) { - String[] arr = (String[]) obj; - boolean w8ing = false; - for (String rofl : arr) { - if (!w8ing) { - s += UnicodeUtils.escapeWithSpaces(rofl) + "/"; - w8ing = true; - } else { - s += UnicodeUtils.escapeWithSpaces(rofl); - } - } - } else { - s += "\"" + UnicodeUtils.escape(String.valueOf(obj)) + "\""; - } - s += ", "; - } - s = s.substring(0, s.length() - 2); - s += " }]"; - } else { - s += "(" + o.getClass().getName().replace(".", "/") + ") " + o + "], "; - } - valBefore = true; - } - } - if (s.endsWith(", ")) - s = s.substring(0, s.length() - 2); - s += ")"; - } - s += "\n"; - } - } - if (fn.equals(nodeToFind)) { - lineFound = s.split("\\n").length; - } - s += "\t" + ClassUtil.getAccessFlagsFull(fn.access).replace("varargs", "transient") - + UnicodeUtils.escapeWithSpaces(fn.desc) + " " + UnicodeUtils.escapeWithSpaces(fn.name); - if (fn.value != null) { - s += " = " + ClassUtil.getDecompiledValue(fn.value, fn.desc, true); - } - s += "\n"; - } - s += "\n// #Methods\n"; - for (MethodNode mn : classNode.methods) { - try { - s += "\t// #Max: l:" + mn.maxLocals + " s:" + mn.maxStack + "\n"; - if (mn.signature != null) - s += "\t// #Signature: " + UnicodeUtils.escapeWithSpaces(mn.signature) + "\n"; - String[] dis = disassembleMethod(classNode.name, mn); - s += dis[2]; - s += dis[1]; - if (mn.visibleAnnotations != null && !mn.visibleAnnotations.isEmpty()) { - for (AnnotationNode annotationNode : mn.visibleAnnotations) { - s += "\t@" + annotationNode.desc; - if (annotationNode.values != null && !annotationNode.values.isEmpty()) { - s += " ("; - boolean valBefore = true; - for (Object o : annotationNode.values) { - if (valBefore) { - s += o + " = ["; - valBefore = false; - continue; - } else { - if (o instanceof String[]) { - String[] arr = (String[]) o; - boolean w8ing = false; - for (String rofl : arr) { - if (!w8ing) { - s += UnicodeUtils.escapeWithSpaces(rofl) + "/"; - w8ing = true; - } else { - s += UnicodeUtils.escapeWithSpaces(rofl) + "]"; - } - } - s += ", "; - } else if (o instanceof List) { - List list = (List) o; - s += "{ "; - for (Object obj : list) { - if (obj instanceof String[]) { - String[] arr = (String[]) obj; - boolean w8ing = false; - for (String rofl : arr) { - if (!w8ing) { - s += UnicodeUtils.escapeWithSpaces(rofl) + "/"; - w8ing = true; - } else { - s += UnicodeUtils.escapeWithSpaces(rofl); - } - } - } else { - s += "\"" + UnicodeUtils.escape(String.valueOf(obj)) + "\""; - } - s += ", "; - } - s = s.substring(0, s.length() - 2); - s += " }]"; - } else { - s += "(" + o.getClass().getName().replace(".", "/") + ") " + o + "], "; - } - valBefore = true; - } - } - if (s.endsWith(", ")) - s = s.substring(0, s.length() - 2); - s += ")"; - } - s += "\n"; - } - } - if (mn.equals(nodeToFind)) { - lineFound = s.split("\\n").length; - } - s += "\t" + ClassUtil.getAccessFlagsFull(mn.access) + UnicodeUtils.escapeWithSpaces(mn.name) + " " - + UnicodeUtils.escapeWithSpaces(mn.desc) + " "; - if (mn.exceptions != null && !mn.exceptions.isEmpty()) { - String exceptionStr = ""; - for (String exc : mn.exceptions) { - if (exceptionStr.isEmpty()) { - exceptionStr += UnicodeUtils.escapeWithSpaces(exc); - } else { - exceptionStr += ", " + UnicodeUtils.escapeWithSpaces(exc); - } - } - if (!exceptionStr.isEmpty()) - s += "throws " + exceptionStr + " "; - } - s += "{\n"; - s += dis[0]; - s += "\t}\n\n"; - } catch (Exception e) { - s += "\t\t// Method couldn't be disassembled:\n\t\t// " - + e.getClass().getName() + ": " + e.getMessage() + "\n" + Arrays.toString(e.getStackTrace()) - .replace(", ", "\n\t\t// \tat ").replace("[", "\t\t// \tat ").replace("]", "") - + "\n\t}\n\n"; - } - } - s += "}\n"; - return new DisassembleTuple(s, lineFound); - } catch (Throwable e) { - return new DisassembleTuple("Class couldn't be decompiled:\n" + e.getClass().getName() + ": " - + e.getMessage() + "\n" - + Arrays.toString(e.getStackTrace()).replace(", ", "\n\tat ").replace("[", "\tat ").replace("]", "") - + "\n"); + s += "\n"; + ctx.next(s); } + return ctx.finish(); } private static String[] disassembleMethod(String className, MethodNode mn) { HashMap labels = new HashMap(); - String s = ""; - String localVarTable = ""; - String tryCatchTable = ""; + String localVarTable; + String tryCatchTable; for (AbstractInsnNode n : mn.instructions.toArray()) { if (n instanceof LabelNode) { labels.put(((LabelNode) n).getLabel(), labels.size() + 1); } } if (mn.localVariables != null && !mn.localVariables.isEmpty()) { - localVarTable = "\t// #LocalVars:\n"; - for (LocalVariableNode lvn : mn.localVariables) { - localVarTable += "\t// " + UnicodeUtils.escapeWithSpaces(lvn.name) + ": " + List list = mn.localVariables; + StringContext ctx = new StringContext(list.size() + 1); + ctx.next("\t// #LocalVars:\n"); + for (LocalVariableNode lvn : list) { + ctx.next("\t// " + UnicodeUtils.escapeWithSpaces(lvn.name) + ": " + UnicodeUtils.escapeWithSpaces(lvn.desc) + " i:" + lvn.index + " s:" + labels.get(lvn.start.getLabel()) + " e:" + labels.get(lvn.end.getLabel()) + " sig:" - + UnicodeUtils.escapeWithSpaces(lvn.signature) + "\n"; + + UnicodeUtils.escapeWithSpaces(lvn.signature) + "\n"); } - } + localVarTable = ctx.finish(); + } else + localVarTable = ""; if (mn.tryCatchBlocks != null && !mn.tryCatchBlocks.isEmpty()) { - tryCatchTable = "\t// #TryCatch:\n"; + List list = mn.tryCatchBlocks; + StringContext ctx = new StringContext(list.size() + 1); + ctx.next("\t// #TryCatch:\n"); for (TryCatchBlockNode tcbn : mn.tryCatchBlocks) { - tryCatchTable += "\t// " + UnicodeUtils.escapeWithSpaces(tcbn.type) + " s:" - + labels.get(tcbn.start.getLabel()) + " e:" + labels.get(tcbn.end.getLabel()) + " h:" - + labels.get(tcbn.handler.getLabel()) + "\n"; + ctx.next("\t// " + UnicodeUtils.escapeWithSpaces(tcbn.type) + " s:" + labels.get(tcbn.start.getLabel()) + + " e:" + labels.get(tcbn.end.getLabel()) + " h:" + labels.get(tcbn.handler.getLabel()) + "\n"); } + tryCatchTable = ctx.finish(); + } else + tryCatchTable = ""; + AbstractInsnNode[] insns = mn.instructions.toArray(); + StringContext ctx = new StringContext(insns.length); + for (AbstractInsnNode n : insns) { + ctx.next(disassembleInstruction(n, labels)); } - for (AbstractInsnNode n : mn.instructions.toArray()) { - s += disassembleInstruction(n, labels); - } - return new String[] { s, localVarTable, tryCatchTable }; + return new String[] { ctx.finish(), localVarTable, tryCatchTable }; } - public static String disassembleInstruction(AbstractInsnNode n, HashMap labels) { - if (FieldInsnNode.class.isInstance(n)) { + public static final HashMap iiMap = new HashMap<>(); + + static { + iiMap.put(FieldInsnNode.class, (n, labels) -> { FieldInsnNode node = (FieldInsnNode) n; return "\t\t" + OpcodesReverse.reverseOpcode(node.getOpcode()) + " " + UnicodeUtils.escapeWithSpaces(node.desc) + " " + UnicodeUtils.escapeWithSpaces(node.owner) + "/" + UnicodeUtils.escapeWithSpaces(node.name).replace("/", "\\u002F") + "\n"; - } else if (LabelNode.class.isInstance(n)) { + }); + iiMap.put(LabelNode.class, (n, labels) -> { LabelNode node = (LabelNode) n; return "\t\t// label " + labels.get(node.getLabel()) + "\n"; - } else if (FrameNode.class.isInstance(n)) { + }); + iiMap.put(FrameNode.class, (n, labels) -> { FrameNode node = (FrameNode) n; String type = ""; switch (node.type) { @@ -470,10 +528,12 @@ public class Disassembler { } s += "\n"; return s; - } else if (LineNumberNode.class.isInstance(n)) { + }); + iiMap.put(LineNumberNode.class, (n, labels) -> { LineNumberNode node = (LineNumberNode) n; return "\t\t// line " + node.line + " " + labels.get(node.start.getLabel()) + "\n"; - } else if (InvokeDynamicInsnNode.class.isInstance(n)) { + }); + iiMap.put(InvokeDynamicInsnNode.class, (n, labels) -> { InvokeDynamicInsnNode node = (InvokeDynamicInsnNode) n; String s = "\t\t" + OpcodesReverse.reverseOpcode(node.getOpcode()) + " [\n\t\t\tname: " + UnicodeUtils.escapeWithSpaces(node.name).replace("/", "\\u002F") + "\n\t\t\tdesc: " @@ -484,7 +544,7 @@ public class Disassembler { + node.bsm.isInterface() + "\n\t\t\t\ttag: " + OpcodesReverse.reverseHandleOpcode(node.bsm.getTag()) + "\n\t\t\t]\n\t\t\targs: [\n"; for (Object l : node.bsmArgs) { - if (l.getClass().getName().equals("org.objectweb.asm.Type")) { + if (l instanceof Type) { Type type = (Type) l; int valueBegin = type.valueBegin; int valueEnd = type.valueEnd; @@ -494,7 +554,7 @@ public class Disassembler { + "\n\t\t\t\t\tstart: " + valueBegin + "\n\t\t\t\t\tend: " + valueEnd + "\n\t\t\t\t\tbuf: " + ClassUtil.getDecompiledValue(buf, ""); s += "\n\t\t\t\t]\n"; - } else if (l.getClass().getName().equals("org.objectweb.asm.Handle")) { + } else if (l instanceof Handle) { Handle h = (Handle) l; s += "\t\t\t\tHandle: [\n\t\t\t\t\tname: " + UnicodeUtils.escapeWithSpaces(h.getName()).replace("/", "\\u002F") + "\n\t\t\t\t\towner: " @@ -508,31 +568,26 @@ public class Disassembler { } s += "\t\t\t]\n\t\t]\n"; return s; - } else if (MethodInsnNode.class.isInstance(n)) { + }); + iiMap.put(MethodInsnNode.class, (n, labels) -> { MethodInsnNode node = (MethodInsnNode) n; return "\t\t" + OpcodesReverse.reverseOpcode(node.getOpcode()) + " " + UnicodeUtils.escapeWithSpaces(node.desc) + " " + UnicodeUtils.escapeWithSpaces(node.owner) + "/" + UnicodeUtils.escapeWithSpaces(node.name).replace("/", "\\u002F") + "\n"; - } else if (TypeInsnNode.class.isInstance(n)) { + }); + iiMap.put(TypeInsnNode.class, (n, labels) -> { TypeInsnNode node = (TypeInsnNode) n; return "\t\t" + OpcodesReverse.reverseOpcode(node.getOpcode()) + " " + UnicodeUtils.escapeWithSpaces(node.desc) + "\n"; - } else if (MultiANewArrayInsnNode.class.isInstance(n)) { + }); + iiMap.put(MultiANewArrayInsnNode.class, (n, labels) -> { MultiANewArrayInsnNode node = (MultiANewArrayInsnNode) n; return "\t\t" + OpcodesReverse.reverseOpcode(node.getOpcode()) + " " + UnicodeUtils.escapeWithSpaces(node.desc) + " " + node.dims + "\n"; - } else if (LdcInsnNode.class.isInstance(n)) { + }); + iiMap.put(LdcInsnNode.class, (n, labels) -> { LdcInsnNode node = (LdcInsnNode) n; - switch (node.cst.getClass().getSimpleName()) { - case "String": - case "Double": - case "Integer": - case "Float": - case "Long": { - return "\t\t" + OpcodesReverse.reverseOpcode(node.getOpcode()) + " " - + ClassUtil.getDecompiledValue(node.cst, "") + "\n"; - } - case "Type": { + if (node.cst instanceof Type) { Type type = (Type) node.cst; int valueBegin = type.valueBegin; int valueEnd = type.valueEnd; @@ -543,19 +598,20 @@ public class Disassembler { + valueEnd + "\n\t\t\tbuf: " + ClassUtil.getDecompiledValue(buf, ""); s += "\n\t\t]\n"; return s; + } else { + return "\t\t" + OpcodesReverse.reverseOpcode(node.getOpcode()) + " " + + ClassUtil.getDecompiledValue(node.cst, "") + "\n"; } - default: { - return "\t\tUNRESOLVED TYPE! " + OpcodesReverse.reverseOpcode(node.getOpcode()) + " " - + node.cst.getClass().getName().replace(".", "/") + " " + node.cst + "\n"; - } - } - } else if (VarInsnNode.class.isInstance(n)) { + }); + iiMap.put(VarInsnNode.class, (n, labels) -> { VarInsnNode node = (VarInsnNode) n; return "\t\t" + OpcodesReverse.reverseOpcode(n.getOpcode()) + " " + node.var + "\n"; - } else if (InsnNode.class.isInstance(n)) { + }); + iiMap.put(InsnNode.class, (n, labels) -> { InsnNode node = (InsnNode) n; return "\t\t" + OpcodesReverse.reverseOpcode(n.getOpcode()) + "\n"; - } else if (IntInsnNode.class.isInstance(n)) { + }); + iiMap.put(IntInsnNode.class, (n, labels) -> { IntInsnNode node = (IntInsnNode) n; if (n.getOpcode() == Opcodes.NEWARRAY) { return "\t\t" + OpcodesReverse.reverseOpcode(n.getOpcode()) + " " @@ -563,11 +619,13 @@ public class Disassembler { } else { return "\t\t" + OpcodesReverse.reverseOpcode(n.getOpcode()) + " " + node.operand + "\n"; } - } else if (JumpInsnNode.class.isInstance(n)) { + }); + iiMap.put(JumpInsnNode.class, (n, labels) -> { JumpInsnNode node = (JumpInsnNode) n; return "\t\t" + OpcodesReverse.reverseOpcode(n.getOpcode()) + " " + labels.get(node.label.getLabel()) + "\n"; - } else if (TableSwitchInsnNode.class.isInstance(n)) { + }); + iiMap.put(TableSwitchInsnNode.class, (n, labels) -> { TableSwitchInsnNode node = (TableSwitchInsnNode) n; String s = "\t\t" + OpcodesReverse.reverseOpcode(n.getOpcode()) + " [\n\t\t\tmin: " + node.min + "\n\t\t\tmax: " + node.max + "\n\t\t\tdefault: " + labels.get(node.dflt.getLabel()) @@ -577,7 +635,8 @@ public class Disassembler { } s += "\t\t\t]\n\t\t]\n"; return s; - } else if (LookupSwitchInsnNode.class.isInstance(n)) { + }); + iiMap.put(LookupSwitchInsnNode.class, (n, labels) -> { LookupSwitchInsnNode node = (LookupSwitchInsnNode) n; String s = "\t\t" + OpcodesReverse.reverseOpcode(n.getOpcode()) + " [\n\t\t\tdefault: " + labels.get(node.dflt.getLabel()) + "\n\t\t\tkeys: [\n"; @@ -590,13 +649,24 @@ public class Disassembler { } s += "\t\t\t]\n\t\t]\n"; return s; - } else if (IincInsnNode.class.isInstance(n)) { + }); + iiMap.put(IincInsnNode.class, (n, labels) -> { IincInsnNode node = (IincInsnNode) n; return "\t\t" + OpcodesReverse.reverseOpcode(n.getOpcode()) + " " + node.var + " " + node.incr + "\n"; - } else { + }); + } + + static interface InstructionInterface { + String apply(AbstractInsnNode n, HashMap labels); + } + + public static String disassembleInstruction(AbstractInsnNode n, HashMap labels) { + InstructionInterface ii = iiMap.get(n.getClass()); + if (ii != null) + return ii.apply(n, labels); + else return "\t\tNOT HANDLED! " + OpcodesReverse.reverseOpcode(n.getOpcode()) + " " + n.getClass().getSimpleName() + "\n"; - } } } diff --git a/src/me/ByteEdit/edit/JavaAssemblyTokenMaker.java b/src/me/ByteEdit/edit/JavaAssemblyTokenMaker.java index 1382777..cfbd533 100644 --- a/src/me/ByteEdit/edit/JavaAssemblyTokenMaker.java +++ b/src/me/ByteEdit/edit/JavaAssemblyTokenMaker.java @@ -2857,8 +2857,8 @@ public class JavaAssemblyTokenMaker extends AbstractJFlexCTokenMaker { * @see #addToken(int, int, int) */ private void addHyperlinkToken(int start, int end, int tokenType) { - int so = start + offsetShift; - addToken(zzBuffer, start, end, tokenType, so, true); + super.addToken(zzBuffer, start, end, tokenType, start + offsetShift, true); + zzStartRead = zzMarkedPos; } /** @@ -2867,7 +2867,8 @@ public class JavaAssemblyTokenMaker extends AbstractJFlexCTokenMaker { * @param tokenType The token's type. */ private void addToken(int tokenType) { - addToken(zzStartRead, zzMarkedPos - 1, tokenType); + super.addToken(zzBuffer, zzStartRead, zzMarkedPos - 1, tokenType, zzStartRead + offsetShift, false); + zzStartRead = zzMarkedPos; } /** @@ -2877,8 +2878,8 @@ public class JavaAssemblyTokenMaker extends AbstractJFlexCTokenMaker { * @see #addHyperlinkToken(int, int, int) */ private void addToken(int start, int end, int tokenType) { - int so = start + offsetShift; - addToken(zzBuffer, start, end, tokenType, so, false); + super.addToken(zzBuffer, start, end, tokenType, start + offsetShift, false); + zzStartRead = zzMarkedPos; } /** diff --git a/src/me/ByteEdit/edit/StringContext.java b/src/me/ByteEdit/edit/StringContext.java new file mode 100644 index 0000000..4ef35b4 --- /dev/null +++ b/src/me/ByteEdit/edit/StringContext.java @@ -0,0 +1,40 @@ +package me.ByteEdit.edit; + +/** + * This is a quiet fast String concatenation helper class. It appears to be a + * lot faster than Java's StringBuilder class, especially for very large + * Strings, which will be made by the Disassembler. + */ +public class StringContext { + + private String[] arrs; + private int idx; + private int len; + + public StringContext(int amt) { + if (amt > 0) + arrs = new String[amt]; + } + + public void next(String s) { + len += (arrs[idx++] = s).length(); + } + + public String finish() { + if (arrs == null) + return ""; + char[] full = new char[len]; + int off = 0; + for (int i = 0; i < idx; i++) { + int len = arrs[i].length(); + arrs[i].getChars(0, len, full, off); + off += len; + arrs[i] = null; + } + String s = new String(full); + arrs = null; + full = null; + return s; + } + +} diff --git a/src/me/ByteEdit/main/Main.java b/src/me/ByteEdit/main/Main.java index 55551dc..900e887 100644 --- a/src/me/ByteEdit/main/Main.java +++ b/src/me/ByteEdit/main/Main.java @@ -848,10 +848,10 @@ public class Main extends JFrame { if (optionBox.chckbxComputeMax.isSelected()) { computeFlags |= ClassWriter.COMPUTE_MAXS; } - for (ClassNode element : classes) { + for (ClassNode node : classes) { ClassWriter writer = new ClassWriter(computeFlags); - element.accept(writer); - output.putNextEntry(new JarEntry(getFullName(element.name))); + node.accept(writer); + output.putNextEntry(new JarEntry(getFullName(node.name))); output.write(writer.toByteArray()); output.closeEntry(); } diff --git a/src/me/ByteEdit/utils/ClassUtil.java b/src/me/ByteEdit/utils/ClassUtil.java index 2d50121..d7ddeb3 100644 --- a/src/me/ByteEdit/utils/ClassUtil.java +++ b/src/me/ByteEdit/utils/ClassUtil.java @@ -522,27 +522,27 @@ public class ClassUtil { return count; } + public static final HashMap diMap = new HashMap<>(); + + static { + diMap.put(String.class, (o, desc, escapeSpaces) -> "\"" + + (escapeSpaces ? UnicodeUtils.escapeWithSpaces((String) o) : UnicodeUtils.escape((String) o)) + "\""); + diMap.put(Integer.class, + (o, desc, escape) -> desc.equals("Z") ? (((int) o) == 0 ? "false" : "true") : o.toString()); + diMap.put(Long.class, (o, desc, escape) -> o.toString() + "l"); + diMap.put(Float.class, (o, desc, escape) -> o.toString() + "f"); + } + + static interface DecompilationInterface { + String apply(Object o, String desc, boolean escape); + } + public static String getDecompiledValue(Object o, String desc, boolean escapeSpaces) { - switch (o.getClass().getName()) { - case "java.lang.String": { - return "\"" + (escapeSpaces ? UnicodeUtils.escapeWithSpaces((String) o) : UnicodeUtils.escape((String) o)) - + "\""; - } - case "java.lang.Integer": { - if (desc.equals("Z")) { - return ((int) o) == 0 ? "false" : "true"; - } + DecompilationInterface di = diMap.get(o.getClass()); + if (di != null) + return di.apply(o, desc, escapeSpaces); + else return o.toString(); - } - case "java.lang.Long": { - return o.toString() + "l"; - } - case "java.lang.Float": { - return o.toString() + "f"; - } - default: - return o.toString(); - } } public static String getDecompiledValue(Object o, String desc) { diff --git a/src/me/ByteEdit/utils/UnicodeUtils.java b/src/me/ByteEdit/utils/UnicodeUtils.java index 11df4c7..08584d4 100644 --- a/src/me/ByteEdit/utils/UnicodeUtils.java +++ b/src/me/ByteEdit/utils/UnicodeUtils.java @@ -82,14 +82,80 @@ public class UnicodeUtils { if (s == null) { return null; } - s = escape(s).replace(" ", "\\u0020"); - if (s.startsWith("/")) { - s = "\\u002F" + s.substring(1); + StringBuilder sb = new StringBuilder(); + char[] arr = s.toCharArray(); + int i = 0; + int len = arr.length; + boolean addSlash = false; + + if (len > 0) { + if (arr[0] == '/') { + sb.append("\\u002F"); + i++; + } + if (arr[len - 1] == '/') { + addSlash = true; + len--; + } } - if (s.endsWith("/")) { - s = s.substring(0, s.length() - 1) + "\\u002F"; + + for (; i < len; i++) { + char c = arr[i]; + switch (c) { + case 'Ä': + case 'ä': + case 'Ö': + case 'ö': + case 'Ü': + case 'ü': + case 'ß': + case '€': + case '©': + case '®': + case '«': + case '»': + case '§': + case '£': + case '¥': + sb.append(c); + break; + case ' ': + sb.append("\\u0020"); + break; + case '\b': + sb.append("\\b"); + break; + case '\t': + sb.append("\\t"); + break; + case '\n': + sb.append("\\n"); + break; + case '\r': + sb.append("\\r"); + break; + case '\f': + sb.append("\\f"); + break; + case '"': + sb.append("\\\""); + break; + case '\\': + sb.append("\\\\"); + break; + default: + if (c > ' ' && c <= '~') { + sb.append(c); + } else { + sb.append(String.format("\\u%04X", (int) c)); + } + break; + } } - return s; + + if (addSlash) + sb.append("\\u002F"); + return sb.toString(); } public static String escape(String s) { @@ -98,63 +164,55 @@ public class UnicodeUtils { } StringBuilder sb = new StringBuilder(); for (char c : s.toCharArray()) { - if (isPrintable(c)) { + switch (c) { + case 'Ä': + case 'ä': + case 'Ö': + case 'ö': + case 'Ü': + case 'ü': + case 'ß': + case '€': + case '©': + case '®': + case '«': + case '»': + case '§': + case '£': + case '¥': sb.append(c); - } else { - switch (c) { - case '\b': - sb.append("\\b"); - break; - case '\t': - sb.append("\\t"); - break; - case '\n': - sb.append("\\n"); - break; - case '\r': - sb.append("\\r"); - break; - case '\f': - sb.append("\\f"); - break; - case '"': - sb.append("\\\""); - break; - case '\\': - sb.append("\\\\"); - break; - default: + break; + case '\b': + sb.append("\\b"); + break; + case '\t': + sb.append("\\t"); + break; + case '\n': + sb.append("\\n"); + break; + case '\r': + sb.append("\\r"); + break; + case '\f': + sb.append("\\f"); + break; + case '"': + sb.append("\\\""); + break; + case '\\': + sb.append("\\\\"); + break; + default: + if (c >= ' ' && c <= '~') { + sb.append(c); + } else { sb.append(String.format("\\u%04X", (int) c)); } + break; } } return sb.toString(); } - private static boolean isPrintable(char c) { - switch (c) { - case 'Ä': - case 'ä': - case 'Ö': - case 'ö': - case 'Ü': - case 'ü': - case 'ß': - case '€': - case '©': - case '®': - case '«': - case '»': - case '§': - case '£': - case '¥': - return true; - case '"': - case '\\': - return false; - default: - return c >= ' ' && c <= '~'; - } - } - }