|
|
|
@@ -17,11 +17,14 @@ 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;
|
|
|
|
@@ -37,6 +40,8 @@ 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;
|
|
|
|
@@ -46,6 +51,7 @@ 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;
|
|
|
|
@@ -72,7 +78,9 @@ import org.fife.ui.rsyntaxtextarea.RSyntaxTextArea;
|
|
|
|
|
import org.fife.ui.rsyntaxtextarea.SyntaxConstants;
|
|
|
|
|
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;
|
|
|
|
@@ -81,7 +89,6 @@ 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;
|
|
|
|
@@ -90,6 +97,7 @@ 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,7 +115,6 @@ 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;
|
|
|
|
@@ -116,6 +123,32 @@ public class Main extends JFrame {
|
|
|
|
|
public static RTextScrollPane scrollPane_ByteEdit;
|
|
|
|
|
public static File saveFolder;
|
|
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
|
|
|
|
|
public static final Object treeLock = new Object();
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
@@ -209,7 +242,6 @@ public class Main extends JFrame {
|
|
|
|
|
globalSearchBox = new GlobalSearchBox();
|
|
|
|
|
searchBox = new SearchBox();
|
|
|
|
|
typeOpenBox = new TypeOpenBox();
|
|
|
|
|
optionBox = new OptionBox();
|
|
|
|
|
unicodeBox = new UnicodeBox();
|
|
|
|
|
renameBox = new RenameBox();
|
|
|
|
|
compilationBox = new CompilationBox();
|
|
|
|
@@ -217,7 +249,6 @@ public class Main extends JFrame {
|
|
|
|
|
ThemeManager.registerFrames(globalSearchBox);
|
|
|
|
|
ThemeManager.registerFrames(searchBox);
|
|
|
|
|
ThemeManager.registerFrames(typeOpenBox);
|
|
|
|
|
ThemeManager.registerFrames(optionBox);
|
|
|
|
|
ThemeManager.registerFrames(unicodeBox);
|
|
|
|
|
ThemeManager.registerFrames(renameBox);
|
|
|
|
|
ThemeManager.registerFrames(compilationBox);
|
|
|
|
@@ -278,7 +309,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);
|
|
|
|
@@ -336,6 +366,56 @@ public class Main extends JFrame {
|
|
|
|
|
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);
|
|
|
|
|
|
|
|
|
|
contentPane = new JPanel();
|
|
|
|
|
contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
|
|
|
|
|
setContentPane(contentPane);
|
|
|
|
@@ -472,7 +552,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);
|
|
|
|
@@ -520,6 +599,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 (BadLocationException e1) {
|
|
|
|
|
}
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
txtByteEditView.addKeyListener(new KeyAdapter() {
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
@@ -551,7 +708,6 @@ 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);
|
|
|
|
@@ -574,8 +730,6 @@ public class Main extends JFrame {
|
|
|
|
|
typeOpenBox.txtSearch.requestFocusInWindow();
|
|
|
|
|
typeOpenBox.txtSearch.select(0, typeOpenBox.txtSearch.getText().length());
|
|
|
|
|
}, ctrlT, JComponent.WHEN_IN_FOCUSED_WINDOW);
|
|
|
|
|
txtByteEditView.registerKeyboardAction(e -> optionBox.setVisible(true), ctrlO,
|
|
|
|
|
JComponent.WHEN_IN_FOCUSED_WINDOW);
|
|
|
|
|
txtByteEditView.registerKeyboardAction(e -> unicodeBox.setVisible(true), ctrlU,
|
|
|
|
|
JComponent.WHEN_IN_FOCUSED_WINDOW);
|
|
|
|
|
txtByteEditView.registerKeyboardAction(e -> compilationBox.setVisible(true), ctrlE,
|
|
|
|
@@ -901,10 +1055,10 @@ 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 node : classes) {
|
|
|
|
@@ -941,21 +1095,6 @@ public class Main extends JFrame {
|
|
|
|
|
return s + ".class";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
|
|
|
|
|
class ArchiveTreeModel extends DefaultTreeModel {
|
|
|
|
|
|
|
|
|
|
public ArrayList<String> paths = new ArrayList<>();
|
|
|
|
|