12 Commits
Author SHA1 Message Date
SuspiciousActivity d1710ea6a5 Better frames 2020-11-29 00:38:20 +01:00
SuspiciousActivity ad55d6793c Fixed number obfuscator 2020-11-27 11:06:26 +01:00
SuspiciousActivity ac247a89ca Fixed number deobfuscator 2020-11-27 01:01:30 +01:00
SuspiciousActivity b5e4847be5 Added number deobfuscator 2020-11-27 00:07:03 +01:00
SuspiciousActivity 30c9c81d38 Fixed crash 2020-11-26 17:07:36 +01:00
SuspiciousActivity 65235c6b5b ToolTips for #... 2020-11-26 15:52:35 +01:00
SuspiciousActivity d8096a4ec5 Fixes and improvements 2020-11-25 23:53:58 +01:00
SuspiciousActivity add82951e6 Huge String improvements 2020-11-25 23:14:14 +01:00
SuspiciousActivity afc59d63d3 Update 2020-11-25 20:32:57 +01:00
SuspiciousActivity 53f214b7b0 Performance improvements 2020-11-25 14:18:11 +01:00
SuspiciousActivity 385c9ad9e3 More stuff 2020-11-24 21:19:05 +01:00
SuspiciousActivity a70bc89deb Improvements 2020-11-23 19:52:23 +01:00
22 changed files with 2411 additions and 951 deletions

No files matched your search

