mirror of
https://github.com/SuspiciousActivity/ByteEdit.git
synced 2026-08-13 17:56:17 +00:00
Added renaming (CTRL + R) and field goto (CTRL + G)
This commit is contained in:
1 parent
30c6a7a69d
commit
1c887abb73
9 files changed
+436
-91
No files matched your search
@@ -1,6 +1,5 @@
|
||||
package me.ByteEdit.boxes;
|
||||
|
||||
import java.awt.EventQueue;
|
||||
import java.awt.Toolkit;
|
||||
|
||||
import javax.swing.JCheckBox;
|
||||
@@ -10,31 +9,11 @@ import javax.swing.UIManager;
|
||||
import javax.swing.border.EmptyBorder;
|
||||
|
||||
public class OptionBox extends JFrame {
|
||||
|
||||
|
||||
private JPanel contentPane;
|
||||
public JCheckBox chckbxComputeFrames;
|
||||
public JCheckBox chckbxComputeMax;
|
||||
|
||||
/**
|
||||
* Launch the application.
|
||||
*/
|
||||
public static void main(String[] args) {
|
||||
EventQueue.invokeLater(new Runnable() {
|
||||
|
||||
public void run() {
|
||||
try {
|
||||
OptionBox frame = new OptionBox();
|
||||
frame.setVisible(true);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the frame.
|
||||
*/
|
||||
|
||||
public OptionBox() {
|
||||
try {
|
||||
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
|
||||
|
||||
@@ -0,0 +1,232 @@
|
||||
package me.ByteEdit.boxes;
|
||||
|
||||
import java.awt.Toolkit;
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.awt.event.ActionListener;
|
||||
import java.util.LinkedList;
|
||||
|
||||
import javax.swing.JButton;
|
||||
import javax.swing.JFrame;
|
||||
import javax.swing.JLabel;
|
||||
import javax.swing.JOptionPane;
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.JTextField;
|
||||
import javax.swing.border.EmptyBorder;
|
||||
|
||||
import org.objectweb.asm.tree.AbstractInsnNode;
|
||||
import org.objectweb.asm.tree.ClassNode;
|
||||
import org.objectweb.asm.tree.FieldInsnNode;
|
||||
import org.objectweb.asm.tree.FieldNode;
|
||||
import org.objectweb.asm.tree.MethodInsnNode;
|
||||
import org.objectweb.asm.tree.MethodNode;
|
||||
|
||||
import me.ByteEdit.edit.Disassembler;
|
||||
import me.ByteEdit.main.Main;
|
||||
import me.ByteEdit.utils.ClassUtil;
|
||||
import me.ByteEdit.utils.UnicodeUtils;
|
||||
|
||||
public class RenameBox extends JFrame {
|
||||
|
||||
private JPanel contentPane;
|
||||
public JTextField txtName;
|
||||
public JTextField txtDesc;
|
||||
|
||||
public String className;
|
||||
public String name;
|
||||
public String desc;
|
||||
|
||||
public RenameBox() {
|
||||
setResizable(false);
|
||||
setTitle("Rename");
|
||||
setDefaultCloseOperation(JFrame.HIDE_ON_CLOSE);
|
||||
setBounds((int) (Toolkit.getDefaultToolkit().getScreenSize().getWidth() / 2 - 225),
|
||||
(int) (Toolkit.getDefaultToolkit().getScreenSize().getHeight() / 2 - 150), 450, 300);
|
||||
contentPane = new JPanel();
|
||||
contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
|
||||
setContentPane(contentPane);
|
||||
contentPane.setLayout(null);
|
||||
|
||||
JLabel lblName = new JLabel("Name");
|
||||
lblName.setBounds(10, 11, 33, 14);
|
||||
contentPane.add(lblName);
|
||||
|
||||
JLabel lblDesc = new JLabel("Desc");
|
||||
lblDesc.setBounds(10, 36, 33, 14);
|
||||
contentPane.add(lblDesc);
|
||||
|
||||
txtName = new JTextField();
|
||||
txtName.setBounds(53, 8, 381, 20);
|
||||
contentPane.add(txtName);
|
||||
txtName.setColumns(10);
|
||||
|
||||
txtDesc = new JTextField();
|
||||
txtDesc.setColumns(10);
|
||||
txtDesc.setBounds(53, 36, 381, 20);
|
||||
contentPane.add(txtDesc);
|
||||
|
||||
JButton btnRename = new JButton("Rename");
|
||||
btnRename.addActionListener(new ActionListener() {
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
if (className == null) {
|
||||
JOptionPane.showMessageDialog(null, "ClassName not set!", "Error!", JOptionPane.ERROR_MESSAGE);
|
||||
return;
|
||||
}
|
||||
if (name == null) {
|
||||
JOptionPane.showMessageDialog(null, "Name not set!", "Error!", JOptionPane.ERROR_MESSAGE);
|
||||
return;
|
||||
}
|
||||
if (desc == null) {
|
||||
JOptionPane.showMessageDialog(null, "Desc not set!", "Error!", JOptionPane.ERROR_MESSAGE);
|
||||
return;
|
||||
}
|
||||
ClassNode clazz = Main.classNodes.get(className.replace("/", ".") + ".class");
|
||||
if (clazz == null) {
|
||||
JOptionPane.showMessageDialog(null, "ClassNode not found!", "Error!", JOptionPane.ERROR_MESSAGE);
|
||||
return;
|
||||
}
|
||||
String newName = UnicodeUtils.unescape(txtName.getText());
|
||||
String newDesc = UnicodeUtils.unescape(txtDesc.getText());
|
||||
if (ClassUtil.isObjectClassMethod(newName, newDesc, true)) {
|
||||
JOptionPane.showMessageDialog(null, "Invalid name!", "Error!", JOptionPane.ERROR_MESSAGE);
|
||||
return;
|
||||
}
|
||||
if (desc.startsWith("(")) {
|
||||
if (newDesc.startsWith("(")) { // method
|
||||
ClassNode lastHit = clazz;
|
||||
while (clazz != null && clazz.superName != null) {
|
||||
ClassNode tmp = Main.classNodes.get(clazz.superName.replace("/", ".") + ".class");
|
||||
if (tmp != null) {
|
||||
boolean found = false;
|
||||
for (MethodNode mn : clazz.methods) {
|
||||
if (mn.name.equals(name) && mn.desc.equals(desc)) {
|
||||
lastHit = clazz;
|
||||
clazz = tmp;
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!found) {
|
||||
clazz = tmp;
|
||||
lastHit = null;
|
||||
}
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (lastHit != null) {
|
||||
clazz = lastHit;
|
||||
}
|
||||
LinkedList<MethodNode> methodsToRename = new LinkedList<>();
|
||||
LinkedList<MethodInsnNode> minsToRename = new LinkedList<>();
|
||||
for (ClassNode cn : Main.classNodes.values()) {
|
||||
boolean extendsMyClass = cn == clazz;
|
||||
if (!extendsMyClass) {
|
||||
ClassNode checkCN = cn;
|
||||
while (checkCN != null && checkCN.superName != null) {
|
||||
if (clazz.name.equals(checkCN.superName)) {
|
||||
extendsMyClass = true;
|
||||
break;
|
||||
}
|
||||
ClassNode tmp = Main.classNodes.get(checkCN.superName.replace("/", ".") + ".class");
|
||||
if (tmp != null) {
|
||||
checkCN = tmp;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
for (MethodNode mn : cn.methods) {
|
||||
if (extendsMyClass) {
|
||||
if (mn.name.equals(newName) && mn.desc.equals(newDesc)) {
|
||||
JOptionPane.showMessageDialog(null, "Method already exists in " + cn.name + "!", "Error!",
|
||||
JOptionPane.ERROR_MESSAGE);
|
||||
return;
|
||||
}
|
||||
if (mn.name.equals(name) && mn.desc.equals(desc)) {
|
||||
methodsToRename.add(mn);
|
||||
}
|
||||
}
|
||||
for (AbstractInsnNode ain : mn.instructions.toArray()) {
|
||||
if (ain instanceof MethodInsnNode) {
|
||||
MethodInsnNode min = (MethodInsnNode) ain;
|
||||
if (min.name.equals(name) && min.desc.equals(desc) && min.owner.equals(clazz.name)) {
|
||||
minsToRename.add(min);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
for (MethodNode mn : methodsToRename) {
|
||||
mn.name = newName;
|
||||
mn.desc = newDesc;
|
||||
}
|
||||
for (MethodInsnNode min : minsToRename) {
|
||||
min.name = newName;
|
||||
min.desc = newDesc;
|
||||
}
|
||||
} else {
|
||||
JOptionPane.showMessageDialog(null, "New Desc is not a method desc!", "Error!", JOptionPane.ERROR_MESSAGE);
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
if (!newDesc.startsWith("(")) { // field
|
||||
FieldNode currentFN = null;
|
||||
for (FieldNode fn : clazz.fields) {
|
||||
if (fn.name.equals(newName) && fn.desc.equals(newDesc)) {
|
||||
JOptionPane.showMessageDialog(null, "Field already exists!", "Error!", JOptionPane.ERROR_MESSAGE);
|
||||
return;
|
||||
}
|
||||
if (fn.name.equals(name) && fn.desc.equals(desc)) {
|
||||
currentFN = fn;
|
||||
}
|
||||
}
|
||||
if (currentFN == null) {
|
||||
JOptionPane.showMessageDialog(null, "Field not found?!", "Error!", JOptionPane.ERROR_MESSAGE);
|
||||
return;
|
||||
}
|
||||
currentFN.name = newName;
|
||||
currentFN.desc = newDesc;
|
||||
for (ClassNode cn : Main.classNodes.values()) {
|
||||
for (MethodNode mn : cn.methods) {
|
||||
for (AbstractInsnNode ain : mn.instructions.toArray()) {
|
||||
if (ain instanceof FieldInsnNode) {
|
||||
FieldInsnNode fin = (FieldInsnNode) ain;
|
||||
if (fin.name.equals(name) && fin.desc.equals(desc) && fin.owner.equals(className)) {
|
||||
fin.name = newName;
|
||||
fin.desc = newDesc;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
JOptionPane.showMessageDialog(null, "New Desc is not a field desc!", "Error!", JOptionPane.ERROR_MESSAGE);
|
||||
return;
|
||||
}
|
||||
}
|
||||
try { // refresh
|
||||
ClassNode classNode = Main.classNodes.get(Main.currentNodeName);
|
||||
int prev = Main.txtByteEditView.getCaretPosition();
|
||||
String dis = Disassembler.disassemble(classNode);
|
||||
String substr = Main.currentNodeName.substring(0, Main.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(Main.classNodes.get(key));
|
||||
}
|
||||
}
|
||||
}
|
||||
Main.txtByteEditView.setText(dis);
|
||||
Main.txtByteEditView.setCaretPosition(prev);
|
||||
} catch (Exception e2) {
|
||||
e2.printStackTrace();
|
||||
}
|
||||
name = newName;
|
||||
desc = newDesc;
|
||||
}
|
||||
});
|
||||
btnRename.setBounds(345, 237, 89, 23);
|
||||
contentPane.add(btnRename);
|
||||
}
|
||||
}
|
||||
@@ -20,15 +20,12 @@ import javax.swing.border.EmptyBorder;
|
||||
import me.ByteEdit.main.Main;
|
||||
|
||||
public class SearchBox extends JFrame {
|
||||
|
||||
|
||||
public JPanel contentPane;
|
||||
public JTextField txtFind;
|
||||
public JTextField txtReplace;
|
||||
public JCheckBox chckbxCaseSensitive;
|
||||
|
||||
/**
|
||||
* Create the frame.
|
||||
*/
|
||||
|
||||
public SearchBox() {
|
||||
try {
|
||||
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
|
||||
@@ -50,7 +47,7 @@ public class SearchBox extends JFrame {
|
||||
txtFind = new JTextField();
|
||||
KeyStroke enter = KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0);
|
||||
txtFind.registerKeyboardAction(new ActionListener() {
|
||||
|
||||
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
find();
|
||||
@@ -71,7 +68,7 @@ public class SearchBox extends JFrame {
|
||||
contentPane.add(chckbxCaseSensitive);
|
||||
JButton btnFind = new JButton("Find");
|
||||
btnFind.addActionListener(new ActionListener() {
|
||||
|
||||
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
find();
|
||||
}
|
||||
@@ -80,7 +77,7 @@ public class SearchBox extends JFrame {
|
||||
contentPane.add(btnFind);
|
||||
JButton btnReplacefind = new JButton("Replace/Find");
|
||||
btnReplacefind.addActionListener(new ActionListener() {
|
||||
|
||||
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
replaceFind();
|
||||
}
|
||||
@@ -89,7 +86,7 @@ public class SearchBox extends JFrame {
|
||||
contentPane.add(btnReplacefind);
|
||||
JButton btnReplace = new JButton("Replace");
|
||||
btnReplace.addActionListener(new ActionListener() {
|
||||
|
||||
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
replace();
|
||||
}
|
||||
@@ -98,7 +95,7 @@ public class SearchBox extends JFrame {
|
||||
contentPane.add(btnReplace);
|
||||
JButton btnReplaceAll = new JButton("Replace All");
|
||||
btnReplaceAll.addActionListener(new ActionListener() {
|
||||
|
||||
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
replaceAll();
|
||||
}
|
||||
@@ -106,7 +103,7 @@ public class SearchBox extends JFrame {
|
||||
btnReplaceAll.setBounds(130, 184, 110, 23);
|
||||
contentPane.add(btnReplaceAll);
|
||||
}
|
||||
|
||||
|
||||
public void find() {
|
||||
int startPos = Main.txtByteEditView.getCaretPosition();
|
||||
String toFind = txtFind.getText();
|
||||
@@ -123,19 +120,19 @@ public class SearchBox extends JFrame {
|
||||
}
|
||||
Main.txtByteEditView.select(startPos + index, startPos + index + toFind.length());
|
||||
}
|
||||
|
||||
|
||||
public void replaceFind() {
|
||||
replace();
|
||||
find();
|
||||
}
|
||||
|
||||
|
||||
public void replace() {
|
||||
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();
|
||||
|
||||
@@ -21,13 +21,10 @@ import javax.swing.event.ListSelectionListener;
|
||||
import me.ByteEdit.main.Main;
|
||||
|
||||
public class TypeOpenBox extends JFrame {
|
||||
|
||||
|
||||
public JPanel contentPane;
|
||||
public JTextField txtSearch;
|
||||
|
||||
/**
|
||||
* Create the frame.
|
||||
*/
|
||||
|
||||
public TypeOpenBox() {
|
||||
try {
|
||||
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
|
||||
@@ -43,11 +40,11 @@ public class TypeOpenBox extends JFrame {
|
||||
contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
|
||||
setContentPane(contentPane);
|
||||
contentPane.setLayout(null);
|
||||
|
||||
|
||||
DefaultListModel<String> model = new DefaultListModel<>();
|
||||
JList<String> list = new JList(model);
|
||||
list.addListSelectionListener(new ListSelectionListener() {
|
||||
|
||||
|
||||
public void valueChanged(ListSelectionEvent e) {
|
||||
String val = list.getSelectedValue();
|
||||
if (val != null && !val.equals(Main.currentNodeName)) {
|
||||
@@ -55,10 +52,10 @@ public class TypeOpenBox extends JFrame {
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
txtSearch = new JTextField();
|
||||
txtSearch.addActionListener(new ActionListener() {
|
||||
|
||||
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
if (model.size() == 1) {
|
||||
list.setSelectedIndex(0);
|
||||
@@ -66,19 +63,19 @@ public class TypeOpenBox extends JFrame {
|
||||
}
|
||||
});
|
||||
txtSearch.getDocument().addDocumentListener(new DocumentListener() {
|
||||
|
||||
|
||||
public void changedUpdate(DocumentEvent e) {
|
||||
updateList();
|
||||
}
|
||||
|
||||
|
||||
public void removeUpdate(DocumentEvent e) {
|
||||
updateList();
|
||||
}
|
||||
|
||||
|
||||
public void insertUpdate(DocumentEvent e) {
|
||||
updateList();
|
||||
}
|
||||
|
||||
|
||||
public void updateList() {
|
||||
model.clear();
|
||||
if (txtSearch.getText().isEmpty()) {
|
||||
@@ -107,13 +104,13 @@ public class TypeOpenBox extends JFrame {
|
||||
txtSearch.setBounds(10, 11, 374, 20);
|
||||
contentPane.add(txtSearch);
|
||||
txtSearch.setColumns(10);
|
||||
|
||||
|
||||
JScrollPane scrollPane = new JScrollPane();
|
||||
scrollPane.setBounds(10, 46, 374, 194);
|
||||
contentPane.add(scrollPane);
|
||||
|
||||
|
||||
list.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
|
||||
scrollPane.setViewportView(list);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -16,12 +16,9 @@ import me.ByteEdit.main.Main;
|
||||
import me.ByteEdit.utils.UnicodeUtils;
|
||||
|
||||
public class UnicodeBox extends JFrame {
|
||||
|
||||
|
||||
private JPanel contentPane;
|
||||
|
||||
/**
|
||||
* Create the frame.
|
||||
*/
|
||||
|
||||
public UnicodeBox() {
|
||||
try {
|
||||
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
|
||||
@@ -37,12 +34,12 @@ public class UnicodeBox extends JFrame {
|
||||
contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
|
||||
setContentPane(contentPane);
|
||||
contentPane.setLayout(null);
|
||||
|
||||
|
||||
JTextArea textArea = new JTextArea();
|
||||
|
||||
|
||||
JButton btnEscape = new JButton("Escape");
|
||||
btnEscape.addActionListener(new ActionListener() {
|
||||
|
||||
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
try {
|
||||
textArea.setText(UnicodeUtils.escape(textArea.getText()));
|
||||
@@ -53,10 +50,10 @@ public class UnicodeBox extends JFrame {
|
||||
});
|
||||
btnEscape.setBounds(10, 137, 89, 23);
|
||||
contentPane.add(btnEscape);
|
||||
|
||||
|
||||
JButton btnUnescape = new JButton("Unescape");
|
||||
btnUnescape.addActionListener(new ActionListener() {
|
||||
|
||||
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
try {
|
||||
textArea.setText(UnicodeUtils.unescape(textArea.getText()));
|
||||
@@ -67,11 +64,11 @@ public class UnicodeBox extends JFrame {
|
||||
});
|
||||
btnUnescape.setBounds(195, 137, 89, 23);
|
||||
contentPane.add(btnUnescape);
|
||||
|
||||
|
||||
JScrollPane scrollPane = new JScrollPane();
|
||||
scrollPane.setBounds(10, 11, 274, 115);
|
||||
contentPane.add(scrollPane);
|
||||
|
||||
|
||||
scrollPane.setViewportView(textArea);
|
||||
}
|
||||
}
|
||||
@@ -70,7 +70,7 @@ public class Disassembler {
|
||||
|
||||
}
|
||||
|
||||
public static DisassembleTuple disassemble(ClassNode classNode, MethodNode methodToFind) {
|
||||
public static DisassembleTuple disassemble(ClassNode classNode, Object nodeToFind) {
|
||||
if (classNode == null) {
|
||||
return new DisassembleTuple("ClassNode is null! This is not a valid java class file!");
|
||||
}
|
||||
@@ -228,6 +228,9 @@ public class Disassembler {
|
||||
s += "\n";
|
||||
}
|
||||
}
|
||||
if (fn.equals(nodeToFind)) {
|
||||
lineFound = s.split("\\n").length;
|
||||
}
|
||||
s += "\t" + ClassUtil.getAccessFlagsFull(fn.access).replace("varargs", "transient") + UnicodeUtils.escapeWithSpaces(fn.desc) + " "
|
||||
+ UnicodeUtils.escapeWithSpaces(fn.name);
|
||||
if (fn.value != null) {
|
||||
@@ -303,7 +306,7 @@ public class Disassembler {
|
||||
s += "\n";
|
||||
}
|
||||
}
|
||||
if (mn.equals(methodToFind)) {
|
||||
if (mn.equals(nodeToFind)) {
|
||||
lineFound = s.split("\\n").length;
|
||||
}
|
||||
s += "\t" + ClassUtil.getAccessFlagsFull(mn.access) + UnicodeUtils.escapeWithSpaces(mn.name) + " "
|
||||
|
||||
@@ -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.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import javax.swing.JComponent;
|
||||
@@ -67,9 +68,11 @@ import org.fife.ui.rtextarea.RTextScrollPane;
|
||||
import org.objectweb.asm.ClassReader;
|
||||
import org.objectweb.asm.ClassWriter;
|
||||
import org.objectweb.asm.tree.ClassNode;
|
||||
import org.objectweb.asm.tree.FieldNode;
|
||||
import org.objectweb.asm.tree.MethodNode;
|
||||
|
||||
import me.ByteEdit.boxes.OptionBox;
|
||||
import me.ByteEdit.boxes.RenameBox;
|
||||
import me.ByteEdit.boxes.SearchBox;
|
||||
import me.ByteEdit.boxes.TypeOpenBox;
|
||||
import me.ByteEdit.boxes.UnicodeBox;
|
||||
@@ -94,6 +97,7 @@ public class Main extends JFrame {
|
||||
public static TypeOpenBox typeOpenBox;
|
||||
public static OptionBox optionBox;
|
||||
public static UnicodeBox unicodeBox;
|
||||
public static RenameBox renameBox;
|
||||
public static JTree tree;
|
||||
public static RTextScrollPane scrollPane_ByteEdit;
|
||||
public static Theme theme;
|
||||
@@ -169,6 +173,7 @@ public class Main extends JFrame {
|
||||
typeOpenBox = new TypeOpenBox();
|
||||
optionBox = new OptionBox();
|
||||
unicodeBox = new UnicodeBox();
|
||||
renameBox = new RenameBox();
|
||||
setTitle("ByteEdit");
|
||||
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
|
||||
setBounds((int) (Toolkit.getDefaultToolkit().getScreenSize().getWidth() / 2 - 407),
|
||||
@@ -267,6 +272,13 @@ public class Main extends JFrame {
|
||||
} catch (IOException e1) {
|
||||
e1.printStackTrace();
|
||||
}
|
||||
txtByteEditView.setText("");
|
||||
currentNodeName = null;
|
||||
searchBox.setVisible(false);
|
||||
typeOpenBox.setVisible(false);
|
||||
optionBox.setVisible(false);
|
||||
unicodeBox.setVisible(false);
|
||||
renameBox.setVisible(false);
|
||||
isChangingFile = false;
|
||||
}
|
||||
dtde.dropComplete(true);
|
||||
@@ -300,7 +312,7 @@ public class Main extends JFrame {
|
||||
|
||||
@Override
|
||||
public void keyReleased(KeyEvent e) {
|
||||
if (e.getKeyCode() == 116 && currentNodeName != null) {
|
||||
if (e.getKeyCode() == 116 && currentNodeName != null) { // F5
|
||||
try {
|
||||
ClassNode classNode = classNodes.get(currentNodeName);
|
||||
int prev = txtByteEditView.getCaretPosition();
|
||||
@@ -316,7 +328,9 @@ public class Main extends JFrame {
|
||||
}
|
||||
txtByteEditView.setText(dis);
|
||||
txtByteEditView.setCaretPosition(prev);
|
||||
} catch (Exception e2) {}
|
||||
} catch (Exception e2) {
|
||||
e2.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -326,6 +340,7 @@ public class Main extends JFrame {
|
||||
KeyStroke ctrlG = KeyStroke.getKeyStroke(KeyEvent.VK_G, KeyEvent.CTRL_DOWN_MASK);
|
||||
KeyStroke ctrlO = KeyStroke.getKeyStroke(KeyEvent.VK_O, KeyEvent.CTRL_DOWN_MASK);
|
||||
KeyStroke ctrlU = KeyStroke.getKeyStroke(KeyEvent.VK_U, KeyEvent.CTRL_DOWN_MASK);
|
||||
KeyStroke ctrlR = KeyStroke.getKeyStroke(KeyEvent.VK_R, KeyEvent.CTRL_DOWN_MASK);
|
||||
// global
|
||||
txtByteEditView.registerKeyboardAction(new ActionListener() {
|
||||
|
||||
@@ -385,6 +400,17 @@ public class Main extends JFrame {
|
||||
}
|
||||
}
|
||||
}, ctrlG, JComponent.WHEN_FOCUSED);
|
||||
txtByteEditView.registerKeyboardAction(new ActionListener() {
|
||||
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
try {
|
||||
renameSelected();
|
||||
} catch (BadLocationException e1) {
|
||||
e1.printStackTrace();
|
||||
}
|
||||
}
|
||||
}, ctrlR, JComponent.WHEN_FOCUSED);
|
||||
txtByteEditView.setEditable(true);
|
||||
txtByteEditView.setSyntaxEditingStyle(SyntaxConstants.SYNTAX_STYLE_JAVA_DISASSEMBLE);
|
||||
txtByteEditView.setCodeFoldingEnabled(true);
|
||||
@@ -445,6 +471,84 @@ public class Main extends JFrame {
|
||||
return;
|
||||
}
|
||||
selectFile(className + ".class");
|
||||
} 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 className = UnicodeUtils.unescape(split[2]);
|
||||
String[] nameSplit = className.split("/");
|
||||
String fieldName = nameSplit[nameSplit.length - 1];
|
||||
className = className.substring(0, className.length() - fieldName.length() - 1);
|
||||
ClassNode classNode = classNodes.get(className + ".class");
|
||||
if (classNode == null) {
|
||||
return;
|
||||
}
|
||||
for (FieldNode fn : classNode.fields) {
|
||||
if (fn.name.equals(fieldName) && fn.desc.equals(desc)) {
|
||||
while (classNode.outerClass != null) {
|
||||
classNode = classNodes.get(classNode.outerClass + ".class");
|
||||
}
|
||||
int lineFound = selectFileWithSearch(classNode.name + ".class", fn);
|
||||
if (lineFound != -1) {
|
||||
Main.txtByteEditView.setCaretPosition(Main.txtByteEditView.getLineStartOffset(lineFound));
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private final Pattern renameableFieldPattern = Pattern.compile("^\t(?:[a-z]+ |0x[0-9a-fA-F]+ )*?(\\[*(?:V|Z|C|B|S|I|F|J|D|L.+?;)) ([^ ]+) ?.*");
|
||||
private final Pattern renameableMethodPattern = Pattern
|
||||
.compile("^\t(?:[a-z]+ |0x[0-9a-fA-F]+ )*?([^ ]+) (\\((?:\\[*(?:V|Z|C|B|S|I|F|J|D|L.+?;))*\\)[^ ]+) .*\\{");
|
||||
|
||||
public void renameSelected() throws BadLocationException {
|
||||
int lineStart = txtByteEditView.getLineStartOffsetOfCurrentLine();
|
||||
int lineEnd = txtByteEditView.getLineEndOffsetOfCurrentLine() - 1;
|
||||
String line = txtByteEditView.getText(lineStart, lineEnd - lineStart);
|
||||
Matcher m = renameableFieldPattern.matcher(line);
|
||||
if (m.find()) {
|
||||
setRenameInfo(m, lineEnd);
|
||||
} else {
|
||||
m = renameableMethodPattern.matcher(line);
|
||||
if (m.find()) {
|
||||
if (ClassUtil.isObjectClassMethod(m.group(1), m.group(2), false)) {
|
||||
JOptionPane.showMessageDialog(null, "This method can not be renamed!", "Error!", JOptionPane.ERROR_MESSAGE);
|
||||
return;
|
||||
}
|
||||
setRenameInfo(m, lineEnd);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void setRenameInfo(Matcher m, int lineEnd) throws BadLocationException {
|
||||
String[] arr = txtByteEditView.getText(0, lineEnd).split("\n");
|
||||
int lastClassLine = 0;
|
||||
for (int i = 0; i < arr.length; i++) {
|
||||
if (arr[i].startsWith("// #Class")) {
|
||||
lastClassLine = i;
|
||||
}
|
||||
}
|
||||
while (lastClassLine < arr.length && arr[lastClassLine].startsWith("// ")) {
|
||||
lastClassLine++;
|
||||
}
|
||||
if (lastClassLine < arr.length) {
|
||||
String s = arr[lastClassLine];
|
||||
s = s.substring(0, s.length() - 2);
|
||||
if (s.contains(" implements "))
|
||||
s = s.substring(0, s.lastIndexOf(" implements "));
|
||||
if (s.contains(" extends "))
|
||||
s = s.substring(0, s.lastIndexOf(" extends "));
|
||||
String[] split = s.split(" ");
|
||||
String className = UnicodeUtils.unescape(split[split.length - 1]);
|
||||
renameBox.className = className;
|
||||
String name = m.pattern() == renameableFieldPattern ? m.group(2) : m.group(1);
|
||||
String desc = m.pattern() == renameableFieldPattern ? m.group(1) : m.group(2);
|
||||
renameBox.name = name;
|
||||
renameBox.desc = desc;
|
||||
renameBox.txtName.setText(name);
|
||||
renameBox.txtDesc.setText(desc);
|
||||
renameBox.setVisible(true);
|
||||
renameBox.txtName.requestFocusInWindow();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -463,13 +567,13 @@ public class Main extends JFrame {
|
||||
}
|
||||
}
|
||||
|
||||
public static int selectFileWithSearch(String s, MethodNode methodToFind) {
|
||||
public static int selectFileWithSearch(String s, Object nodeToFind) {
|
||||
if (s.endsWith(".class")) {
|
||||
currentNodeName = s;
|
||||
int lineFound = -1;
|
||||
ClassNode classNode = classNodes.get(s);
|
||||
String dis = "";
|
||||
DisassembleTuple tuple = Disassembler.disassemble(classNode, methodToFind);
|
||||
DisassembleTuple tuple = Disassembler.disassemble(classNode, nodeToFind);
|
||||
if (tuple.getLine() != -1) {
|
||||
lineFound = dis.split("\\n").length + tuple.getLine() - 1;
|
||||
}
|
||||
@@ -479,7 +583,7 @@ public class Main extends JFrame {
|
||||
if (key.contains("$")) {
|
||||
String[] split = key.split("\\$");
|
||||
if (split[0].equals(substr)) {
|
||||
tuple = Disassembler.disassemble(classNodes.get(key), methodToFind);
|
||||
tuple = Disassembler.disassemble(classNodes.get(key), nodeToFind);
|
||||
if (tuple.getLine() != -1) {
|
||||
lineFound = dis.split("\\n").length + tuple.getLine() + 1;
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@ import java.util.HashSet;
|
||||
import org.objectweb.asm.Type;
|
||||
|
||||
public class ClassUtil {
|
||||
|
||||
|
||||
public static final int ACC_PUBLIC = 0x0001;
|
||||
public static final int ACC_PRIVATE = 0x0002;
|
||||
public static final int ACC_PROTECTED = 0x0004;
|
||||
@@ -25,7 +25,41 @@ public class ClassUtil {
|
||||
public static final int ACC_ANNOTATION = 0x2000;
|
||||
public static final int ACC_ENUM = 0x4000;
|
||||
public static final int ACC_MANDATED = 0x8000;
|
||||
|
||||
|
||||
public static boolean isObjectClassMethod(String name, String desc, boolean forbidInits) {
|
||||
switch (name) {
|
||||
case "<init>":
|
||||
case "<clinit>":
|
||||
if (forbidInits) {
|
||||
return true;
|
||||
}
|
||||
case "notifyAll":
|
||||
case "notify":
|
||||
if (desc.equals("()V")) {
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
case "wait":
|
||||
if (desc.equals("()V") || desc.equals("(J)V") || desc.equals("(JI)V")) {
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
case "equals":
|
||||
if (desc.equals("(Ljava/lang/Object;)Z")) {
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
case "hashCode":
|
||||
if (desc.equals("()I")) {
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static int getIDFromClassNameForType(String s) {
|
||||
s = s.toUpperCase();
|
||||
switch (s) {
|
||||
@@ -64,7 +98,7 @@ public class ClassUtil {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static String getClassNameFromType(Type type) {
|
||||
switch (type.getSort()) {
|
||||
case 0: {
|
||||
@@ -103,7 +137,7 @@ public class ClassUtil {
|
||||
}
|
||||
return Integer.toString(type.getSort());
|
||||
}
|
||||
|
||||
|
||||
public static String getArrayTypeByID(int id) {
|
||||
switch (id) {
|
||||
case 4:
|
||||
@@ -126,7 +160,7 @@ public class ClassUtil {
|
||||
return Integer.toString(id);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static int getArrayIDByType(String type) {
|
||||
switch (type) {
|
||||
case "Z":
|
||||
@@ -149,7 +183,7 @@ public class ClassUtil {
|
||||
return Integer.parseInt(type);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static String getAccessFlagsClass(int access) {
|
||||
String s = "";
|
||||
if ((ACC_PUBLIC & access) != 0) {
|
||||
@@ -175,7 +209,7 @@ public class ClassUtil {
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
public static String getAccessFlagsFull(int access) {
|
||||
int acc = 0;
|
||||
String s = "";
|
||||
@@ -249,7 +283,7 @@ public class ClassUtil {
|
||||
return "0x" + Integer.toHexString(access) + " ";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return { JavaType, Import }
|
||||
*/
|
||||
@@ -308,7 +342,7 @@ public class ClassUtil {
|
||||
}
|
||||
return new String[] { type, importName };
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return { ReturnValue, ParameterValues, Imports } getrennt durch ";"
|
||||
*/
|
||||
@@ -411,7 +445,7 @@ public class ClassUtil {
|
||||
}
|
||||
return new String[] { returnType[0], parameterStr, importStr };
|
||||
}
|
||||
|
||||
|
||||
public static int countMethodParams(String desc) {
|
||||
int count = 0;
|
||||
String parameterType = desc.split("\\)")[0].substring(1);
|
||||
@@ -446,7 +480,7 @@ public class ClassUtil {
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
|
||||
public static String getDecompiledValue(Object o, String desc, boolean escapeSpaces) {
|
||||
switch (o.getClass().getName()) {
|
||||
case "java.lang.String": {
|
||||
@@ -468,11 +502,11 @@ public class ClassUtil {
|
||||
return o.toString();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static String getDecompiledValue(Object o, String desc) {
|
||||
return getDecompiledValue(o, desc, false);
|
||||
}
|
||||
|
||||
|
||||
public static Object getCastedValue(String o, String className) {
|
||||
switch (className) {
|
||||
case "java/lang/String": {
|
||||
@@ -503,7 +537,7 @@ public class ClassUtil {
|
||||
return o.toString();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static String getSimpleDesc(String type) {
|
||||
String desc = "";
|
||||
for (int i = 0; i < countArraySize(type); i++) {
|
||||
@@ -517,7 +551,7 @@ public class ClassUtil {
|
||||
}
|
||||
return desc;
|
||||
}
|
||||
|
||||
|
||||
private static int countArraySize(String type) {
|
||||
int size = 0;
|
||||
for (byte b : type.getBytes()) {
|
||||
@@ -527,7 +561,7 @@ public class ClassUtil {
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
|
||||
public static final HashMap<String, String> VARS = new HashMap<>();
|
||||
static {
|
||||
VARS.put("byte", "B");
|
||||
@@ -540,7 +574,7 @@ public class ClassUtil {
|
||||
VARS.put("boolean", "Z");
|
||||
VARS.put("void", "V");
|
||||
}
|
||||
|
||||
|
||||
public static int externalArrayTypeDimensionCount(String s) {
|
||||
int i = 0;
|
||||
int j = "[]".length();
|
||||
@@ -551,7 +585,7 @@ public class ClassUtil {
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
|
||||
public static String internalMethodDescriptor(String returnType, String methodArgs) {
|
||||
returnType = returnType.replace(".", "/");
|
||||
methodArgs = methodArgs.replace(".", "/");
|
||||
|
||||
Reference in new issue
Block a user