mirror of
https://github.com/SuspiciousActivity/ByteEdit.git
synced 2026-08-13 17:56:17 +00:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d1710ea6a5 | ||
|
|
ad55d6793c | ||
|
|
ac247a89ca | ||
|
|
b5e4847be5 | ||
|
|
30c9c81d38 | ||
|
|
65235c6b5b | ||
|
|
d8096a4ec5 | ||
|
|
add82951e6 | ||
|
|
afc59d63d3 | ||
|
|
53f214b7b0 | ||
|
|
385c9ad9e3 |
No files matched your search
@@ -1,7 +1,6 @@
|
||||
package me.ByteEdit.boxes;
|
||||
|
||||
import java.awt.BorderLayout;
|
||||
import java.awt.Color;
|
||||
import java.awt.Toolkit;
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.awt.event.ActionListener;
|
||||
@@ -22,7 +21,6 @@ import javax.swing.JFrame;
|
||||
import javax.swing.JOptionPane;
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.KeyStroke;
|
||||
import javax.swing.UIManager;
|
||||
import javax.swing.border.EmptyBorder;
|
||||
import javax.tools.JavaCompiler;
|
||||
import javax.tools.SimpleJavaFileObject;
|
||||
@@ -36,6 +34,7 @@ import org.objectweb.asm.tree.ClassNode;
|
||||
|
||||
import me.ByteEdit.edit.Disassembler;
|
||||
import me.ByteEdit.main.Main;
|
||||
import me.ByteEdit.main.ThemeManager;
|
||||
|
||||
public class CompilationBox extends JFrame {
|
||||
|
||||
@@ -46,32 +45,25 @@ public class CompilationBox extends JFrame {
|
||||
|
||||
public CompilationBox() {
|
||||
compSuccess = new CompilationSuccess();
|
||||
try {
|
||||
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
ThemeManager.registerFrames(compSuccess);
|
||||
setTitle("Java Compiler");
|
||||
setDefaultCloseOperation(JFrame.HIDE_ON_CLOSE);
|
||||
setBounds((int) (Toolkit.getDefaultToolkit().getScreenSize().getWidth() / 2 - 400),
|
||||
(int) (Toolkit.getDefaultToolkit().getScreenSize().getHeight() / 2 - 200), 800, 400);
|
||||
contentPane = new JPanel();
|
||||
contentPane.setBackground(Main.dark ? new Color(0x2F2F2F) : Color.GRAY);
|
||||
contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
|
||||
setContentPane(contentPane);
|
||||
contentPane.setLayout(new BorderLayout(0, 0));
|
||||
|
||||
Main.theme.apply(textArea);
|
||||
ThemeManager.registerTextArea(textArea);
|
||||
textArea.setEditable(true);
|
||||
textArea.setSyntaxEditingStyle(SyntaxConstants.SYNTAX_STYLE_JAVA);
|
||||
textArea.setCodeFoldingEnabled(true);
|
||||
textArea.setBackground(Main.dark ? new Color(0x2F2F2F) : Color.LIGHT_GRAY);
|
||||
|
||||
RTextScrollPane scrollPane = new RTextScrollPane();
|
||||
scrollPane.setViewportView(textArea);
|
||||
scrollPane.setLineNumbersEnabled(true);
|
||||
scrollPane.setFoldIndicatorEnabled(true);
|
||||
scrollPane.getGutter().setBackground(Main.dark ? new Color(0x2F2F2F) : Color.LIGHT_GRAY);
|
||||
contentPane.add(scrollPane);
|
||||
|
||||
KeyStroke ctrlS = KeyStroke.getKeyStroke(KeyEvent.VK_S, KeyEvent.CTRL_DOWN_MASK);
|
||||
|
||||
@@ -1,19 +1,17 @@
|
||||
package me.ByteEdit.boxes;
|
||||
|
||||
import java.awt.BorderLayout;
|
||||
import java.awt.Color;
|
||||
import java.awt.Toolkit;
|
||||
|
||||
import javax.swing.JFrame;
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.UIManager;
|
||||
import javax.swing.border.EmptyBorder;
|
||||
|
||||
import org.fife.ui.rsyntaxtextarea.RSyntaxTextArea;
|
||||
import org.fife.ui.rsyntaxtextarea.SyntaxConstants;
|
||||
import org.fife.ui.rtextarea.RTextScrollPane;
|
||||
|
||||
import me.ByteEdit.main.Main;
|
||||
import me.ByteEdit.main.ThemeManager;
|
||||
|
||||
public class CompilationSuccess extends JFrame {
|
||||
|
||||
@@ -21,32 +19,24 @@ public class CompilationSuccess extends JFrame {
|
||||
RSyntaxTextArea textArea = new RSyntaxTextArea();
|
||||
|
||||
public CompilationSuccess() {
|
||||
try {
|
||||
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
setTitle("Java Compiler - Result");
|
||||
setDefaultCloseOperation(JFrame.HIDE_ON_CLOSE);
|
||||
setBounds((int) (Toolkit.getDefaultToolkit().getScreenSize().getWidth() / 2 - 400),
|
||||
(int) (Toolkit.getDefaultToolkit().getScreenSize().getHeight() / 2 - 200), 800, 400);
|
||||
contentPane = new JPanel();
|
||||
contentPane.setBackground(Main.dark ? new Color(0x2F2F2F) : Color.GRAY);
|
||||
contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
|
||||
setContentPane(contentPane);
|
||||
contentPane.setLayout(new BorderLayout(0, 0));
|
||||
|
||||
Main.theme.apply(textArea);
|
||||
ThemeManager.registerTextArea(textArea);
|
||||
textArea.setEditable(true);
|
||||
textArea.setSyntaxEditingStyle(SyntaxConstants.SYNTAX_STYLE_JAVA_DISASSEMBLE);
|
||||
textArea.setCodeFoldingEnabled(true);
|
||||
textArea.setBackground(Main.dark ? new Color(0x2F2F2F) : Color.LIGHT_GRAY);
|
||||
|
||||
RTextScrollPane scrollPane = new RTextScrollPane();
|
||||
scrollPane.setViewportView(textArea);
|
||||
scrollPane.setLineNumbersEnabled(true);
|
||||
scrollPane.setFoldIndicatorEnabled(true);
|
||||
scrollPane.getGutter().setBackground(Main.dark ? new Color(0x2F2F2F) : Color.LIGHT_GRAY);
|
||||
contentPane.add(scrollPane);
|
||||
}
|
||||
}
|
||||
@@ -15,7 +15,6 @@ import javax.swing.JLabel;
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.JTextField;
|
||||
import javax.swing.KeyStroke;
|
||||
import javax.swing.UIManager;
|
||||
import javax.swing.border.EmptyBorder;
|
||||
|
||||
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.main.Main;
|
||||
import me.ByteEdit.main.ThemeManager;
|
||||
import me.ByteEdit.utils.UnicodeUtils;
|
||||
|
||||
public class GlobalSearchBox extends JFrame {
|
||||
@@ -43,12 +43,8 @@ public class GlobalSearchBox extends JFrame {
|
||||
private GlobalSearchOpenBox openBox;
|
||||
|
||||
public GlobalSearchBox() {
|
||||
try {
|
||||
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
openBox = new GlobalSearchOpenBox();
|
||||
ThemeManager.registerFrames(openBox);
|
||||
setResizable(false);
|
||||
setTitle("Global Search");
|
||||
setDefaultCloseOperation(JFrame.HIDE_ON_CLOSE);
|
||||
@@ -141,7 +137,7 @@ public class GlobalSearchBox extends JFrame {
|
||||
openBox.model.clear();
|
||||
Set<Info> set = new HashSet<>();
|
||||
if (!txtString.getText().isEmpty()) {
|
||||
String str = UnicodeUtils.unescape(txtString.getText());
|
||||
String str = UnicodeUtils.unescape(null, txtString.getText(), true);
|
||||
if (ignoreCase) {
|
||||
str = str.toLowerCase();
|
||||
}
|
||||
@@ -161,11 +157,11 @@ public class GlobalSearchBox extends JFrame {
|
||||
}
|
||||
}
|
||||
} else {
|
||||
String owner = UnicodeUtils.unescape(txtOwner.getText());
|
||||
String owner = UnicodeUtils.unescape(null, txtOwner.getText(), true);
|
||||
boolean wildCardOwner = owner.isEmpty();
|
||||
String name = UnicodeUtils.unescape(txtName.getText());
|
||||
String name = UnicodeUtils.unescape(null, txtName.getText(), true);
|
||||
boolean wildCardName = name.isEmpty();
|
||||
String desc = UnicodeUtils.unescape(txtDesc.getText());
|
||||
String desc = UnicodeUtils.unescape(null, txtDesc.getText(), true);
|
||||
boolean wildCardDesc = desc.isEmpty();
|
||||
for (ClassNode cn : Main.classNodes.values()) {
|
||||
for (MethodNode mn : cn.methods) {
|
||||
|
||||
@@ -8,7 +8,6 @@ import javax.swing.JList;
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.JScrollPane;
|
||||
import javax.swing.ListSelectionModel;
|
||||
import javax.swing.UIManager;
|
||||
import javax.swing.border.EmptyBorder;
|
||||
import javax.swing.event.ListSelectionEvent;
|
||||
import javax.swing.event.ListSelectionListener;
|
||||
@@ -24,11 +23,6 @@ public class GlobalSearchOpenBox extends JFrame {
|
||||
DefaultListModel<Info> model;
|
||||
|
||||
public GlobalSearchOpenBox() {
|
||||
try {
|
||||
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
setResizable(false);
|
||||
setTitle("Global Search - Result");
|
||||
setDefaultCloseOperation(JFrame.HIDE_ON_CLOSE);
|
||||
|
||||
@@ -5,7 +5,6 @@ import java.awt.Toolkit;
|
||||
import javax.swing.JCheckBox;
|
||||
import javax.swing.JFrame;
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.UIManager;
|
||||
import javax.swing.border.EmptyBorder;
|
||||
|
||||
public class OptionBox extends JFrame {
|
||||
@@ -15,11 +14,6 @@ public class OptionBox extends JFrame {
|
||||
public JCheckBox chckbxComputeMax;
|
||||
|
||||
public OptionBox() {
|
||||
try {
|
||||
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
setResizable(false);
|
||||
setTitle("Options");
|
||||
setDefaultCloseOperation(JFrame.HIDE_ON_CLOSE);
|
||||
|
||||
@@ -84,8 +84,8 @@ public class RenameBox extends JFrame {
|
||||
JOptionPane.showMessageDialog(null, "ClassNode not found!", "Error!", JOptionPane.ERROR_MESSAGE);
|
||||
return;
|
||||
}
|
||||
String newName = UnicodeUtils.unescape(txtName.getText());
|
||||
String newDesc = UnicodeUtils.unescape(txtDesc.getText());
|
||||
String newName = UnicodeUtils.unescape(null, txtName.getText(), true);
|
||||
String newDesc = UnicodeUtils.unescape(null, txtDesc.getText(), true);
|
||||
if (ClassUtil.isObjectClassMethod(newName, newDesc, true)) {
|
||||
JOptionPane.showMessageDialog(null, "Invalid name!", "Error!", JOptionPane.ERROR_MESSAGE);
|
||||
return;
|
||||
|
||||
@@ -15,7 +15,6 @@ import javax.swing.JLabel;
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.JTextField;
|
||||
import javax.swing.KeyStroke;
|
||||
import javax.swing.UIManager;
|
||||
import javax.swing.border.EmptyBorder;
|
||||
|
||||
import me.ByteEdit.main.Main;
|
||||
@@ -28,11 +27,6 @@ public class SearchBox extends JFrame {
|
||||
public JCheckBox chckbxCaseSensitive;
|
||||
|
||||
public SearchBox() {
|
||||
try {
|
||||
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
setResizable(false);
|
||||
setTitle("Find/Replace");
|
||||
setDefaultCloseOperation(JFrame.HIDE_ON_CLOSE);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -11,7 +11,6 @@ import javax.swing.JPanel;
|
||||
import javax.swing.JScrollPane;
|
||||
import javax.swing.JTextField;
|
||||
import javax.swing.ListSelectionModel;
|
||||
import javax.swing.UIManager;
|
||||
import javax.swing.border.EmptyBorder;
|
||||
import javax.swing.event.DocumentEvent;
|
||||
import javax.swing.event.DocumentListener;
|
||||
@@ -27,11 +26,6 @@ public class TypeOpenBox extends JFrame {
|
||||
public JTextField txtSearch;
|
||||
|
||||
public TypeOpenBox() {
|
||||
try {
|
||||
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
setResizable(false);
|
||||
setTitle("Open Type");
|
||||
setDefaultCloseOperation(JFrame.HIDE_ON_CLOSE);
|
||||
@@ -82,7 +76,7 @@ public class TypeOpenBox extends JFrame {
|
||||
if (txtSearch.getText().isEmpty()) {
|
||||
return;
|
||||
}
|
||||
String search = UnicodeUtils.unescape(txtSearch.getText()).toLowerCase();
|
||||
String search = UnicodeUtils.unescape(null, txtSearch.getText(), true).toLowerCase();
|
||||
if (search.contains("/")) {
|
||||
for (String s : Main.classNodes.keySet()) {
|
||||
String className = s.substring(0, s.length() - 6);
|
||||
|
||||
@@ -9,7 +9,6 @@ import javax.swing.JFrame;
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.JScrollPane;
|
||||
import javax.swing.JTextArea;
|
||||
import javax.swing.UIManager;
|
||||
import javax.swing.border.EmptyBorder;
|
||||
|
||||
import me.ByteEdit.main.Main;
|
||||
@@ -20,11 +19,6 @@ public class UnicodeBox extends JFrame {
|
||||
private JPanel contentPane;
|
||||
|
||||
public UnicodeBox() {
|
||||
try {
|
||||
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
setResizable(false);
|
||||
setTitle("Unicode Converter");
|
||||
setDefaultCloseOperation(JFrame.HIDE_ON_CLOSE);
|
||||
@@ -42,7 +36,7 @@ public class UnicodeBox extends JFrame {
|
||||
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
try {
|
||||
textArea.setText(UnicodeUtils.escape(textArea.getText()));
|
||||
textArea.setText(UnicodeUtils.escape(null, textArea.getText(), true));
|
||||
} catch (IllegalArgumentException ex) {
|
||||
Main.showError(ex.getMessage());
|
||||
}
|
||||
@@ -56,7 +50,7 @@ public class UnicodeBox extends JFrame {
|
||||
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
try {
|
||||
textArea.setText(UnicodeUtils.unescape(textArea.getText()));
|
||||
textArea.setText(UnicodeUtils.unescape(null, textArea.getText(), true));
|
||||
} catch (IllegalArgumentException ex) {
|
||||
Main.showError(ex.getMessage());
|
||||
}
|
||||
|
||||
+306
-313
File diff suppressed because it is too large.
Load diff
File diff suppressed because it is too large.
Load diff
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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)
|
||||
*/
|
||||
private void addHyperlinkToken(int start, int end, int tokenType) {
|
||||
int so = start + offsetShift;
|
||||
addToken(zzBuffer, start, end, tokenType, so, true);
|
||||
super.addToken(zzBuffer, start, end, tokenType, start + offsetShift, true);
|
||||
zzStartRead = zzMarkedPos;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2867,7 +2867,8 @@ public class JavaAssemblyTokenMaker extends AbstractJFlexCTokenMaker {
|
||||
* @param tokenType The token's type.
|
||||
*/
|
||||
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)
|
||||
*/
|
||||
private void addToken(int start, int end, int tokenType) {
|
||||
int so = start + offsetShift;
|
||||
addToken(zzBuffer, start, end, tokenType, so, false);
|
||||
super.addToken(zzBuffer, start, end, tokenType, start + offsetShift, 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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
+433
-176
@@ -1,6 +1,5 @@
|
||||
package me.ByteEdit.main;
|
||||
|
||||
import java.awt.Color;
|
||||
import java.awt.Component;
|
||||
import java.awt.EventQueue;
|
||||
import java.awt.Font;
|
||||
@@ -18,18 +17,20 @@ import java.awt.event.ActionEvent;
|
||||
import java.awt.event.ActionListener;
|
||||
import java.awt.event.KeyAdapter;
|
||||
import java.awt.event.KeyEvent;
|
||||
import java.awt.event.MouseEvent;
|
||||
import java.io.BufferedReader;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.StringReader;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.Enumeration;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.jar.JarEntry;
|
||||
@@ -39,17 +40,22 @@ import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import javax.swing.ButtonGroup;
|
||||
import javax.swing.JCheckBoxMenuItem;
|
||||
import javax.swing.JComponent;
|
||||
import javax.swing.JDialog;
|
||||
import javax.swing.JFileChooser;
|
||||
import javax.swing.JFrame;
|
||||
import javax.swing.JMenu;
|
||||
import javax.swing.JMenuBar;
|
||||
import javax.swing.JMenuItem;
|
||||
import javax.swing.JOptionPane;
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.JRadioButtonMenuItem;
|
||||
import javax.swing.JScrollPane;
|
||||
import javax.swing.JSplitPane;
|
||||
import javax.swing.JTree;
|
||||
import javax.swing.KeyStroke;
|
||||
import javax.swing.UIManager;
|
||||
import javax.swing.border.EmptyBorder;
|
||||
import javax.swing.event.TreeExpansionEvent;
|
||||
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.rsyntaxtextarea.RSyntaxTextArea;
|
||||
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.FoldParserManager;
|
||||
import org.fife.ui.rtextarea.RTextArea;
|
||||
import org.fife.ui.rtextarea.RTextScrollPane;
|
||||
import org.fife.ui.rtextarea.ToolTipSupplier;
|
||||
import org.objectweb.asm.ClassReader;
|
||||
import org.objectweb.asm.ClassWriter;
|
||||
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.GlobalSearchBox;
|
||||
import me.ByteEdit.boxes.OptionBox;
|
||||
import me.ByteEdit.boxes.RenameBox;
|
||||
import me.ByteEdit.boxes.SearchBox;
|
||||
import me.ByteEdit.boxes.ThemeBox;
|
||||
import me.ByteEdit.boxes.TypeOpenBox;
|
||||
import me.ByteEdit.boxes.UnicodeBox;
|
||||
import me.ByteEdit.edit.Assembler;
|
||||
import me.ByteEdit.edit.Disassembler;
|
||||
import me.ByteEdit.edit.Disassembler.DisassembleTuple;
|
||||
import me.ByteEdit.edit.HugeStrings;
|
||||
import me.ByteEdit.utils.ClassUtil;
|
||||
import me.ByteEdit.utils.OpcodesReverse;
|
||||
import me.ByteEdit.utils.UnicodeUtils;
|
||||
@@ -107,16 +115,41 @@ public class Main extends JFrame {
|
||||
public static GlobalSearchBox globalSearchBox;
|
||||
public static SearchBox searchBox;
|
||||
public static TypeOpenBox typeOpenBox;
|
||||
public static OptionBox optionBox;
|
||||
public static UnicodeBox unicodeBox;
|
||||
public static RenameBox renameBox;
|
||||
public static CompilationBox compilationBox;
|
||||
public static ThemeBox themeBox;
|
||||
public static JTree tree;
|
||||
public static RTextScrollPane scrollPane_ByteEdit;
|
||||
public static Theme theme;
|
||||
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();
|
||||
|
||||
@@ -130,11 +163,13 @@ public class Main extends JFrame {
|
||||
try {
|
||||
Main frame = new Main();
|
||||
frame.setVisible(true);
|
||||
ThemeManager.applyRSTATheme();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -196,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}",
|
||||
null, "<html><b><u>method</u></b><br>Creates an example method</html>"));
|
||||
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;
|
||||
}
|
||||
|
||||
public static boolean dark = true;
|
||||
|
||||
/**
|
||||
* Create the frame.
|
||||
*/
|
||||
public Main() {
|
||||
INSTANCE = this;
|
||||
File light = new File(System.getProperty("java.io.tmpdir") + File.pathSeparator + "ByteEditLight.conf");
|
||||
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();
|
||||
}
|
||||
ThemeManager.registerFrames(this);
|
||||
globalSearchBox = new GlobalSearchBox();
|
||||
searchBox = new SearchBox();
|
||||
typeOpenBox = new TypeOpenBox();
|
||||
optionBox = new OptionBox();
|
||||
unicodeBox = new UnicodeBox();
|
||||
renameBox = new RenameBox();
|
||||
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");
|
||||
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
|
||||
setBounds((int) (Toolkit.getDefaultToolkit().getScreenSize().getWidth() / 2 - 407),
|
||||
(int) (Toolkit.getDefaultToolkit().getScreenSize().getHeight() / 2 - 237), 814, 474);
|
||||
try {
|
||||
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
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 {
|
||||
Main.this.setTitle("ByteEdit - Loading '" + jarFile.getCanonicalPath() + "'");
|
||||
} 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();
|
||||
}
|
||||
}
|
||||
}).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.setBackground(dark ? new Color(0x2F2F2F) : Color.GRAY);
|
||||
contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
|
||||
setContentPane(contentPane);
|
||||
contentPane.setLayout(new GridLayout(0, 1, 0, 0));
|
||||
JSplitPane splitPane = new JSplitPane();
|
||||
splitPane.setBackground(dark ? new Color(0x2F2F2F) : Color.GRAY);
|
||||
splitPane.setResizeWeight(0.2);
|
||||
contentPane.add(splitPane);
|
||||
JScrollPane scrollPane = new JScrollPane();
|
||||
@@ -316,14 +515,9 @@ public class Main extends JFrame {
|
||||
}
|
||||
});
|
||||
tree.setFont(new Font("Verdana", Font.PLAIN, 11));
|
||||
tree.setBackground(dark ? new Color(0x2F2F2F) : Color.LIGHT_GRAY);
|
||||
tree.setCellRenderer(new DefaultTreeCellRenderer() {
|
||||
{
|
||||
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);
|
||||
@@ -376,7 +570,6 @@ public class Main extends JFrame {
|
||||
globalSearchBox.setVisible(false);
|
||||
searchBox.setVisible(false);
|
||||
typeOpenBox.setVisible(false);
|
||||
optionBox.setVisible(false);
|
||||
unicodeBox.setVisible(false);
|
||||
renameBox.setVisible(false);
|
||||
compilationBox.setVisible(false);
|
||||
@@ -424,6 +617,84 @@ public class Main extends JFrame {
|
||||
txtByteEditView = new RSyntaxTextArea();
|
||||
ac.install(txtByteEditView);
|
||||
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() {
|
||||
|
||||
@Override
|
||||
@@ -443,7 +714,8 @@ public class Main extends JFrame {
|
||||
}
|
||||
}
|
||||
txtByteEditView.setText(dis);
|
||||
txtByteEditView.setCaretPosition(prev);
|
||||
if (dis.length() > prev)
|
||||
txtByteEditView.setCaretPosition(prev);
|
||||
} catch (Exception e2) {
|
||||
e2.printStackTrace();
|
||||
}
|
||||
@@ -454,126 +726,59 @@ public class Main extends JFrame {
|
||||
KeyStroke ctrlT = KeyStroke.getKeyStroke(KeyEvent.VK_T, KeyEvent.CTRL_DOWN_MASK);
|
||||
KeyStroke ctrlS = KeyStroke.getKeyStroke(KeyEvent.VK_S, KeyEvent.CTRL_DOWN_MASK);
|
||||
KeyStroke ctrlG = KeyStroke.getKeyStroke(KeyEvent.VK_G, KeyEvent.CTRL_DOWN_MASK);
|
||||
KeyStroke ctrlO = KeyStroke.getKeyStroke(KeyEvent.VK_O, KeyEvent.CTRL_DOWN_MASK);
|
||||
KeyStroke ctrlU = KeyStroke.getKeyStroke(KeyEvent.VK_U, 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 ctrlB = KeyStroke.getKeyStroke(KeyEvent.VK_B, KeyEvent.CTRL_DOWN_MASK);
|
||||
// global
|
||||
txtByteEditView.registerKeyboardAction(new ActionListener() {
|
||||
|
||||
@Override
|
||||
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.txtString.requestFocusInWindow();
|
||||
globalSearchBox.txtString.select(0, globalSearchBox.txtString.getText().length());
|
||||
}
|
||||
txtByteEditView.registerKeyboardAction(e -> themeBox.setVisible(true), ctrlB,
|
||||
JComponent.WHEN_IN_FOCUSED_WINDOW);
|
||||
txtByteEditView.registerKeyboardAction(e -> {
|
||||
globalSearchBox.setVisible(true);
|
||||
globalSearchBox.txtString.requestFocusInWindow();
|
||||
globalSearchBox.txtString.select(0, globalSearchBox.txtString.getText().length());
|
||||
}, ctrlG, JComponent.WHEN_IN_FOCUSED_WINDOW);
|
||||
txtByteEditView.registerKeyboardAction(new ActionListener() {
|
||||
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
searchBox.setVisible(true);
|
||||
searchBox.txtFind.requestFocusInWindow();
|
||||
searchBox.txtFind.select(0, searchBox.txtFind.getText().length());
|
||||
}
|
||||
txtByteEditView.registerKeyboardAction(e -> {
|
||||
searchBox.setVisible(true);
|
||||
searchBox.txtFind.requestFocusInWindow();
|
||||
searchBox.txtFind.select(0, searchBox.txtFind.getText().length());
|
||||
}, ctrlF, JComponent.WHEN_IN_FOCUSED_WINDOW);
|
||||
txtByteEditView.registerKeyboardAction(new ActionListener() {
|
||||
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
typeOpenBox.setVisible(true);
|
||||
typeOpenBox.txtSearch.requestFocusInWindow();
|
||||
typeOpenBox.txtSearch.select(0, typeOpenBox.txtSearch.getText().length());
|
||||
}
|
||||
txtByteEditView.registerKeyboardAction(e -> {
|
||||
typeOpenBox.setVisible(true);
|
||||
typeOpenBox.txtSearch.requestFocusInWindow();
|
||||
typeOpenBox.txtSearch.select(0, typeOpenBox.txtSearch.getText().length());
|
||||
}, ctrlT, JComponent.WHEN_IN_FOCUSED_WINDOW);
|
||||
txtByteEditView.registerKeyboardAction(new ActionListener() {
|
||||
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
optionBox.setVisible(true);
|
||||
}
|
||||
}, ctrlO, JComponent.WHEN_IN_FOCUSED_WINDOW);
|
||||
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);
|
||||
txtByteEditView.registerKeyboardAction(e -> unicodeBox.setVisible(true), ctrlU,
|
||||
JComponent.WHEN_IN_FOCUSED_WINDOW);
|
||||
txtByteEditView.registerKeyboardAction(e -> compilationBox.setVisible(true), ctrlE,
|
||||
JComponent.WHEN_IN_FOCUSED_WINDOW);
|
||||
// specific
|
||||
tree.registerKeyboardAction(new ActionListener() {
|
||||
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
save();
|
||||
}
|
||||
}, ctrlS, JComponent.WHEN_FOCUSED);
|
||||
txtByteEditView.registerKeyboardAction(new ActionListener() {
|
||||
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
saveCurrentClassNode();
|
||||
}
|
||||
}, ctrlS, JComponent.WHEN_FOCUSED);
|
||||
txtByteEditView.registerKeyboardAction(new ActionListener() {
|
||||
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
try {
|
||||
goToSelected();
|
||||
} catch (BadLocationException e1) {
|
||||
e1.printStackTrace();
|
||||
}
|
||||
tree.registerKeyboardAction(e -> save(), ctrlS, JComponent.WHEN_FOCUSED);
|
||||
txtByteEditView.registerKeyboardAction(e -> saveCurrentClassNode(), ctrlS, JComponent.WHEN_FOCUSED);
|
||||
txtByteEditView.registerKeyboardAction(e -> {
|
||||
try {
|
||||
goToSelected();
|
||||
} catch (BadLocationException e1) {
|
||||
e1.printStackTrace();
|
||||
}
|
||||
}, ctrlG, JComponent.WHEN_FOCUSED);
|
||||
txtByteEditView.registerKeyboardAction(new ActionListener() {
|
||||
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
try {
|
||||
renameSelected();
|
||||
} catch (BadLocationException e1) {
|
||||
e1.printStackTrace();
|
||||
}
|
||||
txtByteEditView.registerKeyboardAction(e -> {
|
||||
try {
|
||||
renameSelected();
|
||||
} catch (BadLocationException e1) {
|
||||
e1.printStackTrace();
|
||||
}
|
||||
}, ctrlR, JComponent.WHEN_FOCUSED);
|
||||
txtByteEditView.setEditable(true);
|
||||
txtByteEditView.setSyntaxEditingStyle(SyntaxConstants.SYNTAX_STYLE_JAVA_DISASSEMBLE);
|
||||
txtByteEditView.setCodeFoldingEnabled(true);
|
||||
scrollPane_ByteEdit = new RTextScrollPane();
|
||||
theme.apply(txtByteEditView);
|
||||
ThemeManager.registerTextArea(txtByteEditView);
|
||||
|
||||
splitPane.setRightComponent(scrollPane_ByteEdit);
|
||||
txtByteEditView.setBackground(dark ? new Color(0x2F2F2F) : Color.LIGHT_GRAY);
|
||||
scrollPane_ByteEdit.setViewportView(txtByteEditView);
|
||||
scrollPane_ByteEdit.setLineNumbersEnabled(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+).+ .+");
|
||||
@@ -588,11 +793,11 @@ public class Main extends JFrame {
|
||||
line = line.substring(2);
|
||||
if (line.startsWith("invoke")) {
|
||||
String[] split = line.split(" ");
|
||||
String desc = UnicodeUtils.unescape(split[1]);
|
||||
String desc = UnicodeUtils.unescape(null, split[1], true);
|
||||
String target = split[2];
|
||||
int index = target.lastIndexOf("/");
|
||||
String className = UnicodeUtils.unescape(target.substring(0, index));
|
||||
String methodName = UnicodeUtils.unescape(target.substring(index + 1));
|
||||
String className = UnicodeUtils.unescape(null, target.substring(0, index), true);
|
||||
String methodName = UnicodeUtils.unescape(null, target.substring(index + 1), true);
|
||||
ClassNode classNode = classNodes.get(getFullName(className));
|
||||
if (classNode == null) {
|
||||
return;
|
||||
@@ -611,7 +816,7 @@ public class Main extends JFrame {
|
||||
}
|
||||
} else if (line.startsWith("new ")) {
|
||||
String[] split = line.split(" ");
|
||||
String className = UnicodeUtils.unescape(split[1]);
|
||||
String className = UnicodeUtils.unescape(null, split[1], true);
|
||||
ClassNode classNode = classNodes.get(getFullName(className));
|
||||
if (classNode == null) {
|
||||
return;
|
||||
@@ -620,11 +825,11 @@ public class Main extends JFrame {
|
||||
} else if (line.startsWith("getstatic ") || line.startsWith("putstatic ") || line.startsWith("getfield ")
|
||||
|| line.startsWith("putfield ")) {
|
||||
String[] split = line.split(" ");
|
||||
String desc = UnicodeUtils.unescape(split[1]);
|
||||
String desc = UnicodeUtils.unescape(null, split[1], true);
|
||||
String target = split[2];
|
||||
int index = target.lastIndexOf("/");
|
||||
String className = UnicodeUtils.unescape(target.substring(0, index));
|
||||
String fieldName = UnicodeUtils.unescape(target.substring(index + 1));
|
||||
String className = UnicodeUtils.unescape(null, target.substring(0, index), true);
|
||||
String fieldName = UnicodeUtils.unescape(null, target.substring(index + 1), true);
|
||||
ClassNode classNode = classNodes.get(getFullName(className));
|
||||
if (classNode == null) {
|
||||
return;
|
||||
@@ -688,10 +893,12 @@ public class Main extends JFrame {
|
||||
if (s.contains(" extends "))
|
||||
s = s.substring(0, s.lastIndexOf(" extends "));
|
||||
String[] split = s.split(" ");
|
||||
String className = UnicodeUtils.unescape(split[split.length - 1]);
|
||||
String className = UnicodeUtils.unescape(null, split[split.length - 1], true);
|
||||
renameBox.className = className;
|
||||
String name = UnicodeUtils.unescape(m.pattern() == renameableFieldPattern ? m.group(2) : m.group(1));
|
||||
String desc = UnicodeUtils.unescape(m.pattern() == renameableFieldPattern ? m.group(1) : m.group(2));
|
||||
String name = UnicodeUtils.unescape(null, m.pattern() == renameableFieldPattern ? m.group(2) : m.group(1),
|
||||
true);
|
||||
String desc = UnicodeUtils.unescape(null, m.pattern() == renameableFieldPattern ? m.group(1) : m.group(2),
|
||||
true);
|
||||
renameBox.name = name;
|
||||
renameBox.desc = desc;
|
||||
renameBox.txtName.setText(name);
|
||||
@@ -732,8 +939,7 @@ public class Main extends JFrame {
|
||||
}
|
||||
|
||||
public static int selectFileWithSearch(String s, Object nodeToFind) {
|
||||
if (s != null && (s.endsWith(".class")
|
||||
|| (s.endsWith(".class/") && fakedFolders.contains(s.substring(0, s.length() - 7))))) {
|
||||
if (s != null && s.endsWith(".class")) {
|
||||
currentNodeName = s;
|
||||
int lineFound = -1;
|
||||
ClassNode classNode = classNodes.get(s);
|
||||
@@ -787,15 +993,50 @@ public class Main extends JFrame {
|
||||
if (action == 0) {
|
||||
final File file = fileChooser.getSelectedFile();
|
||||
saveFolder = file.getParentFile();
|
||||
boolean shouldSave = false;
|
||||
if (file.exists()) {
|
||||
int dialogResult = JOptionPane.showConfirmDialog(null, "This file already exists! Overwrite it?",
|
||||
"Warning", JOptionPane.YES_NO_OPTION);
|
||||
if (dialogResult == JOptionPane.YES_OPTION) {
|
||||
save(file, classNodes.values());
|
||||
shouldSave = true;
|
||||
}
|
||||
} else {
|
||||
save(file, classNodes.values());
|
||||
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());
|
||||
EventQueue.invokeLater(new Runnable() {
|
||||
public void run() {
|
||||
synchronized (treeLock) {
|
||||
isChangingFile = false;
|
||||
Main.this.setTitle("ByteEdit");
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}).start();
|
||||
} catch (Throwable t) {
|
||||
t.printStackTrace();
|
||||
showError(t);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -832,16 +1073,16 @@ public class Main extends JFrame {
|
||||
output.closeEntry();
|
||||
}
|
||||
int computeFlags = 0;
|
||||
if (optionBox.chckbxComputeFrames.isSelected()) {
|
||||
if (mntmComputeFrames.isSelected()) {
|
||||
computeFlags |= ClassWriter.COMPUTE_FRAMES;
|
||||
}
|
||||
if (optionBox.chckbxComputeMax.isSelected()) {
|
||||
if (mntmComputeMax.isSelected()) {
|
||||
computeFlags |= ClassWriter.COMPUTE_MAXS;
|
||||
}
|
||||
for (ClassNode element : classes) {
|
||||
for (ClassNode node : classes) {
|
||||
ClassWriter writer = new ClassWriter(computeFlags);
|
||||
element.accept(writer);
|
||||
output.putNextEntry(new JarEntry(getFullName(element.name)));
|
||||
node.accept(writer);
|
||||
output.putNextEntry(new JarEntry(getFullName(node.name)));
|
||||
output.write(writer.toByteArray());
|
||||
output.closeEntry();
|
||||
}
|
||||
@@ -869,10 +1110,7 @@ public class Main extends JFrame {
|
||||
}
|
||||
|
||||
public static String getFullName(String s) {
|
||||
if (fakedFolders.contains(s))
|
||||
return s + ".class/";
|
||||
else
|
||||
return s + ".class";
|
||||
return s + ".class";
|
||||
}
|
||||
|
||||
class ArchiveTreeModel extends DefaultTreeModel {
|
||||
@@ -898,20 +1136,20 @@ public class Main extends JFrame {
|
||||
byte[] data = toByteArray(jar.getInputStream(next));
|
||||
if (next.getSize() != 0 && !next.getName().startsWith("META-INF")
|
||||
&& (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 {
|
||||
ClassReader reader = new ClassReader(data);
|
||||
ClassNode node = new ClassNode();
|
||||
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) {
|
||||
OTHER_FILES.put(next.getName(), data);
|
||||
}
|
||||
@@ -950,7 +1188,10 @@ public class Main extends JFrame {
|
||||
// Windows-like sorting (like file explorer)
|
||||
List<String> tmp = new ArrayList<>(paths);
|
||||
|
||||
List<String> folders = tmp.stream().filter(s -> s.contains("/")).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('/');
|
||||
if (idx == s.length() - 1)
|
||||
idx = s.lastIndexOf('/', idx - 1);
|
||||
@@ -982,16 +1223,20 @@ public class Main extends JFrame {
|
||||
tmp.addAll(0, folders);
|
||||
|
||||
for (String s : tmp) {
|
||||
String[] elements = s.split("/");
|
||||
ByteEditTreeNode currentNode = (ByteEditTreeNode) getRoot();
|
||||
for (int i = 0; i < elements.length; i++) {
|
||||
String token = elements[i];
|
||||
ByteEditTreeNode nextNode = findNode(currentNode, token);
|
||||
if (nextNode == null) {
|
||||
nextNode = new ByteEditTreeNode(token, s);
|
||||
currentNode.add(nextNode);
|
||||
String[] elements = SLASH.split(s, 50);
|
||||
if (elements.length >= 50) {
|
||||
((ByteEditTreeNode) getRoot()).add(new ByteEditTreeNode(s, s));
|
||||
} else {
|
||||
ByteEditTreeNode currentNode = (ByteEditTreeNode) getRoot();
|
||||
for (int i = 0; i < elements.length; i++) {
|
||||
String token = elements[i];
|
||||
ByteEditTreeNode nextNode = findNode(currentNode, token);
|
||||
if (nextNode == null) {
|
||||
nextNode = new ByteEditTreeNode(token, s);
|
||||
currentNode.add(nextNode);
|
||||
}
|
||||
currentNode = nextNode;
|
||||
}
|
||||
currentNode = nextNode;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1006,6 +1251,18 @@ public class Main extends JFrame {
|
||||
}
|
||||
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 {
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -6,6 +6,8 @@ import java.util.HashSet;
|
||||
|
||||
import org.objectweb.asm.Type;
|
||||
|
||||
import me.ByteEdit.edit.HugeStrings;
|
||||
|
||||
public class ClassUtil {
|
||||
|
||||
public static final int ACC_PUBLIC = 0x0001;
|
||||
@@ -522,31 +524,32 @@ public class ClassUtil {
|
||||
return count;
|
||||
}
|
||||
|
||||
public static String getDecompiledValue(Object o, String desc, boolean escapeSpaces) {
|
||||
switch (o.getClass().getName()) {
|
||||
case "java.lang.String": {
|
||||
return "\"" + (escapeSpaces ? UnicodeUtils.escapeWithSpaces((String) o) : UnicodeUtils.escape((String) o))
|
||||
+ "\"";
|
||||
}
|
||||
case "java.lang.Integer": {
|
||||
if (desc.equals("Z")) {
|
||||
return ((int) o) == 0 ? "false" : "true";
|
||||
}
|
||||
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 final HashMap<Class, DecompilationInterface> diMap = new HashMap<>();
|
||||
|
||||
static {
|
||||
diMap.put(String.class, (o, desc, escapeSpaces, hs) -> "\""
|
||||
+ (escapeSpaces ? UnicodeUtils.escapeWithSpaces(hs, (String) o) : UnicodeUtils.escape(hs, (String) o))
|
||||
+ "\"");
|
||||
diMap.put(Integer.class,
|
||||
(o, desc, escape, hs) -> desc.equals("Z") ? (((int) o) == 0 ? "false" : "true") : o.toString());
|
||||
diMap.put(Long.class, (o, desc, escape, hs) -> o.toString() + "l");
|
||||
diMap.put(Float.class, (o, desc, escape, hs) -> o.toString() + "f");
|
||||
}
|
||||
|
||||
public static String getDecompiledValue(Object o, String desc) {
|
||||
return getDecompiledValue(o, desc, false);
|
||||
static interface DecompilationInterface {
|
||||
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) {
|
||||
|
||||
@@ -1,11 +1,26 @@
|
||||
package me.ByteEdit.utils;
|
||||
|
||||
import me.ByteEdit.edit.HugeStrings;
|
||||
import me.ByteEdit.edit.HugeStringsRev;
|
||||
|
||||
public class UnicodeUtils {
|
||||
|
||||
public static String unescape(String s) {
|
||||
public static String unescape(HugeStringsRev hsr, String s) {
|
||||
return unescape(hsr, s, false);
|
||||
}
|
||||
|
||||
public static String unescape(HugeStringsRev hsr, String s, boolean force) {
|
||||
if (s == null) {
|
||||
return null;
|
||||
}
|
||||
if (!force && !s.isEmpty() && s.charAt(0) == '#' && s.length() < 12) {
|
||||
try {
|
||||
int id = Integer.parseInt(s.substring(1));
|
||||
return hsr.get(id);
|
||||
} catch (NumberFormatException ex) {
|
||||
// Doesn't seem like a HugeString
|
||||
}
|
||||
}
|
||||
StringBuilder sb = new StringBuilder();
|
||||
char unicodeBuffer = 0;
|
||||
int stage = 0;
|
||||
@@ -78,83 +93,161 @@ public class UnicodeUtils {
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
public static String escapeWithSpaces(String s) {
|
||||
public static String escapeWithSpaces(HugeStrings hs, String s) {
|
||||
if (s == null) {
|
||||
return null;
|
||||
}
|
||||
s = escape(s).replace(" ", "\\u0020");
|
||||
if (s.startsWith("/")) {
|
||||
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;
|
||||
if (s.length() > HugeStrings.THRESHOLD) {
|
||||
return hs.onString(s);
|
||||
}
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (char c : s.toCharArray()) {
|
||||
if (isPrintable(c)) {
|
||||
char[] arr = s.toCharArray();
|
||||
int i = 0;
|
||||
int len = arr.length;
|
||||
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) {
|
||||
case 'Ä':
|
||||
case 'ä':
|
||||
case 'Ö':
|
||||
case 'ö':
|
||||
case 'Ü':
|
||||
case 'ü':
|
||||
case 'ß':
|
||||
case '€':
|
||||
case '©':
|
||||
case '®':
|
||||
case '«':
|
||||
case '»':
|
||||
case '§':
|
||||
case '£':
|
||||
case '¥':
|
||||
sb.append(c);
|
||||
} else {
|
||||
switch (c) {
|
||||
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 '"':
|
||||
sb.append("\\\"");
|
||||
break;
|
||||
case '\\':
|
||||
sb.append("\\\\");
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
case ' ':
|
||||
sb.append("\\u0020");
|
||||
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 '"':
|
||||
sb.append("\\\"");
|
||||
break;
|
||||
case '\\':
|
||||
sb.append("\\\\");
|
||||
break;
|
||||
default:
|
||||
if (c > ' ' && c <= '~') {
|
||||
sb.append(c);
|
||||
} else {
|
||||
sb.append(String.format("\\u%04X", (int) c));
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (addSlash)
|
||||
sb.append("\\u002F");
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
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) {
|
||||
case 'Ä':
|
||||
case 'ä':
|
||||
case 'Ö':
|
||||
case 'ö':
|
||||
case 'Ü':
|
||||
case 'ü':
|
||||
case 'ß':
|
||||
case '€':
|
||||
case '©':
|
||||
case '®':
|
||||
case '«':
|
||||
case '»':
|
||||
case '§':
|
||||
case '£':
|
||||
case '¥':
|
||||
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 '"':
|
||||
sb.append("\\\"");
|
||||
break;
|
||||
case '\\':
|
||||
sb.append("\\\\");
|
||||
break;
|
||||
default:
|
||||
if (c >= ' ' && c <= '~') {
|
||||
sb.append(c);
|
||||
} else {
|
||||
sb.append(String.format("\\u%04X", (int) c));
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
private static boolean isPrintable(char c) {
|
||||
switch (c) {
|
||||
case 'Ä':
|
||||
case 'ä':
|
||||
case 'Ö':
|
||||
case 'ö':
|
||||
case 'Ü':
|
||||
case 'ü':
|
||||
case 'ß':
|
||||
case '€':
|
||||
case '©':
|
||||
case '®':
|
||||
case '«':
|
||||
case '»':
|
||||
case '§':
|
||||
case '£':
|
||||
case '¥':
|
||||
return true;
|
||||
case '"':
|
||||
case '\\':
|
||||
return false;
|
||||
default:
|
||||
return c >= ' ' && c <= '~';
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
File diff suppressed because it is too large.
Load diff
Reference in new issue
Block a user