+3 -11
View File
@@ -1,7 +1,6 @@
package me.ByteEdit.boxes; package me.ByteEdit.boxes;
import java.awt.BorderLayout; import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Toolkit; import java.awt.Toolkit;
import java.awt.event.ActionEvent; import java.awt.event.ActionEvent;
import java.awt.event.ActionListener; import java.awt.event.ActionListener;
@@ -22,7 +21,6 @@ import javax.swing.JFrame;
import javax.swing.JOptionPane; import javax.swing.JOptionPane;
import javax.swing.JPanel; import javax.swing.JPanel;
import javax.swing.KeyStroke; import javax.swing.KeyStroke;
import javax.swing.UIManager;
import javax.swing.border.EmptyBorder; import javax.swing.border.EmptyBorder;
import javax.tools.JavaCompiler; import javax.tools.JavaCompiler;
import javax.tools.SimpleJavaFileObject; import javax.tools.SimpleJavaFileObject;
@@ -36,6 +34,7 @@ import org.objectweb.asm.tree.ClassNode;
import me.ByteEdit.edit.Disassembler; import me.ByteEdit.edit.Disassembler;
import me.ByteEdit.main.Main; import me.ByteEdit.main.Main;
import me.ByteEdit.main.ThemeManager;
public class CompilationBox extends JFrame { public class CompilationBox extends JFrame {
@@ -46,32 +45,25 @@ public class CompilationBox extends JFrame {
public CompilationBox() { public CompilationBox() {
compSuccess = new CompilationSuccess(); compSuccess = new CompilationSuccess();
try { ThemeManager.registerFrames(compSuccess);
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (Exception e) {
e.printStackTrace();
}
setTitle("Java Compiler"); setTitle("Java Compiler");
setDefaultCloseOperation(JFrame.HIDE_ON_CLOSE); setDefaultCloseOperation(JFrame.HIDE_ON_CLOSE);
setBounds((int) (Toolkit.getDefaultToolkit().getScreenSize().getWidth() / 2 - 400), setBounds((int) (Toolkit.getDefaultToolkit().getScreenSize().getWidth() / 2 - 400),
(int) (Toolkit.getDefaultToolkit().getScreenSize().getHeight() / 2 - 200), 800, 400); (int) (Toolkit.getDefaultToolkit().getScreenSize().getHeight() / 2 - 200), 800, 400);
contentPane = new JPanel(); contentPane = new JPanel();
contentPane.setBackground(Main.dark ? new Color(0x2F2F2F) : Color.GRAY);
contentPane.setBorder(new EmptyBorder(5, 5, 5, 5)); contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
setContentPane(contentPane); setContentPane(contentPane);
contentPane.setLayout(new BorderLayout(0, 0)); contentPane.setLayout(new BorderLayout(0, 0));
Main.theme.apply(textArea); ThemeManager.registerTextArea(textArea);
textArea.setEditable(true); textArea.setEditable(true);
textArea.setSyntaxEditingStyle(SyntaxConstants.SYNTAX_STYLE_JAVA); textArea.setSyntaxEditingStyle(SyntaxConstants.SYNTAX_STYLE_JAVA);
textArea.setCodeFoldingEnabled(true); textArea.setCodeFoldingEnabled(true);
textArea.setBackground(Main.dark ? new Color(0x2F2F2F) : Color.LIGHT_GRAY);
RTextScrollPane scrollPane = new RTextScrollPane(); RTextScrollPane scrollPane = new RTextScrollPane();
scrollPane.setViewportView(textArea); scrollPane.setViewportView(textArea);
scrollPane.setLineNumbersEnabled(true); scrollPane.setLineNumbersEnabled(true);
scrollPane.setFoldIndicatorEnabled(true); scrollPane.setFoldIndicatorEnabled(true);
scrollPane.getGutter().setBackground(Main.dark ? new Color(0x2F2F2F) : Color.LIGHT_GRAY);
contentPane.add(scrollPane); contentPane.add(scrollPane);
KeyStroke ctrlS = KeyStroke.getKeyStroke(KeyEvent.VK_S, KeyEvent.CTRL_DOWN_MASK); KeyStroke ctrlS = KeyStroke.getKeyStroke(KeyEvent.VK_S, KeyEvent.CTRL_DOWN_MASK);
+2 -12
View File
@@ -1,19 +1,17 @@
package me.ByteEdit.boxes; package me.ByteEdit.boxes;
import java.awt.BorderLayout; import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Toolkit; import java.awt.Toolkit;
import javax.swing.JFrame; import javax.swing.JFrame;
import javax.swing.JPanel; import javax.swing.JPanel;
import javax.swing.UIManager;
import javax.swing.border.EmptyBorder; import javax.swing.border.EmptyBorder;
import org.fife.ui.rsyntaxtextarea.RSyntaxTextArea; import org.fife.ui.rsyntaxtextarea.RSyntaxTextArea;
import org.fife.ui.rsyntaxtextarea.SyntaxConstants; import org.fife.ui.rsyntaxtextarea.SyntaxConstants;
import org.fife.ui.rtextarea.RTextScrollPane; import org.fife.ui.rtextarea.RTextScrollPane;
import me.ByteEdit.main.Main; import me.ByteEdit.main.ThemeManager;
public class CompilationSuccess extends JFrame { public class CompilationSuccess extends JFrame {
@@ -21,32 +19,24 @@ public class CompilationSuccess extends JFrame {
RSyntaxTextArea textArea = new RSyntaxTextArea(); RSyntaxTextArea textArea = new RSyntaxTextArea();
public CompilationSuccess() { public CompilationSuccess() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (Exception e) {
e.printStackTrace();
}
setTitle("Java Compiler - Result"); setTitle("Java Compiler - Result");
setDefaultCloseOperation(JFrame.HIDE_ON_CLOSE); setDefaultCloseOperation(JFrame.HIDE_ON_CLOSE);
setBounds((int) (Toolkit.getDefaultToolkit().getScreenSize().getWidth() / 2 - 400), setBounds((int) (Toolkit.getDefaultToolkit().getScreenSize().getWidth() / 2 - 400),
(int) (Toolkit.getDefaultToolkit().getScreenSize().getHeight() / 2 - 200), 800, 400); (int) (Toolkit.getDefaultToolkit().getScreenSize().getHeight() / 2 - 200), 800, 400);
contentPane = new JPanel(); contentPane = new JPanel();
contentPane.setBackground(Main.dark ? new Color(0x2F2F2F) : Color.GRAY);
contentPane.setBorder(new EmptyBorder(5, 5, 5, 5)); contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
setContentPane(contentPane); setContentPane(contentPane);
contentPane.setLayout(new BorderLayout(0, 0)); contentPane.setLayout(new BorderLayout(0, 0));
Main.theme.apply(textArea); ThemeManager.registerTextArea(textArea);
textArea.setEditable(true); textArea.setEditable(true);
textArea.setSyntaxEditingStyle(SyntaxConstants.SYNTAX_STYLE_JAVA_DISASSEMBLE); textArea.setSyntaxEditingStyle(SyntaxConstants.SYNTAX_STYLE_JAVA_DISASSEMBLE);
textArea.setCodeFoldingEnabled(true); textArea.setCodeFoldingEnabled(true);
textArea.setBackground(Main.dark ? new Color(0x2F2F2F) : Color.LIGHT_GRAY);
RTextScrollPane scrollPane = new RTextScrollPane(); RTextScrollPane scrollPane = new RTextScrollPane();
scrollPane.setViewportView(textArea); scrollPane.setViewportView(textArea);
scrollPane.setLineNumbersEnabled(true); scrollPane.setLineNumbersEnabled(true);
scrollPane.setFoldIndicatorEnabled(true); scrollPane.setFoldIndicatorEnabled(true);
scrollPane.getGutter().setBackground(Main.dark ? new Color(0x2F2F2F) : Color.LIGHT_GRAY);
contentPane.add(scrollPane); contentPane.add(scrollPane);
} }
} }
+6 -10
View File
@@ -15,7 +15,6 @@ import javax.swing.JLabel;
import javax.swing.JPanel; import javax.swing.JPanel;
import javax.swing.JTextField; import javax.swing.JTextField;
import javax.swing.KeyStroke; import javax.swing.KeyStroke;
import javax.swing.UIManager;
import javax.swing.border.EmptyBorder; import javax.swing.border.EmptyBorder;
import org.objectweb.asm.tree.AbstractInsnNode; import org.objectweb.asm.tree.AbstractInsnNode;
@@ -27,6 +26,7 @@ import org.objectweb.asm.tree.MethodNode;
import me.ByteEdit.boxes.GlobalSearchOpenBox.Info; import me.ByteEdit.boxes.GlobalSearchOpenBox.Info;
import me.ByteEdit.main.Main; import me.ByteEdit.main.Main;
import me.ByteEdit.main.ThemeManager;
import me.ByteEdit.utils.UnicodeUtils; import me.ByteEdit.utils.UnicodeUtils;
public class GlobalSearchBox extends JFrame { public class GlobalSearchBox extends JFrame {
@@ -43,12 +43,8 @@ public class GlobalSearchBox extends JFrame {
private GlobalSearchOpenBox openBox; private GlobalSearchOpenBox openBox;
public GlobalSearchBox() { public GlobalSearchBox() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (Exception e) {
e.printStackTrace();
}
openBox = new GlobalSearchOpenBox(); openBox = new GlobalSearchOpenBox();
ThemeManager.registerFrames(openBox);
setResizable(false); setResizable(false);
setTitle("Global Search"); setTitle("Global Search");
setDefaultCloseOperation(JFrame.HIDE_ON_CLOSE); setDefaultCloseOperation(JFrame.HIDE_ON_CLOSE);
@@ -141,7 +137,7 @@ public class GlobalSearchBox extends JFrame {
openBox.model.clear(); openBox.model.clear();
Set<Info> set = new HashSet<>(); Set<Info> set = new HashSet<>();
if (!txtString.getText().isEmpty()) { if (!txtString.getText().isEmpty()) {
String str = UnicodeUtils.unescape(txtString.getText()); String str = UnicodeUtils.unescape(null, txtString.getText(), true);
if (ignoreCase) { if (ignoreCase) {
str = str.toLowerCase(); str = str.toLowerCase();
} }
@@ -161,11 +157,11 @@ public class GlobalSearchBox extends JFrame {
} }
} }
} else { } else {
String owner = UnicodeUtils.unescape(txtOwner.getText()); String owner = UnicodeUtils.unescape(null, txtOwner.getText(), true);
boolean wildCardOwner = owner.isEmpty(); boolean wildCardOwner = owner.isEmpty();
String name = UnicodeUtils.unescape(txtName.getText()); String name = UnicodeUtils.unescape(null, txtName.getText(), true);
boolean wildCardName = name.isEmpty(); boolean wildCardName = name.isEmpty();
String desc = UnicodeUtils.unescape(txtDesc.getText()); String desc = UnicodeUtils.unescape(null, txtDesc.getText(), true);
boolean wildCardDesc = desc.isEmpty(); boolean wildCardDesc = desc.isEmpty();
for (ClassNode cn : Main.classNodes.values()) { for (ClassNode cn : Main.classNodes.values()) {
for (MethodNode mn : cn.methods) { for (MethodNode mn : cn.methods) {
@@ -8,7 +8,6 @@ import javax.swing.JList;
import javax.swing.JPanel; import javax.swing.JPanel;
import javax.swing.JScrollPane; import javax.swing.JScrollPane;
import javax.swing.ListSelectionModel; import javax.swing.ListSelectionModel;
import javax.swing.UIManager;
import javax.swing.border.EmptyBorder; import javax.swing.border.EmptyBorder;
import javax.swing.event.ListSelectionEvent; import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener; import javax.swing.event.ListSelectionListener;
@@ -24,11 +23,6 @@ public class GlobalSearchOpenBox extends JFrame {
DefaultListModel<Info> model; DefaultListModel<Info> model;
public GlobalSearchOpenBox() { public GlobalSearchOpenBox() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (Exception e) {
e.printStackTrace();
}
setResizable(false); setResizable(false);
setTitle("Global Search - Result"); setTitle("Global Search - Result");
setDefaultCloseOperation(JFrame.HIDE_ON_CLOSE); setDefaultCloseOperation(JFrame.HIDE_ON_CLOSE);
-6
View File
@@ -5,7 +5,6 @@ import java.awt.Toolkit;
import javax.swing.JCheckBox; import javax.swing.JCheckBox;
import javax.swing.JFrame; import javax.swing.JFrame;
import javax.swing.JPanel; import javax.swing.JPanel;
import javax.swing.UIManager;
import javax.swing.border.EmptyBorder; import javax.swing.border.EmptyBorder;
public class OptionBox extends JFrame { public class OptionBox extends JFrame {
@@ -15,11 +14,6 @@ public class OptionBox extends JFrame {
public JCheckBox chckbxComputeMax; public JCheckBox chckbxComputeMax;
public OptionBox() { public OptionBox() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (Exception e) {
e.printStackTrace();
}
setResizable(false); setResizable(false);
setTitle("Options"); setTitle("Options");
setDefaultCloseOperation(JFrame.HIDE_ON_CLOSE); setDefaultCloseOperation(JFrame.HIDE_ON_CLOSE);
+2 -2
View File
@@ -84,8 +84,8 @@ public class RenameBox extends JFrame {
JOptionPane.showMessageDialog(null, "ClassNode not found!", "Error!", JOptionPane.ERROR_MESSAGE); JOptionPane.showMessageDialog(null, "ClassNode not found!", "Error!", JOptionPane.ERROR_MESSAGE);
return; return;
} }
String newName = UnicodeUtils.unescape(txtName.getText()); String newName = UnicodeUtils.unescape(null, txtName.getText(), true);
String newDesc = UnicodeUtils.unescape(txtDesc.getText()); String newDesc = UnicodeUtils.unescape(null, txtDesc.getText(), true);
if (ClassUtil.isObjectClassMethod(newName, newDesc, true)) { if (ClassUtil.isObjectClassMethod(newName, newDesc, true)) {
JOptionPane.showMessageDialog(null, "Invalid name!", "Error!", JOptionPane.ERROR_MESSAGE); JOptionPane.showMessageDialog(null, "Invalid name!", "Error!", JOptionPane.ERROR_MESSAGE);
return; return;
-6
View File
@@ -15,7 +15,6 @@ import javax.swing.JLabel;
import javax.swing.JPanel; import javax.swing.JPanel;
import javax.swing.JTextField; import javax.swing.JTextField;
import javax.swing.KeyStroke; import javax.swing.KeyStroke;
import javax.swing.UIManager;
import javax.swing.border.EmptyBorder; import javax.swing.border.EmptyBorder;
import me.ByteEdit.main.Main; import me.ByteEdit.main.Main;
@@ -28,11 +27,6 @@ public class SearchBox extends JFrame {
public JCheckBox chckbxCaseSensitive; public JCheckBox chckbxCaseSensitive;
public SearchBox() { public SearchBox() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (Exception e) {
e.printStackTrace();
}
setResizable(false); setResizable(false);
setTitle("Find/Replace"); setTitle("Find/Replace");
setDefaultCloseOperation(JFrame.HIDE_ON_CLOSE); setDefaultCloseOperation(JFrame.HIDE_ON_CLOSE);
+101
View File
@@ -0,0 +1,101 @@
package me.ByteEdit.boxes;
import java.awt.BorderLayout;
import java.awt.Font;
import java.awt.Toolkit;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.DefaultListModel;
import javax.swing.JFrame;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.ListSelectionModel;
import javax.swing.UIManager;
import javax.swing.UIManager.LookAndFeelInfo;
import javax.swing.border.EmptyBorder;
import com.formdev.flatlaf.FlatDarculaLaf;
import com.formdev.flatlaf.FlatDarkLaf;
import com.formdev.flatlaf.FlatIntelliJLaf;
import com.formdev.flatlaf.FlatLightLaf;
import com.formdev.flatlaf.intellijthemes.FlatAllIJThemes;
import me.ByteEdit.main.ThemeManager;
public class ThemeBox extends JFrame {
private JPanel contentPane;
private final JScrollPane scrollPane = new JScrollPane();
private final JList<LAFI> list;
public ThemeBox() {
setTitle("Theme Chooser");
setDefaultCloseOperation(JFrame.HIDE_ON_CLOSE);
setBounds((int) (Toolkit.getDefaultToolkit().getScreenSize().getWidth() / 2 - 200),
(int) (Toolkit.getDefaultToolkit().getScreenSize().getHeight() / 2 - 200), 400, 400);
contentPane = new JPanel();
contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
setContentPane(contentPane);
contentPane.setLayout(new BorderLayout(0, 0));
contentPane.add(scrollPane, BorderLayout.CENTER);
DefaultListModel<LAFI> model = new DefaultListModel<>();
list = new JList(model);
list.addMouseListener(new MouseAdapter() {
@Override
public void mouseClicked(MouseEvent e) {
if (e.getClickCount() == 2) {
LAFI lafi = model.get(list.locationToIndex(e.getPoint()));
if (lafi.className != null)
ThemeManager.changeUIManager(lafi.className, lafi.isDark);
}
}
});
list.setFont(new Font("Tahoma", Font.BOLD, 18));
list.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
model.addElement(new LAFI(null, "--- Installed Themes ---"));
for (LookAndFeelInfo info : UIManager.getInstalledLookAndFeels()) {
model.addElement(new LAFI(info.getClassName(), info.getName(), false));
}
model.addElement(new LAFI(null, "--- Core Themes ---"));
model.addElement(new LAFI(FlatLightLaf.class.getName(), "Flat Light", false));
model.addElement(new LAFI(FlatDarkLaf.class.getName(), "Flat Dark", true));
model.addElement(new LAFI(FlatIntelliJLaf.class.getName(), "Flat IntelliJ", false));
model.addElement(new LAFI(FlatDarculaLaf.class.getName(), "Flat Darcula", true));
model.addElement(new LAFI(null, "--- IntelliJ Themes ---"));
for (LookAndFeelInfo info : FlatAllIJThemes.INFOS) {
model.addElement(new LAFI(info.getClassName(), info.getName()));
}
scrollPane.setViewportView(list);
}
static class LAFI {
final String className;
final String name;
final Boolean isDark;
public LAFI(String className, String name) {
this.className = className;
this.name = name;
this.isDark = null;
}
public LAFI(String className, String name, boolean isDark) {
this.className = className;
this.name = name;
this.isDark = Boolean.valueOf(isDark);
}
@Override
public String toString() {
return name;
}
}
}
+1 -7
View File
@@ -11,7 +11,6 @@ import javax.swing.JPanel;
import javax.swing.JScrollPane; import javax.swing.JScrollPane;
import javax.swing.JTextField; import javax.swing.JTextField;
import javax.swing.ListSelectionModel; import javax.swing.ListSelectionModel;
import javax.swing.UIManager;
import javax.swing.border.EmptyBorder; import javax.swing.border.EmptyBorder;
import javax.swing.event.DocumentEvent; import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener; import javax.swing.event.DocumentListener;
@@ -27,11 +26,6 @@ public class TypeOpenBox extends JFrame {
public JTextField txtSearch; public JTextField txtSearch;
public TypeOpenBox() { public TypeOpenBox() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (Exception e) {
e.printStackTrace();
}
setResizable(false); setResizable(false);
setTitle("Open Type"); setTitle("Open Type");
setDefaultCloseOperation(JFrame.HIDE_ON_CLOSE); setDefaultCloseOperation(JFrame.HIDE_ON_CLOSE);
@@ -82,7 +76,7 @@ public class TypeOpenBox extends JFrame {
if (txtSearch.getText().isEmpty()) { if (txtSearch.getText().isEmpty()) {
return; return;
} }
String search = UnicodeUtils.unescape(txtSearch.getText()).toLowerCase(); String search = UnicodeUtils.unescape(null, txtSearch.getText(), true).toLowerCase();
if (search.contains("/")) { if (search.contains("/")) {
for (String s : Main.classNodes.keySet()) { for (String s : Main.classNodes.keySet()) {
String className = s.substring(0, s.length() - 6); String className = s.substring(0, s.length() - 6);
+2 -8
View File
@@ -9,7 +9,6 @@ import javax.swing.JFrame;
import javax.swing.JPanel; import javax.swing.JPanel;
import javax.swing.JScrollPane; import javax.swing.JScrollPane;
import javax.swing.JTextArea; import javax.swing.JTextArea;
import javax.swing.UIManager;
import javax.swing.border.EmptyBorder; import javax.swing.border.EmptyBorder;
import me.ByteEdit.main.Main; import me.ByteEdit.main.Main;
@@ -20,11 +19,6 @@ public class UnicodeBox extends JFrame {
private JPanel contentPane; private JPanel contentPane;
public UnicodeBox() { public UnicodeBox() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (Exception e) {
e.printStackTrace();
}
setResizable(false); setResizable(false);
setTitle("Unicode Converter"); setTitle("Unicode Converter");
setDefaultCloseOperation(JFrame.HIDE_ON_CLOSE); setDefaultCloseOperation(JFrame.HIDE_ON_CLOSE);
@@ -42,7 +36,7 @@ public class UnicodeBox extends JFrame {
public void actionPerformed(ActionEvent e) { public void actionPerformed(ActionEvent e) {
try { try {
textArea.setText(UnicodeUtils.escape(textArea.getText())); textArea.setText(UnicodeUtils.escape(null, textArea.getText(), true));
} catch (IllegalArgumentException ex) { } catch (IllegalArgumentException ex) {
Main.showError(ex.getMessage()); Main.showError(ex.getMessage());
} }
@@ -56,7 +50,7 @@ public class UnicodeBox extends JFrame {
public void actionPerformed(ActionEvent e) { public void actionPerformed(ActionEvent e) {
try { try {
textArea.setText(UnicodeUtils.unescape(textArea.getText())); textArea.setText(UnicodeUtils.unescape(null, textArea.getText(), true));
} catch (IllegalArgumentException ex) { } catch (IllegalArgumentException ex) {
Main.showError(ex.getMessage()); Main.showError(ex.getMessage());
} }
File diff suppressed because it is too large. Load diff
+449 -354
View File
@@ -1,9 +1,33 @@
package me.ByteEdit.edit; package me.ByteEdit.edit;
import static org.objectweb.asm.tree.AbstractInsnNode.FIELD_INSN;
import static org.objectweb.asm.tree.AbstractInsnNode.FRAME;
import static org.objectweb.asm.tree.AbstractInsnNode.IINC_INSN;
import static org.objectweb.asm.tree.AbstractInsnNode.INSN;
import static org.objectweb.asm.tree.AbstractInsnNode.INT_INSN;
import static org.objectweb.asm.tree.AbstractInsnNode.INVOKE_DYNAMIC_INSN;
import static org.objectweb.asm.tree.AbstractInsnNode.JUMP_INSN;
import static org.objectweb.asm.tree.AbstractInsnNode.LABEL;
import static org.objectweb.asm.tree.AbstractInsnNode.LDC_INSN;
import static org.objectweb.asm.tree.AbstractInsnNode.LINE;
import static org.objectweb.asm.tree.AbstractInsnNode.LOOKUPSWITCH_INSN;
import static org.objectweb.asm.tree.AbstractInsnNode.METHOD_INSN;
import static org.objectweb.asm.tree.AbstractInsnNode.MULTIANEWARRAY_INSN;
import static org.objectweb.asm.tree.AbstractInsnNode.TABLESWITCH_INSN;
import static org.objectweb.asm.tree.AbstractInsnNode.TYPE_INSN;
import static org.objectweb.asm.tree.AbstractInsnNode.VAR_INSN;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.FutureTask;
import java.util.concurrent.atomic.AtomicInteger;
import org.objectweb.asm.Handle; import org.objectweb.asm.Handle;
import org.objectweb.asm.Label; import org.objectweb.asm.Label;
@@ -17,7 +41,7 @@ import org.objectweb.asm.tree.FieldNode;
import org.objectweb.asm.tree.FrameNode; import org.objectweb.asm.tree.FrameNode;
import org.objectweb.asm.tree.IincInsnNode; import org.objectweb.asm.tree.IincInsnNode;
import org.objectweb.asm.tree.InnerClassNode; import org.objectweb.asm.tree.InnerClassNode;
import org.objectweb.asm.tree.InsnNode; import org.objectweb.asm.tree.InsnList;
import org.objectweb.asm.tree.IntInsnNode; import org.objectweb.asm.tree.IntInsnNode;
import org.objectweb.asm.tree.InvokeDynamicInsnNode; import org.objectweb.asm.tree.InvokeDynamicInsnNode;
import org.objectweb.asm.tree.JumpInsnNode; import org.objectweb.asm.tree.JumpInsnNode;
@@ -34,12 +58,16 @@ 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.ClassUtil;
import me.ByteEdit.utils.OpcodesReverse; import me.ByteEdit.utils.OpcodesReverse;
import me.ByteEdit.utils.UnicodeUtils; import me.ByteEdit.utils.UnicodeUtils;
public class Disassembler { public class Disassembler {
private static final ExecutorService exec = Executors
.newFixedThreadPool((Runtime.getRuntime().availableProcessors() + 1) / 2);
public static String disassemble(ClassNode classNode) { public static String disassemble(ClassNode classNode) {
return disassemble(classNode, null).getDisassembly(); return disassemble(classNode, null).getDisassembly();
} }
@@ -74,12 +102,75 @@ public class Disassembler {
return new DisassembleTuple("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; HugeStrings hs = new HugeStrings();
String s = ""; AtomicInteger lineFound = new AtomicInteger(-1);
s += "// #Annotations:\n"; StringContext ctx = new StringContext(18);
if (classNode.visibleAnnotations != null && !classNode.visibleAnnotations.isEmpty()) { ctx.next("// #Annotations:\n");
for (AnnotationNode annotationNode : classNode.visibleAnnotations) { ctx.next(doAnnotations(classNode.visibleAnnotations, hs));
s += "@" + UnicodeUtils.escapeWithSpaces(annotationNode.desc); ctx.next("// #Class v:" + classNode.version + "\n");
if (classNode.signature != null)
ctx.next("// #Signature: " + UnicodeUtils.escapeWithSpaces(hs, classNode.signature) + "\n");
if (classNode.outerMethod != null)
ctx.next(
"// #OuterMethod: "
+ (classNode.outerMethod == null ? "null"
: (UnicodeUtils.escapeWithSpaces(hs, classNode.outerMethod) + " "
+ UnicodeUtils.escapeWithSpaces(hs, classNode.outerMethodDesc)))
+ "\n");
if (classNode.outerClass != null)
ctx.next("// #OuterClass: " + UnicodeUtils.escapeWithSpaces(hs, classNode.outerClass) + "\n");
ctx.next("// #InnerClasses:\n");
if (classNode.innerClasses != null) {
String ics = "";
for (InnerClassNode icn : classNode.innerClasses) {
ics += "// " + UnicodeUtils.escapeWithSpaces(hs, icn.name) + " "
+ UnicodeUtils.escapeWithSpaces(hs, icn.outerName) + " "
+ UnicodeUtils.escapeWithSpaces(hs, icn.innerName)
+ (icn.access == 0 ? "" : " " + ClassUtil.getAccessFlagsFull(icn.access).trim()) + "\n";
}
ctx.next(ics);
}
ctx.next(ClassUtil.getAccessFlagsClass(classNode.access) + UnicodeUtils.escapeWithSpaces(hs, classNode.name)
+ " ");
ctx.next("extends " + UnicodeUtils.escapeWithSpaces(hs, classNode.superName) + " ");
if (classNode.interfaces != null && !classNode.interfaces.isEmpty()) {
String interfaceStr = "";
for (String interfc : classNode.interfaces) {
if (interfaceStr.isEmpty()) {
interfaceStr += UnicodeUtils.escapeWithSpaces(hs, interfc);
} else {
interfaceStr += ", " + UnicodeUtils.escapeWithSpaces(hs, interfc);
}
}
if (!interfaceStr.isEmpty())
ctx.next("implements " + interfaceStr + " ");
}
ctx.next("{\n// #SourceFile: "
+ (classNode.sourceFile == null ? "null" : UnicodeUtils.escape(hs, classNode.sourceFile)) + "\n");
int hugeIdx = ctx.next("");
ctx.next("\n// #Fields\n");
ctx.next(doFields(classNode.fields, nodeToFind, lineFound, hs));
ctx.next("\n// #Methods\n");
ctx.next(doMethods(classNode.methods, classNode.name, nodeToFind, lineFound, hs));
ctx.next("}\n");
if (!hs.isEmpty())
ctx.set(hugeIdx, hs.makeStringsList());
return new DisassembleTuple(ctx.finish(), lineFound.get());
} catch (Throwable e) {
return new DisassembleTuple("Class couldn't be decompiled:\n" + e.getClass().getName() + ": "
+ e.getMessage() + "\n"
+ Arrays.toString(e.getStackTrace()).replace(", ", "\n\tat ").replace("[", "\tat ").replace("]", "")
+ "\n");
}
}
private static String doAnnotations(List<AnnotationNode> annotations, HugeStrings hs) {
if (annotations == null)
return "";
StringContext ctx = new StringContext(annotations.size());
for (AnnotationNode annotationNode : annotations) {
String s = "@" + UnicodeUtils.escapeWithSpaces(hs, annotationNode.desc);
if (annotationNode.values != null && !annotationNode.values.isEmpty()) { if (annotationNode.values != null && !annotationNode.values.isEmpty()) {
s += " ("; s += " (";
boolean valBefore = true; boolean valBefore = true;
@@ -94,10 +185,10 @@ public class Disassembler {
boolean w8ing = false; boolean w8ing = false;
for (String rofl : arr) { for (String rofl : arr) {
if (!w8ing) { if (!w8ing) {
s += UnicodeUtils.escapeWithSpaces(rofl) + "/"; s += UnicodeUtils.escapeWithSpaces(hs, rofl) + "/";
w8ing = true; w8ing = true;
} else { } else {
s += UnicodeUtils.escapeWithSpaces(rofl) + "]"; s += UnicodeUtils.escapeWithSpaces(hs, rofl) + "]";
} }
} }
s += ", "; s += ", ";
@@ -110,21 +201,21 @@ public class Disassembler {
boolean w8ing = false; boolean w8ing = false;
for (String rofl : arr) { for (String rofl : arr) {
if (!w8ing) { if (!w8ing) {
s += UnicodeUtils.escapeWithSpaces(rofl) + "/"; s += UnicodeUtils.escapeWithSpaces(hs, rofl) + "/";
w8ing = true; w8ing = true;
} else { } else {
s += UnicodeUtils.escapeWithSpaces(rofl); s += UnicodeUtils.escapeWithSpaces(hs, rofl);
} }
} }
} else { } else {
s += "\"" + UnicodeUtils.escape(String.valueOf(obj)) + "\""; s += "\"" + UnicodeUtils.escape(hs, String.valueOf(obj)) + "\"";
} }
s += ", "; s += ", ";
} }
s = s.substring(0, s.length() - 2); s = s.substring(0, s.length() - 2);
s += " }]"; s += " }]";
} else if (o instanceof String) { } else if (o instanceof String) {
s += "\"" + UnicodeUtils.escapeWithSpaces((String) o) + "\"], "; s += "\"" + UnicodeUtils.escapeWithSpaces(hs, (String) o) + "\"], ";
} else { } else {
s += "(" + o.getClass().getName().replace(".", "/") + ") " + o + "], "; s += "(" + o.getClass().getName().replace(".", "/") + ") " + o + "], ";
} }
@@ -136,50 +227,141 @@ public class Disassembler {
s += ")"; s += ")";
} }
s += "\n"; s += "\n";
ctx.next(s);
} }
return ctx.finish();
} }
s += "// #Class v:" + classNode.version + "\n";
if (classNode.signature != null) private static String doMethods(List<MethodNode> methods, String className, Object nodeToFind,
s += "// #Signature: " + UnicodeUtils.escapeWithSpaces(classNode.signature) + "\n"; AtomicInteger lineFound, HugeStrings hs) throws InterruptedException, ExecutionException {
if (classNode.outerMethod != null) boolean multithreaded = Main.INSTANCE.mntmMultithreaded.isSelected();
s += "// #OuterMethod: " + (classNode.outerMethod == null ? "null" Future<String>[] futures = new Future[methods.size()];
: (UnicodeUtils.escapeWithSpaces(classNode.outerMethod) + " " for (int i = 0; i < futures.length; i++) {
+ UnicodeUtils.escapeWithSpaces(classNode.outerMethodDesc))) MethodNode mn = methods.get(i);
+ "\n"; Callable<String> callable = new Callable<String>() {
if (classNode.outerClass != null) @Override
s += "// #OuterClass: " + UnicodeUtils.escapeWithSpaces(classNode.outerClass) + "\n"; public String call() throws Exception {
s += "// #InnerClasses:\n"; String ms = "";
if (classNode.innerClasses != null) { try {
for (InnerClassNode icn : classNode.innerClasses) { ms += "\t// #Max: l:" + mn.maxLocals + " s:" + mn.maxStack + "\n";
s += "// " + UnicodeUtils.escapeWithSpaces(icn.name) + " " if (mn.signature != null)
+ UnicodeUtils.escapeWithSpaces(icn.outerName) + " " ms += "\t// #Signature: " + UnicodeUtils.escapeWithSpaces(hs, mn.signature) + "\n";
+ UnicodeUtils.escapeWithSpaces(icn.innerName) String[] dis = disassembleMethod(className, mn, hs);
+ (icn.access == 0 ? "" : " " + ClassUtil.getAccessFlagsFull(icn.access).trim()) + "\n"; ms += dis[2];
} ms += dis[1];
} if (mn.visibleAnnotations != null && !mn.visibleAnnotations.isEmpty()) {
s += ClassUtil.getAccessFlagsClass(classNode.access) + UnicodeUtils.escapeWithSpaces(classNode.name) + " "; for (AnnotationNode annotationNode : mn.visibleAnnotations) {
s += "extends " + UnicodeUtils.escapeWithSpaces(classNode.superName) + " "; ms += "\t@" + annotationNode.desc;
if (classNode.interfaces != null && !classNode.interfaces.isEmpty()) { if (annotationNode.values != null && !annotationNode.values.isEmpty()) {
String interfaceStr = ""; ms += " (";
for (String interfc : classNode.interfaces) { boolean valBefore = true;
if (interfaceStr.isEmpty()) { for (Object o : annotationNode.values) {
interfaceStr += UnicodeUtils.escapeWithSpaces(interfc); if (valBefore) {
ms += o + " = [";
valBefore = false;
continue;
} else { } else {
interfaceStr += ", " + UnicodeUtils.escapeWithSpaces(interfc); if (o instanceof String[]) {
String[] arr = (String[]) o;
boolean w8ing = false;
for (String rofl : arr) {
if (!w8ing) {
ms += UnicodeUtils.escapeWithSpaces(hs, rofl) + "/";
w8ing = true;
} else {
ms += UnicodeUtils.escapeWithSpaces(hs, rofl) + "]";
} }
} }
if (!interfaceStr.isEmpty()) ms += ", ";
s += "implements " + interfaceStr + " "; } else if (o instanceof List) {
List list = (List) o;
ms += "{ ";
for (Object obj : list) {
if (obj instanceof String[]) {
String[] arr = (String[]) obj;
boolean w8ing = false;
for (String rofl : arr) {
if (!w8ing) {
ms += UnicodeUtils.escapeWithSpaces(hs, rofl) + "/";
w8ing = true;
} else {
ms += UnicodeUtils.escapeWithSpaces(hs, rofl);
} }
s += "{\n// #SourceFile: " }
+ (classNode.sourceFile == null ? "null" : UnicodeUtils.escape(classNode.sourceFile)) } else {
+ "\n\n// #Fields\n"; ms += "\"" + UnicodeUtils.escape(hs, String.valueOf(obj))
for (FieldNode fn : classNode.fields) { + "\"";
}
ms += ", ";
}
ms = ms.substring(0, ms.length() - 2);
ms += " }]";
} else {
ms += "(" + o.getClass().getName().replace(".", "/") + ") " + o + "], ";
}
valBefore = true;
}
}
if (ms.endsWith(", "))
ms = ms.substring(0, ms.length() - 2);
ms += ")";
}
ms += "\n";
}
}
if (mn.equals(nodeToFind)) {
lineFound.set(ms.split("\\n").length);
}
ms += "\t" + ClassUtil.getAccessFlagsFull(mn.access)
+ UnicodeUtils.escapeWithSpaces(hs, mn.name) + " "
+ UnicodeUtils.escapeWithSpaces(hs, mn.desc) + " ";
if (mn.exceptions != null && !mn.exceptions.isEmpty()) {
String exceptionStr = "";
for (String exc : mn.exceptions) {
if (exceptionStr.isEmpty()) {
exceptionStr += UnicodeUtils.escapeWithSpaces(hs, exc);
} else {
exceptionStr += ", " + UnicodeUtils.escapeWithSpaces(hs, exc);
}
}
if (!exceptionStr.isEmpty())
ms += "throws " + exceptionStr + " ";
}
ms += "{\n";
ms += dis[0];
ms += "\t}\n\n";
} catch (Exception e) {
ms += "\t\t// Method couldn't be disassembled:\n\t\t// " + e.getClass().getName() + ": "
+ e.getMessage() + "\n" + Arrays.toString(e.getStackTrace())
.replace(", ", "\n\t\t// \tat ").replace("[", "\t\t// \tat ").replace("]", "")
+ "\n\t}\n\n";
}
return ms;
}
};
futures[i] = multithreaded ? exec.submit(callable) : new FutureTask<>(callable);
}
StringContext ctx = new StringContext(futures.length);
for (Future<String> f : futures) {
if (f instanceof FutureTask)
((FutureTask) f).run();
ctx.next(f.get());
}
String s = ctx.finish();
if (s.isEmpty())
return "\n";
return s;
}
private static String doFields(List<FieldNode> fields, Object nodeToFind, AtomicInteger lineFound, HugeStrings hs) {
StringContext ctx = new StringContext(fields.size());
for (FieldNode fn : fields) {
String s = "";
if (fn.signature != null) if (fn.signature != null)
s += "\t// #Signature: " + UnicodeUtils.escapeWithSpaces(fn.signature) + "\n"; s += "\t// #Signature: " + UnicodeUtils.escapeWithSpaces(hs, fn.signature) + "\n";
if (fn.visibleAnnotations != null && !fn.visibleAnnotations.isEmpty()) { if (fn.visibleAnnotations != null && !fn.visibleAnnotations.isEmpty()) {
for (AnnotationNode annotationNode : fn.visibleAnnotations) { for (AnnotationNode annotationNode : fn.visibleAnnotations) {
s += "\t@" + UnicodeUtils.escapeWithSpaces(annotationNode.desc); s += "\t@" + UnicodeUtils.escapeWithSpaces(hs, annotationNode.desc);
if (annotationNode.values != null && !annotationNode.values.isEmpty()) { if (annotationNode.values != null && !annotationNode.values.isEmpty()) {
s += " ("; s += " (";
boolean valBefore = true; boolean valBefore = true;
@@ -194,10 +376,10 @@ public class Disassembler {
boolean w8ing = false; boolean w8ing = false;
for (String rofl : arr) { for (String rofl : arr) {
if (!w8ing) { if (!w8ing) {
s += UnicodeUtils.escapeWithSpaces(rofl) + "/"; s += UnicodeUtils.escapeWithSpaces(hs, rofl) + "/";
w8ing = true; w8ing = true;
} else { } else {
s += UnicodeUtils.escapeWithSpaces(rofl) + "]"; s += UnicodeUtils.escapeWithSpaces(hs, rofl) + "]";
} }
} }
s += ", "; s += ", ";
@@ -210,14 +392,14 @@ public class Disassembler {
boolean w8ing = false; boolean w8ing = false;
for (String rofl : arr) { for (String rofl : arr) {
if (!w8ing) { if (!w8ing) {
s += UnicodeUtils.escapeWithSpaces(rofl) + "/"; s += UnicodeUtils.escapeWithSpaces(hs, rofl) + "/";
w8ing = true; w8ing = true;
} else { } else {
s += UnicodeUtils.escapeWithSpaces(rofl); s += UnicodeUtils.escapeWithSpaces(hs, rofl);
} }
} }
} else { } else {
s += "\"" + UnicodeUtils.escape(String.valueOf(obj)) + "\""; s += "\"" + UnicodeUtils.escape(hs, String.valueOf(obj)) + "\"";
} }
s += ", "; s += ", ";
} }
@@ -237,325 +419,88 @@ public class Disassembler {
} }
} }
if (fn.equals(nodeToFind)) { if (fn.equals(nodeToFind)) {
lineFound = s.split("\\n").length; lineFound.set(s.split("\\n").length);
} }
s += "\t" + ClassUtil.getAccessFlagsFull(fn.access).replace("varargs", "transient") s += "\t" + ClassUtil.getAccessFlagsFull(fn.access).replace("varargs", "transient")
+ UnicodeUtils.escapeWithSpaces(fn.desc) + " " + UnicodeUtils.escapeWithSpaces(fn.name); + UnicodeUtils.escapeWithSpaces(hs, fn.desc) + " " + UnicodeUtils.escapeWithSpaces(hs, fn.name);
if (fn.value != null) { if (fn.value != null) {
s += " = " + ClassUtil.getDecompiledValue(fn.value, fn.desc, true); s += " = " + ClassUtil.getDecompiledValue(fn.value, fn.desc, true, hs);
} }
s += "\n"; s += "\n";
ctx.next(s);
} }
s += "\n// #Methods\n"; return ctx.finish();
for (MethodNode mn : classNode.methods) {
try {
s += "\t// #Max: l:" + mn.maxLocals + " s:" + mn.maxStack + "\n";
if (mn.signature != null)
s += "\t// #Signature: " + UnicodeUtils.escapeWithSpaces(mn.signature) + "\n";
String[] dis = disassembleMethod(classNode.name, mn);
s += dis[2];
s += dis[1];
if (mn.visibleAnnotations != null && !mn.visibleAnnotations.isEmpty()) {
for (AnnotationNode annotationNode : mn.visibleAnnotations) {
s += "\t@" + annotationNode.desc;
if (annotationNode.values != null && !annotationNode.values.isEmpty()) {
s += " (";
boolean valBefore = true;
for (Object o : annotationNode.values) {
if (valBefore) {
s += o + " = [";
valBefore = false;
continue;
} else {
if (o instanceof String[]) {
String[] arr = (String[]) o;
boolean w8ing = false;
for (String rofl : arr) {
if (!w8ing) {
s += UnicodeUtils.escapeWithSpaces(rofl) + "/";
w8ing = true;
} else {
s += UnicodeUtils.escapeWithSpaces(rofl) + "]";
}
}
s += ", ";
} else if (o instanceof List) {
List list = (List) o;
s += "{ ";
for (Object obj : list) {
if (obj instanceof String[]) {
String[] arr = (String[]) obj;
boolean w8ing = false;
for (String rofl : arr) {
if (!w8ing) {
s += UnicodeUtils.escapeWithSpaces(rofl) + "/";
w8ing = true;
} else {
s += UnicodeUtils.escapeWithSpaces(rofl);
}
}
} else {
s += "\"" + UnicodeUtils.escape(String.valueOf(obj)) + "\"";
}
s += ", ";
}
s = s.substring(0, s.length() - 2);
s += " }]";
} else {
s += "(" + o.getClass().getName().replace(".", "/") + ") " + o + "], ";
}
valBefore = true;
}
}
if (s.endsWith(", "))
s = s.substring(0, s.length() - 2);
s += ")";
}
s += "\n";
}
}
if (mn.equals(nodeToFind)) {
lineFound = s.split("\\n").length;
}
s += "\t" + ClassUtil.getAccessFlagsFull(mn.access) + UnicodeUtils.escapeWithSpaces(mn.name) + " "
+ UnicodeUtils.escapeWithSpaces(mn.desc) + " ";
if (mn.exceptions != null && !mn.exceptions.isEmpty()) {
String exceptionStr = "";
for (String exc : mn.exceptions) {
if (exceptionStr.isEmpty()) {
exceptionStr += UnicodeUtils.escapeWithSpaces(exc);
} else {
exceptionStr += ", " + UnicodeUtils.escapeWithSpaces(exc);
}
}
if (!exceptionStr.isEmpty())
s += "throws " + exceptionStr + " ";
}
s += "{\n";
s += dis[0];
s += "\t}\n\n";
} catch (Exception e) {
s += "\t\t// Method couldn't be disassembled:\n\t\t// "
+ e.getClass().getName() + ": " + e.getMessage() + "\n" + Arrays.toString(e.getStackTrace())
.replace(", ", "\n\t\t// \tat ").replace("[", "\t\t// \tat ").replace("]", "")
+ "\n\t}\n\n";
}
}
s += "}\n";
return new DisassembleTuple(s, lineFound);
} catch (Throwable e) {
return new DisassembleTuple("Class couldn't be decompiled:\n" + e.getClass().getName() + ": "
+ e.getMessage() + "\n"
+ Arrays.toString(e.getStackTrace()).replace(", ", "\n\tat ").replace("[", "\tat ").replace("]", "")
+ "\n");
}
} }
private static String[] disassembleMethod(String className, MethodNode mn) { private static String[] disassembleMethod(String className, MethodNode mn, HugeStrings hs) {
HashMap<Label, Integer> labels = new HashMap<Label, Integer>(); HashMap<Label, Integer> labels = new HashMap<Label, Integer>();
String s = ""; String localVarTable;
String localVarTable = ""; String tryCatchTable;
String tryCatchTable = "";
for (AbstractInsnNode n : mn.instructions.toArray()) { InsnList insnList = mn.instructions;
boolean deobfNumbers = Main.INSTANCE.mntmNumbers.isSelected();
ArrayList<Label> labelsReversed = deobfNumbers ? new ArrayList<>() : null;
for (AbstractInsnNode n = insnList.getFirst(); n != null; n = n.getNext()) {
if (n instanceof LabelNode) { if (n instanceof LabelNode) {
labels.put(((LabelNode) n).getLabel(), labels.size() + 1); int id = labels.size() + 1;
if (deobfNumbers)
labelsReversed.add(((LabelNode) n).getLabel());
labels.put(((LabelNode) n).getLabel(), id);
} }
} }
if (mn.localVariables != null && !mn.localVariables.isEmpty()) { if (mn.localVariables != null && !mn.localVariables.isEmpty()) {
localVarTable = "\t// #LocalVars:\n"; List<LocalVariableNode> list = mn.localVariables;
for (LocalVariableNode lvn : mn.localVariables) { StringContext ctx = new StringContext(list.size() + 1);
localVarTable += "\t// " + UnicodeUtils.escapeWithSpaces(lvn.name) + ": " ctx.next("\t// #LocalVars:\n");
+ UnicodeUtils.escapeWithSpaces(lvn.desc) + " i:" + lvn.index + " s:" for (LocalVariableNode lvn : list) {
ctx.next("\t// " + UnicodeUtils.escapeWithSpaces(hs, lvn.name) + ": "
+ UnicodeUtils.escapeWithSpaces(hs, lvn.desc) + " i:" + lvn.index + " s:"
+ labels.get(lvn.start.getLabel()) + " e:" + labels.get(lvn.end.getLabel()) + " sig:" + labels.get(lvn.start.getLabel()) + " e:" + labels.get(lvn.end.getLabel()) + " sig:"
+ UnicodeUtils.escapeWithSpaces(lvn.signature) + "\n"; + UnicodeUtils.escapeWithSpaces(hs, lvn.signature) + "\n");
}
} }
localVarTable = ctx.finish();
} else
localVarTable = "";
if (mn.tryCatchBlocks != null && !mn.tryCatchBlocks.isEmpty()) { if (mn.tryCatchBlocks != null && !mn.tryCatchBlocks.isEmpty()) {
tryCatchTable = "\t// #TryCatch:\n"; List<TryCatchBlockNode> list = mn.tryCatchBlocks;
StringContext ctx = new StringContext(list.size() + 1);
ctx.next("\t// #TryCatch:\n");
for (TryCatchBlockNode tcbn : mn.tryCatchBlocks) { for (TryCatchBlockNode tcbn : mn.tryCatchBlocks) {
tryCatchTable += "\t// " + UnicodeUtils.escapeWithSpaces(tcbn.type) + " s:" ctx.next("\t// " + UnicodeUtils.escapeWithSpaces(hs, tcbn.type) + " s:"
+ labels.get(tcbn.start.getLabel()) + " e:" + labels.get(tcbn.end.getLabel()) + " h:" + labels.get(tcbn.start.getLabel()) + " e:" + labels.get(tcbn.end.getLabel()) + " h:"
+ labels.get(tcbn.handler.getLabel()) + "\n"; + labels.get(tcbn.handler.getLabel()) + "\n");
}
tryCatchTable = ctx.finish();
} else
tryCatchTable = "";
if (deobfNumbers) {
StackBasedCalculator calc = new StackBasedCalculator(insnList);
calc.run();
insnList = calc.get();
int i = 0;
for (AbstractInsnNode n = insnList.getFirst(); n != null; n = n.getNext()) {
if (n instanceof LabelNode) {
((LabelNode) n).setLabel(labelsReversed.get(i++));
} }
} }
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) { StringContext ctx = new StringContext(insnList.size());
if (FieldInsnNode.class.isInstance(n)) { for (AbstractInsnNode n = insnList.getFirst(); n != null; n = n.getNext()) {
FieldInsnNode node = (FieldInsnNode) n; ctx.next(disassembleInstruction(n, labels, hs));
return "\t\t" + OpcodesReverse.reverseOpcode(node.getOpcode()) + " "
+ UnicodeUtils.escapeWithSpaces(node.desc) + " " + UnicodeUtils.escapeWithSpaces(node.owner) + "/"
+ UnicodeUtils.escapeWithSpaces(node.name).replace("/", "\\u002F") + "\n";
} else if (LabelNode.class.isInstance(n)) {
LabelNode node = (LabelNode) n;
return "\t\t// label " + labels.get(node.getLabel()) + "\n";
} else if (FrameNode.class.isInstance(n)) {
FrameNode node = (FrameNode) n;
String type = "";
switch (node.type) {
case Opcodes.F_NEW:
type = "NEW";
break;
case Opcodes.F_FULL:
type = "FULL";
break;
case Opcodes.F_APPEND:
type = "APPEND";
break;
case Opcodes.F_CHOP:
type = "CHOP";
break;
case Opcodes.F_SAME:
type = "SAME";
break;
case Opcodes.F_SAME1:
type = "SAME1";
break;
} }
String s = "\t\t// frame " + type + " l:"; return new String[] { ctx.finish(), localVarTable, tryCatchTable };
ArrayList<String> arr = new ArrayList<>();
if (node.local != null) {
for (Object o : node.local) {
if (o == null) {
arr.add(null);
} else {
if (o instanceof String) {
arr.add("\"" + UnicodeUtils.escapeWithSpaces((String) o) + "\"");
} else if (o instanceof LabelNode) {
arr.add("(label) " + labels.get(((LabelNode) o).getLabel()));
} else if (o instanceof Integer) {
String frameType = ClassUtil.getFrameTypeByID(((Integer) o).intValue());
if (frameType != null)
arr.add(frameType);
else
arr.add("(" + o.getClass().getName().replace(".", "/") + ") " + o);
} else {
arr.add("(" + o.getClass().getName().replace(".", "/") + ") " + o);
} }
}
} public static String disassembleInstruction(AbstractInsnNode n, HashMap<Label, Integer> labels, HugeStrings hs) {
s += arr.toString(); switch (n.getType()) {
} else { case INSN: {
s += "null";
}
arr.clear();
s += " s:";
if (node.stack != null) {
for (Object o : node.stack) {
if (o == null) {
arr.add(null);
} else {
if (o instanceof String) {
arr.add("\"" + UnicodeUtils.escapeWithSpaces((String) o) + "\"");
} else if (o instanceof LabelNode) {
arr.add("(label) " + labels.get(((LabelNode) o).getLabel()));
} else if (o instanceof Integer) {
String frameType = ClassUtil.getFrameTypeByID(((Integer) o).intValue());
if (frameType != null)
arr.add(frameType);
else
arr.add("(" + o.getClass().getName().replace(".", "/") + ") " + o);
} else {
arr.add("(" + o.getClass().getName().replace(".", "/") + ") " + o);
}
}
}
s += arr.toString();
} else {
s += "null";
}
s += "\n";
return s;
} else if (LineNumberNode.class.isInstance(n)) {
LineNumberNode node = (LineNumberNode) n;
return "\t\t// line " + node.line + " " + labels.get(node.start.getLabel()) + "\n";
} else if (InvokeDynamicInsnNode.class.isInstance(n)) {
InvokeDynamicInsnNode node = (InvokeDynamicInsnNode) n;
String s = "\t\t" + OpcodesReverse.reverseOpcode(node.getOpcode()) + " [\n\t\t\tname: "
+ UnicodeUtils.escapeWithSpaces(node.name).replace("/", "\\u002F") + "\n\t\t\tdesc: "
+ UnicodeUtils.escapeWithSpaces(node.desc) + "\n\t\t\tHandle: [\n\t\t\t\tname: "
+ UnicodeUtils.escapeWithSpaces(node.bsm.getName()) + "\n\t\t\t\towner: "
+ UnicodeUtils.escapeWithSpaces(node.bsm.getOwner()) + "\n\t\t\t\tdesc: "
+ UnicodeUtils.escapeWithSpaces(node.bsm.getDesc()) + "\n\t\t\t\tisInterface: "
+ node.bsm.isInterface() + "\n\t\t\t\ttag: " + OpcodesReverse.reverseHandleOpcode(node.bsm.getTag())
+ "\n\t\t\t]\n\t\t\targs: [\n";
for (Object l : node.bsmArgs) {
if (l.getClass().getName().equals("org.objectweb.asm.Type")) {
Type type = (Type) l;
int valueBegin = type.valueBegin;
int valueEnd = type.valueEnd;
String buf = type.valueBuffer;
// Reflection
s += "\t\t\t\tType: [\n\t\t\t\t\ttype: " + ClassUtil.getClassNameFromType(type)
+ "\n\t\t\t\t\tstart: " + valueBegin + "\n\t\t\t\t\tend: " + valueEnd + "\n\t\t\t\t\tbuf: "
+ ClassUtil.getDecompiledValue(buf, "");
s += "\n\t\t\t\t]\n";
} 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: "
+ UnicodeUtils.escapeWithSpaces(h.getName()).replace("/", "\\u002F") + "\n\t\t\t\t\towner: "
+ UnicodeUtils.escapeWithSpaces(h.getOwner()) + "\n\t\t\t\t\tdesc: "
+ UnicodeUtils.escapeWithSpaces(h.getDesc()) + "\n\t\t\t\t\tisInterface: " + h.isInterface()
+ "\n\t\t\t\t\ttag: " + OpcodesReverse.reverseHandleOpcode(h.getTag());
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";
return s;
} else if (MethodInsnNode.class.isInstance(n)) {
MethodInsnNode node = (MethodInsnNode) n;
return "\t\t" + OpcodesReverse.reverseOpcode(node.getOpcode()) + " "
+ UnicodeUtils.escapeWithSpaces(node.desc) + " " + UnicodeUtils.escapeWithSpaces(node.owner) + "/"
+ UnicodeUtils.escapeWithSpaces(node.name).replace("/", "\\u002F") + "\n";
} else if (TypeInsnNode.class.isInstance(n)) {
TypeInsnNode node = (TypeInsnNode) n;
return "\t\t" + OpcodesReverse.reverseOpcode(node.getOpcode()) + " "
+ UnicodeUtils.escapeWithSpaces(node.desc) + "\n";
} else if (MultiANewArrayInsnNode.class.isInstance(n)) {
MultiANewArrayInsnNode node = (MultiANewArrayInsnNode) n;
return "\t\t" + OpcodesReverse.reverseOpcode(node.getOpcode()) + " "
+ UnicodeUtils.escapeWithSpaces(node.desc) + " " + node.dims + "\n";
} else if (LdcInsnNode.class.isInstance(n)) {
LdcInsnNode node = (LdcInsnNode) n;
switch (node.cst.getClass().getSimpleName()) {
case "String":
case "Double":
case "Integer":
case "Float":
case "Long": {
return "\t\t" + OpcodesReverse.reverseOpcode(node.getOpcode()) + " "
+ ClassUtil.getDecompiledValue(node.cst, "") + "\n";
}
case "Type": {
Type type = (Type) node.cst;
int valueBegin = type.valueBegin;
int valueEnd = type.valueEnd;
String buf = type.valueBuffer;
// Reflection
String s = "\t\t" + OpcodesReverse.reverseOpcode(n.getOpcode()) + " Type: [\n\t\t\ttype: "
+ ClassUtil.getClassNameFromType(type) + "\n\t\t\tstart: " + valueBegin + "\n\t\t\tend: "
+ valueEnd + "\n\t\t\tbuf: " + ClassUtil.getDecompiledValue(buf, "");
s += "\n\t\t]\n";
return s;
}
default: {
return "\t\tUNRESOLVED TYPE! " + OpcodesReverse.reverseOpcode(node.getOpcode()) + " "
+ node.cst.getClass().getName().replace(".", "/") + " " + node.cst + "\n";
}
}
} else if (VarInsnNode.class.isInstance(n)) {
VarInsnNode node = (VarInsnNode) n;
return "\t\t" + OpcodesReverse.reverseOpcode(n.getOpcode()) + " " + node.var + "\n";
} else if (InsnNode.class.isInstance(n)) {
InsnNode node = (InsnNode) n;
return "\t\t" + OpcodesReverse.reverseOpcode(n.getOpcode()) + "\n"; return "\t\t" + OpcodesReverse.reverseOpcode(n.getOpcode()) + "\n";
} else if (IntInsnNode.class.isInstance(n)) { }
case INT_INSN: {
IntInsnNode node = (IntInsnNode) n; IntInsnNode node = (IntInsnNode) n;
if (n.getOpcode() == Opcodes.NEWARRAY) { if (n.getOpcode() == Opcodes.NEWARRAY) {
return "\t\t" + OpcodesReverse.reverseOpcode(n.getOpcode()) + " " return "\t\t" + OpcodesReverse.reverseOpcode(n.getOpcode()) + " "
@@ -563,11 +508,103 @@ public class Disassembler {
} else { } else {
return "\t\t" + OpcodesReverse.reverseOpcode(n.getOpcode()) + " " + node.operand + "\n"; return "\t\t" + OpcodesReverse.reverseOpcode(n.getOpcode()) + " " + node.operand + "\n";
} }
} else if (JumpInsnNode.class.isInstance(n)) { }
case VAR_INSN: {
VarInsnNode node = (VarInsnNode) n;
return "\t\t" + OpcodesReverse.reverseOpcode(n.getOpcode()) + " " + node.var + "\n";
}
case TYPE_INSN: {
TypeInsnNode node = (TypeInsnNode) n;
return "\t\t" + OpcodesReverse.reverseOpcode(node.getOpcode()) + " "
+ UnicodeUtils.escapeWithSpaces(hs, node.desc) + "\n";
}
case FIELD_INSN: {
FieldInsnNode node = (FieldInsnNode) n;
return "\t\t" + OpcodesReverse.reverseOpcode(node.getOpcode()) + " "
+ UnicodeUtils.escapeWithSpaces(hs, node.desc) + " " + UnicodeUtils.escapeWithSpaces(hs, node.owner)
+ "/" + UnicodeUtils.escapeWithSpaces(hs, node.name).replace("/", "\\u002F") + "\n";
}
case METHOD_INSN: {
MethodInsnNode node = (MethodInsnNode) n;
return "\t\t" + OpcodesReverse.reverseOpcode(node.getOpcode()) + " "
+ UnicodeUtils.escapeWithSpaces(hs, node.desc) + " " + UnicodeUtils.escapeWithSpaces(hs, node.owner)
+ "/" + UnicodeUtils.escapeWithSpaces(hs, node.name).replace("/", "\\u002F") + "\n";
}
case INVOKE_DYNAMIC_INSN: {
InvokeDynamicInsnNode node = (InvokeDynamicInsnNode) n;
String s = "\t\t" + OpcodesReverse.reverseOpcode(node.getOpcode()) + " [\n\t\t\tname: "
+ UnicodeUtils.escapeWithSpaces(hs, node.name).replace("/", "\\u002F") + "\n\t\t\tdesc: "
+ UnicodeUtils.escapeWithSpaces(hs, node.desc) + "\n\t\t\tHandle: [\n\t\t\t\tname: "
+ UnicodeUtils.escapeWithSpaces(hs, node.bsm.getName()) + "\n\t\t\t\towner: "
+ UnicodeUtils.escapeWithSpaces(hs, node.bsm.getOwner()) + "\n\t\t\t\tdesc: "
+ UnicodeUtils.escapeWithSpaces(hs, node.bsm.getDesc()) + "\n\t\t\t\tisInterface: "
+ node.bsm.isInterface() + "\n\t\t\t\ttag: " + OpcodesReverse.reverseHandleOpcode(node.bsm.getTag())
+ "\n\t\t\t]\n\t\t\targs: [\n";
for (Object l : node.bsmArgs) {
if (l instanceof Type) {
Type type = (Type) l;
int valueBegin = type.valueBegin;
int valueEnd = type.valueEnd;
String buf = type.valueBuffer;
// Reflection
s += "\t\t\t\tType: [\n\t\t\t\t\ttype: " + ClassUtil.getClassNameFromType(type)
+ "\n\t\t\t\t\tstart: " + valueBegin + "\n\t\t\t\t\tend: " + valueEnd + "\n\t\t\t\t\tbuf: "
+ ClassUtil.getDecompiledValue(buf, "", hs);
s += "\n\t\t\t\t]\n";
} else if (l instanceof Handle) {
Handle h = (Handle) l;
s += "\t\t\t\tHandle: [\n\t\t\t\t\tname: "
+ UnicodeUtils.escapeWithSpaces(hs, h.getName()).replace("/", "\\u002F")
+ "\n\t\t\t\t\towner: " + UnicodeUtils.escapeWithSpaces(hs, h.getOwner())
+ "\n\t\t\t\t\tdesc: " + UnicodeUtils.escapeWithSpaces(hs, h.getDesc())
+ "\n\t\t\t\t\tisInterface: " + h.isInterface() + "\n\t\t\t\t\ttag: "
+ OpcodesReverse.reverseHandleOpcode(h.getTag());
s += "\n\t\t\t\t]\n";
} else {
s += "\t\t\t\t" + ClassUtil.getDecompiledValue(l, "", hs) + "\n";
}
}
s += "\t\t\t]\n\t\t]\n";
return s;
}
case JUMP_INSN: {
JumpInsnNode node = (JumpInsnNode) n; JumpInsnNode node = (JumpInsnNode) n;
return "\t\t" + OpcodesReverse.reverseOpcode(n.getOpcode()) + " " + labels.get(node.label.getLabel()) return "\t\t" + OpcodesReverse.reverseOpcode(n.getOpcode()) + " " + labels.get(node.label.getLabel())
+ "\n"; + "\n";
} else if (TableSwitchInsnNode.class.isInstance(n)) { }
case LABEL: {
LabelNode node = (LabelNode) n;
return "\t\t// label " + labels.get(node.getLabel()) + "\n";
}
case LDC_INSN: {
LdcInsnNode node = (LdcInsnNode) n;
if (node.cst instanceof Type) {
Type type = (Type) node.cst;
int valueBegin = type.valueBegin;
int valueEnd = type.valueEnd;
String buf = type.valueBuffer;
// Reflection
String s = "\t\t" + OpcodesReverse.reverseOpcode(n.getOpcode()) + " Type: [\n\t\t\ttype: "
+ ClassUtil.getClassNameFromType(type) + "\n\t\t\tstart: " + valueBegin + "\n\t\t\tend: "
+ valueEnd + "\n\t\t\tbuf: " + ClassUtil.getDecompiledValue(buf, "", hs);
s += "\n\t\t]\n";
return s;
} else {
String decomp = ClassUtil.getDecompiledValue(node.cst, "", hs);
if (node.cst instanceof String) {
if (decomp.startsWith("\"#") && decomp.endsWith("\""))
decomp = decomp.substring(1, decomp.length() - 1);
else if (decomp.startsWith("\"\\u0023"))
decomp = "\"#" + decomp.substring(7);
}
return "\t\t" + OpcodesReverse.reverseOpcode(node.getOpcode()) + " " + decomp + "\n";
}
}
case IINC_INSN: {
IincInsnNode node = (IincInsnNode) n;
return "\t\t" + OpcodesReverse.reverseOpcode(n.getOpcode()) + " " + node.var + " " + node.incr + "\n";
}
case TABLESWITCH_INSN: {
TableSwitchInsnNode node = (TableSwitchInsnNode) n; TableSwitchInsnNode node = (TableSwitchInsnNode) n;
String s = "\t\t" + OpcodesReverse.reverseOpcode(n.getOpcode()) + " [\n\t\t\tmin: " + node.min 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\tmax: " + node.max + "\n\t\t\tdefault: " + labels.get(node.dflt.getLabel())
@@ -577,7 +614,8 @@ public class Disassembler {
} }
s += "\t\t\t]\n\t\t]\n"; s += "\t\t\t]\n\t\t]\n";
return s; return s;
} else if (LookupSwitchInsnNode.class.isInstance(n)) { }
case LOOKUPSWITCH_INSN: {
LookupSwitchInsnNode node = (LookupSwitchInsnNode) n; LookupSwitchInsnNode node = (LookupSwitchInsnNode) n;
String s = "\t\t" + OpcodesReverse.reverseOpcode(n.getOpcode()) + " [\n\t\t\tdefault: " String s = "\t\t" + OpcodesReverse.reverseOpcode(n.getOpcode()) + " [\n\t\t\tdefault: "
+ labels.get(node.dflt.getLabel()) + "\n\t\t\tkeys: [\n"; + labels.get(node.dflt.getLabel()) + "\n\t\t\tkeys: [\n";
@@ -590,13 +628,70 @@ public class Disassembler {
} }
s += "\t\t\t]\n\t\t]\n"; s += "\t\t\t]\n\t\t]\n";
return s; return s;
} else if (IincInsnNode.class.isInstance(n)) { }
IincInsnNode node = (IincInsnNode) n; case MULTIANEWARRAY_INSN: {
return "\t\t" + OpcodesReverse.reverseOpcode(n.getOpcode()) + " " + node.var + " " + node.incr + "\n"; MultiANewArrayInsnNode node = (MultiANewArrayInsnNode) n;
} else { return "\t\t" + OpcodesReverse.reverseOpcode(node.getOpcode()) + " "
+ UnicodeUtils.escapeWithSpaces(hs, node.desc) + " " + node.dims + "\n";
}
case FRAME: {
FrameNode node = (FrameNode) n;
String out = "";
switch (node.type) {
case Opcodes.F_SAME:
out = "SAME";
break;
case Opcodes.F_SAME1:
out = "SAME1 " + getFrameArray(hs, node.stack, labels);
break;
case Opcodes.F_CHOP:
out = "CHOP " + Integer.toString(node.local.size());
break;
case Opcodes.F_APPEND:
out = "APPEND " + getFrameArray(hs, node.local, labels);
break;
case Opcodes.F_FULL:
out = "FULL " + getFrameArray(hs, node.local, labels) + " " + getFrameArray(hs, node.stack, labels);
break;
}
return "\t\t// frame " + out + "\n";
}
case LINE: {
LineNumberNode node = (LineNumberNode) n;
return "\t\t// line " + node.line + " " + labels.get(node.start.getLabel()) + "\n";
}
default: {
return "\t\tNOT HANDLED! " + OpcodesReverse.reverseOpcode(n.getOpcode()) + " " return "\t\tNOT HANDLED! " + OpcodesReverse.reverseOpcode(n.getOpcode()) + " "
+ n.getClass().getSimpleName() + "\n"; + n.getClass().getSimpleName() + "\n";
} }
} }
}
private static String getFrameArray(HugeStrings hs, List<Object> list, HashMap<Label, Integer> labels) {
ArrayList<String> arr = new ArrayList<>();
if (list != null) {
for (Object o : list) {
if (o == null) {
arr.add(null);
} else {
if (o instanceof String) {
arr.add("\"" + UnicodeUtils.escapeWithSpaces(hs, (String) o) + "\"");
} else if (o instanceof LabelNode) {
arr.add("(label) " + labels.get(((LabelNode) o).getLabel()));
} else if (o instanceof Integer) {
String frameType = ClassUtil.getFrameTypeByID(((Integer) o).intValue());
if (frameType != null)
arr.add(frameType);
else
arr.add("(" + o.getClass().getName().replace(".", "/") + ") " + o);
} else {
arr.add("(" + o.getClass().getName().replace(".", "/") + ") " + o);
}
}
}
return arr.toString();
}
return "null";
}
} }
+53
View File
@@ -0,0 +1,53 @@
package me.ByteEdit.edit;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import me.ByteEdit.utils.UnicodeUtils;
public class HugeStrings {
public static int THRESHOLD = 1000;
private final HashMap<String, HugeData> map = new HashMap<>();
public String onString(String s) {
synchronized (map) {
HugeData i = map.get(s);
if (i == null)
map.put(s, i = new HugeData(map.size(), UnicodeUtils.escape(this, s, true)));
return "#" + Integer.toString(i.id);
}
}
public boolean isEmpty() {
return map.isEmpty();
}
public String makeStringsList() {
StringContext ctx = new StringContext(map.size());
List<HugeData> list = new ArrayList<>(map.values());
list.sort((o1, o2) -> Integer.compare(o1.id, o2.id));
for (HugeData hd : list) {
StringBuilder sb = new StringBuilder(20 + hd.escaped.length());
sb.append('#');
sb.append(Integer.toString(hd.id));
sb.append(": ");
sb.append(hd.escaped);
sb.append('\n');
ctx.next(sb.toString());
}
return ctx.finish();
}
private static class HugeData {
int id;
String escaped;
public HugeData(int id, String escaped) {
this.id = id;
this.escaped = escaped;
}
}
}
+20
View File
@@ -0,0 +1,20 @@
package me.ByteEdit.edit;
import java.util.HashMap;
public class HugeStringsRev {
private final HashMap<Integer, String> map = new HashMap<>();
public void add(int i, String s) {
map.put(Integer.valueOf(i), s);
}
public String get(int i) {
String s = map.get(Integer.valueOf(i));
if (s == null)
s = "#" + Integer.toString(i);
return s;
}
}
@@ -2857,8 +2857,8 @@ public class JavaAssemblyTokenMaker extends AbstractJFlexCTokenMaker {
* @see #addToken(int, int, int) * @see #addToken(int, int, int)
*/ */
private void addHyperlinkToken(int start, int end, int tokenType) { private void addHyperlinkToken(int start, int end, int tokenType) {
int so = start + offsetShift; super.addToken(zzBuffer, start, end, tokenType, start + offsetShift, true);
addToken(zzBuffer, start, end, tokenType, so, true); zzStartRead = zzMarkedPos;
} }
/** /**
@@ -2867,7 +2867,8 @@ public class JavaAssemblyTokenMaker extends AbstractJFlexCTokenMaker {
* @param tokenType The token's type. * @param tokenType The token's type.
*/ */
private void addToken(int tokenType) { private void addToken(int tokenType) {
addToken(zzStartRead, zzMarkedPos - 1, tokenType); super.addToken(zzBuffer, zzStartRead, zzMarkedPos - 1, tokenType, zzStartRead + offsetShift, false);
zzStartRead = zzMarkedPos;
} }
/** /**
@@ -2877,8 +2878,8 @@ public class JavaAssemblyTokenMaker extends AbstractJFlexCTokenMaker {
* @see #addHyperlinkToken(int, int, int) * @see #addHyperlinkToken(int, int, int)
*/ */
private void addToken(int start, int end, int tokenType) { private void addToken(int start, int end, int tokenType) {
int so = start + offsetShift; super.addToken(zzBuffer, start, end, tokenType, start + offsetShift, false);
addToken(zzBuffer, start, end, tokenType, so, false); zzStartRead = zzMarkedPos;
} }
/** /**
@@ -0,0 +1,689 @@
package me.ByteEdit.edit;
import java.util.EmptyStackException;
import java.util.HashMap;
import java.util.Stack;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.tree.AbstractInsnNode;
import org.objectweb.asm.tree.InsnList;
import org.objectweb.asm.tree.InsnNode;
import org.objectweb.asm.tree.IntInsnNode;
import org.objectweb.asm.tree.LabelNode;
import org.objectweb.asm.tree.LdcInsnNode;
public class StackBasedCalculator implements Opcodes, Runnable {
private final InsnList insns;
private final Stack<Number> stack = new Stack<>();
private AbstractInsnNode start;
private int startIdx = -1;
private boolean isAtEnd = false;
public StackBasedCalculator(InsnList insns) {
this.insns = new InsnList();
HashMap<LabelNode, LabelNode> labelMap = new HashMap<>();
for (AbstractInsnNode node = insns.getFirst(); node != null; node = node.getNext()) {
if (node.getType() == AbstractInsnNode.LABEL) {
labelMap.put((LabelNode) node, new LabelNode());
}
}
for (AbstractInsnNode node = insns.getFirst(); node != null; node = node.getNext()) {
this.insns.add(node.clone(labelMap));
}
}
public InsnList get() {
return insns;
}
@Override
public void run() {
while (!isAtEnd) {
out: {
AbstractInsnNode[] arr = insns.toArray();
for (int i = startIdx == -1 ? 0 : startIdx; i < arr.length; i++) {
if (!handle(arr[i]))
break out;
}
isAtEnd = true;
}
}
}
private boolean handle(AbstractInsnNode node) {
try {
switch (node.getOpcode()) {
case ICONST_0:
stack.push(Integer.valueOf(0));
if (start == null)
start = node;
break;
case ICONST_1:
stack.push(Integer.valueOf(1));
if (start == null)
start = node;
break;
case ICONST_2:
stack.push(Integer.valueOf(2));
if (start == null)
start = node;
break;
case ICONST_3:
stack.push(Integer.valueOf(3));
if (start == null)
start = node;
break;
case ICONST_4:
stack.push(Integer.valueOf(4));
if (start == null)
start = node;
break;
case ICONST_5:
stack.push(Integer.valueOf(5));
if (start == null)
start = node;
break;
case ICONST_M1:
stack.push(Integer.valueOf(-1));
if (start == null)
start = node;
break;
case DCONST_0:
stack.push(Double.valueOf(0));
if (start == null)
start = node;
break;
case DCONST_1:
stack.push(Double.valueOf(1));
if (start == null)
start = node;
break;
case FCONST_0:
stack.push(Float.valueOf(0));
if (start == null)
start = node;
break;
case FCONST_1:
stack.push(Float.valueOf(1));
if (start == null)
start = node;
break;
case FCONST_2:
stack.push(Float.valueOf(2));
if (start == null)
start = node;
break;
case LCONST_0:
stack.push(Long.valueOf(0));
if (start == null)
start = node;
break;
case LCONST_1:
stack.push(Long.valueOf(1));
if (start == null)
start = node;
break;
case BIPUSH:
case SIPUSH:
stack.push(((IntInsnNode) node).operand);
if (start == null)
start = node;
break;
case D2F:
stack.push(((Double) stack.pop()).floatValue());
change(node);
return false;
case D2I:
stack.push(((Double) stack.pop()).intValue());
change(node);
return false;
case D2L:
stack.push(((Double) stack.pop()).longValue());
change(node);
return false;
case F2D:
stack.push(((Float) stack.pop()).doubleValue());
change(node);
return false;
case F2I:
stack.push(((Float) stack.pop()).intValue());
change(node);
return false;
case F2L:
stack.push(((Float) stack.pop()).longValue());
change(node);
return false;
case L2D:
stack.push(((Long) stack.pop()).doubleValue());
change(node);
return false;
case L2F:
stack.push(((Long) stack.pop()).floatValue());
change(node);
return false;
case L2I:
stack.push(((Long) stack.pop()).intValue());
change(node);
return false;
case I2B:
error(node);
return true;
case I2C:
error(node);
return true;
case I2D:
stack.push(((Integer) stack.pop()).doubleValue());
change(node);
return false;
case I2F:
stack.push(((Integer) stack.pop()).floatValue());
change(node);
return false;
case I2L:
stack.push(((Integer) stack.pop()).longValue());
change(node);
return false;
case I2S:
error(node);
return true;
case NOP:
break;
case LDC:
LdcInsnNode ldc = (LdcInsnNode) node;
if (ldc.cst instanceof Number) {
stack.push((Number) ldc.cst);
if (start == null)
start = node;
} else {
error(node);
return true;
}
break;
// long
case LADD: {
long top = ((Long) stack.pop()).longValue();
long bottom = ((Long) stack.pop()).longValue();
stack.push(bottom + top);
change(node);
return false;
}
case LSUB: {
long top = ((Long) stack.pop()).longValue();
long bottom = ((Long) stack.pop()).longValue();
stack.push(bottom - top);
change(node);
return false;
}
case LMUL: {
long top = ((Long) stack.pop()).longValue();
long bottom = ((Long) stack.pop()).longValue();
stack.push(bottom * top);
change(node);
return false;
}
case LDIV: {
long top = ((Long) stack.pop()).longValue();
long bottom = ((Long) stack.pop()).longValue();
stack.push(bottom / top);
change(node);
return false;
}
case LREM: {
long top = ((Long) stack.pop()).longValue();
long bottom = ((Long) stack.pop()).longValue();
stack.push(bottom % top);
change(node);
return false;
}
case LNEG: {
long top = ((Long) stack.pop()).longValue();
stack.push(-top);
change(node);
return false;
}
case LAND: {
long top = ((Long) stack.pop()).longValue();
long bottom = ((Long) stack.pop()).longValue();
stack.push(bottom & top);
change(node);
return false;
}
case LOR: {
long top = ((Long) stack.pop()).longValue();
long bottom = ((Long) stack.pop()).longValue();
stack.push(bottom | top);
change(node);
return false;
}
case LXOR: {
long top = ((Long) stack.pop()).longValue();
long bottom = ((Long) stack.pop()).longValue();
stack.push(bottom ^ top);
change(node);
return false;
}
case LSHR: {
int top = ((Integer) stack.pop()).intValue();
long bottom = ((Long) stack.pop()).longValue();
stack.push(bottom >> top);
change(node);
return false;
}
case LSHL: {
int top = ((Integer) stack.pop()).intValue();
long bottom = ((Long) stack.pop()).longValue();
stack.push(bottom << top);
change(node);
return false;
}
case LUSHR: {
int top = ((Integer) stack.pop()).intValue();
long bottom = ((Long) stack.pop()).longValue();
stack.push(bottom >>> top);
change(node);
return false;
}
// int
case IADD: {
int top = ((Integer) stack.pop()).intValue();
int bottom = ((Integer) stack.pop()).intValue();
stack.push(bottom + top);
change(node);
return false;
}
case ISUB: {
int top = ((Integer) stack.pop()).intValue();
int bottom = ((Integer) stack.pop()).intValue();
stack.push(bottom - top);
change(node);
return false;
}
case IMUL: {
int top = ((Integer) stack.pop()).intValue();
int bottom = ((Integer) stack.pop()).intValue();
stack.push(bottom * top);
change(node);
return false;
}
case IDIV: {
int top = ((Integer) stack.pop()).intValue();
int bottom = ((Integer) stack.pop()).intValue();
stack.push(bottom / top);
change(node);
return false;
}
case IREM: {
int top = ((Integer) stack.pop()).intValue();
int bottom = ((Integer) stack.pop()).intValue();
stack.push(bottom % top);
change(node);
return false;
}
case INEG: {
int top = ((Integer) stack.pop()).intValue();
stack.push(-top);
change(node);
return false;
}
case IAND: {
int top = ((Integer) stack.pop()).intValue();
int bottom = ((Integer) stack.pop()).intValue();
stack.push(bottom & top);
change(node);
return false;
}
case IOR: {
int top = ((Integer) stack.pop()).intValue();
int bottom = ((Integer) stack.pop()).intValue();
stack.push(bottom | top);
change(node);
return false;
}
case IXOR: {
int top = ((Integer) stack.pop()).intValue();
int bottom = ((Integer) stack.pop()).intValue();
stack.push(bottom ^ top);
change(node);
return false;
}
case ISHR: {
int top = ((Integer) stack.pop()).intValue();
int bottom = ((Integer) stack.pop()).intValue();
stack.push(bottom >> top);
change(node);
return false;
}
case ISHL: {
int top = ((Integer) stack.pop()).intValue();
int bottom = ((Integer) stack.pop()).intValue();
stack.push(bottom << top);
change(node);
return false;
}
case IUSHR: {
int top = ((Integer) stack.pop()).intValue();
int bottom = ((Integer) stack.pop()).intValue();
stack.push(bottom >>> top);
change(node);
return false;
}
// double
case DADD: {
double top = ((Double) stack.pop()).doubleValue();
double bottom = ((Double) stack.pop()).doubleValue();
stack.push(bottom + top);
change(node);
return false;
}
case DSUB: {
double top = ((Double) stack.pop()).doubleValue();
double bottom = ((Double) stack.pop()).doubleValue();
stack.push(bottom - top);
change(node);
return false;
}
case DMUL: {
double top = ((Double) stack.pop()).doubleValue();
double bottom = ((Double) stack.pop()).doubleValue();
stack.push(bottom * top);
change(node);
return false;
}
case DDIV: {
double top = ((Double) stack.pop()).doubleValue();
double bottom = ((Double) stack.pop()).doubleValue();
stack.push(bottom / top);
change(node);
return false;
}
case DREM: {
double top = ((Double) stack.pop()).doubleValue();
double bottom = ((Double) stack.pop()).doubleValue();
stack.push(bottom % top);
change(node);
return false;
}
case DNEG: {
double top = ((Double) stack.pop()).doubleValue();
stack.push(-top);
change(node);
return false;
}
// float
case FADD: {
float top = ((Float) stack.pop()).floatValue();
float bottom = ((Float) stack.pop()).floatValue();
stack.push(bottom + top);
change(node);
return false;
}
case FSUB: {
float top = ((Float) stack.pop()).floatValue();
float bottom = ((Float) stack.pop()).floatValue();
stack.push(bottom - top);
change(node);
return false;
}
case FMUL: {
float top = ((Float) stack.pop()).floatValue();
float bottom = ((Float) stack.pop()).floatValue();
stack.push(bottom * top);
change(node);
return false;
}
case FDIV: {
float top = ((Float) stack.pop()).floatValue();
float bottom = ((Float) stack.pop()).floatValue();
stack.push(bottom / top);
change(node);
return false;
}
case FREM: {
float top = ((Float) stack.pop()).floatValue();
float bottom = ((Float) stack.pop()).floatValue();
stack.push(bottom % top);
change(node);
return false;
}
case FNEG: {
float top = ((Float) stack.pop()).floatValue();
stack.push(-top);
change(node);
return false;
}
// dup
case DUP: {
Number num = stack.pop();
if (num instanceof Double || num instanceof Long) {
error(node);
return true;
}
stack.push(num);
stack.push(num);
change(node);
return false;
}
case DUP_X1: {
Number top = stack.pop();
Number bottom = stack.pop();
if (bottom instanceof Double || bottom instanceof Long || top instanceof Double
|| top instanceof Long) {
error(node);
return true;
}
stack.push(top);
stack.push(bottom);
stack.push(top);
change(node);
return false;
}
case DUP_X2: {
Number top = stack.pop();
Number bottom = stack.pop();
if (top instanceof Double || top instanceof Long) {
error(node);
return true;
}
Number bottom2 = null;
if (!(bottom instanceof Double || bottom instanceof Long)) {
bottom2 = stack.pop();
if (bottom instanceof Double || bottom instanceof Long) {
error(node);
return true;
}
}
stack.push(top);
if (bottom2 != null)
stack.push(bottom2);
stack.push(bottom);
stack.push(top);
change(node);
return false;
}
case DUP2: {
Number top = stack.pop();
Number bottom = null;
if (!(top instanceof Double || top instanceof Long)) {
bottom = stack.pop();
if (bottom instanceof Double || bottom instanceof Long) {
error(node);
return true;
}
}
if (bottom != null)
stack.push(bottom);
stack.push(top);
if (bottom != null)
stack.push(bottom);
stack.push(top);
change(node);
return false;
}
case DUP2_X1: {
Number top = stack.pop();
Number bottom = null;
if (!(top instanceof Double || top instanceof Long)) {
bottom = stack.pop();
if (bottom instanceof Double || bottom instanceof Long) {
error(node);
return true;
}
}
Number bottom2 = stack.pop();
if (bottom != null)
stack.push(bottom);
stack.push(top);
stack.push(bottom2);
if (bottom != null)
stack.push(bottom);
stack.push(top);
change(node);
return false;
}
case DUP2_X2: {
Number top = stack.pop();
Number bottom = null;
if (!(top instanceof Double || top instanceof Long)) {
bottom = stack.pop();
if (bottom instanceof Double || bottom instanceof Long) {
error(node);
return true;
}
}
Number top2 = stack.pop();
Number bottom2 = null;
if (!(top2 instanceof Double || top2 instanceof Long)) {
bottom2 = stack.pop();
if (bottom2 instanceof Double || bottom2 instanceof Long) {
error(node);
return true;
}
}
if (bottom != null)
stack.push(bottom);
stack.push(top);
if (bottom2 != null)
stack.push(bottom2);
stack.push(top2);
if (bottom != null)
stack.push(bottom);
stack.push(top);
change(node);
return false;
}
// stack
case POP:
stack.pop();
change(node);
return false;
case POP2:
stack.pop();
stack.pop();
change(node);
return false;
case SWAP: {
Number top = stack.pop();
Number bottom = stack.pop();
if (bottom instanceof Double || bottom instanceof Long || top instanceof Double
|| top instanceof Long) {
error(node);
return true;
}
stack.push(top);
stack.push(bottom);
change(node);
return false;
}
default:
error(node);
return true;
}
} catch (ClassCastException | EmptyStackException ex) {
error(node);
return true;
}
return true;
}
private void error(AbstractInsnNode node) {
change(node.getPrevious());
stack.clear();
start = null;
}
private void change(AbstractInsnNode node) {
if (start == null)
return;
int idx = insns.indexOf(start);
startIdx = idx;
int idx2 = insns.indexOf(node);
if (idx != idx2) {
for (int i = 0; i <= idx2 - idx; i++) {
insns.remove(insns.get(idx));
}
while (!stack.isEmpty()) {
addNode(idx, stack.pop());
}
}
stack.clear();
start = null;
}
private void addNode(int idx, Number n) {
if (n instanceof Double) {
double val = n.doubleValue();
if (val == 0.0)
insns.insertBefore(insns.get(idx), new InsnNode(DCONST_0));
else if (val == 1.0)
insns.insertBefore(insns.get(idx), new InsnNode(DCONST_1));
else
insns.insertBefore(insns.get(idx), new LdcInsnNode(val));
} else if (n instanceof Float) {
float val = n.floatValue();
if (val == 0.0f)
insns.insertBefore(insns.get(idx), new InsnNode(FCONST_0));
else if (val == 1.0f)
insns.insertBefore(insns.get(idx), new InsnNode(FCONST_1));
else if (val == 2.0f)
insns.insertBefore(insns.get(idx), new InsnNode(FCONST_2));
else
insns.insertBefore(insns.get(idx), new LdcInsnNode(val));
} else if (n instanceof Long) {
long val = n.longValue();
if (val == 0l)
insns.insertBefore(insns.get(idx), new InsnNode(LCONST_0));
else if (val == 1l)
insns.insertBefore(insns.get(idx), new InsnNode(LCONST_1));
else
insns.insertBefore(insns.get(idx), new LdcInsnNode(val));
} else if (n instanceof Integer) {
int val = n.intValue();
if (val == 0)
insns.insertBefore(insns.get(idx), new InsnNode(ICONST_0));
else if (val == 1)
insns.insertBefore(insns.get(idx), new InsnNode(ICONST_1));
else if (val == 2)
insns.insertBefore(insns.get(idx), new InsnNode(ICONST_2));
else if (val == 3)
insns.insertBefore(insns.get(idx), new InsnNode(ICONST_3));
else if (val == 4)
insns.insertBefore(insns.get(idx), new InsnNode(ICONST_4));
else if (val == 5)
insns.insertBefore(insns.get(idx), new InsnNode(ICONST_5));
else if (val == -1)
insns.insertBefore(insns.get(idx), new InsnNode(ICONST_M1));
else if (val == (byte) val)
insns.insertBefore(insns.get(idx), new IntInsnNode(BIPUSH, (byte) val));
else if (val == (short) val)
insns.insertBefore(insns.get(idx), new IntInsnNode(SIPUSH, (short) val));
else
insns.insertBefore(insns.get(idx), new LdcInsnNode(val));
} else {
throw new RuntimeException("Unexpected number: " + n);
}
}
}
+48
View File
@@ -0,0 +1,48 @@
package me.ByteEdit.edit;
/**
* This is a quiet fast String concatenation helper class. It appears to be a
* lot faster than Java's StringBuilder class, especially for very large
* Strings, which will be made by the Disassembler.
*/
public class StringContext {
private String[] arrs;
private int idx;
private int len;
public StringContext(int amt) {
if (amt > 0)
arrs = new String[amt];
}
public int next(String s) {
int i = idx;
len += (arrs[idx++] = s).length();
return i;
}
public void set(int i, String s) {
if (arrs[i] != null)
len -= arrs[i].length();
len += (arrs[i] = s).length();
}
public String finish() {
if (arrs == null)
return "";
char[] full = new char[len];
int off = 0;
for (int i = 0; i < idx; i++) {
int len = arrs[i].length();
arrs[i].getChars(0, len, full, off);
off += len;
arrs[i] = null;
}
String s = new String(full);
arrs = null;
full = null;
return s;
}
}
+461 -165
View File
@@ -1,6 +1,5 @@
package me.ByteEdit.main; package me.ByteEdit.main;
import java.awt.Color;
import java.awt.Component; import java.awt.Component;
import java.awt.EventQueue; import java.awt.EventQueue;
import java.awt.Font; import java.awt.Font;
@@ -18,18 +17,20 @@ import java.awt.event.ActionEvent;
import java.awt.event.ActionListener; import java.awt.event.ActionListener;
import java.awt.event.KeyAdapter; import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent; import java.awt.event.KeyEvent;
import java.awt.event.MouseEvent;
import java.io.BufferedReader;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
import java.io.File; import java.io.File;
import java.io.FileOutputStream; import java.io.FileOutputStream;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.StringReader;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.Collections; import java.util.Collections;
import java.util.Comparator; import java.util.Comparator;
import java.util.Enumeration; import java.util.Enumeration;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Map.Entry; import java.util.Map.Entry;
import java.util.jar.JarEntry; import java.util.jar.JarEntry;
@@ -39,17 +40,22 @@ import java.util.regex.Matcher;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import javax.swing.ButtonGroup;
import javax.swing.JCheckBoxMenuItem;
import javax.swing.JComponent; import javax.swing.JComponent;
import javax.swing.JDialog; import javax.swing.JDialog;
import javax.swing.JFileChooser; import javax.swing.JFileChooser;
import javax.swing.JFrame; import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane; import javax.swing.JOptionPane;
import javax.swing.JPanel; import javax.swing.JPanel;
import javax.swing.JRadioButtonMenuItem;
import javax.swing.JScrollPane; import javax.swing.JScrollPane;
import javax.swing.JSplitPane; import javax.swing.JSplitPane;
import javax.swing.JTree; import javax.swing.JTree;
import javax.swing.KeyStroke; import javax.swing.KeyStroke;
import javax.swing.UIManager;
import javax.swing.border.EmptyBorder; import javax.swing.border.EmptyBorder;
import javax.swing.event.TreeExpansionEvent; import javax.swing.event.TreeExpansionEvent;
import javax.swing.event.TreeExpansionListener; import javax.swing.event.TreeExpansionListener;
@@ -70,10 +76,11 @@ import org.fife.ui.autocomplete.DefaultCompletionProvider;
import org.fife.ui.autocomplete.ShorthandCompletion; import org.fife.ui.autocomplete.ShorthandCompletion;
import org.fife.ui.rsyntaxtextarea.RSyntaxTextArea; import org.fife.ui.rsyntaxtextarea.RSyntaxTextArea;
import org.fife.ui.rsyntaxtextarea.SyntaxConstants; import org.fife.ui.rsyntaxtextarea.SyntaxConstants;
import org.fife.ui.rsyntaxtextarea.Theme;
import org.fife.ui.rsyntaxtextarea.folding.CurlyFoldParser; import org.fife.ui.rsyntaxtextarea.folding.CurlyFoldParser;
import org.fife.ui.rsyntaxtextarea.folding.FoldParserManager; import org.fife.ui.rsyntaxtextarea.folding.FoldParserManager;
import org.fife.ui.rtextarea.RTextArea;
import org.fife.ui.rtextarea.RTextScrollPane; import org.fife.ui.rtextarea.RTextScrollPane;
import org.fife.ui.rtextarea.ToolTipSupplier;
import org.objectweb.asm.ClassReader; import org.objectweb.asm.ClassReader;
import org.objectweb.asm.ClassWriter; import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.tree.ClassNode; import org.objectweb.asm.tree.ClassNode;
@@ -82,14 +89,15 @@ import org.objectweb.asm.tree.MethodNode;
import me.ByteEdit.boxes.CompilationBox; import me.ByteEdit.boxes.CompilationBox;
import me.ByteEdit.boxes.GlobalSearchBox; import me.ByteEdit.boxes.GlobalSearchBox;
import me.ByteEdit.boxes.OptionBox;
import me.ByteEdit.boxes.RenameBox; import me.ByteEdit.boxes.RenameBox;
import me.ByteEdit.boxes.SearchBox; import me.ByteEdit.boxes.SearchBox;
import me.ByteEdit.boxes.ThemeBox;
import me.ByteEdit.boxes.TypeOpenBox; import me.ByteEdit.boxes.TypeOpenBox;
import me.ByteEdit.boxes.UnicodeBox; import me.ByteEdit.boxes.UnicodeBox;
import me.ByteEdit.edit.Assembler; import me.ByteEdit.edit.Assembler;
import me.ByteEdit.edit.Disassembler; import me.ByteEdit.edit.Disassembler;
import me.ByteEdit.edit.Disassembler.DisassembleTuple; import me.ByteEdit.edit.Disassembler.DisassembleTuple;
import me.ByteEdit.edit.HugeStrings;
import me.ByteEdit.utils.ClassUtil; import me.ByteEdit.utils.ClassUtil;
import me.ByteEdit.utils.OpcodesReverse; import me.ByteEdit.utils.OpcodesReverse;
import me.ByteEdit.utils.UnicodeUtils; import me.ByteEdit.utils.UnicodeUtils;
@@ -98,7 +106,7 @@ public class Main extends JFrame {
public static Main INSTANCE; public static Main INSTANCE;
private JPanel contentPane; private JPanel contentPane;
private boolean isChangingFile; private volatile boolean isChangingFile;
public static File jarFile; public static File jarFile;
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<>();
@@ -107,16 +115,43 @@ public class Main extends JFrame {
public static GlobalSearchBox globalSearchBox; public static GlobalSearchBox globalSearchBox;
public static SearchBox searchBox; public static SearchBox searchBox;
public static TypeOpenBox typeOpenBox; public static TypeOpenBox typeOpenBox;
public static OptionBox optionBox;
public static UnicodeBox unicodeBox; public static UnicodeBox unicodeBox;
public static RenameBox renameBox; public static RenameBox renameBox;
public static CompilationBox compilationBox; public static CompilationBox compilationBox;
public static ThemeBox themeBox;
public static JTree tree; public static JTree tree;
public static RTextScrollPane scrollPane_ByteEdit; public static RTextScrollPane scrollPane_ByteEdit;
public static Theme theme;
public static File saveFolder; public static File saveFolder;
public static HashSet<String> fakedFolders = new HashSet<>(); private static final Pattern SLASH = Pattern.compile("/");
private JMenuBar menuBar;
private JMenu mnFile;
private JMenuItem mntmOpenJar;
private JMenuItem mntmSaveBytecode;
private JMenuItem mntmSaveJar;
private JMenu mnWindow;
private JMenuItem mntmThemes;
private JMenuItem mntmSearchMembers;
private JMenuItem mntmSearch;
private JMenuItem mntmOpenType;
private JMenuItem mntmUnicode;
private JMenuItem mntmCompiler;
private JMenu mnSearch;
private JMenu mnOptions;
private JCheckBoxMenuItem mntmComputeFrames;
private JCheckBoxMenuItem mntmComputeMax;
private JMenu mnStringLimit;
private JRadioButtonMenuItem rdbtnmntm0;
private JMenuItem rdbtnmntm100;
private JMenuItem rdbtnmntm1000;
private JMenuItem rdbtnmntm500;
private JMenuItem rdbtnmntm5000;
private JMenuItem rdbtnmntm10000;
public JCheckBoxMenuItem mntmMultithreaded;
private JMenu mnDeobfuscation;
public JCheckBoxMenuItem mntmNumbers;
public static final Object treeLock = new Object();
/** /**
* Launch the application. * Launch the application.
@@ -128,11 +163,13 @@ public class Main extends JFrame {
try { try {
Main frame = new Main(); Main frame = new Main();
frame.setVisible(true); frame.setVisible(true);
ThemeManager.applyRSTATheme();
} catch (Exception e) { } catch (Exception e) {
e.printStackTrace(); e.printStackTrace();
} }
} }
}); });
} }
/** /**
@@ -194,50 +231,214 @@ public class Main extends JFrame {
"// #Max: l:0 s:0\n\t// #TryCatch:\n\t// #LocalVars:\n\tpublic static method ()V {\n\t\treturn\n\t}", "// #Max: l:0 s:0\n\t// #TryCatch:\n\t// #LocalVars:\n\tpublic static method ()V {\n\t\treturn\n\t}",
null, "<html><b><u>method</u></b><br>Creates an example method</html>")); null, "<html><b><u>method</u></b><br>Creates an example method</html>"));
provider.addCompletion(new ShorthandCompletion(provider, "frame", "frame FULL l:[] s:[]", null, provider.addCompletion(new ShorthandCompletion(provider, "frame", "frame FULL l:[] s:[]", null,
"<html><b><u>frame</u></b><br>Creates a stack map frame</html>")); "<html><b><u>frame</u></b><br>Creates a stack map frame<br><br><b>Possible frames:</b><br><ul><li><code>SAME: same locals, empty stack</code></li><li><code>SAME1: same locals, stack has 1 entry</code></li><li><code>CHOP: same locals - k, empty stack</code></li><li><code>APPEND: same locals + k, empty stack</code></li><li><code>FULL: define locals, define stack</code></li></ul></html>"));
provider.addCompletion(new BasicCompletion(provider, "SAME", null,
"<html><b><u>Frames:</u></b><br><code>SAME</code><br><br><u>Locals:</u> same as previous<br><u>Stack:</u> empty</html>"));
provider.addCompletion(new BasicCompletion(provider, "SAME1", null,
"<html><b><u>Frames:</u></b><br><code>SAME1 [(type)]</code><br><br><u>Locals:</u> same as previous<br><u>Stack:</u> 1 entry</html>"));
provider.addCompletion(new BasicCompletion(provider, "CHOP", null,
"<html><b><u>Frames:</u></b><br><code>CHOP (int:k)</code><br><br><u>Locals:</u> removes the top <i>k</i> elements<br><u>Stack:</u> empty</html>"));
provider.addCompletion(new BasicCompletion(provider, "APPEND", null,
"<html><b><u>Frames:</u></b><br><code>APPEND [(type), (type), ...]</code><br><br><u>Locals:</u> adds the elements to the top<br><u>Stack:</u> empty</html>"));
provider.addCompletion(new BasicCompletion(provider, "FULL", null,
"<html><b><u>Frames:</u></b><br><code>FULL [(type), (type), ...] [(type), (type), ...]</code><br><i>first locals, then stack</i><br><br><u>Locals:</u> sets the elements<br><u>Stack:</u> sets the elements</html>"));
return provider; return provider;
} }
public static boolean dark = true;
/** /**
* Create the frame. * Create the frame.
*/ */
public Main() { public Main() {
INSTANCE = this; INSTANCE = this;
File light = new File(System.getProperty("java.io.tmpdir") + File.pathSeparator + "ByteEditLight.conf"); ThemeManager.registerFrames(this);
if (light.exists()) {
dark = false;
}
try {
theme = Theme.load(getClass().getClassLoader()
.getResourceAsStream(dark ? "org/fife/eclipse_dark.xml" : "org/fife/eclipse.xml"));
} catch (IOException e2) {
e2.printStackTrace();
}
globalSearchBox = new GlobalSearchBox(); globalSearchBox = new GlobalSearchBox();
searchBox = new SearchBox(); searchBox = new SearchBox();
typeOpenBox = new TypeOpenBox(); typeOpenBox = new TypeOpenBox();
optionBox = new OptionBox();
unicodeBox = new UnicodeBox(); unicodeBox = new UnicodeBox();
renameBox = new RenameBox(); renameBox = new RenameBox();
compilationBox = new CompilationBox(); compilationBox = new CompilationBox();
themeBox = new ThemeBox();
ThemeManager.registerFrames(globalSearchBox);
ThemeManager.registerFrames(searchBox);
ThemeManager.registerFrames(typeOpenBox);
ThemeManager.registerFrames(unicodeBox);
ThemeManager.registerFrames(renameBox);
ThemeManager.registerFrames(compilationBox);
ThemeManager.registerFrames(themeBox);
ThemeManager.load();
setTitle("ByteEdit"); setTitle("ByteEdit");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setBounds((int) (Toolkit.getDefaultToolkit().getScreenSize().getWidth() / 2 - 407), setBounds((int) (Toolkit.getDefaultToolkit().getScreenSize().getWidth() / 2 - 407),
(int) (Toolkit.getDefaultToolkit().getScreenSize().getHeight() / 2 - 237), 814, 474); (int) (Toolkit.getDefaultToolkit().getScreenSize().getHeight() / 2 - 237), 814, 474);
menuBar = new JMenuBar();
setJMenuBar(menuBar);
mnFile = new JMenu("File");
menuBar.add(mnFile);
mntmOpenJar = new JMenuItem("Open Jar");
mntmOpenJar.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
final JFileChooser fileChooser = new JFileChooser(saveFolder) {
@Override
protected JDialog createDialog(final Component parent) throws HeadlessException {
final JDialog dialog = super.createDialog(parent);
dialog.setAlwaysOnTop(true);
return dialog;
}
};
fileChooser.setDialogTitle("Open File");
fileChooser.setFileSelectionMode(0);
fileChooser.setAcceptAllFileFilterUsed(false);
fileChooser.addChoosableFileFilter(new FileNameExtensionFilter("Jar File", "jar"));
final int action = fileChooser.showOpenDialog(Main.this);
if (action == 0) {
final File file = fileChooser.getSelectedFile();
saveFolder = file.getParentFile();
boolean shouldSave = false;
if (file.exists()) {
synchronized (treeLock) {
jarFile = file;
saveFolder = file.getParentFile();
isChangingFile = true;
try { try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); Main.this.setTitle("ByteEdit - Loading '" + jarFile.getCanonicalPath() + "'");
} catch (Exception e) { } catch (IOException ex) {
Main.this.setTitle("ByteEdit - Loading '" + jarFile.getAbsolutePath() + "'");
}
new Thread(new Runnable() {
public void run() {
try {
ArchiveTreeModel model = new ArchiveTreeModel(new JarFile(jarFile));
EventQueue.invokeLater(new Runnable() {
public void run() {
synchronized (treeLock) {
tree.setModel(model);
txtByteEditView.setText("");
currentNodeName = null;
globalSearchBox.setVisible(false);
searchBox.setVisible(false);
typeOpenBox.setVisible(false);
unicodeBox.setVisible(false);
renameBox.setVisible(false);
compilationBox.setVisible(false);
isChangingFile = false;
Main.this.setTitle("ByteEdit");
}
}
});
} catch (IOException e) {
e.printStackTrace(); e.printStackTrace();
} }
}
}).start();
}
}
}
}
});
mnFile.add(mntmOpenJar);
mntmSaveBytecode = new JMenuItem("Save Bytecode");
mntmSaveBytecode.addActionListener(e -> saveCurrentClassNode());
mnFile.add(mntmSaveBytecode);
mntmSaveJar = new JMenuItem("Save Jar");
mntmSaveJar.addActionListener(e -> save());
mnFile.add(mntmSaveJar);
mnSearch = new JMenu("Search");
menuBar.add(mnSearch);
mntmSearchMembers = new JMenuItem("Search Members");
mnSearch.add(mntmSearchMembers);
mntmSearch = new JMenuItem("Search");
mnSearch.add(mntmSearch);
mntmSearch.addActionListener(e -> searchBox.setVisible(true));
mntmSearchMembers.addActionListener(e -> globalSearchBox.setVisible(true));
mnWindow = new JMenu("Window");
menuBar.add(mnWindow);
mntmThemes = new JMenuItem("Themes");
mntmThemes.addActionListener(e -> themeBox.setVisible(true));
mnWindow.add(mntmThemes);
mntmOpenType = new JMenuItem("Open Type");
mntmOpenType.addActionListener(e -> typeOpenBox.setVisible(true));
mnWindow.add(mntmOpenType);
mntmUnicode = new JMenuItem("Unicode Helper");
mntmUnicode.addActionListener(e -> unicodeBox.setVisible(true));
mnWindow.add(mntmUnicode);
mntmCompiler = new JMenuItem("Compiler");
mntmCompiler.addActionListener(e -> compilationBox.setVisible(true));
mnWindow.add(mntmCompiler);
mnOptions = new JMenu("Options");
menuBar.add(mnOptions);
mntmComputeFrames = new JCheckBoxMenuItem("Compute Frames");
mnOptions.add(mntmComputeFrames);
mntmComputeMax = new JCheckBoxMenuItem("Compute Max");
mnOptions.add(mntmComputeMax);
mntmMultithreaded = new JCheckBoxMenuItem("Multithreaded");
mntmMultithreaded.setSelected(true);
mnOptions.add(mntmMultithreaded);
mnStringLimit = new JMenu("Huge String Limit");
mnOptions.add(mnStringLimit);
rdbtnmntm0 = new JRadioButtonMenuItem("0");
rdbtnmntm0.addActionListener(e -> HugeStrings.THRESHOLD = 0);
mnStringLimit.add(rdbtnmntm0);
rdbtnmntm100 = new JRadioButtonMenuItem("100");
rdbtnmntm100.addActionListener(e -> HugeStrings.THRESHOLD = 100);
mnStringLimit.add(rdbtnmntm100);
rdbtnmntm500 = new JRadioButtonMenuItem("500");
rdbtnmntm500.addActionListener(e -> HugeStrings.THRESHOLD = 500);
mnStringLimit.add(rdbtnmntm500);
rdbtnmntm1000 = new JRadioButtonMenuItem("1000");
rdbtnmntm1000.addActionListener(e -> HugeStrings.THRESHOLD = 1000);
rdbtnmntm1000.setSelected(true);
mnStringLimit.add(rdbtnmntm1000);
rdbtnmntm5000 = new JRadioButtonMenuItem("5000");
rdbtnmntm5000.addActionListener(e -> HugeStrings.THRESHOLD = 5000);
mnStringLimit.add(rdbtnmntm5000);
rdbtnmntm10000 = new JRadioButtonMenuItem("10000");
rdbtnmntm10000.addActionListener(e -> HugeStrings.THRESHOLD = 10000);
mnStringLimit.add(rdbtnmntm10000);
ButtonGroup group = new ButtonGroup();
group.add(rdbtnmntm0);
group.add(rdbtnmntm100);
group.add(rdbtnmntm500);
group.add(rdbtnmntm1000);
group.add(rdbtnmntm5000);
group.add(rdbtnmntm10000);
mnDeobfuscation = new JMenu("Deobfuscation");
menuBar.add(mnDeobfuscation);
mntmNumbers = new JCheckBoxMenuItem("Numbers");
mnDeobfuscation.add(mntmNumbers);
contentPane = new JPanel(); contentPane = new JPanel();
contentPane.setBackground(dark ? new Color(0x2F2F2F) : Color.GRAY);
contentPane.setBorder(new EmptyBorder(5, 5, 5, 5)); contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
setContentPane(contentPane); setContentPane(contentPane);
contentPane.setLayout(new GridLayout(0, 1, 0, 0)); contentPane.setLayout(new GridLayout(0, 1, 0, 0));
JSplitPane splitPane = new JSplitPane(); JSplitPane splitPane = new JSplitPane();
splitPane.setBackground(dark ? new Color(0x2F2F2F) : Color.GRAY);
splitPane.setResizeWeight(0.2); splitPane.setResizeWeight(0.2);
contentPane.add(splitPane); contentPane.add(splitPane);
JScrollPane scrollPane = new JScrollPane(); JScrollPane scrollPane = new JScrollPane();
@@ -255,18 +456,36 @@ public class Main extends JFrame {
@Override @Override
public void keyReleased(KeyEvent e) { public void keyReleased(KeyEvent e) {
if (e.getKeyCode() == 116 && jarFile != null) { // F5 if (e.getKeyCode() == 116 && jarFile != null) { // F5
synchronized (treeLock) {
if (isChangingFile) {
return;
}
try { try {
isChangingFile = true; isChangingFile = true;
Main.this.setTitle("ByteEdit - Reloading...");
new Thread(new Runnable() {
public void run() {
try { try {
tree.setModel(new ArchiveTreeModel(new JarFile(jarFile))); ArchiveTreeModel model = new ArchiveTreeModel(new JarFile(jarFile));
} catch (IOException e1) { EventQueue.invokeLater(new Runnable() {
e1.printStackTrace(); public void run() {
} synchronized (treeLock) {
tree.setModel(model);
isChangingFile = false; isChangingFile = false;
Main.this.setTitle("ByteEdit");
}
}
});
} catch (IOException e) {
e.printStackTrace();
}
}
}).start();
} catch (Throwable t) { } catch (Throwable t) {
t.printStackTrace(); t.printStackTrace();
showError(t); showError(t);
} }
}
} else if (e.getKeyCode() == 127) { // del } else if (e.getKeyCode() == 127) { // del
if (tree.getSelectionPath() == null) if (tree.getSelectionPath() == null)
return; return;
@@ -296,29 +515,31 @@ public class Main extends JFrame {
} }
}); });
tree.setFont(new Font("Verdana", Font.PLAIN, 11)); tree.setFont(new Font("Verdana", Font.PLAIN, 11));
tree.setBackground(dark ? new Color(0x2F2F2F) : Color.LIGHT_GRAY);
tree.setCellRenderer(new DefaultTreeCellRenderer() { tree.setCellRenderer(new DefaultTreeCellRenderer() {
{ {
putClientProperty("html.disable", Boolean.TRUE); putClientProperty("html.disable", Boolean.TRUE);
setBackgroundNonSelectionColor(dark ? new Color(0x2F2F2F) : Color.LIGHT_GRAY);
setBackgroundSelectionColor(Color.GRAY);
setTextNonSelectionColor(dark ? new Color(0xeeeeee) : Color.BLACK);
setTextSelectionColor(dark ? new Color(0xeeeeee) : Color.BLACK);
} }
}); });
scrollPane.setViewportView(tree); scrollPane.setViewportView(tree);
tree.addTreeSelectionListener(new TreeSelectionListener() { tree.addTreeSelectionListener(new TreeSelectionListener() {
public void valueChanged(TreeSelectionEvent e) { public void valueChanged(TreeSelectionEvent e) {
synchronized (treeLock) {
if (!isChangingFile) { if (!isChangingFile) {
selectFile(((ByteEditTreeNode) e.getPath().getLastPathComponent()).path); selectFile(((ByteEditTreeNode) e.getPath().getLastPathComponent()).path);
} }
} }
}
}); });
new DropTarget(tree, new DropTargetListener() { new DropTarget(tree, new DropTargetListener() {
@Override @Override
public void drop(DropTargetDropEvent dtde) { public void drop(DropTargetDropEvent dtde) {
synchronized (treeLock) {
if (isChangingFile) {
dtde.rejectDrop();
return;
}
try { try {
Transferable tr = dtde.getTransferable(); Transferable tr = dtde.getTransferable();
DataFlavor[] flavors = tr.getTransferDataFlavors(); DataFlavor[] flavors = tr.getTransferDataFlavors();
@@ -332,22 +553,39 @@ public class Main extends JFrame {
saveFolder = file.getParentFile(); saveFolder = file.getParentFile();
isChangingFile = true; isChangingFile = true;
try { try {
tree.setModel(new ArchiveTreeModel(new JarFile(jarFile))); Main.this.setTitle("ByteEdit - Loading '" + jarFile.getCanonicalPath() + "'");
} catch (IOException e1) { } catch (IOException ex) {
e1.printStackTrace(); Main.this.setTitle("ByteEdit - Loading '" + jarFile.getAbsolutePath() + "'");
} }
new Thread(new Runnable() {
public void run() {
try {
ArchiveTreeModel model = new ArchiveTreeModel(new JarFile(jarFile));
EventQueue.invokeLater(new Runnable() {
public void run() {
synchronized (treeLock) {
tree.setModel(model);
txtByteEditView.setText(""); txtByteEditView.setText("");
currentNodeName = null; currentNodeName = null;
globalSearchBox.setVisible(false); globalSearchBox.setVisible(false);
searchBox.setVisible(false); searchBox.setVisible(false);
typeOpenBox.setVisible(false); typeOpenBox.setVisible(false);
optionBox.setVisible(false);
unicodeBox.setVisible(false); unicodeBox.setVisible(false);
renameBox.setVisible(false); renameBox.setVisible(false);
compilationBox.setVisible(false); compilationBox.setVisible(false);
isChangingFile = false; isChangingFile = false;
Main.this.setTitle("ByteEdit");
}
}
});
} catch (IOException e) {
e.printStackTrace();
}
}
}).start();
} }
dtde.dropComplete(true); dtde.dropComplete(true);
break;
} }
} }
return; return;
@@ -355,6 +593,7 @@ public class Main extends JFrame {
t.printStackTrace(); t.printStackTrace();
showError(t); showError(t);
} }
}
dtde.rejectDrop(); dtde.rejectDrop();
} }
@@ -378,6 +617,84 @@ public class Main extends JFrame {
txtByteEditView = new RSyntaxTextArea(); txtByteEditView = new RSyntaxTextArea();
ac.install(txtByteEditView); ac.install(txtByteEditView);
txtByteEditView.setCodeFoldingEnabled(true); txtByteEditView.setCodeFoldingEnabled(true);
// ToolTips for HugeStrings
txtByteEditView.setToolTipSupplier(new ToolTipSupplier() {
@Override
public String getToolTipText(RTextArea textArea, MouseEvent e) {
int idx = textArea.viewToModel(e.getPoint());
if (idx < 0)
return null;
int subIdx = Math.max(idx - 15, 0);
int subLen = Math.min(30, textArea.getDocument().getLength() - subIdx);
if (subLen <= 0)
return null;
try {
String cut = textArea.getText(subIdx, subLen);
int hashIdx = -1;
for (int off = idx - subIdx; off >= 0; off--) {
if (cut.charAt(off) == '#') {
hashIdx = off;
break;
}
}
if (hashIdx < 0) {
for (int off = idx - subIdx; off < cut.length(); off++) {
if (cut.charAt(off) == '#') {
hashIdx = off;
break;
}
}
}
if (hashIdx < 0)
return null;
if (hashIdx >= 5 && cut.substring(hashIdx - 5, hashIdx).equals("ldc \"")) // ldc "#..."
return null;
int numLen = 1;
for (int i = hashIdx + 1; i < cut.length(); i++) {
if (!(cut.charAt(i) - '0' >= 0 && cut.charAt(i) - '0' <= 9)) {
break;
}
numLen++;
}
if (numLen < 2 || hashIdx > idx - subIdx || idx - subIdx - numLen >= hashIdx)
return null;
String hashNum = cut.substring(hashIdx, hashIdx + numLen);
String txt = txtByteEditView.getText();
int len = 0;
for (String asm : txt.split("\\/\\/ #Annotations:\n")) {
len += 19; // "\\/\\/ #Annotations:\n".length()
if (asm.isEmpty())
continue;
if (idx >= len && idx < len + asm.length()) {
try (BufferedReader reader = new BufferedReader(new StringReader(asm))) {
String s;
while (!(s = reader.readLine()).startsWith("// #SourceFile: ")) {
}
while (!(s = reader.readLine()).equals("// #Fields")) {
if (s.startsWith("#")) {
String[] split = Assembler.SPACE.split(s, 2);
if (hashNum.equals(split[0].substring(0, split[0].length() - 1))) {
String toolTip = split[1];
if (toolTip.length() > 500)
toolTip = toolTip.substring(0, 500) + "...";
return toolTip;
}
}
}
} catch (IOException e1) {
}
break;
} else {
len += asm.length();
}
}
} catch (Exception e1) {
}
return null;
}
});
txtByteEditView.addKeyListener(new KeyAdapter() { txtByteEditView.addKeyListener(new KeyAdapter() {
@Override @Override
@@ -397,6 +714,7 @@ public class Main extends JFrame {
} }
} }
txtByteEditView.setText(dis); txtByteEditView.setText(dis);
if (dis.length() > prev)
txtByteEditView.setCaretPosition(prev); txtByteEditView.setCaretPosition(prev);
} catch (Exception e2) { } catch (Exception e2) {
e2.printStackTrace(); e2.printStackTrace();
@@ -408,126 +726,59 @@ public class Main extends JFrame {
KeyStroke ctrlT = KeyStroke.getKeyStroke(KeyEvent.VK_T, 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 ctrlS = KeyStroke.getKeyStroke(KeyEvent.VK_S, KeyEvent.CTRL_DOWN_MASK);
KeyStroke ctrlG = KeyStroke.getKeyStroke(KeyEvent.VK_G, 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);
KeyStroke ctrlU = KeyStroke.getKeyStroke(KeyEvent.VK_U, 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); KeyStroke ctrlR = KeyStroke.getKeyStroke(KeyEvent.VK_R, KeyEvent.CTRL_DOWN_MASK);
KeyStroke ctrlE = KeyStroke.getKeyStroke(KeyEvent.VK_E, KeyEvent.CTRL_DOWN_MASK); KeyStroke ctrlE = KeyStroke.getKeyStroke(KeyEvent.VK_E, KeyEvent.CTRL_DOWN_MASK);
KeyStroke ctrlB = KeyStroke.getKeyStroke(KeyEvent.VK_B, KeyEvent.CTRL_DOWN_MASK); KeyStroke ctrlB = KeyStroke.getKeyStroke(KeyEvent.VK_B, KeyEvent.CTRL_DOWN_MASK);
// global // global
txtByteEditView.registerKeyboardAction(new ActionListener() { txtByteEditView.registerKeyboardAction(e -> themeBox.setVisible(true), ctrlB,
JComponent.WHEN_IN_FOCUSED_WINDOW);
@Override txtByteEditView.registerKeyboardAction(e -> {
public void actionPerformed(ActionEvent e) {
if (light.exists())
light.delete();
else
try {
light.createNewFile();
} catch (IOException e1) {
}
dark = !dark;
JOptionPane.showMessageDialog(Main.this,
"Theme switched to " + (dark ? "Dark" : "Light") + ".\nPlease restart ByteEdit.",
"Theme changed", JOptionPane.INFORMATION_MESSAGE);
}
}, ctrlB, JComponent.WHEN_IN_FOCUSED_WINDOW);
txtByteEditView.registerKeyboardAction(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
globalSearchBox.setVisible(true); globalSearchBox.setVisible(true);
globalSearchBox.txtString.requestFocusInWindow(); globalSearchBox.txtString.requestFocusInWindow();
globalSearchBox.txtString.select(0, globalSearchBox.txtString.getText().length()); globalSearchBox.txtString.select(0, globalSearchBox.txtString.getText().length());
}
}, ctrlG, JComponent.WHEN_IN_FOCUSED_WINDOW); }, ctrlG, JComponent.WHEN_IN_FOCUSED_WINDOW);
txtByteEditView.registerKeyboardAction(new ActionListener() { txtByteEditView.registerKeyboardAction(e -> {
@Override
public void actionPerformed(ActionEvent e) {
searchBox.setVisible(true); searchBox.setVisible(true);
searchBox.txtFind.requestFocusInWindow(); searchBox.txtFind.requestFocusInWindow();
searchBox.txtFind.select(0, searchBox.txtFind.getText().length()); searchBox.txtFind.select(0, searchBox.txtFind.getText().length());
}
}, ctrlF, JComponent.WHEN_IN_FOCUSED_WINDOW); }, ctrlF, JComponent.WHEN_IN_FOCUSED_WINDOW);
txtByteEditView.registerKeyboardAction(new ActionListener() { txtByteEditView.registerKeyboardAction(e -> {
@Override
public void actionPerformed(ActionEvent e) {
typeOpenBox.setVisible(true); typeOpenBox.setVisible(true);
typeOpenBox.txtSearch.requestFocusInWindow(); typeOpenBox.txtSearch.requestFocusInWindow();
typeOpenBox.txtSearch.select(0, typeOpenBox.txtSearch.getText().length()); typeOpenBox.txtSearch.select(0, typeOpenBox.txtSearch.getText().length());
}
}, ctrlT, JComponent.WHEN_IN_FOCUSED_WINDOW); }, ctrlT, JComponent.WHEN_IN_FOCUSED_WINDOW);
txtByteEditView.registerKeyboardAction(new ActionListener() { txtByteEditView.registerKeyboardAction(e -> unicodeBox.setVisible(true), ctrlU,
JComponent.WHEN_IN_FOCUSED_WINDOW);
@Override txtByteEditView.registerKeyboardAction(e -> compilationBox.setVisible(true), ctrlE,
public void actionPerformed(ActionEvent e) { JComponent.WHEN_IN_FOCUSED_WINDOW);
optionBox.setVisible(true);
}
}, ctrlO, JComponent.WHEN_IN_FOCUSED_WINDOW);
txtByteEditView.registerKeyboardAction(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
unicodeBox.setVisible(true);
}
}, ctrlU, JComponent.WHEN_IN_FOCUSED_WINDOW);
txtByteEditView.registerKeyboardAction(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
compilationBox.setVisible(true);
}
}, ctrlE, JComponent.WHEN_IN_FOCUSED_WINDOW);
// specific // specific
tree.registerKeyboardAction(new ActionListener() { tree.registerKeyboardAction(e -> save(), ctrlS, JComponent.WHEN_FOCUSED);
txtByteEditView.registerKeyboardAction(e -> saveCurrentClassNode(), ctrlS, JComponent.WHEN_FOCUSED);
@Override txtByteEditView.registerKeyboardAction(e -> {
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 { try {
goToSelected(); goToSelected();
} catch (BadLocationException e1) { } catch (BadLocationException e1) {
e1.printStackTrace(); e1.printStackTrace();
} }
}
}, ctrlG, JComponent.WHEN_FOCUSED); }, ctrlG, JComponent.WHEN_FOCUSED);
txtByteEditView.registerKeyboardAction(new ActionListener() { txtByteEditView.registerKeyboardAction(e -> {
@Override
public void actionPerformed(ActionEvent e) {
try { try {
renameSelected(); renameSelected();
} catch (BadLocationException e1) { } catch (BadLocationException e1) {
e1.printStackTrace(); e1.printStackTrace();
} }
}
}, ctrlR, JComponent.WHEN_FOCUSED); }, ctrlR, JComponent.WHEN_FOCUSED);
txtByteEditView.setEditable(true); txtByteEditView.setEditable(true);
txtByteEditView.setSyntaxEditingStyle(SyntaxConstants.SYNTAX_STYLE_JAVA_DISASSEMBLE); txtByteEditView.setSyntaxEditingStyle(SyntaxConstants.SYNTAX_STYLE_JAVA_DISASSEMBLE);
txtByteEditView.setCodeFoldingEnabled(true); txtByteEditView.setCodeFoldingEnabled(true);
scrollPane_ByteEdit = new RTextScrollPane(); scrollPane_ByteEdit = new RTextScrollPane();
theme.apply(txtByteEditView); ThemeManager.registerTextArea(txtByteEditView);
splitPane.setRightComponent(scrollPane_ByteEdit); splitPane.setRightComponent(scrollPane_ByteEdit);
txtByteEditView.setBackground(dark ? new Color(0x2F2F2F) : Color.LIGHT_GRAY);
scrollPane_ByteEdit.setViewportView(txtByteEditView); scrollPane_ByteEdit.setViewportView(txtByteEditView);
scrollPane_ByteEdit.setLineNumbersEnabled(true); scrollPane_ByteEdit.setLineNumbersEnabled(true);
scrollPane_ByteEdit.setFoldIndicatorEnabled(true); scrollPane_ByteEdit.setFoldIndicatorEnabled(true);
scrollPane_ByteEdit.getGutter().setBackground(dark ? new Color(0x2F2F2F) : Color.LIGHT_GRAY);
} }
private final Pattern jumpableInstructionPattern = Pattern.compile("^\t\t(?!//|\t+).+ .+"); private final Pattern jumpableInstructionPattern = Pattern.compile("^\t\t(?!//|\t+).+ .+");
@@ -542,15 +793,11 @@ public class Main extends JFrame {
line = line.substring(2); line = line.substring(2);
if (line.startsWith("invoke")) { if (line.startsWith("invoke")) {
String[] split = line.split(" "); String[] split = line.split(" ");
String desc = UnicodeUtils.unescape(split[1]); String desc = UnicodeUtils.unescape(null, split[1], true);
String className = UnicodeUtils.unescape(split[2]); String target = split[2];
String[] nameSplit = className.split("/"); int index = target.lastIndexOf("/");
String methodName = nameSplit[nameSplit.length - 1]; String className = UnicodeUtils.unescape(null, target.substring(0, index), true);
className = className.substring(0, className.length() - methodName.length() - 1); String methodName = UnicodeUtils.unescape(null, target.substring(index + 1), true);
while (className.endsWith("/")) {
methodName = "/" + methodName;
className = className.substring(0, className.length() - 1);
}
ClassNode classNode = classNodes.get(getFullName(className)); ClassNode classNode = classNodes.get(getFullName(className));
if (classNode == null) { if (classNode == null) {
return; return;
@@ -569,7 +816,7 @@ public class Main extends JFrame {
} }
} else if (line.startsWith("new ")) { } else if (line.startsWith("new ")) {
String[] split = line.split(" "); String[] split = line.split(" ");
String className = UnicodeUtils.unescape(split[1]); String className = UnicodeUtils.unescape(null, split[1], true);
ClassNode classNode = classNodes.get(getFullName(className)); ClassNode classNode = classNodes.get(getFullName(className));
if (classNode == null) { if (classNode == null) {
return; return;
@@ -578,15 +825,11 @@ public class Main extends JFrame {
} else if (line.startsWith("getstatic ") || line.startsWith("putstatic ") || line.startsWith("getfield ") } else if (line.startsWith("getstatic ") || line.startsWith("putstatic ") || line.startsWith("getfield ")
|| line.startsWith("putfield ")) { || line.startsWith("putfield ")) {
String[] split = line.split(" "); String[] split = line.split(" ");
String desc = UnicodeUtils.unescape(split[1]); String desc = UnicodeUtils.unescape(null, split[1], true);
String className = UnicodeUtils.unescape(split[2]); String target = split[2];
String[] nameSplit = className.split("/"); int index = target.lastIndexOf("/");
String fieldName = nameSplit[nameSplit.length - 1]; String className = UnicodeUtils.unescape(null, target.substring(0, index), true);
className = className.substring(0, className.length() - fieldName.length() - 1); String fieldName = UnicodeUtils.unescape(null, target.substring(index + 1), true);
while (className.endsWith("/")) {
fieldName = "/" + fieldName;
className = className.substring(0, className.length() - 1);
}
ClassNode classNode = classNodes.get(getFullName(className)); ClassNode classNode = classNodes.get(getFullName(className));
if (classNode == null) { if (classNode == null) {
return; return;
@@ -650,10 +893,12 @@ public class Main extends JFrame {
if (s.contains(" extends ")) if (s.contains(" extends "))
s = s.substring(0, s.lastIndexOf(" extends ")); s = s.substring(0, s.lastIndexOf(" extends "));
String[] split = s.split(" "); String[] split = s.split(" ");
String className = UnicodeUtils.unescape(split[split.length - 1]); String className = UnicodeUtils.unescape(null, split[split.length - 1], true);
renameBox.className = className; renameBox.className = className;
String name = UnicodeUtils.unescape(m.pattern() == renameableFieldPattern ? m.group(2) : m.group(1)); String name = UnicodeUtils.unescape(null, m.pattern() == renameableFieldPattern ? m.group(2) : m.group(1),
String desc = UnicodeUtils.unescape(m.pattern() == renameableFieldPattern ? m.group(1) : m.group(2)); true);
String desc = UnicodeUtils.unescape(null, m.pattern() == renameableFieldPattern ? m.group(1) : m.group(2),
true);
renameBox.name = name; renameBox.name = name;
renameBox.desc = desc; renameBox.desc = desc;
renameBox.txtName.setText(name); renameBox.txtName.setText(name);
@@ -694,8 +939,7 @@ public class Main extends JFrame {
} }
public static int selectFileWithSearch(String s, Object nodeToFind) { public static int selectFileWithSearch(String s, Object nodeToFind) {
if (s != null && (s.endsWith(".class") if (s != null && s.endsWith(".class")) {
|| (s.endsWith(".class/") && fakedFolders.contains(s.substring(0, s.length() - 7))))) {
currentNodeName = s; currentNodeName = s;
int lineFound = -1; int lineFound = -1;
ClassNode classNode = classNodes.get(s); ClassNode classNode = classNodes.get(s);
@@ -749,14 +993,49 @@ public class Main extends JFrame {
if (action == 0) { if (action == 0) {
final File file = fileChooser.getSelectedFile(); final File file = fileChooser.getSelectedFile();
saveFolder = file.getParentFile(); saveFolder = file.getParentFile();
boolean shouldSave = false;
if (file.exists()) { if (file.exists()) {
int dialogResult = JOptionPane.showConfirmDialog(null, "This file already exists! Overwrite it?", int dialogResult = JOptionPane.showConfirmDialog(null, "This file already exists! Overwrite it?",
"Warning", JOptionPane.YES_NO_OPTION); "Warning", JOptionPane.YES_NO_OPTION);
if (dialogResult == JOptionPane.YES_OPTION) { if (dialogResult == JOptionPane.YES_OPTION) {
save(file, classNodes.values()); save(file, classNodes.values());
shouldSave = true;
} }
} else { } else {
shouldSave = true;
}
if (shouldSave)
synchronized (treeLock) {
if (isChangingFile) {
return;
}
try {
isChangingFile = true;
try {
Main.this.setTitle("ByteEdit - Saving '" + file.getCanonicalPath() + "'");
} catch (IOException ex) {
Main.this.setTitle("ByteEdit - Saving '" + file.getAbsolutePath() + "'");
}
new Thread(new Runnable() {
public void run() {
synchronized (treeLock) {
save(file, classNodes.values()); save(file, classNodes.values());
EventQueue.invokeLater(new Runnable() {
public void run() {
synchronized (treeLock) {
isChangingFile = false;
Main.this.setTitle("ByteEdit");
}
}
});
}
}
}).start();
} catch (Throwable t) {
t.printStackTrace();
showError(t);
}
} }
} }
} }
@@ -794,16 +1073,16 @@ public class Main extends JFrame {
output.closeEntry(); output.closeEntry();
} }
int computeFlags = 0; int computeFlags = 0;
if (optionBox.chckbxComputeFrames.isSelected()) { if (mntmComputeFrames.isSelected()) {
computeFlags |= ClassWriter.COMPUTE_FRAMES; computeFlags |= ClassWriter.COMPUTE_FRAMES;
} }
if (optionBox.chckbxComputeMax.isSelected()) { if (mntmComputeMax.isSelected()) {
computeFlags |= ClassWriter.COMPUTE_MAXS; computeFlags |= ClassWriter.COMPUTE_MAXS;
} }
for (ClassNode element : classes) { for (ClassNode node : classes) {
ClassWriter writer = new ClassWriter(computeFlags); ClassWriter writer = new ClassWriter(computeFlags);
element.accept(writer); node.accept(writer);
output.putNextEntry(new JarEntry(getFullName(element.name))); output.putNextEntry(new JarEntry(getFullName(node.name)));
output.write(writer.toByteArray()); output.write(writer.toByteArray());
output.closeEntry(); output.closeEntry();
} }
@@ -831,9 +1110,6 @@ public class Main extends JFrame {
} }
public static String getFullName(String s) { public static String getFullName(String s) {
if (fakedFolders.contains(s))
return s + ".class/";
else
return s + ".class"; return s + ".class";
} }
@@ -860,20 +1136,20 @@ public class Main extends JFrame {
byte[] data = toByteArray(jar.getInputStream(next)); byte[] data = toByteArray(jar.getInputStream(next));
if (next.getSize() != 0 && !next.getName().startsWith("META-INF") if (next.getSize() != 0 && !next.getName().startsWith("META-INF")
&& (next.getName().endsWith(".class") || next.getName().endsWith(".class/"))) { && (next.getName().endsWith(".class") || next.getName().endsWith(".class/"))) {
if ((next.getName().contains("/")
? (!next.getName().split("/")[next.getName().split("/").length - 1].contains("$"))
: (!next.getName().contains("$")))
|| (next.getName().startsWith("$") || next.getName().contains("$$")
|| next.getName().endsWith("$"))) {
paths.add(next.getName());
if (next.getName().endsWith(".class/") && next.getSize() != 0)
fakedFolders.add(next.getName().substring(0, next.getName().length() - 7));
}
try { try {
ClassReader reader = new ClassReader(data); ClassReader reader = new ClassReader(data);
ClassNode node = new ClassNode(); ClassNode node = new ClassNode();
reader.accept(node, 0); reader.accept(node, 0);
classNodes.put(next.getName(), node); classNodes.put(getFullName(node.name), node);
if ((next.getName().contains("/")
? (!SLASH.split(next.getName())[SLASH.split(next.getName()).length - 1]
.contains("$"))
: (!next.getName().contains("$")))
|| (next.getName().startsWith("$") || next.getName().contains("$$")
|| next.getName().endsWith("$"))) {
paths.add(getFullName(node.name));
}
} catch (Exception e) { } catch (Exception e) {
OTHER_FILES.put(next.getName(), data); OTHER_FILES.put(next.getName(), data);
} }
@@ -909,9 +1185,13 @@ public class Main extends JFrame {
} }
}); });
// Windows-like sorting (like file explorer)
List<String> tmp = new ArrayList<>(paths); List<String> tmp = new ArrayList<>(paths);
List<String> folders = tmp.stream().map(s -> { List<String> folders = tmp.stream().filter(s -> {
int c = countSlashes(s, 50);
return c > 0 && c < 50;
}).map(s -> {
int idx = s.lastIndexOf('/'); int idx = s.lastIndexOf('/');
if (idx == s.length() - 1) if (idx == s.length() - 1)
idx = s.lastIndexOf('/', idx - 1); idx = s.lastIndexOf('/', idx - 1);
@@ -943,7 +1223,10 @@ public class Main extends JFrame {
tmp.addAll(0, folders); tmp.addAll(0, folders);
for (String s : tmp) { for (String s : tmp) {
String[] elements = s.split("/"); String[] elements = SLASH.split(s, 50);
if (elements.length >= 50) {
((ByteEditTreeNode) getRoot()).add(new ByteEditTreeNode(s, s));
} else {
ByteEditTreeNode currentNode = (ByteEditTreeNode) getRoot(); ByteEditTreeNode currentNode = (ByteEditTreeNode) getRoot();
for (int i = 0; i < elements.length; i++) { for (int i = 0; i < elements.length; i++) {
String token = elements[i]; String token = elements[i];
@@ -956,6 +1239,7 @@ public class Main extends JFrame {
} }
} }
} }
}
private ByteEditTreeNode findNode(ByteEditTreeNode parent, String name) { private ByteEditTreeNode findNode(ByteEditTreeNode parent, String name) {
Enumeration<?> e = parent.children(); Enumeration<?> e = parent.children();
@@ -967,6 +1251,18 @@ public class Main extends JFrame {
} }
return null; return null;
} }
private int countSlashes(String s, int max) {
int count = 0;
for (char c : s.toCharArray()) {
if (c == '/') {
count++;
if (count == max)
break;
}
}
return count;
}
} }
private static class FurtherExpandingTreeExpansionListener implements TreeExpansionListener { private static class FurtherExpandingTreeExpansionListener implements TreeExpansionListener {
+110
View File
@@ -0,0 +1,110 @@
package me.ByteEdit.main;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JFrame;
import javax.swing.LookAndFeel;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import org.fife.ui.rsyntaxtextarea.RSyntaxTextArea;
import org.fife.ui.rsyntaxtextarea.Theme;
import com.formdev.flatlaf.IntelliJTheme;
import com.formdev.flatlaf.intellijthemes.FlatArcDarkIJTheme;
public class ThemeManager {
private static boolean dark = true;
private static File file;
private static Theme rstaThemeDark, rstaThemeLight;
private static List<RSyntaxTextArea> textAreas = new ArrayList();
private static List<JFrame> frames = new ArrayList();
static {
String s = System.getenv("APPDATA");
if (s == null)
s = System.getProperty("user.home");
file = new File(s, "ByteEditTheme.conf");
}
public static void save() {
try (BufferedWriter wr = new BufferedWriter(new FileWriter(file))) {
wr.write(UIManager.getLookAndFeel().getClass().getName() + "\n");
wr.write(Boolean.toString(dark));
} catch (Exception ex) {
ex.printStackTrace();
}
}
public static void load() {
try {
rstaThemeDark = Theme
.load(ThemeManager.class.getClassLoader().getResourceAsStream("org/fife/eclipse_dark.xml"));
rstaThemeLight = Theme
.load(ThemeManager.class.getClassLoader().getResourceAsStream("org/fife/eclipse.xml"));
} catch (IOException ex) {
ex.printStackTrace();
}
String theme = null;
if (file.exists()) {
try (BufferedReader read = new BufferedReader(new FileReader(file))) {
theme = read.readLine();
boolean dark = Boolean.parseBoolean(read.readLine());
changeUIManager(theme, dark);
} catch (Exception ex) {
ex.printStackTrace();
}
} else {
theme = FlatArcDarkIJTheme.class.getName();
changeUIManager(theme, true);
}
}
public static void changeUIManager(String clazz, Boolean isDark) {
try {
UIManager.setLookAndFeel(clazz);
LookAndFeel laf = UIManager.getLookAndFeel();
boolean nextDark = false;
if (laf instanceof IntelliJTheme.ThemeLaf) {
IntelliJTheme.ThemeLaf t = (IntelliJTheme.ThemeLaf) laf;
nextDark = t.isDark();
} else if (isDark != null) {
nextDark = isDark.booleanValue();
}
if (nextDark != dark) {
dark = nextDark;
applyRSTATheme();
}
frames.forEach(SwingUtilities::updateComponentTreeUI);
save();
} catch (Exception ex) {
ex.printStackTrace();
}
}
public static void applyRSTATheme() {
Theme theme = dark ? rstaThemeDark : rstaThemeLight;
textAreas.forEach(theme::apply);
}
public static void registerFrames(JFrame frame) {
frames.add(frame);
}
public static void registerTextArea(RSyntaxTextArea textArea) {
textAreas.add(textArea);
}
}
+26 -23
View File
@@ -6,6 +6,8 @@ import java.util.HashSet;
import org.objectweb.asm.Type; import org.objectweb.asm.Type;
import me.ByteEdit.edit.HugeStrings;
public class ClassUtil { public class ClassUtil {
public static final int ACC_PUBLIC = 0x0001; public static final int ACC_PUBLIC = 0x0001;
@@ -522,31 +524,32 @@ public class ClassUtil {
return count; return count;
} }
public static String getDecompiledValue(Object o, String desc, boolean escapeSpaces) { public static final HashMap<Class, DecompilationInterface> diMap = new HashMap<>();
switch (o.getClass().getName()) {
case "java.lang.String": { static {
return "\"" + (escapeSpaces ? UnicodeUtils.escapeWithSpaces((String) o) : UnicodeUtils.escape((String) o)) diMap.put(String.class, (o, desc, escapeSpaces, hs) -> "\""
+ "\""; + (escapeSpaces ? UnicodeUtils.escapeWithSpaces(hs, (String) o) : UnicodeUtils.escape(hs, (String) o))
} + "\"");
case "java.lang.Integer": { diMap.put(Integer.class,
if (desc.equals("Z")) { (o, desc, escape, hs) -> desc.equals("Z") ? (((int) o) == 0 ? "false" : "true") : o.toString());
return ((int) o) == 0 ? "false" : "true"; diMap.put(Long.class, (o, desc, escape, hs) -> o.toString() + "l");
} diMap.put(Float.class, (o, desc, escape, hs) -> o.toString() + "f");
return o.toString();
}
case "java.lang.Long": {
return o.toString() + "l";
}
case "java.lang.Float": {
return o.toString() + "f";
}
default:
return o.toString();
}
} }
public static String getDecompiledValue(Object o, String desc) { static interface DecompilationInterface {
return getDecompiledValue(o, desc, false); String apply(Object o, String desc, boolean escape, HugeStrings hs);
}
public static String getDecompiledValue(Object o, String desc, boolean escapeSpaces, HugeStrings hs) {
DecompilationInterface di = diMap.get(o.getClass());
if (di != null)
return di.apply(o, desc, escapeSpaces, hs);
else
return o.toString();
}
public static String getDecompiledValue(Object o, String desc, HugeStrings hs) {
return getDecompiledValue(o, desc, false, hs);
} }
public static Object getCastedValue(String o, String className) { public static Object getCastedValue(String o, String className) {
+116 -23
View File
@@ -1,11 +1,26 @@
package me.ByteEdit.utils; package me.ByteEdit.utils;
import me.ByteEdit.edit.HugeStrings;
import me.ByteEdit.edit.HugeStringsRev;
public class UnicodeUtils { public class UnicodeUtils {
public static String unescape(String s) { public static String unescape(HugeStringsRev hsr, String s) {
return unescape(hsr, s, false);
}
public static String unescape(HugeStringsRev hsr, String s, boolean force) {
if (s == null) { if (s == null) {
return null; return null;
} }
if (!force && !s.isEmpty() && s.charAt(0) == '#' && s.length() < 12) {
try {
int id = Integer.parseInt(s.substring(1));
return hsr.get(id);
} catch (NumberFormatException ex) {
// Doesn't seem like a HugeString
}
}
StringBuilder sb = new StringBuilder(); StringBuilder sb = new StringBuilder();
char unicodeBuffer = 0; char unicodeBuffer = 0;
int stage = 0; int stage = 0;
@@ -78,30 +93,56 @@ public class UnicodeUtils {
return sb.toString(); return sb.toString();
} }
public static String escapeWithSpaces(String s) { public static String escapeWithSpaces(HugeStrings hs, String s) {
if (s == null) { if (s == null) {
return null; return null;
} }
s = escape(s).replace(" ", "\\u0020"); if (s.length() > HugeStrings.THRESHOLD) {
if (s.startsWith("/")) { return hs.onString(s);
s = "\\u002F" + s.substring(1);
}
if (s.endsWith("/")) {
s = s.substring(0, s.length() - 1) + "\\u002F";
}
return s;
}
public static String escape(String s) {
if (s == null) {
return null;
} }
StringBuilder sb = new StringBuilder(); StringBuilder sb = new StringBuilder();
for (char c : s.toCharArray()) { char[] arr = s.toCharArray();
if (isPrintable(c)) { int i = 0;
sb.append(c); int len = arr.length;
} else { boolean addSlash = false;
if (len > 0) {
if (arr[0] == '/') {
sb.append("\\u002F");
i++;
} else if (arr[0] == '#') {
sb.append("\\u0023");
i++;
}
if (arr[len - 1] == '/') {
addSlash = true;
len--;
}
}
for (; i < len; i++) {
char c = arr[i];
switch (c) { switch (c) {
case 'Ä':
case 'ä':
case 'Ö':
case 'ö':
case 'Ü':
case 'ü':
case 'ß':
case '€':
case '©':
case '®':
case '«':
case '»':
case '§':
case '£':
case '¥':
sb.append(c);
break;
case ' ':
sb.append("\\u0020");
break;
case '\b': case '\b':
sb.append("\\b"); sb.append("\\b");
break; break;
@@ -124,14 +165,40 @@ public class UnicodeUtils {
sb.append("\\\\"); sb.append("\\\\");
break; break;
default: default:
if (c > ' ' && c <= '~') {
sb.append(c);
} else {
sb.append(String.format("\\u%04X", (int) c)); sb.append(String.format("\\u%04X", (int) c));
} }
break;
} }
} }
if (addSlash)
sb.append("\\u002F");
return sb.toString(); return sb.toString();
} }
private static boolean isPrintable(char c) { public static String escape(HugeStrings hs, String s) {
return escape(hs, s, false);
}
public static String escape(HugeStrings hs, String s, boolean force) {
if (s == null) {
return null;
}
if (!force && s.length() > HugeStrings.THRESHOLD) {
return hs.onString(s);
}
char[] arr = s.toCharArray();
StringBuilder sb = new StringBuilder(arr.length);
int i = 0;
if (arr.length > 0 && arr[0] == '#') {
sb.append("\\u0023");
i++;
}
for (; i < arr.length; i++) {
char c = arr[i];
switch (c) { switch (c) {
case 'Ä': case 'Ä':
case 'ä': case 'ä':
@@ -148,13 +215,39 @@ public class UnicodeUtils {
case '§': case '§':
case '£': case '£':
case '¥': case '¥':
return true; sb.append(c);
break;
case '\b':
sb.append("\\b");
break;
case '\t':
sb.append("\\t");
break;
case '\n':
sb.append("\\n");
break;
case '\r':
sb.append("\\r");
break;
case '\f':
sb.append("\\f");
break;
case '"': case '"':
sb.append("\\\"");
break;
case '\\': case '\\':
return false; sb.append("\\\\");
break;
default: default:
return c >= ' ' && c <= '~'; if (c >= ' ' && c <= '~') {
sb.append(c);
} else {
sb.append(String.format("\\u%04X", (int) c));
} }
break;
}
}
return sb.toString();
} }
} }
@@ -403,6 +403,9 @@ public class TokenImpl implements Token {
int last = getOffset(); int last = getOffset();
FontMetrics fm = null; FontMetrics fm = null;
while (token != null && token.isPaintable()) { while (token != null && token.isPaintable()) {
if (token.textCount > 10000) {
return getOffset() + (int) (x / 7);
}
fm = textArea.getFontMetricsForTokenType(token.getType()); fm = textArea.getFontMetricsForTokenType(token.getType());
char[] text = token.text; char[] text = token.text;
int start = token.textOffset; int start = token.textOffset;
@@ -786,6 +789,13 @@ public class TokenImpl implements Token {
this.type = type; this.type = type;
} }
public void reset() {
text = null;
offset = -1;
type = Token.NULL;
nextToken = null;
}
/** /**
* {@inheritDoc} * {@inheritDoc}
*/ */