mirror of
https://github.com/SuspiciousActivity/ByteEdit.git
synced 2026-08-13 17:56:17 +00:00
Cleanup
This commit is contained in:
1 parent
ea282d240e
commit
c2e22e55ad
7 files changed
+384
-330
No files matched your search
@@ -160,7 +160,7 @@ public class CompilationBox extends JFrame {
|
|||||||
}, ctrlS, JComponent.WHEN_FOCUSED);
|
}, ctrlS, JComponent.WHEN_FOCUSED);
|
||||||
}
|
}
|
||||||
|
|
||||||
class JavaSourceFromString extends SimpleJavaFileObject {
|
private static class JavaSourceFromString extends SimpleJavaFileObject {
|
||||||
final String code;
|
final String code;
|
||||||
|
|
||||||
public JavaSourceFromString(String name, String code) {
|
public JavaSourceFromString(String name, String code) {
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import java.io.IOException;
|
|||||||
import java.io.PrintWriter;
|
import java.io.PrintWriter;
|
||||||
import java.io.StringWriter;
|
import java.io.StringWriter;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
import java.util.Map.Entry;
|
||||||
import java.util.jar.Manifest;
|
import java.util.jar.Manifest;
|
||||||
|
|
||||||
import org.jetbrains.java.decompiler.main.Fernflower;
|
import org.jetbrains.java.decompiler.main.Fernflower;
|
||||||
@@ -60,8 +61,8 @@ public class FernflowerDecompiler implements IBytecodeProvider, IResultSaver, ID
|
|||||||
// TODO decompile method only
|
// TODO decompile method only
|
||||||
this.bytes = b;
|
this.bytes = b;
|
||||||
HashMap<String, Object> map = new HashMap<>();
|
HashMap<String, Object> map = new HashMap<>();
|
||||||
for (String key : options.keySet()) {
|
for (Entry<String, Boolean> entry : options.entrySet()) {
|
||||||
map.put(key, options.get(key) ? "1" : "0");
|
map.put(entry.getKey(), entry.getValue() ? "1" : "0");
|
||||||
}
|
}
|
||||||
Fernflower f = new Fernflower(this, this, map, new IFernflowerLogger() {
|
Fernflower f = new Fernflower(this, this, map, new IFernflowerLogger() {
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -494,12 +494,14 @@ public class Assembler {
|
|||||||
}
|
}
|
||||||
return clazz;
|
return clazz;
|
||||||
} catch (Throwable e) {
|
} catch (Throwable e) {
|
||||||
|
if (read != null) {
|
||||||
System.err.println("Error at line: " + read.currentLine);
|
System.err.println("Error at line: " + read.currentLine);
|
||||||
try {
|
try {
|
||||||
Main.txtByteEditView.setCaretPosition(Main.txtByteEditView.getLineStartOffset(read.currentLine));
|
Main.txtByteEditView.setCaretPosition(Main.txtByteEditView.getLineStartOffset(read.currentLine));
|
||||||
} catch (BadLocationException e1) {
|
} catch (BadLocationException e1) {
|
||||||
System.err.println("Can't show line!");
|
System.err.println("Can't show line!");
|
||||||
}
|
}
|
||||||
|
}
|
||||||
Main.showError(e.getMessage());
|
Main.showError(e.getMessage());
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
return null;
|
return null;
|
||||||
@@ -599,26 +601,28 @@ public class Assembler {
|
|||||||
if (args.length == 0) {
|
if (args.length == 0) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
String ret = args[start];
|
StringBuilder sb = new StringBuilder(args[start]);
|
||||||
if (args.length > start + 1) {
|
if (args.length > start + 1) {
|
||||||
for (int i = start + 1; i < args.length; i++) {
|
for (int i = start + 1; i < args.length; i++) {
|
||||||
ret = ret + " " + args[i];
|
sb.append(' ');
|
||||||
|
sb.append(args[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return ret;
|
return sb.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static String consolidateStrings(String[] args, int start, int end) {
|
private static String consolidateStrings(String[] args, int start, int end) {
|
||||||
if (end == 0) {
|
if (end == 0) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
String ret = args[start];
|
StringBuilder sb = new StringBuilder(args[start]);
|
||||||
if (end > start + 1) {
|
if (end > start + 1) {
|
||||||
for (int i = start + 1; i < end; i++) {
|
for (int i = start + 1; i < end; i++) {
|
||||||
ret = ret + " " + args[i];
|
sb.append(' ');
|
||||||
|
sb.append(args[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return ret;
|
return sb.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Object getValue(HugeStringsRev hsr, String s, String to) {
|
private static Object getValue(HugeStringsRev hsr, String s, String to) {
|
||||||
@@ -1567,7 +1571,7 @@ public class Assembler {
|
|||||||
if (!asd.startsWith("(")) {
|
if (!asd.startsWith("(")) {
|
||||||
int frameType = ClassUtil.getFrameTypeByName(asd);
|
int frameType = ClassUtil.getFrameTypeByName(asd);
|
||||||
if (frameType != -1)
|
if (frameType != -1)
|
||||||
list.add(new Integer(frameType));
|
list.add(Integer.valueOf(frameType));
|
||||||
else
|
else
|
||||||
list.add(UnicodeUtils.unescape(hsr, asd.substring(1, asd.length() - 1)));
|
list.add(UnicodeUtils.unescape(hsr, asd.substring(1, asd.length() - 1)));
|
||||||
} else {
|
} else {
|
||||||
@@ -1590,13 +1594,7 @@ public class Assembler {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Object[] arr = new Object[list.size()];
|
return list.toArray(new Object[list.size()]);
|
||||||
int c = 0;
|
|
||||||
for (Object o : list) {
|
|
||||||
arr[c] = o;
|
|
||||||
c++;
|
|
||||||
}
|
|
||||||
return arr;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,198 @@
|
|||||||
|
package me.ByteEdit.main;
|
||||||
|
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.Comparator;
|
||||||
|
import java.util.Enumeration;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
import java.util.zip.ZipEntry;
|
||||||
|
import java.util.zip.ZipFile;
|
||||||
|
|
||||||
|
import javax.swing.tree.DefaultTreeModel;
|
||||||
|
|
||||||
|
import org.objectweb.asm.ClassReader;
|
||||||
|
import org.objectweb.asm.tree.ClassNode;
|
||||||
|
|
||||||
|
public class ArchiveTreeModel extends DefaultTreeModel {
|
||||||
|
|
||||||
|
public final ArrayList<String> paths = new ArrayList<>();
|
||||||
|
private final HashMap<String, ClassNode> classNodes;
|
||||||
|
private final HashMap<String, byte[]> otherFiles;
|
||||||
|
private final ZipFile jar;
|
||||||
|
|
||||||
|
public boolean newCreated = false;
|
||||||
|
|
||||||
|
public ArchiveTreeModel(HashMap<String, ClassNode> classNodes, HashMap<String, byte[]> otherFiles) {
|
||||||
|
super(new ByteEditTreeNode("New"));
|
||||||
|
this.newCreated = true;
|
||||||
|
this.jar = null;
|
||||||
|
this.classNodes = classNodes;
|
||||||
|
this.otherFiles = otherFiles;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ArchiveTreeModel(ZipFile jar, HashMap<String, ClassNode> classNodes, HashMap<String, byte[]> otherFiles) {
|
||||||
|
super(new ByteEditTreeNode(jar.getName().split(File.separator.equals("\\") ? "\\\\"
|
||||||
|
: File.separator)[jar.getName().split(File.separator.equals("\\") ? "\\\\" : File.separator).length
|
||||||
|
- 1]));
|
||||||
|
this.newCreated = true;
|
||||||
|
this.jar = jar;
|
||||||
|
this.classNodes = classNodes;
|
||||||
|
this.otherFiles = otherFiles;
|
||||||
|
initialize();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void initialize() {
|
||||||
|
try {
|
||||||
|
classNodes.clear();
|
||||||
|
otherFiles.clear();
|
||||||
|
Enumeration<? extends ZipEntry> enumeration = jar.entries();
|
||||||
|
while (enumeration.hasMoreElements()) {
|
||||||
|
ZipEntry next = enumeration.nextElement();
|
||||||
|
byte[] data = toByteArray(jar.getInputStream(next));
|
||||||
|
if (next.getSize() != 0 && !next.getName().startsWith("META-INF")
|
||||||
|
&& (next.getName().endsWith(".class") || next.getName().endsWith(".class/"))) {
|
||||||
|
try {
|
||||||
|
ClassReader reader = new ClassReader(data);
|
||||||
|
ClassNode node = new ClassNode();
|
||||||
|
reader.accept(node, 0);
|
||||||
|
classNodes.put(Main.getFullName(node.name), node);
|
||||||
|
|
||||||
|
if ((next.getName().contains("/")
|
||||||
|
? (!Main.patternSlash
|
||||||
|
.split(next.getName())[Main.patternSlash.split(next.getName()).length - 1]
|
||||||
|
.contains("$"))
|
||||||
|
: (!next.getName().contains("$")))
|
||||||
|
|| (next.getName().startsWith("$") || next.getName().contains("$$")
|
||||||
|
|| next.getName().endsWith("$"))) {
|
||||||
|
paths.add(Main.getFullName(node.name));
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
otherFiles.put(next.getName(), data);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
otherFiles.put(next.getName(), data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
jar.close();
|
||||||
|
refresh();
|
||||||
|
} catch (Throwable e) {
|
||||||
|
classNodes.clear();
|
||||||
|
otherFiles.clear();
|
||||||
|
e.printStackTrace();
|
||||||
|
Main.showError(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private int getSlashCount(String s) {
|
||||||
|
int count = 0;
|
||||||
|
for (char c : s.toCharArray()) {
|
||||||
|
if (c == '/')
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void refresh() {
|
||||||
|
setRoot(new ByteEditTreeNode(((ByteEditTreeNode) getRoot()).toString()));
|
||||||
|
Collections.sort(paths, String.CASE_INSENSITIVE_ORDER);
|
||||||
|
Collections.sort(paths, new Comparator<String>() {
|
||||||
|
public int compare(String s1, String s2) {
|
||||||
|
return getSlashCount(s2) - getSlashCount(s1);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Windows-like sorting (like file explorer)
|
||||||
|
List<String> tmp = new ArrayList<>(paths);
|
||||||
|
|
||||||
|
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);
|
||||||
|
if (idx == -1)
|
||||||
|
return s;
|
||||||
|
return s.substring(0, idx);
|
||||||
|
}).distinct().sorted(new Comparator<String>() {
|
||||||
|
@Override
|
||||||
|
public int compare(String s, String s2) {
|
||||||
|
// From String#compareToIgnoreCase(String)
|
||||||
|
int n = s.length();
|
||||||
|
int n2 = s2.length();
|
||||||
|
int n3 = Math.min(n, n2);
|
||||||
|
for (int i = 0; i < n3; ++i) {
|
||||||
|
char c;
|
||||||
|
char c2 = s.charAt(i);
|
||||||
|
if (c2 == (c = s2.charAt(i)) || (c2 = Character.toUpperCase(c2)) == (c = Character.toUpperCase(c))
|
||||||
|
|| (c2 = Character.toLowerCase(c2)) == (c = Character.toLowerCase(c)))
|
||||||
|
continue;
|
||||||
|
return c2 - c;
|
||||||
|
}
|
||||||
|
// Other way around
|
||||||
|
return n2 - n;
|
||||||
|
}
|
||||||
|
}).collect(Collectors.toList());
|
||||||
|
|
||||||
|
tmp.removeAll(folders);
|
||||||
|
tmp.addAll(0, folders);
|
||||||
|
|
||||||
|
for (String s : tmp) {
|
||||||
|
String[] elements = Main.patternSlash.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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static ByteEditTreeNode findNode(ByteEditTreeNode parent, String name) {
|
||||||
|
Enumeration<?> e = parent.children();
|
||||||
|
while (e.hasMoreElements()) {
|
||||||
|
ByteEditTreeNode element = (ByteEditTreeNode) e.nextElement();
|
||||||
|
if (element.getUserObject().equals(name)) {
|
||||||
|
return element;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static 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 byte[] toByteArray(final InputStream input) throws IOException {
|
||||||
|
try (final ByteArrayOutputStream output = new ByteArrayOutputStream()) {
|
||||||
|
byte[] buffer = new byte[4096];
|
||||||
|
int read;
|
||||||
|
while ((read = input.read(buffer)) != -1) {
|
||||||
|
output.write(buffer, 0, read);
|
||||||
|
}
|
||||||
|
return output.toByteArray();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
package me.ByteEdit.main;
|
||||||
|
|
||||||
|
import javax.swing.JTree;
|
||||||
|
import javax.swing.event.TreeExpansionEvent;
|
||||||
|
import javax.swing.event.TreeExpansionListener;
|
||||||
|
import javax.swing.tree.TreeNode;
|
||||||
|
import javax.swing.tree.TreePath;
|
||||||
|
|
||||||
|
public class FurtherExpandingTreeExpansionListener implements TreeExpansionListener {
|
||||||
|
|
||||||
|
private final JTree tree;
|
||||||
|
|
||||||
|
public FurtherExpandingTreeExpansionListener(JTree tree) {
|
||||||
|
this.tree = tree;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void treeExpanded(TreeExpansionEvent event) {
|
||||||
|
TreePath treePath = event.getPath();
|
||||||
|
Object expandedTreePathObject = treePath.getLastPathComponent();
|
||||||
|
if (!(expandedTreePathObject instanceof TreeNode))
|
||||||
|
return;
|
||||||
|
TreeNode expandedTreeNode = (TreeNode) expandedTreePathObject;
|
||||||
|
if (expandedTreeNode.getChildCount() == 1) {
|
||||||
|
TreeNode descendantTreeNode = expandedTreeNode.getChildAt(0);
|
||||||
|
if (descendantTreeNode.isLeaf())
|
||||||
|
return;
|
||||||
|
TreePath nextTreePath = treePath.pathByAddingChild(descendantTreeNode);
|
||||||
|
tree.expandPath(nextTreePath);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void treeCollapsed(TreeExpansionEvent event) {
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,97 @@
|
|||||||
|
package me.ByteEdit.main;
|
||||||
|
|
||||||
|
import java.awt.event.MouseEvent;
|
||||||
|
import java.io.BufferedReader;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.StringReader;
|
||||||
|
|
||||||
|
import org.fife.ui.rsyntaxtextarea.RSyntaxTextArea;
|
||||||
|
import org.fife.ui.rtextarea.RTextArea;
|
||||||
|
import org.fife.ui.rtextarea.ToolTipSupplier;
|
||||||
|
|
||||||
|
import me.ByteEdit.edit.Assembler;
|
||||||
|
|
||||||
|
public class HugeStringsToolTips implements ToolTipSupplier {
|
||||||
|
|
||||||
|
private final RSyntaxTextArea txtByteEditView;
|
||||||
|
|
||||||
|
public HugeStringsToolTips(RSyntaxTextArea txtByteEditView) {
|
||||||
|
this.txtByteEditView = txtByteEditView;
|
||||||
|
}
|
||||||
|
|
||||||
|
@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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
+39
-313
@@ -20,26 +20,17 @@ import java.awt.event.ItemEvent;
|
|||||||
import java.awt.event.ItemListener;
|
import java.awt.event.ItemListener;
|
||||||
import java.awt.event.KeyAdapter;
|
import java.awt.event.KeyAdapter;
|
||||||
import java.awt.event.KeyEvent;
|
import java.awt.event.KeyEvent;
|
||||||
import java.awt.event.MouseEvent;
|
|
||||||
import java.io.BufferedReader;
|
|
||||||
import java.io.ByteArrayOutputStream;
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.FileOutputStream;
|
import java.io.FileOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
|
||||||
import java.io.StringReader;
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.Comparator;
|
|
||||||
import java.util.Enumeration;
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map.Entry;
|
import java.util.Map.Entry;
|
||||||
import java.util.regex.Matcher;
|
import java.util.regex.Matcher;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Stream;
|
||||||
import java.util.zip.ZipEntry;
|
import java.util.zip.ZipEntry;
|
||||||
import java.util.zip.ZipFile;
|
import java.util.zip.ZipFile;
|
||||||
import java.util.zip.ZipOutputStream;
|
import java.util.zip.ZipOutputStream;
|
||||||
@@ -63,16 +54,12 @@ import javax.swing.JSplitPane;
|
|||||||
import javax.swing.JTree;
|
import javax.swing.JTree;
|
||||||
import javax.swing.KeyStroke;
|
import javax.swing.KeyStroke;
|
||||||
import javax.swing.border.EmptyBorder;
|
import javax.swing.border.EmptyBorder;
|
||||||
import javax.swing.event.TreeExpansionEvent;
|
|
||||||
import javax.swing.event.TreeExpansionListener;
|
|
||||||
import javax.swing.event.TreeSelectionEvent;
|
import javax.swing.event.TreeSelectionEvent;
|
||||||
import javax.swing.event.TreeSelectionListener;
|
import javax.swing.event.TreeSelectionListener;
|
||||||
import javax.swing.filechooser.FileNameExtensionFilter;
|
import javax.swing.filechooser.FileNameExtensionFilter;
|
||||||
import javax.swing.text.BadLocationException;
|
import javax.swing.text.BadLocationException;
|
||||||
import javax.swing.tree.DefaultTreeCellRenderer;
|
import javax.swing.tree.DefaultTreeCellRenderer;
|
||||||
import javax.swing.tree.DefaultTreeModel;
|
import javax.swing.tree.DefaultTreeModel;
|
||||||
import javax.swing.tree.TreeNode;
|
|
||||||
import javax.swing.tree.TreePath;
|
|
||||||
import javax.swing.tree.TreeSelectionModel;
|
import javax.swing.tree.TreeSelectionModel;
|
||||||
|
|
||||||
import org.fife.ui.autocomplete.AutoCompletion;
|
import org.fife.ui.autocomplete.AutoCompletion;
|
||||||
@@ -84,10 +71,7 @@ import org.fife.ui.rsyntaxtextarea.RSyntaxTextArea;
|
|||||||
import org.fife.ui.rsyntaxtextarea.SyntaxConstants;
|
import org.fife.ui.rsyntaxtextarea.SyntaxConstants;
|
||||||
import org.fife.ui.rsyntaxtextarea.folding.CurlyFoldParser;
|
import org.fife.ui.rsyntaxtextarea.folding.CurlyFoldParser;
|
||||||
import org.fife.ui.rsyntaxtextarea.folding.FoldParserManager;
|
import org.fife.ui.rsyntaxtextarea.folding.FoldParserManager;
|
||||||
import org.fife.ui.rtextarea.RTextArea;
|
|
||||||
import org.fife.ui.rtextarea.RTextScrollPane;
|
import org.fife.ui.rtextarea.RTextScrollPane;
|
||||||
import org.fife.ui.rtextarea.ToolTipSupplier;
|
|
||||||
import org.objectweb.asm.ClassReader;
|
|
||||||
import org.objectweb.asm.ClassWriter;
|
import org.objectweb.asm.ClassWriter;
|
||||||
import org.objectweb.asm.tree.ClassNode;
|
import org.objectweb.asm.tree.ClassNode;
|
||||||
import org.objectweb.asm.tree.MethodNode;
|
import org.objectweb.asm.tree.MethodNode;
|
||||||
@@ -110,11 +94,18 @@ import me.ByteEdit.utils.UnicodeUtils;
|
|||||||
public class Main extends JFrame {
|
public class Main extends JFrame {
|
||||||
|
|
||||||
public static Main INSTANCE;
|
public static Main INSTANCE;
|
||||||
|
|
||||||
|
public static final Pattern patternSlash = Pattern.compile("/");
|
||||||
|
private static final Pattern patternRenameableField = Pattern
|
||||||
|
.compile("^\t(?:[a-z]+ |0x[0-9a-fA-F]+ )*?(\\[*(?:V|Z|C|B|S|I|F|J|D|L.+?;)) ([^ ]+) ?.*");
|
||||||
|
private static final Pattern patternRenameableMethod = Pattern
|
||||||
|
.compile("^\t(?:[a-z]+ |0x[0-9a-fA-F]+ )*?([^ ]+) (\\((?:\\[*(?:V|Z|C|B|S|I|F|J|D|L.+?;))*\\)[^ ]+) .*\\{");
|
||||||
|
|
||||||
private JPanel contentPane;
|
private JPanel contentPane;
|
||||||
private volatile boolean isChangingFile;
|
private volatile boolean isChangingFile;
|
||||||
public static File jarFile;
|
public static File jarFile;
|
||||||
public static HashMap<String, byte[]> OTHER_FILES = new HashMap<>();
|
public static final HashMap<String, ClassNode> classNodes = new HashMap<>();
|
||||||
public static HashMap<String, ClassNode> classNodes = new HashMap<>();
|
public static final HashMap<String, byte[]> otherFiles = new HashMap<>();
|
||||||
public static String currentNodeName;
|
public static String currentNodeName;
|
||||||
public static RSyntaxTextArea txtByteEditView;
|
public static RSyntaxTextArea txtByteEditView;
|
||||||
public static GlobalSearchBox globalSearchBox;
|
public static GlobalSearchBox globalSearchBox;
|
||||||
@@ -128,7 +119,6 @@ public class Main extends JFrame {
|
|||||||
public static RTextScrollPane scrollPane_ByteEdit;
|
public static RTextScrollPane scrollPane_ByteEdit;
|
||||||
public static File saveFolder;
|
public static File saveFolder;
|
||||||
|
|
||||||
private static final Pattern SLASH = Pattern.compile("/");
|
|
||||||
private JMenuBar menuBar;
|
private JMenuBar menuBar;
|
||||||
private JMenu mnFile;
|
private JMenu mnFile;
|
||||||
private JMenuItem mntmOpenJar;
|
private JMenuItem mntmOpenJar;
|
||||||
@@ -158,6 +148,8 @@ public class Main extends JFrame {
|
|||||||
|
|
||||||
public static final Object treeLock = new Object();
|
public static final Object treeLock = new Object();
|
||||||
|
|
||||||
|
public static EnumDecompiler decompiler = EnumDecompiler.BYTEEDIT;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Launch the application.
|
* Launch the application.
|
||||||
*/
|
*/
|
||||||
@@ -312,7 +304,8 @@ public class Main extends JFrame {
|
|||||||
new Thread(new Runnable() {
|
new Thread(new Runnable() {
|
||||||
public void run() {
|
public void run() {
|
||||||
try {
|
try {
|
||||||
ArchiveTreeModel model = new ArchiveTreeModel(new ZipFile(jarFile));
|
ArchiveTreeModel model = new ArchiveTreeModel(new ZipFile(jarFile), classNodes,
|
||||||
|
otherFiles);
|
||||||
EventQueue.invokeLater(new Runnable() {
|
EventQueue.invokeLater(new Runnable() {
|
||||||
public void run() {
|
public void run() {
|
||||||
synchronized (treeLock) {
|
synchronized (treeLock) {
|
||||||
@@ -451,7 +444,7 @@ public class Main extends JFrame {
|
|||||||
new CurlyFoldParser(false, true));
|
new CurlyFoldParser(false, true));
|
||||||
tree = new JTree(new DefaultTreeModel(null));
|
tree = new JTree(new DefaultTreeModel(null));
|
||||||
tree.getSelectionModel().setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION);
|
tree.getSelectionModel().setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION);
|
||||||
tree.addTreeExpansionListener(new FurtherExpandingTreeExpansionListener());
|
tree.addTreeExpansionListener(new FurtherExpandingTreeExpansionListener(tree));
|
||||||
tree.addKeyListener(new KeyAdapter() {
|
tree.addKeyListener(new KeyAdapter() {
|
||||||
@Override
|
@Override
|
||||||
public void keyReleased(KeyEvent e) {
|
public void keyReleased(KeyEvent e) {
|
||||||
@@ -466,7 +459,8 @@ public class Main extends JFrame {
|
|||||||
new Thread(new Runnable() {
|
new Thread(new Runnable() {
|
||||||
public void run() {
|
public void run() {
|
||||||
try {
|
try {
|
||||||
ArchiveTreeModel model = new ArchiveTreeModel(new ZipFile(jarFile));
|
ArchiveTreeModel model = new ArchiveTreeModel(new ZipFile(jarFile), classNodes,
|
||||||
|
otherFiles);
|
||||||
EventQueue.invokeLater(new Runnable() {
|
EventQueue.invokeLater(new Runnable() {
|
||||||
public void run() {
|
public void run() {
|
||||||
synchronized (treeLock) {
|
synchronized (treeLock) {
|
||||||
@@ -561,7 +555,8 @@ public class Main extends JFrame {
|
|||||||
new Thread(new Runnable() {
|
new Thread(new Runnable() {
|
||||||
public void run() {
|
public void run() {
|
||||||
try {
|
try {
|
||||||
ArchiveTreeModel model = new ArchiveTreeModel(new ZipFile(jarFile));
|
ArchiveTreeModel model = new ArchiveTreeModel(new ZipFile(jarFile),
|
||||||
|
classNodes, otherFiles);
|
||||||
EventQueue.invokeLater(new Runnable() {
|
EventQueue.invokeLater(new Runnable() {
|
||||||
public void run() {
|
public void run() {
|
||||||
synchronized (treeLock) {
|
synchronized (treeLock) {
|
||||||
@@ -618,84 +613,7 @@ public class Main extends JFrame {
|
|||||||
txtByteEditView = new RSyntaxTextArea();
|
txtByteEditView = new RSyntaxTextArea();
|
||||||
ac.install(txtByteEditView);
|
ac.install(txtByteEditView);
|
||||||
txtByteEditView.setCodeFoldingEnabled(true);
|
txtByteEditView.setCodeFoldingEnabled(true);
|
||||||
// ToolTips for HugeStrings
|
txtByteEditView.setToolTipSupplier(new HugeStringsToolTips(txtByteEditView));
|
||||||
txtByteEditView.setToolTipSupplier(new ToolTipSupplier() {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getToolTipText(RTextArea textArea, MouseEvent e) {
|
|
||||||
int idx = textArea.viewToModel(e.getPoint());
|
|
||||||
if (idx < 0)
|
|
||||||
return null;
|
|
||||||
int subIdx = Math.max(idx - 15, 0);
|
|
||||||
int subLen = Math.min(30, textArea.getDocument().getLength() - subIdx);
|
|
||||||
if (subLen <= 0)
|
|
||||||
return null;
|
|
||||||
try {
|
|
||||||
String cut = textArea.getText(subIdx, subLen);
|
|
||||||
int hashIdx = -1;
|
|
||||||
for (int off = idx - subIdx; off >= 0; off--) {
|
|
||||||
if (cut.charAt(off) == '#') {
|
|
||||||
hashIdx = off;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (hashIdx < 0) {
|
|
||||||
for (int off = idx - subIdx; off < cut.length(); off++) {
|
|
||||||
if (cut.charAt(off) == '#') {
|
|
||||||
hashIdx = off;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (hashIdx < 0)
|
|
||||||
return null;
|
|
||||||
if (hashIdx >= 5 && cut.substring(hashIdx - 5, hashIdx).equals("ldc \"")) // ldc "#..."
|
|
||||||
return null;
|
|
||||||
int numLen = 1;
|
|
||||||
for (int i = hashIdx + 1; i < cut.length(); i++) {
|
|
||||||
if (!(cut.charAt(i) - '0' >= 0 && cut.charAt(i) - '0' <= 9)) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
numLen++;
|
|
||||||
}
|
|
||||||
if (numLen < 2 || hashIdx > idx - subIdx || idx - subIdx - numLen >= hashIdx)
|
|
||||||
return null;
|
|
||||||
String hashNum = cut.substring(hashIdx, hashIdx + numLen);
|
|
||||||
|
|
||||||
String txt = txtByteEditView.getText();
|
|
||||||
int len = 0;
|
|
||||||
for (String asm : txt.split("\\/\\/ #Annotations:\n")) {
|
|
||||||
len += 19; // "\\/\\/ #Annotations:\n".length()
|
|
||||||
if (asm.isEmpty())
|
|
||||||
continue;
|
|
||||||
if (idx >= len && idx < len + asm.length()) {
|
|
||||||
try (BufferedReader reader = new BufferedReader(new StringReader(asm))) {
|
|
||||||
String s;
|
|
||||||
while (!(s = reader.readLine()).startsWith("// #SourceFile: ")) {
|
|
||||||
}
|
|
||||||
while (!(s = reader.readLine()).equals("// #Fields")) {
|
|
||||||
if (s.startsWith("#")) {
|
|
||||||
String[] split = Assembler.SPACE.split(s, 2);
|
|
||||||
if (hashNum.equals(split[0].substring(0, split[0].length() - 1))) {
|
|
||||||
String toolTip = split[1];
|
|
||||||
if (toolTip.length() > 500)
|
|
||||||
toolTip = toolTip.substring(0, 500) + "...";
|
|
||||||
return toolTip;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (IOException e1) {
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
} else {
|
|
||||||
len += asm.length();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (Exception e1) {
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
txtByteEditView.addKeyListener(new KeyAdapter() {
|
txtByteEditView.addKeyListener(new KeyAdapter() {
|
||||||
@Override
|
@Override
|
||||||
public void keyReleased(KeyEvent e) {
|
public void keyReleased(KeyEvent e) {
|
||||||
@@ -737,24 +655,18 @@ public class Main extends JFrame {
|
|||||||
// specific
|
// specific
|
||||||
tree.registerKeyboardAction(e -> save(), ctrlS, JComponent.WHEN_FOCUSED);
|
tree.registerKeyboardAction(e -> save(), ctrlS, JComponent.WHEN_FOCUSED);
|
||||||
txtByteEditView.registerKeyboardAction(e -> saveCurrentClassNode(), ctrlS, JComponent.WHEN_FOCUSED);
|
txtByteEditView.registerKeyboardAction(e -> saveCurrentClassNode(), ctrlS, JComponent.WHEN_FOCUSED);
|
||||||
txtByteEditView.registerKeyboardAction(e -> {
|
txtByteEditView.registerKeyboardAction(e -> renameSelected(), ctrlR, JComponent.WHEN_FOCUSED);
|
||||||
try {
|
|
||||||
renameSelected();
|
|
||||||
} catch (BadLocationException e1) {
|
|
||||||
e1.printStackTrace();
|
|
||||||
}
|
|
||||||
}, ctrlR, JComponent.WHEN_FOCUSED);
|
|
||||||
txtByteEditView.setEditable(true);
|
txtByteEditView.setEditable(true);
|
||||||
txtByteEditView.setSyntaxEditingStyle(SyntaxConstants.SYNTAX_STYLE_JAVA_DISASSEMBLE);
|
txtByteEditView.setSyntaxEditingStyle(SyntaxConstants.SYNTAX_STYLE_JAVA_DISASSEMBLE);
|
||||||
txtByteEditView.setCodeFoldingEnabled(true);
|
txtByteEditView.setCodeFoldingEnabled(true);
|
||||||
scrollPane_ByteEdit = new RTextScrollPane();
|
scrollPane_ByteEdit = new RTextScrollPane();
|
||||||
ThemeManager.registerTextArea(txtByteEditView);
|
ThemeManager.registerTextArea(txtByteEditView);
|
||||||
JPanel panel = new JPanel(new BorderLayout());
|
|
||||||
|
|
||||||
|
JPanel panel = new JPanel(new BorderLayout());
|
||||||
panel.add(scrollPane_ByteEdit, BorderLayout.CENTER);
|
panel.add(scrollPane_ByteEdit, BorderLayout.CENTER);
|
||||||
final JComboBox<String> decompilerMode = new JComboBox<>();
|
final JComboBox<String> decompilerMode = new JComboBox<>();
|
||||||
DefaultComboBoxModel model = new DefaultComboBoxModel();
|
DefaultComboBoxModel model = new DefaultComboBoxModel();
|
||||||
Arrays.stream(EnumDecompiler.values()).forEach(model::addElement);
|
Stream.of(EnumDecompiler.values()).forEach(model::addElement);
|
||||||
decompilerMode.setModel(model);
|
decompilerMode.setModel(model);
|
||||||
decompilerMode.addItemListener(new ItemListener() {
|
decompilerMode.addItemListener(new ItemListener() {
|
||||||
@Override
|
@Override
|
||||||
@@ -790,22 +702,16 @@ public class Main extends JFrame {
|
|||||||
scrollPane_ByteEdit.setFoldIndicatorEnabled(true);
|
scrollPane_ByteEdit.setFoldIndicatorEnabled(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static EnumDecompiler decompiler = EnumDecompiler.BYTEEDIT;
|
public void renameSelected() {
|
||||||
|
try {
|
||||||
private final Pattern renameableFieldPattern = Pattern
|
|
||||||
.compile("^\t(?:[a-z]+ |0x[0-9a-fA-F]+ )*?(\\[*(?:V|Z|C|B|S|I|F|J|D|L.+?;)) ([^ ]+) ?.*");
|
|
||||||
private final Pattern renameableMethodPattern = Pattern
|
|
||||||
.compile("^\t(?:[a-z]+ |0x[0-9a-fA-F]+ )*?([^ ]+) (\\((?:\\[*(?:V|Z|C|B|S|I|F|J|D|L.+?;))*\\)[^ ]+) .*\\{");
|
|
||||||
|
|
||||||
public void renameSelected() throws BadLocationException {
|
|
||||||
int lineStart = txtByteEditView.getLineStartOffsetOfCurrentLine();
|
int lineStart = txtByteEditView.getLineStartOffsetOfCurrentLine();
|
||||||
int lineEnd = txtByteEditView.getLineEndOffsetOfCurrentLine() - 1;
|
int lineEnd = txtByteEditView.getLineEndOffsetOfCurrentLine() - 1;
|
||||||
String line = txtByteEditView.getText(lineStart, lineEnd - lineStart);
|
String line = txtByteEditView.getText(lineStart, lineEnd - lineStart);
|
||||||
Matcher m = renameableFieldPattern.matcher(line);
|
Matcher m = patternRenameableField.matcher(line);
|
||||||
if (m.find()) {
|
if (m.find()) {
|
||||||
setRenameInfo(m, lineEnd);
|
setRenameInfo(m, lineEnd);
|
||||||
} else {
|
} else {
|
||||||
m = renameableMethodPattern.matcher(line);
|
m = patternRenameableMethod.matcher(line);
|
||||||
if (m.find()) {
|
if (m.find()) {
|
||||||
if (ClassUtil.isObjectClassMethod(m.group(1), m.group(2), false)) {
|
if (ClassUtil.isObjectClassMethod(m.group(1), m.group(2), false)) {
|
||||||
JOptionPane.showMessageDialog(null, "This method can not be renamed!", "Error!",
|
JOptionPane.showMessageDialog(null, "This method can not be renamed!", "Error!",
|
||||||
@@ -815,6 +721,9 @@ public class Main extends JFrame {
|
|||||||
setRenameInfo(m, lineEnd);
|
setRenameInfo(m, lineEnd);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} catch (BadLocationException ex) {
|
||||||
|
ex.printStackTrace();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setRenameInfo(Matcher m, int lineEnd) throws BadLocationException {
|
public void setRenameInfo(Matcher m, int lineEnd) throws BadLocationException {
|
||||||
@@ -838,9 +747,9 @@ public class Main extends JFrame {
|
|||||||
String[] split = s.split(" ");
|
String[] split = s.split(" ");
|
||||||
String className = UnicodeUtils.unescape(null, split[split.length - 1], true);
|
String className = UnicodeUtils.unescape(null, split[split.length - 1], true);
|
||||||
renameBox.className = className;
|
renameBox.className = className;
|
||||||
String name = UnicodeUtils.unescape(null, m.pattern() == renameableFieldPattern ? m.group(2) : m.group(1),
|
String name = UnicodeUtils.unescape(null, m.pattern() == patternRenameableField ? m.group(2) : m.group(1),
|
||||||
true);
|
true);
|
||||||
String desc = UnicodeUtils.unescape(null, m.pattern() == renameableFieldPattern ? m.group(1) : m.group(2),
|
String desc = UnicodeUtils.unescape(null, m.pattern() == patternRenameableField ? m.group(1) : m.group(2),
|
||||||
true);
|
true);
|
||||||
renameBox.name = name;
|
renameBox.name = name;
|
||||||
renameBox.desc = desc;
|
renameBox.desc = desc;
|
||||||
@@ -864,7 +773,7 @@ public class Main extends JFrame {
|
|||||||
classNodes.put(getFullName(node.name), node);
|
classNodes.put(getFullName(node.name), node);
|
||||||
ArchiveTreeModel model;
|
ArchiveTreeModel model;
|
||||||
if (tree.getModel().getClass().equals(DefaultTreeModel.class)) {
|
if (tree.getModel().getClass().equals(DefaultTreeModel.class)) {
|
||||||
tree.setModel(model = new ArchiveTreeModel());
|
tree.setModel(model = new ArchiveTreeModel(classNodes, otherFiles));
|
||||||
} else {
|
} else {
|
||||||
model = (ArchiveTreeModel) tree.getModel();
|
model = (ArchiveTreeModel) tree.getModel();
|
||||||
}
|
}
|
||||||
@@ -890,11 +799,11 @@ public class Main extends JFrame {
|
|||||||
String dis = decompiler.getDecompiler().decompile(classNode);
|
String dis = decompiler.getDecompiler().decompile(classNode);
|
||||||
String substr = current.substring(0, current.length() - 6);
|
String substr = current.substring(0, current.length() - 6);
|
||||||
synchronized (Main.classNodes) {
|
synchronized (Main.classNodes) {
|
||||||
for (String key : Main.classNodes.keySet()) {
|
for (Entry<String, ClassNode> entry : Main.classNodes.entrySet()) {
|
||||||
if (key.contains("$")) {
|
if (entry.getKey().contains("$")) {
|
||||||
String[] split = key.split("\\$");
|
String[] split = entry.getKey().split("\\$");
|
||||||
if (split[0].equals(substr)) {
|
if (split[0].equals(substr)) {
|
||||||
dis += "\n" + decompiler.getDecompiler().decompile(classNodes.get(key));
|
dis += "\n" + decompiler.getDecompiler().decompile(entry.getValue());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1000,12 +909,12 @@ public class Main extends JFrame {
|
|||||||
if (name != null && !name.isEmpty()) {
|
if (name != null && !name.isEmpty()) {
|
||||||
String val = "Manifest-Version: 1.0\n" + "Class-Path: .\n" + "Main-Class: " + name.replace('/', '.')
|
String val = "Manifest-Version: 1.0\n" + "Class-Path: .\n" + "Main-Class: " + name.replace('/', '.')
|
||||||
+ "\n\n";
|
+ "\n\n";
|
||||||
OTHER_FILES.put("META-INF/MANIFEST.MF", val.getBytes());
|
otherFiles.put("META-INF/MANIFEST.MF", val.getBytes());
|
||||||
}
|
}
|
||||||
if (tree.getModel() instanceof ArchiveTreeModel)
|
if (tree.getModel() instanceof ArchiveTreeModel)
|
||||||
((ArchiveTreeModel) tree.getModel()).newCreated = false;
|
((ArchiveTreeModel) tree.getModel()).newCreated = false;
|
||||||
}
|
}
|
||||||
for (Entry<String, byte[]> entry : OTHER_FILES.entrySet()) {
|
for (Entry<String, byte[]> entry : otherFiles.entrySet()) {
|
||||||
ZipEntry ent = new ZipEntry(entry.getKey());
|
ZipEntry ent = new ZipEntry(entry.getKey());
|
||||||
output.putNextEntry(ent);
|
output.putNextEntry(ent);
|
||||||
output.write(entry.getValue());
|
output.write(entry.getValue());
|
||||||
@@ -1051,187 +960,4 @@ public class Main extends JFrame {
|
|||||||
public static String getFullName(String s) {
|
public static String getFullName(String s) {
|
||||||
return s + ".class";
|
return s + ".class";
|
||||||
}
|
}
|
||||||
|
|
||||||
class ArchiveTreeModel extends DefaultTreeModel {
|
|
||||||
|
|
||||||
public ArrayList<String> paths = new ArrayList<>();
|
|
||||||
public boolean newCreated = false;
|
|
||||||
|
|
||||||
public ArchiveTreeModel() {
|
|
||||||
super(new ByteEditTreeNode("New"));
|
|
||||||
newCreated = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ArchiveTreeModel(ZipFile jar) {
|
|
||||||
super(new ByteEditTreeNode(jar.getName().split(File.separator.equals("\\") ? "\\\\"
|
|
||||||
: File.separator)[jar.getName().split(File.separator.equals("\\") ? "\\\\" : File.separator).length
|
|
||||||
- 1]));
|
|
||||||
try {
|
|
||||||
classNodes.clear();
|
|
||||||
OTHER_FILES.clear();
|
|
||||||
Enumeration<? extends ZipEntry> enumeration = jar.entries();
|
|
||||||
while (enumeration.hasMoreElements()) {
|
|
||||||
ZipEntry next = enumeration.nextElement();
|
|
||||||
byte[] data = toByteArray(jar.getInputStream(next));
|
|
||||||
if (next.getSize() != 0 && !next.getName().startsWith("META-INF")
|
|
||||||
&& (next.getName().endsWith(".class") || next.getName().endsWith(".class/"))) {
|
|
||||||
try {
|
|
||||||
ClassReader reader = new ClassReader(data);
|
|
||||||
ClassNode node = new ClassNode();
|
|
||||||
reader.accept(node, 0);
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
OTHER_FILES.put(next.getName(), data);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
jar.close();
|
|
||||||
refresh();
|
|
||||||
} catch (Throwable e) {
|
|
||||||
classNodes.clear();
|
|
||||||
OTHER_FILES.clear();
|
|
||||||
e.printStackTrace();
|
|
||||||
showError(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private int getSlashCount(String s) {
|
|
||||||
int count = 0;
|
|
||||||
for (char c : s.toCharArray()) {
|
|
||||||
if (c == '/')
|
|
||||||
count++;
|
|
||||||
}
|
|
||||||
return count;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void refresh() {
|
|
||||||
setRoot(new ByteEditTreeNode(((ByteEditTreeNode) getRoot()).toString()));
|
|
||||||
Collections.sort(paths, String.CASE_INSENSITIVE_ORDER);
|
|
||||||
Collections.sort(paths, new Comparator<String>() {
|
|
||||||
public int compare(String s1, String s2) {
|
|
||||||
return getSlashCount(s2) - getSlashCount(s1);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// Windows-like sorting (like file explorer)
|
|
||||||
List<String> tmp = new ArrayList<>(paths);
|
|
||||||
|
|
||||||
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);
|
|
||||||
if (idx == -1)
|
|
||||||
return s;
|
|
||||||
return s.substring(0, idx);
|
|
||||||
}).distinct().sorted(new Comparator<String>() {
|
|
||||||
@Override
|
|
||||||
public int compare(String s, String s2) {
|
|
||||||
// From String#compareToIgnoreCase(String)
|
|
||||||
int n = s.length();
|
|
||||||
int n2 = s2.length();
|
|
||||||
int n3 = Math.min(n, n2);
|
|
||||||
for (int i = 0; i < n3; ++i) {
|
|
||||||
char c;
|
|
||||||
char c2 = s.charAt(i);
|
|
||||||
if (c2 == (c = s2.charAt(i))
|
|
||||||
|| (c2 = Character.toUpperCase(c2)) == (c = Character.toUpperCase(c))
|
|
||||||
|| (c2 = Character.toLowerCase(c2)) == (c = Character.toLowerCase(c)))
|
|
||||||
continue;
|
|
||||||
return c2 - c;
|
|
||||||
}
|
|
||||||
// Other way around
|
|
||||||
return n2 - n;
|
|
||||||
}
|
|
||||||
}).collect(Collectors.toList());
|
|
||||||
|
|
||||||
tmp.removeAll(folders);
|
|
||||||
tmp.addAll(0, folders);
|
|
||||||
|
|
||||||
for (String s : tmp) {
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private ByteEditTreeNode findNode(ByteEditTreeNode parent, String name) {
|
|
||||||
Enumeration<?> e = parent.children();
|
|
||||||
while (e.hasMoreElements()) {
|
|
||||||
ByteEditTreeNode element = (ByteEditTreeNode) e.nextElement();
|
|
||||||
if (element.getUserObject().equals(name)) {
|
|
||||||
return element;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
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 {
|
|
||||||
public void treeExpanded(TreeExpansionEvent event) {
|
|
||||||
TreePath treePath = event.getPath();
|
|
||||||
Object expandedTreePathObject = treePath.getLastPathComponent();
|
|
||||||
if (!(expandedTreePathObject instanceof TreeNode))
|
|
||||||
return;
|
|
||||||
TreeNode expandedTreeNode = (TreeNode) expandedTreePathObject;
|
|
||||||
if (expandedTreeNode.getChildCount() == 1) {
|
|
||||||
TreeNode descendantTreeNode = expandedTreeNode.getChildAt(0);
|
|
||||||
if (descendantTreeNode.isLeaf())
|
|
||||||
return;
|
|
||||||
TreePath nextTreePath = treePath.pathByAddingChild(descendantTreeNode);
|
|
||||||
tree.expandPath(nextTreePath);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void treeCollapsed(TreeExpansionEvent event) {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static byte[] toByteArray(final InputStream input) throws IOException {
|
|
||||||
try (final ByteArrayOutputStream output = new ByteArrayOutputStream()) {
|
|
||||||
byte[] buffer = new byte[4096];
|
|
||||||
int read;
|
|
||||||
while ((read = input.read(buffer)) != -1) {
|
|
||||||
output.write(buffer, 0, read);
|
|
||||||
}
|
|
||||||
return output.toByteArray();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
Reference in new issue
Block a user