mirror of
https://github.com/SuspiciousActivity/ByteEdit.git
synced 2026-08-13 17:56:17 +00:00
Some refactoring, added "GoTo" feature
This commit is contained in:
1 parent
e81f5f6ee9
commit
6995318302
13 files changed
+319
-189
No files matched your search
@@ -11,3 +11,5 @@ To search/replace in a file, press CTRL + F.
|
||||
To open a class, press CTRL + T.
|
||||
|
||||
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.lang.reflect.Constructor;
|
||||
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.VarInsnNode;
|
||||
|
||||
import me.ByteEdit.main.Main;
|
||||
import me.ByteEdit.utils.ClassUtil;
|
||||
import me.ByteEdit.utils.CustomBufferedReader;
|
||||
|
||||
public class Assembler {
|
||||
|
||||
public static ClassNode assemble(String input) {
|
||||
Main.textArea.removeAllLineHighlights();
|
||||
Main.txtByteEditView.removeAllLineHighlights();
|
||||
CustomBufferedReader read = null;
|
||||
try {
|
||||
ClassNode clazz = new ClassNode();
|
||||
@@ -80,15 +83,15 @@ public class Assembler {
|
||||
{
|
||||
s = s.substring(0, s.length() - 2);
|
||||
if (s.contains(" implements ")) {
|
||||
String interfaces = s.substring(s.indexOf(" implements ") + 12);
|
||||
String interfaces = s.substring(s.lastIndexOf(" implements ") + 12);
|
||||
clazz.interfaces = new ArrayList<>();
|
||||
for (String interf : interfaces.split(", ")) {
|
||||
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);
|
||||
s = s.substring(0, s.indexOf(" extends "));
|
||||
clazz.superName = s.substring(s.lastIndexOf(" extends ") + 9);
|
||||
s = s.substring(0, s.lastIndexOf(" extends "));
|
||||
String[] split = s.split(" ");
|
||||
clazz.name = split[split.length - 1];
|
||||
clazz.access = ClassUtil.ACC_SUPER;
|
||||
@@ -319,11 +322,11 @@ public class Assembler {
|
||||
} else if (!s.startsWith("\t")) {
|
||||
s = s.substring(0, s.length() - 2);
|
||||
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(", ")) {
|
||||
node.exceptions.add(excp);
|
||||
}
|
||||
s = s.substring(0, s.indexOf(" throws "));
|
||||
s = s.substring(0, s.lastIndexOf(" throws "));
|
||||
}
|
||||
String[] split = s.split(" ");
|
||||
node.desc = split[split.length - 1];
|
||||
@@ -410,7 +413,8 @@ public class Assembler {
|
||||
} catch (Throwable e) {
|
||||
System.err.println("Error at line: " + read.currentLine);
|
||||
try {
|
||||
Main.textArea.addLineHighlight(read.currentLine, Color.RED.darker());
|
||||
Main.txtByteEditView.setCaretPosition(Main.txtByteEditView.getLineStartOffset(read.currentLine));
|
||||
Main.showError(e.getMessage());
|
||||
} catch (BadLocationException e1) {
|
||||
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.util.ArrayList;
|
||||
@@ -8,6 +8,7 @@ import java.util.List;
|
||||
|
||||
import org.objectweb.asm.Handle;
|
||||
import org.objectweb.asm.Label;
|
||||
import org.objectweb.asm.Opcodes;
|
||||
import org.objectweb.asm.Type;
|
||||
import org.objectweb.asm.tree.AbstractInsnNode;
|
||||
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.VarInsnNode;
|
||||
|
||||
import me.ByteEdit.utils.ClassUtil;
|
||||
import me.ByteEdit.utils.OpcodesReverse;
|
||||
|
||||
public class Disassembler {
|
||||
|
||||
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) {
|
||||
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 {
|
||||
int lineFound = -1;
|
||||
String s = "";
|
||||
s += "// #Annotations\n";
|
||||
if (classNode.visibleAnnotations != null && !classNode.visibleAnnotations.isEmpty()) {
|
||||
@@ -264,6 +298,9 @@ public class Disassembler {
|
||||
s += "\n";
|
||||
}
|
||||
}
|
||||
if (mn.equals(methodToFind)) {
|
||||
lineFound = s.split("\\n").length;
|
||||
}
|
||||
s += "\t" + ClassUtil.getAccessFlagsFull(mn.access) + mn.name + " " + mn.desc + " ";
|
||||
if (mn.exceptions != null && !mn.exceptions.isEmpty()) {
|
||||
String exceptionStr = "";
|
||||
@@ -287,10 +324,10 @@ public class Disassembler {
|
||||
}
|
||||
}
|
||||
s += "}\n";
|
||||
return s;
|
||||
return new DisassembleTuple(s, lineFound);
|
||||
} catch (Throwable e) {
|
||||
return "Class couldn't be decompiled:\n" + e.getClass().getName() + ": " + e.getMessage() + "\n"
|
||||
+ Arrays.toString(e.getStackTrace()).replace(", ", "\n\tat ").replace("[", "\tat ").replace("]", "") + "\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");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -317,21 +354,25 @@ public class Disassembler {
|
||||
}
|
||||
}
|
||||
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()) {
|
||||
case "FieldInsnNode": {
|
||||
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";
|
||||
break;
|
||||
}
|
||||
case "LabelNode": {
|
||||
LabelNode node = (LabelNode) n;
|
||||
s += "\t\t// label " + labels.get(node.getLabel()) + "\n";
|
||||
break;
|
||||
return "\t\t// label " + labels.get(node.getLabel()) + "\n";
|
||||
}
|
||||
case "FrameNode": {
|
||||
FrameNode node = (FrameNode) n;
|
||||
s += "\t\t// frame " + node.type + " l:";
|
||||
String s = "\t\t// frame " + node.type + " l:";
|
||||
ArrayList<String> arr = new ArrayList<>();
|
||||
if (node.local != null) {
|
||||
for (Object o : node.local) {
|
||||
@@ -372,19 +413,18 @@ public class Disassembler {
|
||||
s += "null";
|
||||
}
|
||||
s += "\n";
|
||||
break;
|
||||
return s;
|
||||
}
|
||||
case "LineNumberNode": {
|
||||
LineNumberNode node = (LineNumberNode) n;
|
||||
s += "\t\t// line " + node.line + " " + labels.get(node.start.getLabel()) + "\n";
|
||||
break;
|
||||
return "\t\t// line " + node.line + " " + labels.get(node.start.getLabel()) + "\n";
|
||||
}
|
||||
case "InvokeDynamicInsnNode": {
|
||||
InvokeDynamicInsnNode node = (InvokeDynamicInsnNode) n;
|
||||
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.bsm.getOwner() + "\n\t\t\t\tdesc: " + node.bsm.getDesc() + "\n\t\t\t\tisInterface: "
|
||||
+ node.bsm.isInterface() + "\n\t\t\t\ttag: " + node.bsm.getTag() + "\n\t\t\t]\n\t\t\targs: [\n";
|
||||
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.bsm.getOwner()
|
||||
+ "\n\t\t\t\tdesc: " + node.bsm.getDesc() + "\n\t\t\t\tisInterface: " + node.bsm.isInterface() + "\n\t\t\t\ttag: "
|
||||
+ node.bsm.getTag() + "\n\t\t\t]\n\t\t\targs: [\n";
|
||||
for (Object l : node.bsmArgs) {
|
||||
if (l.getClass().getName().equals("org.objectweb.asm.Type")) {
|
||||
Type type = (Type) l;
|
||||
@@ -408,31 +448,28 @@ public class Disassembler {
|
||||
} else if (l.getClass().getName().equals("org.objectweb.asm.Handle")) {
|
||||
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()
|
||||
+ "\n\t\t\t\t\tdesc: " + h.getDesc() + "\n\t\t\t\t\tisInterface: " + h.isInterface()
|
||||
+ "\n\t\t\t\t\ttag: " + h.getTag();
|
||||
+ "\n\t\t\t\t\tdesc: " + h.getDesc() + "\n\t\t\t\t\tisInterface: " + h.isInterface() + "\n\t\t\t\t\ttag: "
|
||||
+ h.getTag();
|
||||
s += "\n\t\t\t\t]\n";
|
||||
} else {
|
||||
s += "\t\t\t\t" + ClassUtil.getDecompiledValue(l, "") + "\n";
|
||||
}
|
||||
}
|
||||
s += "\t\t\t]\n\t\t]\n";
|
||||
break;
|
||||
return s;
|
||||
}
|
||||
case "MethodInsnNode": {
|
||||
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";
|
||||
break;
|
||||
}
|
||||
case "TypeInsnNode": {
|
||||
TypeInsnNode node = (TypeInsnNode) n;
|
||||
s += "\t\t" + OpcodesReverse.reverseOpcode(n.getOpcode()) + " " + node.desc + "\n";
|
||||
break;
|
||||
return "\t\t" + OpcodesReverse.reverseOpcode(n.getOpcode()) + " " + node.desc + "\n";
|
||||
}
|
||||
case "MultiANewArrayInsnNode": {
|
||||
MultiANewArrayInsnNode node = (MultiANewArrayInsnNode) n;
|
||||
s += "\t\t" + OpcodesReverse.reverseOpcode(node.getOpcode()) + " " + node.desc + " " + node.dims + "\n";
|
||||
break;
|
||||
return "\t\t" + OpcodesReverse.reverseOpcode(node.getOpcode()) + " " + node.desc + " " + node.dims + "\n";
|
||||
}
|
||||
case "LdcInsnNode": {
|
||||
LdcInsnNode node = (LdcInsnNode) n;
|
||||
@@ -442,9 +479,8 @@ public class Disassembler {
|
||||
case "Integer":
|
||||
case "Float":
|
||||
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";
|
||||
break;
|
||||
}
|
||||
case "Type": {
|
||||
Type type = (Type) node.cst;
|
||||
@@ -462,57 +498,51 @@ public class Disassembler {
|
||||
f_buf.setAccessible(true);
|
||||
buf = (char[]) f_buf.get(type);
|
||||
} 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.getDecompiledValue(new String(buf), "");
|
||||
s += "\n\t\t]\n";
|
||||
break;
|
||||
return s;
|
||||
}
|
||||
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";
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case "VarInsnNode": {
|
||||
VarInsnNode node = (VarInsnNode) n;
|
||||
s += "\t\t" + OpcodesReverse.reverseOpcode(n.getOpcode()) + " " + node.var + "\n";
|
||||
break;
|
||||
return "\t\t" + OpcodesReverse.reverseOpcode(n.getOpcode()) + " " + node.var + "\n";
|
||||
}
|
||||
case "InsnNode": {
|
||||
InsnNode node = (InsnNode) n;
|
||||
s += "\t\t" + OpcodesReverse.reverseOpcode(n.getOpcode()) + "\n";
|
||||
break;
|
||||
return "\t\t" + OpcodesReverse.reverseOpcode(n.getOpcode()) + "\n";
|
||||
}
|
||||
case "IntInsnNode": {
|
||||
IntInsnNode node = (IntInsnNode) n;
|
||||
if (n.getOpcode() == 188) {
|
||||
s += "\t\t" + OpcodesReverse.reverseOpcode(n.getOpcode()) + " " + ClassUtil.getArrayTypeByID(node.operand) + "\n";
|
||||
if (n.getOpcode() == Opcodes.NEWARRAY) {
|
||||
return "\t\t" + OpcodesReverse.reverseOpcode(n.getOpcode()) + " " + ClassUtil.getArrayTypeByID(node.operand) + "\n";
|
||||
} else {
|
||||
s += "\t\t" + OpcodesReverse.reverseOpcode(n.getOpcode()) + " " + node.operand + "\n";
|
||||
return "\t\t" + OpcodesReverse.reverseOpcode(n.getOpcode()) + " " + node.operand + "\n";
|
||||
}
|
||||
break;
|
||||
}
|
||||
case "JumpInsnNode": {
|
||||
JumpInsnNode node = (JumpInsnNode) n;
|
||||
s += "\t\t" + OpcodesReverse.reverseOpcode(n.getOpcode()) + " " + labels.get(node.label.getLabel()) + "\n";
|
||||
break;
|
||||
return "\t\t" + OpcodesReverse.reverseOpcode(n.getOpcode()) + " " + labels.get(node.label.getLabel()) + "\n";
|
||||
}
|
||||
case "TableSwitchInsnNode": {
|
||||
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";
|
||||
for (LabelNode l : node.labels) {
|
||||
s += "\t\t\t\t" + labels.get(l.getLabel()) + "\n";
|
||||
}
|
||||
s += "\t\t\t]\n\t\t]\n";
|
||||
break;
|
||||
return s;
|
||||
}
|
||||
case "LookupSwitchInsnNode": {
|
||||
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";
|
||||
for (Integer l : node.keys) {
|
||||
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]\n\t\t]\n";
|
||||
break;
|
||||
return s;
|
||||
}
|
||||
case "IincInsnNode": {
|
||||
IincInsnNode node = (IincInsnNode) n;
|
||||
s += "\t\t" + OpcodesReverse.reverseOpcode(n.getOpcode()) + " " + node.var + " " + node.incr + "\n";
|
||||
break;
|
||||
return "\t\t" + OpcodesReverse.reverseOpcode(n.getOpcode()) + " " + node.var + " " + node.incr + "\n";
|
||||
}
|
||||
default:
|
||||
s += "\t\tNOT HANDLED! " + OpcodesReverse.reverseOpcode(n.getOpcode()) + " " + n.getClass().getSimpleName() + "\n";
|
||||
break;
|
||||
return "\t\tNOT HANDLED! " + OpcodesReverse.reverseOpcode(n.getOpcode()) + " " + n.getClass().getSimpleName() + "\n";
|
||||
}
|
||||
}
|
||||
return new String[] { s, localVarTable, tryCatchTable };
|
||||
}
|
||||
|
||||
}
|
||||
+1
-1
@@ -5,7 +5,7 @@
|
||||
* This library is distributed under a modified BSD license. See the included
|
||||
* RSyntaxTextArea.License.txt file for details.
|
||||
*/
|
||||
package me.ByteEdit.main;
|
||||
package me.ByteEdit.edit;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.Reader;
|
||||
@@ -1,4 +1,4 @@
|
||||
package me.ByteEdit.main;
|
||||
package me.ByteEdit.edit;
|
||||
|
||||
import java.awt.EventQueue;
|
||||
import java.awt.Toolkit;
|
||||
@@ -1,4 +1,4 @@
|
||||
package me.ByteEdit.main;
|
||||
package me.ByteEdit.edit;
|
||||
|
||||
import java.awt.Toolkit;
|
||||
import java.awt.event.ActionEvent;
|
||||
@@ -17,6 +17,8 @@ import javax.swing.KeyStroke;
|
||||
import javax.swing.UIManager;
|
||||
import javax.swing.border.EmptyBorder;
|
||||
|
||||
import me.ByteEdit.main.Main;
|
||||
|
||||
public class SearchBox extends JFrame {
|
||||
|
||||
public JPanel contentPane;
|
||||
@@ -106,20 +108,20 @@ public class SearchBox extends JFrame {
|
||||
}
|
||||
|
||||
public void find() {
|
||||
int startPos = Main.textArea.getCaretPosition();
|
||||
int startPos = Main.txtByteEditView.getCaretPosition();
|
||||
String toFind = txtFind.getText();
|
||||
String txt = chckbxCaseSensitive.isSelected() ? Main.textArea.getText().substring(startPos)
|
||||
: Main.textArea.getText().substring(startPos).toLowerCase();
|
||||
String txt = chckbxCaseSensitive.isSelected() ? Main.txtByteEditView.getText().substring(startPos)
|
||||
: Main.txtByteEditView.getText().substring(startPos).toLowerCase();
|
||||
int index = txt.indexOf(chckbxCaseSensitive.isSelected() ? toFind : toFind.toLowerCase());
|
||||
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());
|
||||
startPos = 0;
|
||||
if (index == -1) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
Main.textArea.select(startPos + index, startPos + index + toFind.length());
|
||||
Main.txtByteEditView.select(startPos + index, startPos + index + toFind.length());
|
||||
}
|
||||
|
||||
public void replaceFind() {
|
||||
@@ -128,22 +130,22 @@ public class SearchBox extends JFrame {
|
||||
}
|
||||
|
||||
public void replace() {
|
||||
String txt = Main.textArea.getText();
|
||||
int startPos = Main.textArea.getSelectionStart();
|
||||
Main.textArea.replaceSelection(txtReplace.getText());
|
||||
Main.textArea.select(startPos, startPos + txtReplace.getText().length());
|
||||
String txt = Main.txtByteEditView.getText();
|
||||
int startPos = Main.txtByteEditView.getSelectionStart();
|
||||
Main.txtByteEditView.replaceSelection(txtReplace.getText());
|
||||
Main.txtByteEditView.select(startPos, startPos + txtReplace.getText().length());
|
||||
}
|
||||
|
||||
public void replaceAll() {
|
||||
String toFind = txtFind.getText();
|
||||
String toReplace = txtReplace.getText();
|
||||
String txt = Main.textArea.getText();
|
||||
int prev = Main.textArea.getCaretPosition();
|
||||
String txt = Main.txtByteEditView.getText();
|
||||
int prev = Main.txtByteEditView.getCaretPosition();
|
||||
if (chckbxCaseSensitive.isSelected()) {
|
||||
Main.textArea.replaceRange(txt.replace(toFind, toReplace), 0, txt.length());
|
||||
Main.txtByteEditView.replaceRange(txt.replace(toFind, toReplace), 0, txt.length());
|
||||
} 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.event.ActionEvent;
|
||||
@@ -18,6 +18,8 @@ import javax.swing.event.DocumentListener;
|
||||
import javax.swing.event.ListSelectionEvent;
|
||||
import javax.swing.event.ListSelectionListener;
|
||||
|
||||
import me.ByteEdit.main.Main;
|
||||
|
||||
public class TypeOpenBox extends JFrame {
|
||||
|
||||
public JPanel contentPane;
|
||||
+196
-103
@@ -30,6 +30,7 @@ import java.util.Map.Entry;
|
||||
import java.util.jar.JarEntry;
|
||||
import java.util.jar.JarFile;
|
||||
import java.util.jar.JarOutputStream;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import javax.swing.JComponent;
|
||||
import javax.swing.JDialog;
|
||||
@@ -46,6 +47,7 @@ import javax.swing.border.EmptyBorder;
|
||||
import javax.swing.event.TreeSelectionEvent;
|
||||
import javax.swing.event.TreeSelectionListener;
|
||||
import javax.swing.filechooser.FileNameExtensionFilter;
|
||||
import javax.swing.text.BadLocationException;
|
||||
import javax.swing.tree.DefaultMutableTreeNode;
|
||||
import javax.swing.tree.DefaultTreeCellRenderer;
|
||||
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.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 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, ClassNode> classNodes = new HashMap<>();
|
||||
public static String currentNodeName;
|
||||
public static RSyntaxTextArea textArea;
|
||||
public static RSyntaxTextArea txtByteEditView;
|
||||
public static SearchBox searchBox;
|
||||
public static TypeOpenBox typeOpenBox;
|
||||
public static OptionBox optionBox;
|
||||
public static JTree tree;
|
||||
public static RTextScrollPane scrollPane_ByteEdit;
|
||||
public static Theme theme;
|
||||
|
||||
/**
|
||||
* Launch the application.
|
||||
@@ -172,90 +185,12 @@ public class Main extends JFrame {
|
||||
contentPane.add(splitPane);
|
||||
JScrollPane scrollPane = new JScrollPane();
|
||||
splitPane.setLeftComponent(scrollPane);
|
||||
textArea = new RSyntaxTextArea();
|
||||
CompletionProvider provider = createCompletionProvider();
|
||||
AutoCompletion ac = new AutoCompletion(provider);
|
||||
ac.setShowDescWindow(true);
|
||||
ac.install(textArea);
|
||||
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 {
|
||||
Theme theme = Theme.load(getClass().getClassLoader().getResourceAsStream("org/fife/eclipse.xml"));
|
||||
theme.apply(textArea);
|
||||
} catch (IOException e2) {
|
||||
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.setBackground(Color.LIGHT_GRAY);
|
||||
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() {
|
||||
|
||||
@Override
|
||||
@@ -367,14 +288,20 @@ public class Main extends JFrame {
|
||||
@Override
|
||||
public void dragExit(DropTargetEvent dte) {}
|
||||
});
|
||||
}
|
||||
|
||||
public static void selectFile(String s) {
|
||||
if (s.endsWith(".class")) {
|
||||
currentNodeName = s;
|
||||
ClassNode classNode = classNodes.get(s);
|
||||
txtByteEditView = new RSyntaxTextArea();
|
||||
ac.install(txtByteEditView);
|
||||
txtByteEditView.setCodeFoldingEnabled(true);
|
||||
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 substr = s.substring(0, s.length() - 6);
|
||||
String substr = currentNodeName.substring(0, currentNodeName.length() - 6);
|
||||
for (String key : Main.classNodes.keySet()) {
|
||||
if (key.contains("$")) {
|
||||
String[] split = key.split("\\$");
|
||||
@@ -383,10 +310,173 @@ public class Main extends JFrame {
|
||||
}
|
||||
}
|
||||
}
|
||||
textArea.setText(dis);
|
||||
textArea.setCaretPosition(0);
|
||||
txtByteEditView.setText(dis);
|
||||
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() {
|
||||
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";
|
||||
StackTraceElement[] stackTrace = e.getStackTrace();
|
||||
for (StackTraceElement ste : stackTrace) {
|
||||
@@ -482,7 +572,10 @@ public class Main extends JFrame {
|
||||
break;
|
||||
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 {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
package me.ByteEdit.main;
|
||||
package me.ByteEdit.utils;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package me.ByteEdit.main;
|
||||
package me.ByteEdit.utils;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package me.ByteEdit.main;
|
||||
package me.ByteEdit.utils;
|
||||
|
||||
public class ExternalTypeEnumeration {
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package me.ByteEdit.main;
|
||||
package me.ByteEdit.utils;
|
||||
|
||||
public class OpcodesReverse {
|
||||
|
||||
@@ -22,7 +22,7 @@ import org.fife.ui.rsyntaxtextarea.modes.AbstractMarkupTokenMaker;
|
||||
import org.fife.ui.rtextarea.RDocument;
|
||||
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}.
|
||||
|
||||
Reference in new issue
Block a user