Some refactoring, added "GoTo" feature

This commit is contained in:
SuspiciousActivity committed 2018-08-29 17:32:42 +02:00
1 parent e81f5f6ee9
commit 6995318302
13 files changed
+319 -189

No files matched your search

+2
View File
@@ -11,3 +11,5 @@ To search/replace in a file, press CTRL + F.
To open a class, press CTRL + T. To open a class, press CTRL + T.
To change settings like auto-computation of stack frames and max locals/stack press CTRL + O. To change settings like auto-computation of stack frames and max locals/stack press CTRL + O.
To go to the method definition of the selected line's invoke-method press CTRL + G.
@@ -1,6 +1,5 @@
package me.ByteEdit.main; package me.ByteEdit.edit;
import java.awt.Color;
import java.io.StringReader; import java.io.StringReader;
import java.lang.reflect.Constructor; import java.lang.reflect.Constructor;
import java.util.ArrayList; import java.util.ArrayList;
@@ -42,10 +41,14 @@ import org.objectweb.asm.tree.TryCatchBlockNode;
import org.objectweb.asm.tree.TypeInsnNode; import org.objectweb.asm.tree.TypeInsnNode;
import org.objectweb.asm.tree.VarInsnNode; import org.objectweb.asm.tree.VarInsnNode;
import me.ByteEdit.main.Main;
import me.ByteEdit.utils.ClassUtil;
import me.ByteEdit.utils.CustomBufferedReader;
public class Assembler { public class Assembler {
public static ClassNode assemble(String input) { public static ClassNode assemble(String input) {
Main.textArea.removeAllLineHighlights(); Main.txtByteEditView.removeAllLineHighlights();
CustomBufferedReader read = null; CustomBufferedReader read = null;
try { try {
ClassNode clazz = new ClassNode(); ClassNode clazz = new ClassNode();
@@ -80,15 +83,15 @@ public class Assembler {
{ {
s = s.substring(0, s.length() - 2); s = s.substring(0, s.length() - 2);
if (s.contains(" implements ")) { if (s.contains(" implements ")) {
String interfaces = s.substring(s.indexOf(" implements ") + 12); String interfaces = s.substring(s.lastIndexOf(" implements ") + 12);
clazz.interfaces = new ArrayList<>(); clazz.interfaces = new ArrayList<>();
for (String interf : interfaces.split(", ")) { for (String interf : interfaces.split(", ")) {
clazz.interfaces.add(interf); clazz.interfaces.add(interf);
} }
s = s.substring(0, s.indexOf(" implements ")); s = s.substring(0, s.lastIndexOf(" implements "));
} }
clazz.superName = s.substring(s.indexOf(" extends ") + 9); clazz.superName = s.substring(s.lastIndexOf(" extends ") + 9);
s = s.substring(0, s.indexOf(" extends ")); s = s.substring(0, s.lastIndexOf(" extends "));
String[] split = s.split(" "); String[] split = s.split(" ");
clazz.name = split[split.length - 1]; clazz.name = split[split.length - 1];
clazz.access = ClassUtil.ACC_SUPER; clazz.access = ClassUtil.ACC_SUPER;
@@ -319,11 +322,11 @@ public class Assembler {
} else if (!s.startsWith("\t")) { } else if (!s.startsWith("\t")) {
s = s.substring(0, s.length() - 2); s = s.substring(0, s.length() - 2);
if (s.contains(" throws ")) { if (s.contains(" throws ")) {
String exceptions = s.substring(s.indexOf(" throws ") + 8); String exceptions = s.substring(s.lastIndexOf(" throws ") + 8);
for (String excp : exceptions.split(", ")) { for (String excp : exceptions.split(", ")) {
node.exceptions.add(excp); node.exceptions.add(excp);
} }
s = s.substring(0, s.indexOf(" throws ")); s = s.substring(0, s.lastIndexOf(" throws "));
} }
String[] split = s.split(" "); String[] split = s.split(" ");
node.desc = split[split.length - 1]; node.desc = split[split.length - 1];
@@ -410,7 +413,8 @@ public class Assembler {
} catch (Throwable e) { } catch (Throwable e) {
System.err.println("Error at line: " + read.currentLine); System.err.println("Error at line: " + read.currentLine);
try { try {
Main.textArea.addLineHighlight(read.currentLine, Color.RED.darker()); Main.txtByteEditView.setCaretPosition(Main.txtByteEditView.getLineStartOffset(read.currentLine));
Main.showError(e.getMessage());
} catch (BadLocationException e1) { } catch (BadLocationException e1) {
System.err.println("Can't show line!"); System.err.println("Can't show line!");
} }
@@ -1,4 +1,4 @@
package me.ByteEdit.main; package me.ByteEdit.edit;
import java.lang.reflect.Field; import java.lang.reflect.Field;
import java.util.ArrayList; import java.util.ArrayList;
@@ -8,6 +8,7 @@ import java.util.List;
import org.objectweb.asm.Handle; import org.objectweb.asm.Handle;
import org.objectweb.asm.Label; import org.objectweb.asm.Label;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.Type; import org.objectweb.asm.Type;
import org.objectweb.asm.tree.AbstractInsnNode; import org.objectweb.asm.tree.AbstractInsnNode;
import org.objectweb.asm.tree.AnnotationNode; import org.objectweb.asm.tree.AnnotationNode;
@@ -34,13 +35,46 @@ import org.objectweb.asm.tree.TryCatchBlockNode;
import org.objectweb.asm.tree.TypeInsnNode; import org.objectweb.asm.tree.TypeInsnNode;
import org.objectweb.asm.tree.VarInsnNode; import org.objectweb.asm.tree.VarInsnNode;
import me.ByteEdit.utils.ClassUtil;
import me.ByteEdit.utils.OpcodesReverse;
public class Disassembler { public class Disassembler {
public static String disassemble(ClassNode classNode) { public static String disassemble(ClassNode classNode) {
return disassemble(classNode, null).getDisassembly();
}
public static class DisassembleTuple {
private final String dis;
private final int line;
public DisassembleTuple(String dis) {
this.dis = dis;
this.line = -1;
}
public DisassembleTuple(String dis, int line) {
this.dis = dis;
this.line = line;
}
public String getDisassembly() {
return dis;
}
public int getLine() {
return line;
}
}
public static DisassembleTuple disassemble(ClassNode classNode, MethodNode methodToFind) {
if (classNode == null) { if (classNode == null) {
return "ClassNode is null! This is not a valid java class file!"; return new DisassembleTuple("ClassNode is null! This is not a valid java class file!");
} }
try { try {
int lineFound = -1;
String s = ""; String s = "";
s += "// #Annotations\n"; s += "// #Annotations\n";
if (classNode.visibleAnnotations != null && !classNode.visibleAnnotations.isEmpty()) { if (classNode.visibleAnnotations != null && !classNode.visibleAnnotations.isEmpty()) {
@@ -264,6 +298,9 @@ public class Disassembler {
s += "\n"; s += "\n";
} }
} }
if (mn.equals(methodToFind)) {
lineFound = s.split("\\n").length;
}
s += "\t" + ClassUtil.getAccessFlagsFull(mn.access) + mn.name + " " + mn.desc + " "; s += "\t" + ClassUtil.getAccessFlagsFull(mn.access) + mn.name + " " + mn.desc + " ";
if (mn.exceptions != null && !mn.exceptions.isEmpty()) { if (mn.exceptions != null && !mn.exceptions.isEmpty()) {
String exceptionStr = ""; String exceptionStr = "";
@@ -287,10 +324,10 @@ public class Disassembler {
} }
} }
s += "}\n"; s += "}\n";
return s; return new DisassembleTuple(s, lineFound);
} catch (Throwable e) { } catch (Throwable e) {
return "Class couldn't be decompiled:\n" + e.getClass().getName() + ": " + e.getMessage() + "\n" 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"; + Arrays.toString(e.getStackTrace()).replace(", ", "\n\tat ").replace("[", "\tat ").replace("]", "") + "\n");
} }
} }
@@ -317,21 +354,25 @@ public class Disassembler {
} }
} }
for (AbstractInsnNode n : mn.instructions.toArray()) { for (AbstractInsnNode n : mn.instructions.toArray()) {
s += disassembleInstruction(n, labels);
}
return new String[] { s, localVarTable, tryCatchTable };
}
public static String disassembleInstruction(AbstractInsnNode n, HashMap<Label, Integer> labels) {
switch (n.getClass().getSimpleName()) { switch (n.getClass().getSimpleName()) {
case "FieldInsnNode": { case "FieldInsnNode": {
FieldInsnNode node = (FieldInsnNode) n; FieldInsnNode node = (FieldInsnNode) n;
s += "\t\t" + OpcodesReverse.reverseOpcode(node.getOpcode()) + " " + node.desc + " " + node.owner + "/" + node.name return "\t\t" + OpcodesReverse.reverseOpcode(node.getOpcode()) + " " + node.desc + " " + node.owner + "/" + node.name
+ "\n"; + "\n";
break;
} }
case "LabelNode": { case "LabelNode": {
LabelNode node = (LabelNode) n; LabelNode node = (LabelNode) n;
s += "\t\t// label " + labels.get(node.getLabel()) + "\n"; return "\t\t// label " + labels.get(node.getLabel()) + "\n";
break;
} }
case "FrameNode": { case "FrameNode": {
FrameNode node = (FrameNode) n; FrameNode node = (FrameNode) n;
s += "\t\t// frame " + node.type + " l:"; String s = "\t\t// frame " + node.type + " l:";
ArrayList<String> arr = new ArrayList<>(); ArrayList<String> arr = new ArrayList<>();
if (node.local != null) { if (node.local != null) {
for (Object o : node.local) { for (Object o : node.local) {
@@ -372,19 +413,18 @@ public class Disassembler {
s += "null"; s += "null";
} }
s += "\n"; s += "\n";
break; return s;
} }
case "LineNumberNode": { case "LineNumberNode": {
LineNumberNode node = (LineNumberNode) n; LineNumberNode node = (LineNumberNode) n;
s += "\t\t// line " + node.line + " " + labels.get(node.start.getLabel()) + "\n"; return "\t\t// line " + node.line + " " + labels.get(node.start.getLabel()) + "\n";
break;
} }
case "InvokeDynamicInsnNode": { case "InvokeDynamicInsnNode": {
InvokeDynamicInsnNode node = (InvokeDynamicInsnNode) n; InvokeDynamicInsnNode node = (InvokeDynamicInsnNode) n;
s += "\t\t" + OpcodesReverse.reverseOpcode(node.getOpcode()) + " [\n\t\t\tname: " + node.name + "\n\t\t\tdesc: " String s = "\t\t" + OpcodesReverse.reverseOpcode(node.getOpcode()) + " [\n\t\t\tname: " + node.name + "\n\t\t\tdesc: "
+ node.desc + "\n\t\t\tHandle: [\n\t\t\t\tname: " + node.bsm.getName() + "\n\t\t\t\towner: " + node.desc + "\n\t\t\tHandle: [\n\t\t\t\tname: " + node.bsm.getName() + "\n\t\t\t\towner: " + node.bsm.getOwner()
+ node.bsm.getOwner() + "\n\t\t\t\tdesc: " + node.bsm.getDesc() + "\n\t\t\t\tisInterface: " + "\n\t\t\t\tdesc: " + node.bsm.getDesc() + "\n\t\t\t\tisInterface: " + node.bsm.isInterface() + "\n\t\t\t\ttag: "
+ node.bsm.isInterface() + "\n\t\t\t\ttag: " + node.bsm.getTag() + "\n\t\t\t]\n\t\t\targs: [\n"; + node.bsm.getTag() + "\n\t\t\t]\n\t\t\targs: [\n";
for (Object l : node.bsmArgs) { for (Object l : node.bsmArgs) {
if (l.getClass().getName().equals("org.objectweb.asm.Type")) { if (l.getClass().getName().equals("org.objectweb.asm.Type")) {
Type type = (Type) l; Type type = (Type) l;
@@ -408,31 +448,28 @@ public class Disassembler {
} else if (l.getClass().getName().equals("org.objectweb.asm.Handle")) { } else if (l.getClass().getName().equals("org.objectweb.asm.Handle")) {
Handle h = (Handle) l; Handle h = (Handle) l;
s += "\t\t\t\tHandle: [\n\t\t\t\t\tname: " + h.getName() + "\n\t\t\t\t\towner: " + h.getOwner() s += "\t\t\t\tHandle: [\n\t\t\t\t\tname: " + h.getName() + "\n\t\t\t\t\towner: " + h.getOwner()
+ "\n\t\t\t\t\tdesc: " + h.getDesc() + "\n\t\t\t\t\tisInterface: " + h.isInterface() + "\n\t\t\t\t\tdesc: " + h.getDesc() + "\n\t\t\t\t\tisInterface: " + h.isInterface() + "\n\t\t\t\t\ttag: "
+ "\n\t\t\t\t\ttag: " + h.getTag(); + h.getTag();
s += "\n\t\t\t\t]\n"; s += "\n\t\t\t\t]\n";
} else { } else {
s += "\t\t\t\t" + ClassUtil.getDecompiledValue(l, "") + "\n"; s += "\t\t\t\t" + ClassUtil.getDecompiledValue(l, "") + "\n";
} }
} }
s += "\t\t\t]\n\t\t]\n"; s += "\t\t\t]\n\t\t]\n";
break; return s;
} }
case "MethodInsnNode": { case "MethodInsnNode": {
MethodInsnNode node = (MethodInsnNode) n; MethodInsnNode node = (MethodInsnNode) n;
s += "\t\t" + OpcodesReverse.reverseOpcode(node.getOpcode()) + " " + node.desc + " " + node.owner + "/" + node.name return "\t\t" + OpcodesReverse.reverseOpcode(node.getOpcode()) + " " + node.desc + " " + node.owner + "/" + node.name
+ "\n"; + "\n";
break;
} }
case "TypeInsnNode": { case "TypeInsnNode": {
TypeInsnNode node = (TypeInsnNode) n; TypeInsnNode node = (TypeInsnNode) n;
s += "\t\t" + OpcodesReverse.reverseOpcode(n.getOpcode()) + " " + node.desc + "\n"; return "\t\t" + OpcodesReverse.reverseOpcode(n.getOpcode()) + " " + node.desc + "\n";
break;
} }
case "MultiANewArrayInsnNode": { case "MultiANewArrayInsnNode": {
MultiANewArrayInsnNode node = (MultiANewArrayInsnNode) n; MultiANewArrayInsnNode node = (MultiANewArrayInsnNode) n;
s += "\t\t" + OpcodesReverse.reverseOpcode(node.getOpcode()) + " " + node.desc + " " + node.dims + "\n"; return "\t\t" + OpcodesReverse.reverseOpcode(node.getOpcode()) + " " + node.desc + " " + node.dims + "\n";
break;
} }
case "LdcInsnNode": { case "LdcInsnNode": {
LdcInsnNode node = (LdcInsnNode) n; LdcInsnNode node = (LdcInsnNode) n;
@@ -442,9 +479,8 @@ public class Disassembler {
case "Integer": case "Integer":
case "Float": case "Float":
case "Long": { case "Long": {
s += "\t\t" + OpcodesReverse.reverseOpcode(node.getOpcode()) + " " + ClassUtil.getDecompiledValue(node.cst, "") return "\t\t" + OpcodesReverse.reverseOpcode(node.getOpcode()) + " " + ClassUtil.getDecompiledValue(node.cst, "")
+ "\n"; + "\n";
break;
} }
case "Type": { case "Type": {
Type type = (Type) node.cst; Type type = (Type) node.cst;
@@ -462,57 +498,51 @@ public class Disassembler {
f_buf.setAccessible(true); f_buf.setAccessible(true);
buf = (char[]) f_buf.get(type); buf = (char[]) f_buf.get(type);
} catch (Exception e) {} } catch (Exception e) {}
s += "\t\t" + OpcodesReverse.reverseOpcode(n.getOpcode()) + " Type: [\n\t\t\ttype: " String s = "\t\t" + OpcodesReverse.reverseOpcode(n.getOpcode()) + " Type: [\n\t\t\ttype: "
+ ClassUtil.getClassNameFromType(type) + "\n\t\t\toff: " + off + "\n\t\t\tlen: " + len + "\n\t\t\tbuf: " + ClassUtil.getClassNameFromType(type) + "\n\t\t\toff: " + off + "\n\t\t\tlen: " + len + "\n\t\t\tbuf: "
+ ClassUtil.getDecompiledValue(new String(buf), ""); + ClassUtil.getDecompiledValue(new String(buf), "");
s += "\n\t\t]\n"; s += "\n\t\t]\n";
break; return s;
} }
default: { default: {
s += "\t\tUNRESOLVED TYPE! " + OpcodesReverse.reverseOpcode(node.getOpcode()) + " " return "\t\tUNRESOLVED TYPE! " + OpcodesReverse.reverseOpcode(node.getOpcode()) + " "
+ node.cst.getClass().getName().replace(".", "/") + " " + node.cst + "\n"; + node.cst.getClass().getName().replace(".", "/") + " " + node.cst + "\n";
break;
} }
} }
break;
} }
case "VarInsnNode": { case "VarInsnNode": {
VarInsnNode node = (VarInsnNode) n; VarInsnNode node = (VarInsnNode) n;
s += "\t\t" + OpcodesReverse.reverseOpcode(n.getOpcode()) + " " + node.var + "\n"; return "\t\t" + OpcodesReverse.reverseOpcode(n.getOpcode()) + " " + node.var + "\n";
break;
} }
case "InsnNode": { case "InsnNode": {
InsnNode node = (InsnNode) n; InsnNode node = (InsnNode) n;
s += "\t\t" + OpcodesReverse.reverseOpcode(n.getOpcode()) + "\n"; return "\t\t" + OpcodesReverse.reverseOpcode(n.getOpcode()) + "\n";
break;
} }
case "IntInsnNode": { case "IntInsnNode": {
IntInsnNode node = (IntInsnNode) n; IntInsnNode node = (IntInsnNode) n;
if (n.getOpcode() == 188) { if (n.getOpcode() == Opcodes.NEWARRAY) {
s += "\t\t" + OpcodesReverse.reverseOpcode(n.getOpcode()) + " " + ClassUtil.getArrayTypeByID(node.operand) + "\n"; return "\t\t" + OpcodesReverse.reverseOpcode(n.getOpcode()) + " " + ClassUtil.getArrayTypeByID(node.operand) + "\n";
} else { } else {
s += "\t\t" + OpcodesReverse.reverseOpcode(n.getOpcode()) + " " + node.operand + "\n"; return "\t\t" + OpcodesReverse.reverseOpcode(n.getOpcode()) + " " + node.operand + "\n";
} }
break;
} }
case "JumpInsnNode": { case "JumpInsnNode": {
JumpInsnNode node = (JumpInsnNode) n; JumpInsnNode node = (JumpInsnNode) n;
s += "\t\t" + OpcodesReverse.reverseOpcode(n.getOpcode()) + " " + labels.get(node.label.getLabel()) + "\n"; return "\t\t" + OpcodesReverse.reverseOpcode(n.getOpcode()) + " " + labels.get(node.label.getLabel()) + "\n";
break;
} }
case "TableSwitchInsnNode": { case "TableSwitchInsnNode": {
TableSwitchInsnNode node = (TableSwitchInsnNode) n; TableSwitchInsnNode node = (TableSwitchInsnNode) n;
s += "\t\t" + OpcodesReverse.reverseOpcode(n.getOpcode()) + " [\n\t\t\tmin: " + node.min + "\n\t\t\tmax: " + node.max 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()) + "\n\t\t\tlabels: [\n"; + "\n\t\t\tdefault: " + labels.get(node.dflt.getLabel()) + "\n\t\t\tlabels: [\n";
for (LabelNode l : node.labels) { for (LabelNode l : node.labels) {
s += "\t\t\t\t" + labels.get(l.getLabel()) + "\n"; s += "\t\t\t\t" + labels.get(l.getLabel()) + "\n";
} }
s += "\t\t\t]\n\t\t]\n"; s += "\t\t\t]\n\t\t]\n";
break; return s;
} }
case "LookupSwitchInsnNode": { case "LookupSwitchInsnNode": {
LookupSwitchInsnNode node = (LookupSwitchInsnNode) n; LookupSwitchInsnNode node = (LookupSwitchInsnNode) n;
s += "\t\t" + OpcodesReverse.reverseOpcode(n.getOpcode()) + " [\n\t\t\tdefault: " + labels.get(node.dflt.getLabel()) String s = "\t\t" + OpcodesReverse.reverseOpcode(n.getOpcode()) + " [\n\t\t\tdefault: " + labels.get(node.dflt.getLabel())
+ "\n\t\t\tkeys: [\n"; + "\n\t\t\tkeys: [\n";
for (Integer l : node.keys) { for (Integer l : node.keys) {
s += "\t\t\t\t" + l + "\n"; s += "\t\t\t\t" + l + "\n";
@@ -522,18 +552,15 @@ public class Disassembler {
s += "\t\t\t\t" + labels.get(l.getLabel()) + "\n"; s += "\t\t\t\t" + labels.get(l.getLabel()) + "\n";
} }
s += "\t\t\t]\n\t\t]\n"; s += "\t\t\t]\n\t\t]\n";
break; return s;
} }
case "IincInsnNode": { case "IincInsnNode": {
IincInsnNode node = (IincInsnNode) n; IincInsnNode node = (IincInsnNode) n;
s += "\t\t" + OpcodesReverse.reverseOpcode(n.getOpcode()) + " " + node.var + " " + node.incr + "\n"; return "\t\t" + OpcodesReverse.reverseOpcode(n.getOpcode()) + " " + node.var + " " + node.incr + "\n";
break;
} }
default: default:
s += "\t\tNOT HANDLED! " + OpcodesReverse.reverseOpcode(n.getOpcode()) + " " + n.getClass().getSimpleName() + "\n"; return "\t\tNOT HANDLED! " + OpcodesReverse.reverseOpcode(n.getOpcode()) + " " + n.getClass().getSimpleName() + "\n";
break;
} }
} }
return new String[] { s, localVarTable, tryCatchTable };
}
} }
@@ -5,7 +5,7 @@
* This library is distributed under a modified BSD license. See the included * This library is distributed under a modified BSD license. See the included
* RSyntaxTextArea.License.txt file for details. * RSyntaxTextArea.License.txt file for details.
*/ */
package me.ByteEdit.main; package me.ByteEdit.edit;
import java.io.IOException; import java.io.IOException;
import java.io.Reader; import java.io.Reader;
@@ -1,4 +1,4 @@
package me.ByteEdit.main; package me.ByteEdit.edit;
import java.awt.EventQueue; import java.awt.EventQueue;
import java.awt.Toolkit; import java.awt.Toolkit;
@@ -1,4 +1,4 @@
package me.ByteEdit.main; package me.ByteEdit.edit;
import java.awt.Toolkit; import java.awt.Toolkit;
import java.awt.event.ActionEvent; import java.awt.event.ActionEvent;
@@ -17,6 +17,8 @@ import javax.swing.KeyStroke;
import javax.swing.UIManager; import javax.swing.UIManager;
import javax.swing.border.EmptyBorder; import javax.swing.border.EmptyBorder;
import me.ByteEdit.main.Main;
public class SearchBox extends JFrame { public class SearchBox extends JFrame {
public JPanel contentPane; public JPanel contentPane;
@@ -106,20 +108,20 @@ public class SearchBox extends JFrame {
} }
public void find() { public void find() {
int startPos = Main.textArea.getCaretPosition(); int startPos = Main.txtByteEditView.getCaretPosition();
String toFind = txtFind.getText(); String toFind = txtFind.getText();
String txt = chckbxCaseSensitive.isSelected() ? Main.textArea.getText().substring(startPos) String txt = chckbxCaseSensitive.isSelected() ? Main.txtByteEditView.getText().substring(startPos)
: Main.textArea.getText().substring(startPos).toLowerCase(); : Main.txtByteEditView.getText().substring(startPos).toLowerCase();
int index = txt.indexOf(chckbxCaseSensitive.isSelected() ? toFind : toFind.toLowerCase()); int index = txt.indexOf(chckbxCaseSensitive.isSelected() ? toFind : toFind.toLowerCase());
if (index == -1) { if (index == -1) {
txt = chckbxCaseSensitive.isSelected() ? Main.textArea.getText() : Main.textArea.getText().toLowerCase(); txt = chckbxCaseSensitive.isSelected() ? Main.txtByteEditView.getText() : Main.txtByteEditView.getText().toLowerCase();
index = txt.indexOf(chckbxCaseSensitive.isSelected() ? toFind : toFind.toLowerCase()); index = txt.indexOf(chckbxCaseSensitive.isSelected() ? toFind : toFind.toLowerCase());
startPos = 0; startPos = 0;
if (index == -1) { if (index == -1) {
return; return;
} }
} }
Main.textArea.select(startPos + index, startPos + index + toFind.length()); Main.txtByteEditView.select(startPos + index, startPos + index + toFind.length());
} }
public void replaceFind() { public void replaceFind() {
@@ -128,22 +130,22 @@ public class SearchBox extends JFrame {
} }
public void replace() { public void replace() {
String txt = Main.textArea.getText(); String txt = Main.txtByteEditView.getText();
int startPos = Main.textArea.getSelectionStart(); int startPos = Main.txtByteEditView.getSelectionStart();
Main.textArea.replaceSelection(txtReplace.getText()); Main.txtByteEditView.replaceSelection(txtReplace.getText());
Main.textArea.select(startPos, startPos + txtReplace.getText().length()); Main.txtByteEditView.select(startPos, startPos + txtReplace.getText().length());
} }
public void replaceAll() { public void replaceAll() {
String toFind = txtFind.getText(); String toFind = txtFind.getText();
String toReplace = txtReplace.getText(); String toReplace = txtReplace.getText();
String txt = Main.textArea.getText(); String txt = Main.txtByteEditView.getText();
int prev = Main.textArea.getCaretPosition(); int prev = Main.txtByteEditView.getCaretPosition();
if (chckbxCaseSensitive.isSelected()) { if (chckbxCaseSensitive.isSelected()) {
Main.textArea.replaceRange(txt.replace(toFind, toReplace), 0, txt.length()); Main.txtByteEditView.replaceRange(txt.replace(toFind, toReplace), 0, txt.length());
} else { } else {
Main.textArea.replaceRange(txt.replaceAll("(?i)" + Pattern.quote(toFind), toReplace), 0, txt.length()); Main.txtByteEditView.replaceRange(txt.replaceAll("(?i)" + Pattern.quote(toFind), toReplace), 0, txt.length());
} }
Main.textArea.setCaretPosition(prev); Main.txtByteEditView.setCaretPosition(prev);
} }
} }
@@ -1,4 +1,4 @@
package me.ByteEdit.main; package me.ByteEdit.edit;
import java.awt.Toolkit; import java.awt.Toolkit;
import java.awt.event.ActionEvent; import java.awt.event.ActionEvent;
@@ -18,6 +18,8 @@ import javax.swing.event.DocumentListener;
import javax.swing.event.ListSelectionEvent; import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener; import javax.swing.event.ListSelectionListener;
import me.ByteEdit.main.Main;
public class TypeOpenBox extends JFrame { public class TypeOpenBox extends JFrame {
public JPanel contentPane; public JPanel contentPane;
+196 -103
View File
@@ -30,6 +30,7 @@ import java.util.Map.Entry;
import java.util.jar.JarEntry; import java.util.jar.JarEntry;
import java.util.jar.JarFile; import java.util.jar.JarFile;
import java.util.jar.JarOutputStream; import java.util.jar.JarOutputStream;
import java.util.regex.Pattern;
import javax.swing.JComponent; import javax.swing.JComponent;
import javax.swing.JDialog; import javax.swing.JDialog;
@@ -46,6 +47,7 @@ import javax.swing.border.EmptyBorder;
import javax.swing.event.TreeSelectionEvent; import javax.swing.event.TreeSelectionEvent;
import javax.swing.event.TreeSelectionListener; import javax.swing.event.TreeSelectionListener;
import javax.swing.filechooser.FileNameExtensionFilter; import javax.swing.filechooser.FileNameExtensionFilter;
import javax.swing.text.BadLocationException;
import javax.swing.tree.DefaultMutableTreeNode; import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeCellRenderer; import javax.swing.tree.DefaultTreeCellRenderer;
import javax.swing.tree.DefaultTreeModel; import javax.swing.tree.DefaultTreeModel;
@@ -67,6 +69,15 @@ import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.tree.ClassNode; import org.objectweb.asm.tree.ClassNode;
import org.objectweb.asm.tree.MethodNode; import org.objectweb.asm.tree.MethodNode;
import me.ByteEdit.edit.Assembler;
import me.ByteEdit.edit.Disassembler;
import me.ByteEdit.edit.Disassembler.DisassembleTuple;
import me.ByteEdit.edit.OptionBox;
import me.ByteEdit.edit.SearchBox;
import me.ByteEdit.edit.TypeOpenBox;
import me.ByteEdit.utils.ClassUtil;
import me.ByteEdit.utils.OpcodesReverse;
public class Main extends JFrame { public class Main extends JFrame {
public static Main INSTANCE; public static Main INSTANCE;
@@ -76,11 +87,13 @@ public class Main extends JFrame {
public static HashMap<String, byte[]> OTHER_FILES = new HashMap<>(); public static HashMap<String, byte[]> OTHER_FILES = new HashMap<>();
public static HashMap<String, ClassNode> classNodes = new HashMap<>(); public static HashMap<String, ClassNode> classNodes = new HashMap<>();
public static String currentNodeName; public static String currentNodeName;
public static RSyntaxTextArea textArea; public static RSyntaxTextArea txtByteEditView;
public static SearchBox searchBox; public static SearchBox searchBox;
public static TypeOpenBox typeOpenBox; public static TypeOpenBox typeOpenBox;
public static OptionBox optionBox; public static OptionBox optionBox;
public static JTree tree; public static JTree tree;
public static RTextScrollPane scrollPane_ByteEdit;
public static Theme theme;
/** /**
* Launch the application. * Launch the application.
@@ -172,90 +185,12 @@ public class Main extends JFrame {
contentPane.add(splitPane); contentPane.add(splitPane);
JScrollPane scrollPane = new JScrollPane(); JScrollPane scrollPane = new JScrollPane();
splitPane.setLeftComponent(scrollPane); splitPane.setLeftComponent(scrollPane);
textArea = new RSyntaxTextArea();
CompletionProvider provider = createCompletionProvider(); CompletionProvider provider = createCompletionProvider();
AutoCompletion ac = new AutoCompletion(provider); AutoCompletion ac = new AutoCompletion(provider);
ac.setShowDescWindow(true); ac.setShowDescWindow(true);
ac.install(textArea);
FoldParserManager.get().addFoldParserMapping(SyntaxConstants.SYNTAX_STYLE_JAVA_DISASSEMBLE, new CurlyFoldParser(false, true)); FoldParserManager.get().addFoldParserMapping(SyntaxConstants.SYNTAX_STYLE_JAVA_DISASSEMBLE, new CurlyFoldParser(false, true));
textArea.setCodeFoldingEnabled(true);
textArea.addKeyListener(new KeyAdapter() {
@Override
public void keyReleased(KeyEvent e) {
if (e.getKeyCode() == 116 && currentNodeName != null) {
try {
ClassNode classNode = classNodes.get(currentNodeName);
int prev = textArea.getCaretPosition();
String dis = Disassembler.disassemble(classNode);
String substr = currentNodeName.substring(0, currentNodeName.length() - 6);
for (String key : Main.classNodes.keySet()) {
if (key.contains("$")) {
String[] split = key.split("\\$");
if (split[0].equals(substr)) {
dis += "\n" + Disassembler.disassemble(classNodes.get(key));
}
}
}
textArea.setText(dis);
textArea.setCaretPosition(prev);
} catch (Exception e2) {}
}
}
});
KeyStroke ctrlF = KeyStroke.getKeyStroke(KeyEvent.VK_F, KeyEvent.CTRL_DOWN_MASK);
textArea.registerKeyboardAction(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
searchBox.setVisible(true);
searchBox.txtFind.requestFocusInWindow();
searchBox.txtFind.select(0, searchBox.txtFind.getText().length());
}
}, ctrlF, JComponent.WHEN_IN_FOCUSED_WINDOW);
KeyStroke ctrlT = KeyStroke.getKeyStroke(KeyEvent.VK_T, KeyEvent.CTRL_DOWN_MASK);
textArea.registerKeyboardAction(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
typeOpenBox.setVisible(true);
typeOpenBox.txtSearch.requestFocusInWindow();
typeOpenBox.txtSearch.select(0, typeOpenBox.txtSearch.getText().length());
}
}, ctrlT, JComponent.WHEN_IN_FOCUSED_WINDOW);
KeyStroke ctrlS = KeyStroke.getKeyStroke(KeyEvent.VK_S, KeyEvent.CTRL_DOWN_MASK);
textArea.registerKeyboardAction(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
String txt = textArea.getText();
for (String s : txt.split("\\/\\/ #Annotations\n")) {
if (s.isEmpty())
continue;
ClassNode node = Assembler.assemble(s);
if (node == null) {
continue;
}
if (classNodes.replace(node.name + ".class", node) == null) {
classNodes.put(node.name + ".class", node);
}
}
}
}, ctrlS, JComponent.WHEN_FOCUSED);
KeyStroke ctrlO = KeyStroke.getKeyStroke(KeyEvent.VK_O, KeyEvent.CTRL_DOWN_MASK);
textArea.registerKeyboardAction(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
optionBox.setVisible(true);
}
}, ctrlO, JComponent.WHEN_IN_FOCUSED_WINDOW);
textArea.setEditable(true);
textArea.setSyntaxEditingStyle(SyntaxConstants.SYNTAX_STYLE_JAVA_DISASSEMBLE);
textArea.setCodeFoldingEnabled(true);
try { try {
Theme theme = Theme.load(getClass().getClassLoader().getResourceAsStream("org/fife/eclipse.xml")); Theme theme = Theme.load(getClass().getClassLoader().getResourceAsStream("org/fife/eclipse.xml"));
theme.apply(textArea);
} catch (IOException e2) { } catch (IOException e2) {
e2.printStackTrace(); e2.printStackTrace();
} }
@@ -280,13 +215,6 @@ public class Main extends JFrame {
} }
} }
}); });
tree.registerKeyboardAction(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
save();
}
}, ctrlS, JComponent.WHEN_FOCUSED);
tree.setFont(new Font("Verdana", Font.PLAIN, 11)); tree.setFont(new Font("Verdana", Font.PLAIN, 11));
tree.setBackground(Color.LIGHT_GRAY); tree.setBackground(Color.LIGHT_GRAY);
if (tree.getCellRenderer() instanceof DefaultTreeCellRenderer) { if (tree.getCellRenderer() instanceof DefaultTreeCellRenderer) {
@@ -315,13 +243,6 @@ public class Main extends JFrame {
} }
} }
}); });
RTextScrollPane scrollPane_TextArea = new RTextScrollPane();
textArea.setBackground(Color.LIGHT_GRAY);
scrollPane_TextArea.setViewportView(textArea);
scrollPane_TextArea.setLineNumbersEnabled(true);
scrollPane_TextArea.setFoldIndicatorEnabled(true);
scrollPane_TextArea.getGutter().setBackground(Color.LIGHT_GRAY);
splitPane.setRightComponent(scrollPane_TextArea);
new DropTarget(tree, new DropTargetListener() { new DropTarget(tree, new DropTargetListener() {
@Override @Override
@@ -367,14 +288,20 @@ public class Main extends JFrame {
@Override @Override
public void dragExit(DropTargetEvent dte) {} public void dragExit(DropTargetEvent dte) {}
}); });
}
public static void selectFile(String s) { txtByteEditView = new RSyntaxTextArea();
if (s.endsWith(".class")) { ac.install(txtByteEditView);
currentNodeName = s; txtByteEditView.setCodeFoldingEnabled(true);
ClassNode classNode = classNodes.get(s); txtByteEditView.addKeyListener(new KeyAdapter() {
@Override
public void keyReleased(KeyEvent e) {
if (e.getKeyCode() == 116 && currentNodeName != null) {
try {
ClassNode classNode = classNodes.get(currentNodeName);
int prev = txtByteEditView.getCaretPosition();
String dis = Disassembler.disassemble(classNode); String dis = Disassembler.disassemble(classNode);
String substr = s.substring(0, s.length() - 6); String substr = currentNodeName.substring(0, currentNodeName.length() - 6);
for (String key : Main.classNodes.keySet()) { for (String key : Main.classNodes.keySet()) {
if (key.contains("$")) { if (key.contains("$")) {
String[] split = key.split("\\$"); String[] split = key.split("\\$");
@@ -383,10 +310,173 @@ public class Main extends JFrame {
} }
} }
} }
textArea.setText(dis); txtByteEditView.setText(dis);
textArea.setCaretPosition(0); txtByteEditView.setCaretPosition(prev);
} catch (Exception e2) {}
} }
} }
});
KeyStroke ctrlF = KeyStroke.getKeyStroke(KeyEvent.VK_F, KeyEvent.CTRL_DOWN_MASK);
KeyStroke ctrlT = KeyStroke.getKeyStroke(KeyEvent.VK_T, KeyEvent.CTRL_DOWN_MASK);
KeyStroke ctrlS = KeyStroke.getKeyStroke(KeyEvent.VK_S, KeyEvent.CTRL_DOWN_MASK);
KeyStroke ctrlG = KeyStroke.getKeyStroke(KeyEvent.VK_G, KeyEvent.CTRL_DOWN_MASK);
KeyStroke ctrlO = KeyStroke.getKeyStroke(KeyEvent.VK_O, KeyEvent.CTRL_DOWN_MASK);
// global
txtByteEditView.registerKeyboardAction(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
searchBox.setVisible(true);
searchBox.txtFind.requestFocusInWindow();
searchBox.txtFind.select(0, searchBox.txtFind.getText().length());
}
}, ctrlF, JComponent.WHEN_IN_FOCUSED_WINDOW);
txtByteEditView.registerKeyboardAction(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
typeOpenBox.setVisible(true);
typeOpenBox.txtSearch.requestFocusInWindow();
typeOpenBox.txtSearch.select(0, typeOpenBox.txtSearch.getText().length());
}
}, ctrlT, JComponent.WHEN_IN_FOCUSED_WINDOW);
txtByteEditView.registerKeyboardAction(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
optionBox.setVisible(true);
}
}, ctrlO, JComponent.WHEN_IN_FOCUSED_WINDOW);
// specific
tree.registerKeyboardAction(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
save();
}
}, ctrlS, JComponent.WHEN_FOCUSED);
txtByteEditView.registerKeyboardAction(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
saveCurrentClassNode();
}
}, ctrlS, JComponent.WHEN_FOCUSED);
txtByteEditView.registerKeyboardAction(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
try {
goToSelected();
} catch (BadLocationException e1) {
e1.printStackTrace();
}
}
}, ctrlG, JComponent.WHEN_FOCUSED);
txtByteEditView.setEditable(true);
txtByteEditView.setSyntaxEditingStyle(SyntaxConstants.SYNTAX_STYLE_JAVA_DISASSEMBLE);
txtByteEditView.setCodeFoldingEnabled(true);
scrollPane_ByteEdit = new RTextScrollPane();
try {
theme = Theme.load(getClass().getClassLoader().getResourceAsStream("org/fife/eclipse.xml"));
theme.apply(txtByteEditView);
} catch (IOException e2) {
e2.printStackTrace();
}
splitPane.setRightComponent(scrollPane_ByteEdit);
txtByteEditView.setBackground(Color.LIGHT_GRAY);
scrollPane_ByteEdit.setViewportView(txtByteEditView);
scrollPane_ByteEdit.setLineNumbersEnabled(true);
scrollPane_ByteEdit.setFoldIndicatorEnabled(true);
scrollPane_ByteEdit.getGutter().setBackground(Color.LIGHT_GRAY);
}
private final Pattern jumpableInstructionPattern = Pattern.compile("^\t\t(?!//|\t+).+ .+");
public void goToSelected() throws BadLocationException {
int lineStart = txtByteEditView.getLineStartOffsetOfCurrentLine();
int lineEnd = txtByteEditView.getLineEndOffsetOfCurrentLine() - 1;
String line = txtByteEditView.getText(lineStart, lineEnd - lineStart);
if (!jumpableInstructionPattern.matcher(line).matches()) {
return;
}
line = line.substring(2);
if (line.startsWith("invoke")) {
String[] split = line.split(" ");
String desc = split[1];
String className = split[2];
String[] nameSplit = className.split("/");
String methodName = nameSplit[nameSplit.length - 1];
className = className.substring(0, className.length() - methodName.length() - 1);
ClassNode classNode = classNodes.get(className + ".class");
if (classNode == null) {
return;
}
for (MethodNode mn : classNode.methods) {
if (mn.name.equals(methodName) && mn.desc.equals(desc)) {
while (classNode.outerClass != null) {
classNode = classNodes.get(classNode.outerClass + ".class");
}
int lineFound = selectFileWithSearch(classNode.name + ".class", mn);
if (lineFound != -1) {
Main.txtByteEditView.setCaretPosition(Main.txtByteEditView.getLineStartOffset(lineFound));
}
break;
}
}
}
}
private void saveCurrentClassNode() {
String txt = txtByteEditView.getText();
for (String s : txt.split("\\/\\/ #Annotations\n")) {
if (s.isEmpty())
continue;
ClassNode node = Assembler.assemble(s);
if (node == null) {
continue;
}
if (classNodes.replace(node.name + ".class", node) == null) {
classNodes.put(node.name + ".class", node);
}
}
}
public static int selectFileWithSearch(String s, MethodNode methodToFind) {
if (s.endsWith(".class")) {
currentNodeName = s;
int lineFound = -1;
ClassNode classNode = classNodes.get(s);
String dis = "";
DisassembleTuple tuple = Disassembler.disassemble(classNode, methodToFind);
if (tuple.getLine() != -1) {
lineFound = dis.split("\\n").length + tuple.getLine() - 1;
}
dis += tuple.getDisassembly();
String substr = s.substring(0, s.length() - 6);
for (String key : Main.classNodes.keySet()) {
if (key.contains("$")) {
String[] split = key.split("\\$");
if (split[0].equals(substr)) {
tuple = Disassembler.disassemble(classNodes.get(key), methodToFind);
if (tuple.getLine() != -1) {
lineFound = dis.split("\\n").length + tuple.getLine() + 1;
}
dis += "\n" + tuple.getDisassembly();
}
}
}
txtByteEditView.setText(dis);
txtByteEditView.setCaretPosition(0);
return lineFound;
}
return -1;
}
public static int selectFile(String s) {
return selectFileWithSearch(s, null);
}
public void save() { public void save() {
final JFileChooser fileChooser = new JFileChooser() { final JFileChooser fileChooser = new JFileChooser() {
@@ -474,7 +564,7 @@ public class Main extends JFrame {
} }
} }
public void showError(Throwable e) { public static void showError(Throwable e) {
String s = e.toString() + "\n"; String s = e.toString() + "\n";
StackTraceElement[] stackTrace = e.getStackTrace(); StackTraceElement[] stackTrace = e.getStackTrace();
for (StackTraceElement ste : stackTrace) { for (StackTraceElement ste : stackTrace) {
@@ -482,7 +572,10 @@ public class Main extends JFrame {
break; break;
s += "\tat " + ste + "\n"; s += "\tat " + ste + "\n";
} }
JOptionPane.showMessageDialog(this, s, "Error!", JOptionPane.ERROR_MESSAGE); }
public static void showError(String s) {
JOptionPane.showMessageDialog(INSTANCE, s, "Error!", JOptionPane.ERROR_MESSAGE);
} }
class ArchiveTreeModel extends DefaultTreeModel { class ArchiveTreeModel extends DefaultTreeModel {
@@ -1,4 +1,4 @@
package me.ByteEdit.main; package me.ByteEdit.utils;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
@@ -1,4 +1,4 @@
package me.ByteEdit.main; package me.ByteEdit.utils;
import java.io.BufferedReader; import java.io.BufferedReader;
import java.io.IOException; import java.io.IOException;
@@ -1,4 +1,4 @@
package me.ByteEdit.main; package me.ByteEdit.utils;
public class ExternalTypeEnumeration { public class ExternalTypeEnumeration {
@@ -1,4 +1,4 @@
package me.ByteEdit.main; package me.ByteEdit.utils;
public class OpcodesReverse { public class OpcodesReverse {
@@ -22,7 +22,7 @@ import org.fife.ui.rsyntaxtextarea.modes.AbstractMarkupTokenMaker;
import org.fife.ui.rtextarea.RDocument; import org.fife.ui.rtextarea.RDocument;
import org.fife.util.DynamicIntArray; import org.fife.util.DynamicIntArray;
import me.ByteEdit.main.JavaAssemblyTokenMaker; import me.ByteEdit.edit.JavaAssemblyTokenMaker;
/** /**
* The document used by {@link org.fife.ui.rsyntaxtextarea.RSyntaxTextArea}. * The document used by {@link org.fife.ui.rsyntaxtextarea.RSyntaxTextArea}.