diff --git a/src/me/ByteEdit/boxes/GlobalSearchBox.java b/src/me/ByteEdit/boxes/GlobalSearchBox.java index bc904e4..caa2f4a 100644 --- a/src/me/ByteEdit/boxes/GlobalSearchBox.java +++ b/src/me/ByteEdit/boxes/GlobalSearchBox.java @@ -137,7 +137,7 @@ public class GlobalSearchBox extends JFrame { openBox.model.clear(); Set set = new HashSet<>(); if (!txtString.getText().isEmpty()) { - String str = UnicodeUtils.unescape(txtString.getText()); + String str = UnicodeUtils.unescape(null, txtString.getText(), true); if (ignoreCase) { str = str.toLowerCase(); } @@ -157,11 +157,11 @@ public class GlobalSearchBox extends JFrame { } } } else { - String owner = UnicodeUtils.unescape(txtOwner.getText()); + String owner = UnicodeUtils.unescape(null, txtOwner.getText(), true); boolean wildCardOwner = owner.isEmpty(); - String name = UnicodeUtils.unescape(txtName.getText()); + String name = UnicodeUtils.unescape(null, txtName.getText(), true); boolean wildCardName = name.isEmpty(); - String desc = UnicodeUtils.unescape(txtDesc.getText()); + String desc = UnicodeUtils.unescape(null, txtDesc.getText(), true); boolean wildCardDesc = desc.isEmpty(); for (ClassNode cn : Main.classNodes.values()) { for (MethodNode mn : cn.methods) { diff --git a/src/me/ByteEdit/boxes/RenameBox.java b/src/me/ByteEdit/boxes/RenameBox.java index 349a6e7..1e9755c 100644 --- a/src/me/ByteEdit/boxes/RenameBox.java +++ b/src/me/ByteEdit/boxes/RenameBox.java @@ -84,8 +84,8 @@ public class RenameBox extends JFrame { JOptionPane.showMessageDialog(null, "ClassNode not found!", "Error!", JOptionPane.ERROR_MESSAGE); return; } - String newName = UnicodeUtils.unescape(txtName.getText()); - String newDesc = UnicodeUtils.unescape(txtDesc.getText()); + String newName = UnicodeUtils.unescape(null, txtName.getText(), true); + String newDesc = UnicodeUtils.unescape(null, txtDesc.getText(), true); if (ClassUtil.isObjectClassMethod(newName, newDesc, true)) { JOptionPane.showMessageDialog(null, "Invalid name!", "Error!", JOptionPane.ERROR_MESSAGE); return; diff --git a/src/me/ByteEdit/boxes/TypeOpenBox.java b/src/me/ByteEdit/boxes/TypeOpenBox.java index 304bd9b..dc216ad 100644 --- a/src/me/ByteEdit/boxes/TypeOpenBox.java +++ b/src/me/ByteEdit/boxes/TypeOpenBox.java @@ -76,7 +76,7 @@ public class TypeOpenBox extends JFrame { if (txtSearch.getText().isEmpty()) { return; } - String search = UnicodeUtils.unescape(txtSearch.getText()).toLowerCase(); + String search = UnicodeUtils.unescape(null, txtSearch.getText(), true).toLowerCase(); if (search.contains("/")) { for (String s : Main.classNodes.keySet()) { String className = s.substring(0, s.length() - 6); diff --git a/src/me/ByteEdit/boxes/UnicodeBox.java b/src/me/ByteEdit/boxes/UnicodeBox.java index b1dc335..471ab39 100644 --- a/src/me/ByteEdit/boxes/UnicodeBox.java +++ b/src/me/ByteEdit/boxes/UnicodeBox.java @@ -36,7 +36,7 @@ public class UnicodeBox extends JFrame { public void actionPerformed(ActionEvent e) { try { - textArea.setText(UnicodeUtils.escape(textArea.getText())); + textArea.setText(UnicodeUtils.escape(null, textArea.getText(), true)); } catch (IllegalArgumentException ex) { Main.showError(ex.getMessage()); } @@ -50,7 +50,7 @@ public class UnicodeBox extends JFrame { public void actionPerformed(ActionEvent e) { try { - textArea.setText(UnicodeUtils.unescape(textArea.getText())); + textArea.setText(UnicodeUtils.unescape(null, textArea.getText(), true)); } catch (IllegalArgumentException ex) { Main.showError(ex.getMessage()); } diff --git a/src/me/ByteEdit/edit/Assembler.java b/src/me/ByteEdit/edit/Assembler.java index e608a7e..12aedc7 100644 --- a/src/me/ByteEdit/edit/Assembler.java +++ b/src/me/ByteEdit/edit/Assembler.java @@ -1,5 +1,6 @@ package me.ByteEdit.edit; +import java.io.BufferedReader; import java.io.StringReader; import java.math.BigInteger; import java.util.ArrayList; @@ -9,6 +10,7 @@ import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.function.BiFunction; +import java.util.regex.Pattern; import javax.swing.text.BadLocationException; @@ -51,30 +53,47 @@ import me.ByteEdit.utils.UnicodeUtils; public class Assembler { + private static final Pattern SPACE = Pattern.compile(" "); + public static ClassNode assemble(String input) { Main.txtByteEditView.removeAllLineHighlights(); CustomBufferedReader read = null; try { ClassNode clazz = new ClassNode(); + HugeStringsRev hsr = new HugeStringsRev(); + try (BufferedReader reader = new BufferedReader(new StringReader(input))) { + String s; + while (!(s = reader.readLine()).startsWith("// #SourceFile: ")) { + } + while (!(s = reader.readLine()).equals("// #Fields")) { + if (s.startsWith("#")) { + String[] split = SPACE.split(s, 2); + hsr.add(Integer.parseInt(split[0].substring(1, split[0].length() - 1)), + UnicodeUtils.unescape(null, split[1], true)); + } + } + } read = new CustomBufferedReader(new StringReader(input)); String s; while (!(s = read.readLine()).startsWith("// #Class v:")) { if (clazz.visibleAnnotations == null) { clazz.visibleAnnotations = new ArrayList<>(); } - clazz.visibleAnnotations.add(parseAnnotation(s)); + clazz.visibleAnnotations.add(parseAnnotation(hsr, s)); } clazz.version = Integer.parseInt(s.substring(12)); while ((s = read.readLine()).startsWith("// ")) { if (s.startsWith("// #Signature: ")) { - clazz.signature = s.substring(15).equals("null") ? null : UnicodeUtils.unescape(s.substring(15)); + clazz.signature = s.substring(15).equals("null") ? null + : UnicodeUtils.unescape(hsr, s.substring(15)); } else if (s.startsWith("// #OuterClass: ")) { - clazz.outerClass = s.substring(16).equals("null") ? null : UnicodeUtils.unescape(s.substring(16)); + clazz.outerClass = s.substring(16).equals("null") ? null + : UnicodeUtils.unescape(hsr, s.substring(16)); } else if (s.startsWith("// #OuterMethod: ")) { String[] split = s.split(" "); if (split.length > 3) { - clazz.outerMethod = UnicodeUtils.unescape(split[2]); - clazz.outerMethodDesc = UnicodeUtils.unescape(split[3]); + clazz.outerMethod = UnicodeUtils.unescape(hsr, split[2]); + clazz.outerMethodDesc = UnicodeUtils.unescape(hsr, split[3]); } } else if (s.equals("// #InnerClasses:")) { clazz.innerClasses = new ArrayList<>(); @@ -137,9 +156,9 @@ public class Assembler { access ^= ClassUtil.ACC_MANDATED; } } - clazz.innerClasses.add(new InnerClassNode(UnicodeUtils.unescape(split[1]), - split[2].equals("null") ? null : UnicodeUtils.unescape(split[2]), - split[3].equals("null") ? null : UnicodeUtils.unescape(split[3]), access)); + clazz.innerClasses.add(new InnerClassNode(UnicodeUtils.unescape(hsr, split[1]), + split[2].equals("null") ? null : UnicodeUtils.unescape(hsr, split[2]), + split[3].equals("null") ? null : UnicodeUtils.unescape(hsr, split[3]), access)); } } { @@ -148,14 +167,14 @@ public class Assembler { String interfaces = s.substring(s.lastIndexOf(" implements ") + 12); clazz.interfaces = new ArrayList<>(); for (String interf : interfaces.split(", ")) { - clazz.interfaces.add(UnicodeUtils.unescape(interf)); + clazz.interfaces.add(UnicodeUtils.unescape(hsr, interf)); } s = s.substring(0, s.lastIndexOf(" implements ")); } - clazz.superName = UnicodeUtils.unescape(s.substring(s.lastIndexOf(" extends ") + 9)); + clazz.superName = UnicodeUtils.unescape(hsr, s.substring(s.lastIndexOf(" extends ") + 9)); s = s.substring(0, s.lastIndexOf(" extends ")); String[] split = s.split(" "); - clazz.name = UnicodeUtils.unescape(split[split.length - 1]); + clazz.name = UnicodeUtils.unescape(hsr, split[split.length - 1]); clazz.access = ClassUtil.ACC_SUPER; switch (split[split.length - 2]) { case "class": @@ -192,7 +211,7 @@ public class Assembler { } } s = read.readLine(); - clazz.sourceFile = s.substring(16).equals("null") ? null : UnicodeUtils.unescape(s.substring(16)); + clazz.sourceFile = s.substring(16).equals("null") ? null : UnicodeUtils.unescape(hsr, s.substring(16)); while (!(s = read.readLine()).equals("// #Fields")) { } clazz.fields = new ArrayList<>(); @@ -207,7 +226,7 @@ public class Assembler { annotationsForNext.add(s); } else { if (s.startsWith("// #Signature: ")) { - signature = UnicodeUtils.unescape(s.substring(15)); + signature = UnicodeUtils.unescape(hsr, s.substring(15)); } else { String[] split = s.split(" "); boolean hasValue = false; @@ -218,9 +237,9 @@ public class Assembler { if (hasValue) { split = s.substring(0, s.indexOf(" = ")).split(" "); } - String name = UnicodeUtils.unescape(split[split.length - 1]); - String desc = UnicodeUtils.unescape(split[split.length - 2]); - value = getValue((String) value, desc); + String name = UnicodeUtils.unescape(hsr, split[split.length - 1]); + String desc = UnicodeUtils.unescape(hsr, split[split.length - 2]); + value = getValue(hsr, (String) value, desc); int access = 0; if (split.length > 2) { String cons = consolidateStrings(split, 0, split.length - 2); @@ -283,7 +302,7 @@ public class Assembler { node.visibleAnnotations = new ArrayList<>(); } for (String anno : annotationsForNext) { - node.visibleAnnotations.add(parseAnnotation(anno)); + node.visibleAnnotations.add(parseAnnotation(hsr, anno)); } annotationsForNext.clear(); } @@ -319,7 +338,7 @@ public class Assembler { tryCatchBlocksToParse.clear(); stage = 0; } else if (s.startsWith("// #Signature: ")) { - node.signature = UnicodeUtils.unescape(s.substring(15)); + node.signature = UnicodeUtils.unescape(hsr, s.substring(15)); } else if (s.equals("// #TryCatch:")) { stage = 1; } else if (s.equals("// #LocalVars:")) { @@ -337,7 +356,7 @@ public class Assembler { node.visibleAnnotations = new ArrayList<>(); } for (String anno : annotationsForNext) { - node.visibleAnnotations.add(parseAnnotation(anno)); + node.visibleAnnotations.add(parseAnnotation(hsr, anno)); } annotationsForNext.clear(); } @@ -345,7 +364,7 @@ public class Assembler { String[] sp = st.split(":"); int start = Integer.parseInt(sp[3].substring(0, sp[3].length() - 2)); int end = Integer.parseInt(sp[4].substring(0, sp[4].length() - 4)); - String signat = sp[5].equals("null") ? null : UnicodeUtils.unescape(sp[5]); + String signat = sp[5].equals("null") ? null : UnicodeUtils.unescape(hsr, sp[5]); LabelNode _start = null; LabelNode _end = null; for (Entry entry : methodLabelMap.entrySet()) { @@ -356,9 +375,9 @@ public class Assembler { _end = entry.getKey(); } } - node.localVariables.add(new LocalVariableNode(UnicodeUtils.unescape(sp[0]), - UnicodeUtils.unescape(sp[1].substring(1, sp[1].length() - 2)), signat, _start, _end, - Integer.parseInt(sp[2].substring(0, sp[2].length() - 2)))); + node.localVariables.add(new LocalVariableNode(UnicodeUtils.unescape(hsr, sp[0]), + UnicodeUtils.unescape(hsr, sp[1].substring(1, sp[1].length() - 2)), signat, _start, + _end, Integer.parseInt(sp[2].substring(0, sp[2].length() - 2)))); } for (String st : tryCatchBlocksToParse) { String[] sp = st.split(" "); @@ -380,7 +399,7 @@ public class Assembler { } } node.tryCatchBlocks.add(new TryCatchBlockNode(_start, _end, _handler, - sp[0].equals("null") ? null : UnicodeUtils.unescape(sp[0]))); + sp[0].equals("null") ? null : UnicodeUtils.unescape(hsr, sp[0]))); } clazz.methods.add(node); } else if (!s.startsWith("\t")) { @@ -388,13 +407,13 @@ public class Assembler { if (s.contains(" throws ")) { String exceptions = s.substring(s.lastIndexOf(" throws ") + 8); for (String excp : exceptions.split(", ")) { - node.exceptions.add(UnicodeUtils.unescape(excp)); + node.exceptions.add(UnicodeUtils.unescape(hsr, excp)); } s = s.substring(0, s.lastIndexOf(" throws ")); } String[] split = s.split(" "); - node.desc = UnicodeUtils.unescape(split[split.length - 1]); - node.name = UnicodeUtils.unescape(split[split.length - 2]); + node.desc = UnicodeUtils.unescape(hsr, split[split.length - 1]); + node.name = UnicodeUtils.unescape(hsr, split[split.length - 2]); int access = 0; if (split.length > 2) { String cons = consolidateStrings(split, 0, split.length - 2); @@ -458,7 +477,7 @@ public class Assembler { if (!temp.isEmpty()) { if (s.equals("]")) { temp += s; - node.instructions.add(getNode(temp, methodLabelMap)); + node.instructions.add(getNode(hsr, temp, methodLabelMap)); temp = ""; } else { temp += s + "\n"; @@ -467,7 +486,7 @@ public class Assembler { if (s.endsWith("[")) { temp += s + "\n"; } else { - node.instructions.add(getNode(s, methodLabelMap)); + node.instructions.add(getNode(hsr, s, methodLabelMap)); } } } @@ -496,31 +515,37 @@ public class Assembler { ArrayList ret = new ArrayList<>(); String[] split = s.split(", "); String building = null; + boolean inString = false; for (int i = 0; i < split.length; i++) { if (split[i].startsWith("(")) { ret.add(split[i]); - } else if (split[i].endsWith("\"")) { + } else if (split[i].startsWith("\"") && split[i].endsWith("\"")) { + ret.add(split[i]); + } else if (split[i].endsWith("\"") && inString) { if (building == null) ret.add(split[i]); else ret.add(building + ", " + split[i]); building = null; - } else { + } else if (inString || split[i].startsWith("\"")) { + inString = true; if (building == null) building = split[i]; else building += ", " + split[i]; + } else { + ret.add(split[i]); } } return ret.toArray(new String[0]); } - private static AnnotationNode parseAnnotation(String s) { + private static AnnotationNode parseAnnotation(HugeStringsRev hsr, String s) { s = s.substring(1); String[] split = s.split(" "); - AnnotationNode node = new AnnotationNode(UnicodeUtils.unescape(split[0])); + AnnotationNode node = new AnnotationNode(UnicodeUtils.unescape(hsr, split[0])); if (split.length > 1) { if (node.values == null) { node.values = new ArrayList<>(); @@ -538,7 +563,7 @@ public class Assembler { String split3[] = splitWithStrings(value.substring(2, value.length() - 2)); List list = new ArrayList<>(); for (String rofl : split3) { - rofl = UnicodeUtils.unescape(rofl); + rofl = UnicodeUtils.unescape(hsr, rofl); if (rofl.startsWith("\"")) { int index = rofl.lastIndexOf("\""); list.add(rofl.substring(1, index)); @@ -552,7 +577,7 @@ public class Assembler { } node.values.add(list); } else { - value = UnicodeUtils.unescape(value); + value = UnicodeUtils.unescape(hsr, value); if (value.startsWith("\"")) { int index = value.lastIndexOf("\""); node.values.add(value.substring(1, index)); @@ -596,7 +621,7 @@ public class Assembler { return ret; } - private static Object getValue(String s, String to) { + private static Object getValue(HugeStringsRev hsr, String s, String to) { if (s == null) { return null; } @@ -618,14 +643,15 @@ public class Assembler { case "S": return Short.parseShort(s); case "Ljava/lang/String;": - return UnicodeUtils.unescape(s.substring(1, s.length() - 1)); + return UnicodeUtils.unescape(hsr, s.substring(1, s.length() - 1)); default: { return null; } } } - private static AbstractInsnNode getNode(String s, HashMap labels) throws Exception { + private static AbstractInsnNode getNode(HugeStringsRev hsr, String s, HashMap labels) + throws Exception { if (s.startsWith("// label ")) { int labelNr = Integer.parseInt(s.substring(9)); for (Map.Entry entry : labels.entrySet()) { @@ -666,7 +692,7 @@ public class Assembler { if (frameType != -1) arr.add(new Integer(frameType)); else { - String frame = UnicodeUtils.unescape(asd); + String frame = UnicodeUtils.unescape(hsr, asd); frame = frame.substring(1, frame.length() - 1); arr.add(frame); } @@ -712,7 +738,7 @@ public class Assembler { if (frameType != -1) arr.add(new Integer(frameType)); else { - String frame = UnicodeUtils.unescape(asd); + String frame = UnicodeUtils.unescape(hsr, asd); frame = frame.substring(1, frame.length() - 1); arr.add(frame); } @@ -818,10 +844,10 @@ public class Assembler { String type = split2[0].substring(7); // Reflection val = new Type(ClassUtil.getIDFromClassNameForType(type), - UnicodeUtils.unescape(split2[3].substring(6, split2[3].length() - 1)), + UnicodeUtils.unescape(hsr, split2[3].substring(6, split2[3].length() - 1)), Integer.parseInt(split2[1].substring(7)), Integer.parseInt(split2[2].substring(5))); } else if (str.startsWith("\"") && str.endsWith("\"")) { - val = UnicodeUtils.unescape(str.substring(1, str.length() - 1)); + val = UnicodeUtils.unescape(hsr, str.substring(1, str.length() - 1)); } else if (str.endsWith("l")) { val = Long.parseLong(str.substring(0, str.length() - 1)); } else if (str.endsWith("f")) { @@ -1437,50 +1463,54 @@ public class Assembler { case "getstatic": { String target = split[2]; int index = target.lastIndexOf("/"); - return new FieldInsnNode(178, UnicodeUtils.unescape(target.substring(0, index)), - UnicodeUtils.unescape(target.substring(index + 1)), UnicodeUtils.unescape(split[1])); + return new FieldInsnNode(178, UnicodeUtils.unescape(hsr, target.substring(0, index)), + UnicodeUtils.unescape(hsr, target.substring(index + 1)), UnicodeUtils.unescape(hsr, split[1])); } case "putstatic": { String target = split[2]; int index = target.lastIndexOf("/"); - return new FieldInsnNode(179, UnicodeUtils.unescape(target.substring(0, index)), - UnicodeUtils.unescape(target.substring(index + 1)), UnicodeUtils.unescape(split[1])); + return new FieldInsnNode(179, UnicodeUtils.unescape(hsr, target.substring(0, index)), + UnicodeUtils.unescape(hsr, target.substring(index + 1)), UnicodeUtils.unescape(hsr, split[1])); } case "getfield": { String target = split[2]; int index = target.lastIndexOf("/"); - return new FieldInsnNode(180, UnicodeUtils.unescape(target.substring(0, index)), - UnicodeUtils.unescape(target.substring(index + 1)), UnicodeUtils.unescape(split[1])); + return new FieldInsnNode(180, UnicodeUtils.unescape(hsr, target.substring(0, index)), + UnicodeUtils.unescape(hsr, target.substring(index + 1)), UnicodeUtils.unescape(hsr, split[1])); } case "putfield": { String target = split[2]; int index = target.lastIndexOf("/"); - return new FieldInsnNode(181, UnicodeUtils.unescape(target.substring(0, index)), - UnicodeUtils.unescape(target.substring(index + 1)), UnicodeUtils.unescape(split[1])); + return new FieldInsnNode(181, UnicodeUtils.unescape(hsr, target.substring(0, index)), + UnicodeUtils.unescape(hsr, target.substring(index + 1)), UnicodeUtils.unescape(hsr, split[1])); } case "invokevirtual": { String target = split[2]; int index = target.lastIndexOf("/"); - return new MethodInsnNode(182, UnicodeUtils.unescape(target.substring(0, index)), - UnicodeUtils.unescape(target.substring(index + 1)), UnicodeUtils.unescape(split[1]), false); + return new MethodInsnNode(182, UnicodeUtils.unescape(hsr, target.substring(0, index)), + UnicodeUtils.unescape(hsr, target.substring(index + 1)), UnicodeUtils.unescape(hsr, split[1]), + false); } case "invokespecial": { String target = split[2]; int index = target.lastIndexOf("/"); - return new MethodInsnNode(183, UnicodeUtils.unescape(target.substring(0, index)), - UnicodeUtils.unescape(target.substring(index + 1)), UnicodeUtils.unescape(split[1]), false); + return new MethodInsnNode(183, UnicodeUtils.unescape(hsr, target.substring(0, index)), + UnicodeUtils.unescape(hsr, target.substring(index + 1)), UnicodeUtils.unescape(hsr, split[1]), + false); } case "invokestatic": { String target = split[2]; int index = target.lastIndexOf("/"); - return new MethodInsnNode(184, UnicodeUtils.unescape(target.substring(0, index)), - UnicodeUtils.unescape(target.substring(index + 1)), UnicodeUtils.unescape(split[1]), false); + return new MethodInsnNode(184, UnicodeUtils.unescape(hsr, target.substring(0, index)), + UnicodeUtils.unescape(hsr, target.substring(index + 1)), UnicodeUtils.unescape(hsr, split[1]), + false); } case "invokeinterface": { String target = split[2]; int index = target.lastIndexOf("/"); - return new MethodInsnNode(185, UnicodeUtils.unescape(target.substring(0, index)), - UnicodeUtils.unescape(target.substring(index + 1)), UnicodeUtils.unescape(split[1]), true); + return new MethodInsnNode(185, UnicodeUtils.unescape(hsr, target.substring(0, index)), + UnicodeUtils.unescape(hsr, target.substring(index + 1)), UnicodeUtils.unescape(hsr, split[1]), + true); } case "invokedynamic": { String str = s.substring(16, s.length() - 2).replace("", ""); @@ -1495,7 +1525,7 @@ public class Assembler { try { // Reflection args.add(new Type(ClassUtil.getIDFromClassNameForType(vals.get(0).substring(6)), - UnicodeUtils.unescape(vals.get(3).substring(6, vals.get(3).length() - 1)), + UnicodeUtils.unescape(hsr, vals.get(3).substring(6, vals.get(3).length() - 1)), Integer.parseInt(vals.get(1).substring(7)), Integer.parseInt(vals.get(2).substring(5)))); } catch (Exception e) { @@ -1503,9 +1533,9 @@ public class Assembler { } } else if (stage == 2) { args.add(new Handle(OpcodesReverse.getHandleOpcode(vals.get(4).substring(5)), - UnicodeUtils.unescape(vals.get(1).substring(7)), - UnicodeUtils.unescape(vals.get(0).substring(6)), - UnicodeUtils.unescape(vals.get(2).substring(6)), + UnicodeUtils.unescape(hsr, vals.get(1).substring(7)), + UnicodeUtils.unescape(hsr, vals.get(0).substring(6)), + UnicodeUtils.unescape(hsr, vals.get(2).substring(6)), Boolean.parseBoolean(vals.get(3).substring(13)))); vals.clear(); } @@ -1523,7 +1553,7 @@ public class Assembler { vals.add(st); } else if (stage == 0) { if (st.startsWith("\"") && st.endsWith("\"")) { - args.add(UnicodeUtils.unescape(st.substring(1, st.length() - 1))); + args.add(UnicodeUtils.unescape(hsr, st.substring(1, st.length() - 1))); } else if (st.endsWith("l")) { args.add(Long.parseLong(st.substring(0, st.length() - 1))); } else if (st.endsWith("f")) { @@ -1541,21 +1571,23 @@ public class Assembler { _args[stage] = o; stage++; } - return new InvokeDynamicInsnNode(UnicodeUtils.unescape(sp[0].substring(7)), - UnicodeUtils.unescape(sp[1].substring(6)), + return new InvokeDynamicInsnNode(UnicodeUtils.unescape(hsr, sp[0].substring(7)), + UnicodeUtils.unescape(hsr, sp[1].substring(6)), new Handle(OpcodesReverse.getHandleOpcode(sp[7].substring(6)), - UnicodeUtils.unescape(sp[4].substring(8)), UnicodeUtils.unescape(sp[3].substring(7)), - UnicodeUtils.unescape(sp[5].substring(7)), Boolean.parseBoolean(sp[6].substring(14))), + UnicodeUtils.unescape(hsr, sp[4].substring(8)), + UnicodeUtils.unescape(hsr, sp[3].substring(7)), + UnicodeUtils.unescape(hsr, sp[5].substring(7)), + Boolean.parseBoolean(sp[6].substring(14))), _args); } case "new": { - return new TypeInsnNode(187, UnicodeUtils.unescape(split[1])); + return new TypeInsnNode(187, UnicodeUtils.unescape(hsr, split[1])); } case "newarray": { return new IntInsnNode(188, ClassUtil.getArrayIDByType(split[1])); } case "anewarray": { - return new TypeInsnNode(189, UnicodeUtils.unescape(split[1])); + return new TypeInsnNode(189, UnicodeUtils.unescape(hsr, split[1])); } case "arraylength": { return new InsnNode(190); @@ -1564,10 +1596,10 @@ public class Assembler { return new InsnNode(191); } case "checkcast": { - return new TypeInsnNode(192, UnicodeUtils.unescape(split[1])); + return new TypeInsnNode(192, UnicodeUtils.unescape(hsr, split[1])); } case "instanceof": { - return new TypeInsnNode(193, UnicodeUtils.unescape(split[1])); + return new TypeInsnNode(193, UnicodeUtils.unescape(hsr, split[1])); } case "monitorenter": { return new InsnNode(194); @@ -1576,7 +1608,7 @@ public class Assembler { return new InsnNode(195); } case "multianewarray": { - return new MultiANewArrayInsnNode(UnicodeUtils.unescape(split[1]), Integer.parseInt(split[2])); + return new MultiANewArrayInsnNode(UnicodeUtils.unescape(hsr, split[1]), Integer.parseInt(split[2])); } case "ifnull": { int labelNr = Integer.parseInt(s.split(" ")[1]); diff --git a/src/me/ByteEdit/edit/Disassembler.java b/src/me/ByteEdit/edit/Disassembler.java index f586fa1..d02e2c3 100644 --- a/src/me/ByteEdit/edit/Disassembler.java +++ b/src/me/ByteEdit/edit/Disassembler.java @@ -83,53 +83,60 @@ public class Disassembler { return new DisassembleTuple("ClassNode is null! This is not a valid java class file!"); } try { + HugeStrings hs = new HugeStrings(); AtomicInteger lineFound = new AtomicInteger(-1); - StringContext ctx = new StringContext(16); + StringContext ctx = new StringContext(18); ctx.next("// #Annotations:\n"); - ctx.next(doAnnotations(classNode.visibleAnnotations)); + ctx.next(doAnnotations(classNode.visibleAnnotations, hs)); ctx.next("// #Class v:" + classNode.version + "\n"); if (classNode.signature != null) - ctx.next("// #Signature: " + UnicodeUtils.escapeWithSpaces(classNode.signature) + "\n"); + ctx.next("// #Signature: " + UnicodeUtils.escapeWithSpaces(hs, classNode.signature) + "\n"); if (classNode.outerMethod != null) - ctx.next("// #OuterMethod: " + (classNode.outerMethod == null ? "null" - : (UnicodeUtils.escapeWithSpaces(classNode.outerMethod) + " " - + UnicodeUtils.escapeWithSpaces(classNode.outerMethodDesc))) - + "\n"); + ctx.next( + "// #OuterMethod: " + + (classNode.outerMethod == null ? "null" + : (UnicodeUtils.escapeWithSpaces(hs, classNode.outerMethod) + " " + + UnicodeUtils.escapeWithSpaces(hs, classNode.outerMethodDesc))) + + "\n"); if (classNode.outerClass != null) - ctx.next("// #OuterClass: " + UnicodeUtils.escapeWithSpaces(classNode.outerClass) + "\n"); + ctx.next("// #OuterClass: " + UnicodeUtils.escapeWithSpaces(hs, 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) + ics += "// " + UnicodeUtils.escapeWithSpaces(hs, icn.name) + " " + + UnicodeUtils.escapeWithSpaces(hs, icn.outerName) + " " + + UnicodeUtils.escapeWithSpaces(hs, 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(ClassUtil.getAccessFlagsClass(classNode.access) + UnicodeUtils.escapeWithSpaces(hs, classNode.name) + " "); - ctx.next("extends " + UnicodeUtils.escapeWithSpaces(classNode.superName) + " "); + ctx.next("extends " + UnicodeUtils.escapeWithSpaces(hs, classNode.superName) + " "); if (classNode.interfaces != null && !classNode.interfaces.isEmpty()) { String interfaceStr = ""; for (String interfc : classNode.interfaces) { if (interfaceStr.isEmpty()) { - interfaceStr += UnicodeUtils.escapeWithSpaces(interfc); + interfaceStr += UnicodeUtils.escapeWithSpaces(hs, interfc); } else { - interfaceStr += ", " + UnicodeUtils.escapeWithSpaces(interfc); + interfaceStr += ", " + UnicodeUtils.escapeWithSpaces(hs, 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)); + + (classNode.sourceFile == null ? "null" : UnicodeUtils.escape(hs, classNode.sourceFile)) + "\n"); + int hugeIdx = ctx.next(""); + ctx.next("\n// #Fields\n"); + ctx.next(doFields(classNode.fields, nodeToFind, lineFound, hs)); ctx.next("\n// #Methods\n"); - ctx.next(doMethods(classNode.methods, classNode.name, nodeToFind, lineFound)); + ctx.next(doMethods(classNode.methods, classNode.name, nodeToFind, lineFound, hs)); ctx.next("}\n"); + + if (!hs.isEmpty()) + ctx.set(hugeIdx, hs.makeStringsList()); return new DisassembleTuple(ctx.finish(), lineFound.get()); } catch (Throwable e) { return new DisassembleTuple("Class couldn't be decompiled:\n" + e.getClass().getName() + ": " @@ -139,12 +146,12 @@ public class Disassembler { } } - private static String doAnnotations(List annotations) { + private static String doAnnotations(List annotations, HugeStrings hs) { if (annotations == null) return ""; StringContext ctx = new StringContext(annotations.size()); for (AnnotationNode annotationNode : annotations) { - String s = "@" + UnicodeUtils.escapeWithSpaces(annotationNode.desc); + String s = "@" + UnicodeUtils.escapeWithSpaces(hs, annotationNode.desc); if (annotationNode.values != null && !annotationNode.values.isEmpty()) { s += " ("; boolean valBefore = true; @@ -159,10 +166,10 @@ public class Disassembler { boolean w8ing = false; for (String rofl : arr) { if (!w8ing) { - s += UnicodeUtils.escapeWithSpaces(rofl) + "/"; + s += UnicodeUtils.escapeWithSpaces(hs, rofl) + "/"; w8ing = true; } else { - s += UnicodeUtils.escapeWithSpaces(rofl) + "]"; + s += UnicodeUtils.escapeWithSpaces(hs, rofl) + "]"; } } s += ", "; @@ -175,21 +182,21 @@ public class Disassembler { boolean w8ing = false; for (String rofl : arr) { if (!w8ing) { - s += UnicodeUtils.escapeWithSpaces(rofl) + "/"; + s += UnicodeUtils.escapeWithSpaces(hs, rofl) + "/"; w8ing = true; } else { - s += UnicodeUtils.escapeWithSpaces(rofl); + s += UnicodeUtils.escapeWithSpaces(hs, rofl); } } } else { - s += "\"" + UnicodeUtils.escape(String.valueOf(obj)) + "\""; + s += "\"" + UnicodeUtils.escape(hs, String.valueOf(obj)) + "\""; } s += ", "; } s = s.substring(0, s.length() - 2); s += " }]"; } else if (o instanceof String) { - s += "\"" + UnicodeUtils.escapeWithSpaces((String) o) + "\"], "; + s += "\"" + UnicodeUtils.escapeWithSpaces(hs, (String) o) + "\"], "; } else { s += "(" + o.getClass().getName().replace(".", "/") + ") " + o + "], "; } @@ -207,7 +214,7 @@ public class Disassembler { } private static String doMethods(List methods, String className, Object nodeToFind, - AtomicInteger lineFound) throws InterruptedException, ExecutionException { + AtomicInteger lineFound, HugeStrings hs) throws InterruptedException, ExecutionException { Future[] futures = new Future[methods.size()]; for (int i = 0; i < futures.length; i++) { MethodNode mn = methods.get(i); @@ -218,8 +225,8 @@ public class Disassembler { 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 += "\t// #Signature: " + UnicodeUtils.escapeWithSpaces(hs, mn.signature) + "\n"; + String[] dis = disassembleMethod(className, mn, hs); ms += dis[2]; ms += dis[1]; if (mn.visibleAnnotations != null && !mn.visibleAnnotations.isEmpty()) { @@ -239,10 +246,10 @@ public class Disassembler { boolean w8ing = false; for (String rofl : arr) { if (!w8ing) { - ms += UnicodeUtils.escapeWithSpaces(rofl) + "/"; + ms += UnicodeUtils.escapeWithSpaces(hs, rofl) + "/"; w8ing = true; } else { - ms += UnicodeUtils.escapeWithSpaces(rofl) + "]"; + ms += UnicodeUtils.escapeWithSpaces(hs, rofl) + "]"; } } ms += ", "; @@ -255,14 +262,15 @@ public class Disassembler { boolean w8ing = false; for (String rofl : arr) { if (!w8ing) { - ms += UnicodeUtils.escapeWithSpaces(rofl) + "/"; + ms += UnicodeUtils.escapeWithSpaces(hs, rofl) + "/"; w8ing = true; } else { - ms += UnicodeUtils.escapeWithSpaces(rofl); + ms += UnicodeUtils.escapeWithSpaces(hs, rofl); } } } else { - ms += "\"" + UnicodeUtils.escape(String.valueOf(obj)) + "\""; + ms += "\"" + UnicodeUtils.escape(hs, String.valueOf(obj)) + + "\""; } ms += ", "; } @@ -284,15 +292,16 @@ public class Disassembler { if (mn.equals(nodeToFind)) { lineFound.set(ms.split("\\n").length); } - ms += "\t" + ClassUtil.getAccessFlagsFull(mn.access) + UnicodeUtils.escapeWithSpaces(mn.name) - + " " + UnicodeUtils.escapeWithSpaces(mn.desc) + " "; + ms += "\t" + ClassUtil.getAccessFlagsFull(mn.access) + + UnicodeUtils.escapeWithSpaces(hs, mn.name) + " " + + UnicodeUtils.escapeWithSpaces(hs, mn.desc) + " "; if (mn.exceptions != null && !mn.exceptions.isEmpty()) { String exceptionStr = ""; for (String exc : mn.exceptions) { if (exceptionStr.isEmpty()) { - exceptionStr += UnicodeUtils.escapeWithSpaces(exc); + exceptionStr += UnicodeUtils.escapeWithSpaces(hs, exc); } else { - exceptionStr += ", " + UnicodeUtils.escapeWithSpaces(exc); + exceptionStr += ", " + UnicodeUtils.escapeWithSpaces(hs, exc); } } if (!exceptionStr.isEmpty()) @@ -321,15 +330,15 @@ public class Disassembler { return s; } - private static String doFields(List fields, Object nodeToFind, AtomicInteger lineFound) { + private static String doFields(List fields, Object nodeToFind, AtomicInteger lineFound, HugeStrings hs) { StringContext ctx = new StringContext(fields.size()); for (FieldNode fn : fields) { String s = ""; if (fn.signature != null) - s += "\t// #Signature: " + UnicodeUtils.escapeWithSpaces(fn.signature) + "\n"; + s += "\t// #Signature: " + UnicodeUtils.escapeWithSpaces(hs, fn.signature) + "\n"; if (fn.visibleAnnotations != null && !fn.visibleAnnotations.isEmpty()) { for (AnnotationNode annotationNode : fn.visibleAnnotations) { - s += "\t@" + UnicodeUtils.escapeWithSpaces(annotationNode.desc); + s += "\t@" + UnicodeUtils.escapeWithSpaces(hs, annotationNode.desc); if (annotationNode.values != null && !annotationNode.values.isEmpty()) { s += " ("; boolean valBefore = true; @@ -344,10 +353,10 @@ public class Disassembler { boolean w8ing = false; for (String rofl : arr) { if (!w8ing) { - s += UnicodeUtils.escapeWithSpaces(rofl) + "/"; + s += UnicodeUtils.escapeWithSpaces(hs, rofl) + "/"; w8ing = true; } else { - s += UnicodeUtils.escapeWithSpaces(rofl) + "]"; + s += UnicodeUtils.escapeWithSpaces(hs, rofl) + "]"; } } s += ", "; @@ -360,14 +369,14 @@ public class Disassembler { boolean w8ing = false; for (String rofl : arr) { if (!w8ing) { - s += UnicodeUtils.escapeWithSpaces(rofl) + "/"; + s += UnicodeUtils.escapeWithSpaces(hs, rofl) + "/"; w8ing = true; } else { - s += UnicodeUtils.escapeWithSpaces(rofl); + s += UnicodeUtils.escapeWithSpaces(hs, rofl); } } } else { - s += "\"" + UnicodeUtils.escape(String.valueOf(obj)) + "\""; + s += "\"" + UnicodeUtils.escape(hs, String.valueOf(obj)) + "\""; } s += ", "; } @@ -390,9 +399,9 @@ public class Disassembler { lineFound.set(s.split("\\n").length); } s += "\t" + ClassUtil.getAccessFlagsFull(fn.access).replace("varargs", "transient") - + UnicodeUtils.escapeWithSpaces(fn.desc) + " " + UnicodeUtils.escapeWithSpaces(fn.name); + + UnicodeUtils.escapeWithSpaces(hs, fn.desc) + " " + UnicodeUtils.escapeWithSpaces(hs, fn.name); if (fn.value != null) { - s += " = " + ClassUtil.getDecompiledValue(fn.value, fn.desc, true); + s += " = " + ClassUtil.getDecompiledValue(fn.value, fn.desc, true, hs); } s += "\n"; ctx.next(s); @@ -400,7 +409,7 @@ public class Disassembler { return ctx.finish(); } - private static String[] disassembleMethod(String className, MethodNode mn) { + private static String[] disassembleMethod(String className, MethodNode mn, HugeStrings hs) { HashMap labels = new HashMap(); String localVarTable; String tryCatchTable; @@ -414,10 +423,10 @@ public class Disassembler { 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:" + ctx.next("\t// " + UnicodeUtils.escapeWithSpaces(hs, lvn.name) + ": " + + UnicodeUtils.escapeWithSpaces(hs, 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(hs, lvn.signature) + "\n"); } localVarTable = ctx.finish(); } else @@ -427,8 +436,9 @@ public class Disassembler { StringContext ctx = new StringContext(list.size() + 1); ctx.next("\t// #TryCatch:\n"); for (TryCatchBlockNode tcbn : mn.tryCatchBlocks) { - 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"); + ctx.next("\t// " + UnicodeUtils.escapeWithSpaces(hs, 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 @@ -436,7 +446,7 @@ public class Disassembler { AbstractInsnNode[] insns = mn.instructions.toArray(); StringContext ctx = new StringContext(insns.length); for (AbstractInsnNode n : insns) { - ctx.next(disassembleInstruction(n, labels)); + ctx.next(disassembleInstruction(n, labels, hs)); } return new String[] { ctx.finish(), localVarTable, tryCatchTable }; } @@ -444,17 +454,17 @@ public class Disassembler { public static final HashMap iiMap = new HashMap<>(); static { - iiMap.put(FieldInsnNode.class, (n, labels) -> { + iiMap.put(FieldInsnNode.class, (n, labels, hs) -> { 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"; + + UnicodeUtils.escapeWithSpaces(hs, node.desc) + " " + UnicodeUtils.escapeWithSpaces(hs, node.owner) + + "/" + UnicodeUtils.escapeWithSpaces(hs, node.name).replace("/", "\\u002F") + "\n"; }); - iiMap.put(LabelNode.class, (n, labels) -> { + iiMap.put(LabelNode.class, (n, labels, hs) -> { LabelNode node = (LabelNode) n; return "\t\t// label " + labels.get(node.getLabel()) + "\n"; }); - iiMap.put(FrameNode.class, (n, labels) -> { + iiMap.put(FrameNode.class, (n, labels, hs) -> { FrameNode node = (FrameNode) n; String type = ""; switch (node.type) { @@ -485,7 +495,7 @@ public class Disassembler { arr.add(null); } else { if (o instanceof String) { - arr.add("\"" + UnicodeUtils.escapeWithSpaces((String) o) + "\""); + arr.add("\"" + UnicodeUtils.escapeWithSpaces(hs, (String) o) + "\""); } else if (o instanceof LabelNode) { arr.add("(label) " + labels.get(((LabelNode) o).getLabel())); } else if (o instanceof Integer) { @@ -511,7 +521,7 @@ public class Disassembler { arr.add(null); } else { if (o instanceof String) { - arr.add("\"" + UnicodeUtils.escapeWithSpaces((String) o) + "\""); + arr.add("\"" + UnicodeUtils.escapeWithSpaces(hs, (String) o) + "\""); } else if (o instanceof LabelNode) { arr.add("(label) " + labels.get(((LabelNode) o).getLabel())); } else if (o instanceof Integer) { @@ -532,18 +542,18 @@ public class Disassembler { s += "\n"; return s; }); - iiMap.put(LineNumberNode.class, (n, labels) -> { + iiMap.put(LineNumberNode.class, (n, labels, hs) -> { LineNumberNode node = (LineNumberNode) n; return "\t\t// line " + node.line + " " + labels.get(node.start.getLabel()) + "\n"; }); - iiMap.put(InvokeDynamicInsnNode.class, (n, labels) -> { + iiMap.put(InvokeDynamicInsnNode.class, (n, labels, hs) -> { 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: " - + UnicodeUtils.escapeWithSpaces(node.desc) + "\n\t\t\tHandle: [\n\t\t\t\tname: " - + UnicodeUtils.escapeWithSpaces(node.bsm.getName()) + "\n\t\t\t\towner: " - + UnicodeUtils.escapeWithSpaces(node.bsm.getOwner()) + "\n\t\t\t\tdesc: " - + UnicodeUtils.escapeWithSpaces(node.bsm.getDesc()) + "\n\t\t\t\tisInterface: " + + UnicodeUtils.escapeWithSpaces(hs, node.name).replace("/", "\\u002F") + "\n\t\t\tdesc: " + + UnicodeUtils.escapeWithSpaces(hs, node.desc) + "\n\t\t\tHandle: [\n\t\t\t\tname: " + + UnicodeUtils.escapeWithSpaces(hs, node.bsm.getName()) + "\n\t\t\t\towner: " + + UnicodeUtils.escapeWithSpaces(hs, node.bsm.getOwner()) + "\n\t\t\t\tdesc: " + + UnicodeUtils.escapeWithSpaces(hs, node.bsm.getDesc()) + "\n\t\t\t\tisInterface: " + 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) { @@ -555,40 +565,41 @@ public class Disassembler { // Reflection s += "\t\t\t\tType: [\n\t\t\t\t\ttype: " + ClassUtil.getClassNameFromType(type) + "\n\t\t\t\t\tstart: " + valueBegin + "\n\t\t\t\t\tend: " + valueEnd + "\n\t\t\t\t\tbuf: " - + ClassUtil.getDecompiledValue(buf, ""); + + ClassUtil.getDecompiledValue(buf, "", hs); s += "\n\t\t\t\t]\n"; } 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: " - + UnicodeUtils.escapeWithSpaces(h.getOwner()) + "\n\t\t\t\t\tdesc: " - + UnicodeUtils.escapeWithSpaces(h.getDesc()) + "\n\t\t\t\t\tisInterface: " + h.isInterface() - + "\n\t\t\t\t\ttag: " + OpcodesReverse.reverseHandleOpcode(h.getTag()); + + UnicodeUtils.escapeWithSpaces(hs, h.getName()).replace("/", "\\u002F") + + "\n\t\t\t\t\towner: " + UnicodeUtils.escapeWithSpaces(hs, h.getOwner()) + + "\n\t\t\t\t\tdesc: " + UnicodeUtils.escapeWithSpaces(hs, h.getDesc()) + + "\n\t\t\t\t\tisInterface: " + h.isInterface() + "\n\t\t\t\t\ttag: " + + OpcodesReverse.reverseHandleOpcode(h.getTag()); s += "\n\t\t\t\t]\n"; } else { - s += "\t\t\t\t" + ClassUtil.getDecompiledValue(l, "") + "\n"; + s += "\t\t\t\t" + ClassUtil.getDecompiledValue(l, "", hs) + "\n"; } } s += "\t\t\t]\n\t\t]\n"; return s; }); - iiMap.put(MethodInsnNode.class, (n, labels) -> { + iiMap.put(MethodInsnNode.class, (n, labels, hs) -> { 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"; + + UnicodeUtils.escapeWithSpaces(hs, node.desc) + " " + UnicodeUtils.escapeWithSpaces(hs, node.owner) + + "/" + UnicodeUtils.escapeWithSpaces(hs, node.name).replace("/", "\\u002F") + "\n"; }); - iiMap.put(TypeInsnNode.class, (n, labels) -> { + iiMap.put(TypeInsnNode.class, (n, labels, hs) -> { TypeInsnNode node = (TypeInsnNode) n; return "\t\t" + OpcodesReverse.reverseOpcode(node.getOpcode()) + " " - + UnicodeUtils.escapeWithSpaces(node.desc) + "\n"; + + UnicodeUtils.escapeWithSpaces(hs, node.desc) + "\n"; }); - iiMap.put(MultiANewArrayInsnNode.class, (n, labels) -> { + iiMap.put(MultiANewArrayInsnNode.class, (n, labels, hs) -> { MultiANewArrayInsnNode node = (MultiANewArrayInsnNode) n; return "\t\t" + OpcodesReverse.reverseOpcode(node.getOpcode()) + " " - + UnicodeUtils.escapeWithSpaces(node.desc) + " " + node.dims + "\n"; + + UnicodeUtils.escapeWithSpaces(hs, node.desc) + " " + node.dims + "\n"; }); - iiMap.put(LdcInsnNode.class, (n, labels) -> { + iiMap.put(LdcInsnNode.class, (n, labels, hs) -> { LdcInsnNode node = (LdcInsnNode) n; if (node.cst instanceof Type) { Type type = (Type) node.cst; @@ -598,23 +609,23 @@ public class Disassembler { // Reflection String s = "\t\t" + OpcodesReverse.reverseOpcode(n.getOpcode()) + " Type: [\n\t\t\ttype: " + ClassUtil.getClassNameFromType(type) + "\n\t\t\tstart: " + valueBegin + "\n\t\t\tend: " - + valueEnd + "\n\t\t\tbuf: " + ClassUtil.getDecompiledValue(buf, ""); + + valueEnd + "\n\t\t\tbuf: " + ClassUtil.getDecompiledValue(buf, "", hs); s += "\n\t\t]\n"; return s; } else { return "\t\t" + OpcodesReverse.reverseOpcode(node.getOpcode()) + " " - + ClassUtil.getDecompiledValue(node.cst, "") + "\n"; + + ClassUtil.getDecompiledValue(node.cst, "", hs) + "\n"; } }); - iiMap.put(VarInsnNode.class, (n, labels) -> { + iiMap.put(VarInsnNode.class, (n, labels, hs) -> { VarInsnNode node = (VarInsnNode) n; return "\t\t" + OpcodesReverse.reverseOpcode(n.getOpcode()) + " " + node.var + "\n"; }); - iiMap.put(InsnNode.class, (n, labels) -> { + iiMap.put(InsnNode.class, (n, labels, hs) -> { InsnNode node = (InsnNode) n; return "\t\t" + OpcodesReverse.reverseOpcode(n.getOpcode()) + "\n"; }); - iiMap.put(IntInsnNode.class, (n, labels) -> { + iiMap.put(IntInsnNode.class, (n, labels, hs) -> { IntInsnNode node = (IntInsnNode) n; if (n.getOpcode() == Opcodes.NEWARRAY) { return "\t\t" + OpcodesReverse.reverseOpcode(n.getOpcode()) + " " @@ -623,12 +634,12 @@ public class Disassembler { return "\t\t" + OpcodesReverse.reverseOpcode(n.getOpcode()) + " " + node.operand + "\n"; } }); - iiMap.put(JumpInsnNode.class, (n, labels) -> { + iiMap.put(JumpInsnNode.class, (n, labels, hs) -> { JumpInsnNode node = (JumpInsnNode) n; return "\t\t" + OpcodesReverse.reverseOpcode(n.getOpcode()) + " " + labels.get(node.label.getLabel()) + "\n"; }); - iiMap.put(TableSwitchInsnNode.class, (n, labels) -> { + iiMap.put(TableSwitchInsnNode.class, (n, labels, hs) -> { 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()) @@ -639,7 +650,7 @@ public class Disassembler { s += "\t\t\t]\n\t\t]\n"; return s; }); - iiMap.put(LookupSwitchInsnNode.class, (n, labels) -> { + iiMap.put(LookupSwitchInsnNode.class, (n, labels, hs) -> { 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"; @@ -653,20 +664,20 @@ public class Disassembler { s += "\t\t\t]\n\t\t]\n"; return s; }); - iiMap.put(IincInsnNode.class, (n, labels) -> { + iiMap.put(IincInsnNode.class, (n, labels, hs) -> { IincInsnNode node = (IincInsnNode) n; return "\t\t" + OpcodesReverse.reverseOpcode(n.getOpcode()) + " " + node.var + " " + node.incr + "\n"; }); } static interface InstructionInterface { - String apply(AbstractInsnNode n, HashMap labels); + String apply(AbstractInsnNode n, HashMap labels, HugeStrings hs); } - public static String disassembleInstruction(AbstractInsnNode n, HashMap labels) { + public static String disassembleInstruction(AbstractInsnNode n, HashMap labels, HugeStrings hs) { InstructionInterface ii = iiMap.get(n.getClass()); if (ii != null) - return ii.apply(n, labels); + return ii.apply(n, labels, hs); else return "\t\tNOT HANDLED! " + OpcodesReverse.reverseOpcode(n.getOpcode()) + " " + n.getClass().getSimpleName() + "\n"; diff --git a/src/me/ByteEdit/edit/HugeStrings.java b/src/me/ByteEdit/edit/HugeStrings.java new file mode 100644 index 0000000..1213d90 --- /dev/null +++ b/src/me/ByteEdit/edit/HugeStrings.java @@ -0,0 +1,53 @@ +package me.ByteEdit.edit; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; + +import me.ByteEdit.utils.UnicodeUtils; + +public class HugeStrings { + + public static final int THRESHOLD = 1000; + private final HashMap map = new HashMap<>(); + + public String onString(String s) { + synchronized (map) { + HugeData i = map.get(s); + if (i == null) + map.put(s, i = new HugeData(map.size(), UnicodeUtils.escape(this, s, true))); + return "#" + Integer.toString(i.id); + } + } + + public boolean isEmpty() { + return map.isEmpty(); + } + + public String makeStringsList() { + StringContext ctx = new StringContext(map.size()); + List list = new ArrayList<>(map.values()); + list.sort((o1, o2) -> Integer.compare(o1.id, o2.id)); + for (HugeData hd : list) { + StringBuilder sb = new StringBuilder(20 + hd.escaped.length()); + sb.append('#'); + sb.append(Integer.toString(hd.id)); + sb.append(": "); + sb.append(hd.escaped); + sb.append('\n'); + ctx.next(sb.toString()); + } + return ctx.finish(); + } + + private static class HugeData { + int id; + String escaped; + + public HugeData(int id, String escaped) { + this.id = id; + this.escaped = escaped; + } + } + +} diff --git a/src/me/ByteEdit/edit/HugeStringsRev.java b/src/me/ByteEdit/edit/HugeStringsRev.java new file mode 100644 index 0000000..8ba6607 --- /dev/null +++ b/src/me/ByteEdit/edit/HugeStringsRev.java @@ -0,0 +1,20 @@ +package me.ByteEdit.edit; + +import java.util.HashMap; + +public class HugeStringsRev { + + private final HashMap map = new HashMap<>(); + + public void add(int i, String s) { + map.put(Integer.valueOf(i), s); + } + + public String get(int i) { + String s = map.get(Integer.valueOf(i)); + if (s == null) + s = "#" + Integer.toString(i); + return s; + } + +} diff --git a/src/me/ByteEdit/edit/StringContext.java b/src/me/ByteEdit/edit/StringContext.java index 4ef35b4..a0c3fe3 100644 --- a/src/me/ByteEdit/edit/StringContext.java +++ b/src/me/ByteEdit/edit/StringContext.java @@ -16,8 +16,16 @@ public class StringContext { arrs = new String[amt]; } - public void next(String s) { + public int next(String s) { + int i = idx; len += (arrs[idx++] = s).length(); + return i; + } + + public void set(int i, String s) { + if (arrs[i] != null) + len -= arrs[i].length(); + len += (arrs[i] = s).length(); } public String finish() { diff --git a/src/me/ByteEdit/main/Main.java b/src/me/ByteEdit/main/Main.java index 52782fb..6bc8a6b 100644 --- a/src/me/ByteEdit/main/Main.java +++ b/src/me/ByteEdit/main/Main.java @@ -621,11 +621,11 @@ public class Main extends JFrame { line = line.substring(2); if (line.startsWith("invoke")) { String[] split = line.split(" "); - String desc = UnicodeUtils.unescape(split[1]); + String desc = UnicodeUtils.unescape(null, split[1], true); String target = split[2]; int index = target.lastIndexOf("/"); - String className = UnicodeUtils.unescape(target.substring(0, index)); - String methodName = UnicodeUtils.unescape(target.substring(index + 1)); + String className = UnicodeUtils.unescape(null, target.substring(0, index), true); + String methodName = UnicodeUtils.unescape(null, target.substring(index + 1), true); ClassNode classNode = classNodes.get(getFullName(className)); if (classNode == null) { return; @@ -644,7 +644,7 @@ public class Main extends JFrame { } } else if (line.startsWith("new ")) { String[] split = line.split(" "); - String className = UnicodeUtils.unescape(split[1]); + String className = UnicodeUtils.unescape(null, split[1], true); ClassNode classNode = classNodes.get(getFullName(className)); if (classNode == null) { return; @@ -653,11 +653,11 @@ public class Main extends JFrame { } else if (line.startsWith("getstatic ") || line.startsWith("putstatic ") || line.startsWith("getfield ") || line.startsWith("putfield ")) { String[] split = line.split(" "); - String desc = UnicodeUtils.unescape(split[1]); + String desc = UnicodeUtils.unescape(null, split[1], true); String target = split[2]; int index = target.lastIndexOf("/"); - String className = UnicodeUtils.unescape(target.substring(0, index)); - String fieldName = UnicodeUtils.unescape(target.substring(index + 1)); + String className = UnicodeUtils.unescape(null, target.substring(0, index), true); + String fieldName = UnicodeUtils.unescape(null, target.substring(index + 1), true); ClassNode classNode = classNodes.get(getFullName(className)); if (classNode == null) { return; @@ -721,10 +721,12 @@ public class Main extends JFrame { if (s.contains(" extends ")) s = s.substring(0, s.lastIndexOf(" extends ")); String[] split = s.split(" "); - String className = UnicodeUtils.unescape(split[split.length - 1]); + String className = UnicodeUtils.unescape(null, split[split.length - 1], true); renameBox.className = className; - String name = UnicodeUtils.unescape(m.pattern() == renameableFieldPattern ? m.group(2) : m.group(1)); - String desc = UnicodeUtils.unescape(m.pattern() == renameableFieldPattern ? m.group(1) : m.group(2)); + String name = UnicodeUtils.unescape(null, m.pattern() == renameableFieldPattern ? m.group(2) : m.group(1), + true); + String desc = UnicodeUtils.unescape(null, m.pattern() == renameableFieldPattern ? m.group(1) : m.group(2), + true); renameBox.name = name; renameBox.desc = desc; renameBox.txtName.setText(name); diff --git a/src/me/ByteEdit/utils/ClassUtil.java b/src/me/ByteEdit/utils/ClassUtil.java index d7ddeb3..5069bd5 100644 --- a/src/me/ByteEdit/utils/ClassUtil.java +++ b/src/me/ByteEdit/utils/ClassUtil.java @@ -6,6 +6,8 @@ import java.util.HashSet; import org.objectweb.asm.Type; +import me.ByteEdit.edit.HugeStrings; + public class ClassUtil { public static final int ACC_PUBLIC = 0x0001; @@ -525,28 +527,29 @@ public class ClassUtil { 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(String.class, (o, desc, escapeSpaces, hs) -> "\"" + + (escapeSpaces ? UnicodeUtils.escapeWithSpaces(hs, (String) o) : UnicodeUtils.escape(hs, (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"); + (o, desc, escape, hs) -> desc.equals("Z") ? (((int) o) == 0 ? "false" : "true") : o.toString()); + diMap.put(Long.class, (o, desc, escape, hs) -> o.toString() + "l"); + diMap.put(Float.class, (o, desc, escape, hs) -> o.toString() + "f"); } static interface DecompilationInterface { - String apply(Object o, String desc, boolean escape); + String apply(Object o, String desc, boolean escape, HugeStrings hs); } - public static String getDecompiledValue(Object o, String desc, boolean escapeSpaces) { + public static String getDecompiledValue(Object o, String desc, boolean escapeSpaces, HugeStrings hs) { DecompilationInterface di = diMap.get(o.getClass()); if (di != null) - return di.apply(o, desc, escapeSpaces); + return di.apply(o, desc, escapeSpaces, hs); else return o.toString(); } - public static String getDecompiledValue(Object o, String desc) { - return getDecompiledValue(o, desc, false); + public static String getDecompiledValue(Object o, String desc, HugeStrings hs) { + return getDecompiledValue(o, desc, false, hs); } public static Object getCastedValue(String o, String className) { diff --git a/src/me/ByteEdit/utils/UnicodeUtils.java b/src/me/ByteEdit/utils/UnicodeUtils.java index 08584d4..eedf30d 100644 --- a/src/me/ByteEdit/utils/UnicodeUtils.java +++ b/src/me/ByteEdit/utils/UnicodeUtils.java @@ -1,11 +1,26 @@ package me.ByteEdit.utils; +import me.ByteEdit.edit.HugeStrings; +import me.ByteEdit.edit.HugeStringsRev; + public class UnicodeUtils { - public static String unescape(String s) { + public static String unescape(HugeStringsRev hsr, String s) { + return unescape(hsr, s, false); + } + + public static String unescape(HugeStringsRev hsr, String s, boolean force) { if (s == null) { return null; } + if (!force && !s.isEmpty() && s.charAt(0) == '#' && s.length() < 12) { + try { + int id = Integer.parseInt(s.substring(1)); + return hsr.get(id); + } catch (NumberFormatException ex) { + // Doesn't seem like a HugeString + } + } StringBuilder sb = new StringBuilder(); char unicodeBuffer = 0; int stage = 0; @@ -78,10 +93,13 @@ public class UnicodeUtils { return sb.toString(); } - public static String escapeWithSpaces(String s) { + public static String escapeWithSpaces(HugeStrings hs, String s) { if (s == null) { return null; } + if (s.length() > HugeStrings.THRESHOLD) { + return hs.onString(s); + } StringBuilder sb = new StringBuilder(); char[] arr = s.toCharArray(); int i = 0; @@ -92,6 +110,9 @@ public class UnicodeUtils { if (arr[0] == '/') { sb.append("\\u002F"); i++; + } else if (arr[0] == '#') { + sb.append("\\u0023"); + i++; } if (arr[len - 1] == '/') { addSlash = true; @@ -158,12 +179,26 @@ public class UnicodeUtils { return sb.toString(); } - public static String escape(String s) { + public static String escape(HugeStrings hs, String s) { + return escape(hs, s, false); + } + + public static String escape(HugeStrings hs, String s, boolean force) { if (s == null) { return null; } - StringBuilder sb = new StringBuilder(); - for (char c : s.toCharArray()) { + if (!force && s.length() > HugeStrings.THRESHOLD) { + return hs.onString(s); + } + char[] arr = s.toCharArray(); + StringBuilder sb = new StringBuilder(arr.length); + int i = 0; + if (arr.length > 0 && arr[0] == '#') { + sb.append("\\u0023"); + i++; + } + for (; i < arr.length; i++) { + char c = arr[i]; switch (c) { case 'Ä': case 'ä':