mirror of
https://github.com/SuspiciousActivity/ByteEdit.git
synced 2026-08-13 17:56:17 +00:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5bec62789e | ||
|
|
be2930f720 | ||
|
|
e665527182 | ||
|
|
3a30fbdd78 | ||
|
|
bc0ec73071 | ||
|
|
b2267947c8 | ||
|
|
15c581ceb6 | ||
|
|
c0005493fd |
No files matched your search
@@ -2,8 +2,6 @@
|
|||||||
A simple, text based Java Bytecode Editor.
|
A simple, text based Java Bytecode Editor.
|
||||||
It uses ObjectWeb ASM (http://asm.ow2.org/) and the RSyntaxTextArea from https://github.com/bobbylight/RSyntaxTextArea
|
It uses ObjectWeb ASM (http://asm.ow2.org/) and the RSyntaxTextArea from https://github.com/bobbylight/RSyntaxTextArea
|
||||||
|
|
||||||
Get the precompiled version from here: https://github.com/SuspiciousActivity/Random-Java-Stuff/blob/master/ByteEdit.jar
|
|
||||||
|
|
||||||
To open up a file, drag it onto the left side. To save a class, press CTRL + S on the right side, to save the jar file, press on the left side. With F5 you can reload either the file or only the class.
|
To open up a file, drag it onto the left side. To save a class, press CTRL + S on the right side, to save the jar file, press on the left side. With F5 you can reload either the file or only the class.
|
||||||
|
|
||||||
To search/replace in a file, press CTRL + F.
|
To search/replace in a file, press CTRL + F.
|
||||||
@@ -12,12 +10,10 @@ To open a class, press CTRL + T.
|
|||||||
|
|
||||||
To change settings like auto-computation of stack frames and max locals/stack press CTRL + O.
|
To change settings like auto-computation of stack frames and max locals/stack press CTRL + O.
|
||||||
|
|
||||||
To go to the field/method definition in the selected line press CTRL + G.
|
|
||||||
|
|
||||||
To (un-)escape unicode characters, press CTRL + U.
|
To (un-)escape unicode characters, press CTRL + U.
|
||||||
|
|
||||||
To rename a field/method with attention to references in the selected line, press CTRL + R.
|
To rename a field/method with attention to references in the selected line, press CTRL + R.
|
||||||
|
|
||||||
To quickly compile some java code, press CTRL + E.
|
To quickly compile some java code, press CTRL + E.
|
||||||
|
|
||||||
To switch between light and dark theme, press CTRL + B.
|
To switch between themes, press CTRL + B.
|
||||||
@@ -32,7 +32,8 @@ import org.fife.ui.rtextarea.RTextScrollPane;
|
|||||||
import org.objectweb.asm.ClassReader;
|
import org.objectweb.asm.ClassReader;
|
||||||
import org.objectweb.asm.tree.ClassNode;
|
import org.objectweb.asm.tree.ClassNode;
|
||||||
|
|
||||||
import me.ByteEdit.edit.Disassembler;
|
import me.ByteEdit.decompiler.EnumDecompiler;
|
||||||
|
import me.ByteEdit.decompiler.SingleThreadedExecutor;
|
||||||
import me.ByteEdit.main.Main;
|
import me.ByteEdit.main.Main;
|
||||||
import me.ByteEdit.main.ThemeManager;
|
import me.ByteEdit.main.ThemeManager;
|
||||||
|
|
||||||
@@ -105,6 +106,8 @@ public class CompilationBox extends JFrame {
|
|||||||
null, Arrays.asList(new JavaSourceFromString("Compiled", source))).call();
|
null, Arrays.asList(new JavaSourceFromString("Compiled", source))).call();
|
||||||
String res = out.toString();
|
String res = out.toString();
|
||||||
if (res.isEmpty()) {
|
if (res.isEmpty()) {
|
||||||
|
SingleThreadedExecutor.execute(() -> {
|
||||||
|
try {
|
||||||
File clazz = new File(tmpFolder, "Compiled.class");
|
File clazz = new File(tmpFolder, "Compiled.class");
|
||||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||||
InputStream is = new FileInputStream(clazz);
|
InputStream is = new FileInputStream(clazz);
|
||||||
@@ -114,10 +117,12 @@ public class CompilationBox extends JFrame {
|
|||||||
baos.write(tmp, 0, r);
|
baos.write(tmp, 0, r);
|
||||||
}
|
}
|
||||||
is.close();
|
is.close();
|
||||||
|
|
||||||
ClassReader read = new ClassReader(baos.toByteArray());
|
ClassReader read = new ClassReader(baos.toByteArray());
|
||||||
ClassNode node = new ClassNode();
|
ClassNode node = new ClassNode();
|
||||||
read.accept(node, 0);
|
read.accept(node, 0);
|
||||||
String dis = Disassembler.disassemble(node);
|
EnumDecompiler decompiler = EnumDecompiler.BYTEEDIT;
|
||||||
|
String dis = decompiler.getDecompiler().decompile(node);
|
||||||
File[] files = tmpFolder.listFiles();
|
File[] files = tmpFolder.listFiles();
|
||||||
if (files != null)
|
if (files != null)
|
||||||
for (File f : files) {
|
for (File f : files) {
|
||||||
@@ -132,10 +137,15 @@ public class CompilationBox extends JFrame {
|
|||||||
read = new ClassReader(baos.toByteArray());
|
read = new ClassReader(baos.toByteArray());
|
||||||
node = new ClassNode();
|
node = new ClassNode();
|
||||||
read.accept(node, 0);
|
read.accept(node, 0);
|
||||||
dis += "\n" + Disassembler.disassemble(node);
|
dis += "\n" + decompiler.getDecompiler().decompile(node);
|
||||||
}
|
}
|
||||||
compSuccess.textArea.setText(dis);
|
compSuccess.textArea.setText(dis);
|
||||||
compSuccess.setVisible(true);
|
compSuccess.setVisible(true);
|
||||||
|
} catch (IOException e2) {
|
||||||
|
e2.printStackTrace();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
JOptionPane.showMessageDialog(CompilationBox.this, res, "Error!", JOptionPane.ERROR_MESSAGE);
|
JOptionPane.showMessageDialog(CompilationBox.this, res, "Error!", JOptionPane.ERROR_MESSAGE);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,10 +11,10 @@ import javax.swing.ListSelectionModel;
|
|||||||
import javax.swing.border.EmptyBorder;
|
import javax.swing.border.EmptyBorder;
|
||||||
import javax.swing.event.ListSelectionEvent;
|
import javax.swing.event.ListSelectionEvent;
|
||||||
import javax.swing.event.ListSelectionListener;
|
import javax.swing.event.ListSelectionListener;
|
||||||
import javax.swing.text.BadLocationException;
|
|
||||||
|
|
||||||
import org.objectweb.asm.tree.MethodNode;
|
import org.objectweb.asm.tree.MethodNode;
|
||||||
|
|
||||||
|
import me.ByteEdit.decompiler.SingleThreadedExecutor;
|
||||||
import me.ByteEdit.main.Main;
|
import me.ByteEdit.main.Main;
|
||||||
|
|
||||||
public class GlobalSearchOpenBox extends JFrame {
|
public class GlobalSearchOpenBox extends JFrame {
|
||||||
@@ -36,19 +36,13 @@ public class GlobalSearchOpenBox extends JFrame {
|
|||||||
model = new DefaultListModel<>();
|
model = new DefaultListModel<>();
|
||||||
JList<Info> list = new JList(model);
|
JList<Info> list = new JList(model);
|
||||||
list.addListSelectionListener(new ListSelectionListener() {
|
list.addListSelectionListener(new ListSelectionListener() {
|
||||||
|
|
||||||
public void valueChanged(ListSelectionEvent e) {
|
public void valueChanged(ListSelectionEvent e) {
|
||||||
|
SingleThreadedExecutor.execute(() -> {
|
||||||
Info val = list.getSelectedValue();
|
Info val = list.getSelectedValue();
|
||||||
if (val != null && !val.owner.equals(Main.currentNodeName)) {
|
if (val != null && !val.owner.equals(Main.currentNodeName)) {
|
||||||
int lineFound = Main.selectFileWithSearch(val.nodePath, val.mn);
|
Main.selectFile(val.nodePath);
|
||||||
if (lineFound != -1) {
|
|
||||||
try {
|
|
||||||
Main.txtByteEditView.setCaretPosition(Main.txtByteEditView.getLineStartOffset(lineFound));
|
|
||||||
} catch (BadLocationException e1) {
|
|
||||||
e1.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ import org.objectweb.asm.tree.FieldNode;
|
|||||||
import org.objectweb.asm.tree.MethodInsnNode;
|
import org.objectweb.asm.tree.MethodInsnNode;
|
||||||
import org.objectweb.asm.tree.MethodNode;
|
import org.objectweb.asm.tree.MethodNode;
|
||||||
|
|
||||||
import me.ByteEdit.edit.Disassembler;
|
import me.ByteEdit.decompiler.SingleThreadedExecutor;
|
||||||
import me.ByteEdit.main.Main;
|
import me.ByteEdit.main.Main;
|
||||||
import me.ByteEdit.utils.ClassUtil;
|
import me.ByteEdit.utils.ClassUtil;
|
||||||
import me.ByteEdit.utils.UnicodeUtils;
|
import me.ByteEdit.utils.UnicodeUtils;
|
||||||
@@ -210,27 +210,14 @@ public class RenameBox extends JFrame {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
try { // refresh
|
|
||||||
ClassNode classNode = Main.classNodes.get(Main.currentNodeName);
|
SingleThreadedExecutor.execute(() -> {
|
||||||
int prev = Main.txtByteEditView.getCaretPosition();
|
// refresh
|
||||||
String dis = Disassembler.disassemble(classNode);
|
Main.decompileCurrentNode();
|
||||||
String substr = Main.currentNodeName.substring(0, Main.currentNodeName.length() - 6);
|
|
||||||
for (String key : Main.classNodes.keySet()) {
|
|
||||||
if (key.contains("$")) {
|
|
||||||
String[] split = key.split("\\$");
|
|
||||||
if (split[0].equals(substr)) {
|
|
||||||
dis += "\n" + Disassembler.disassemble(Main.classNodes.get(key));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Main.txtByteEditView.setText(dis);
|
|
||||||
Main.txtByteEditView.setCaretPosition(prev);
|
|
||||||
} catch (Exception e2) {
|
|
||||||
e2.printStackTrace();
|
|
||||||
}
|
|
||||||
name = newName;
|
name = newName;
|
||||||
desc = newDesc;
|
desc = newDesc;
|
||||||
RenameBox.this.setVisible(false);
|
RenameBox.this.setVisible(false);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
btnRename.setBounds(345, 237, 89, 23);
|
btnRename.setBounds(345, 237, 89, 23);
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ import javax.swing.event.DocumentListener;
|
|||||||
import javax.swing.event.ListSelectionEvent;
|
import javax.swing.event.ListSelectionEvent;
|
||||||
import javax.swing.event.ListSelectionListener;
|
import javax.swing.event.ListSelectionListener;
|
||||||
|
|
||||||
|
import me.ByteEdit.decompiler.SingleThreadedExecutor;
|
||||||
import me.ByteEdit.main.Main;
|
import me.ByteEdit.main.Main;
|
||||||
import me.ByteEdit.utils.UnicodeUtils;
|
import me.ByteEdit.utils.UnicodeUtils;
|
||||||
|
|
||||||
@@ -43,7 +44,8 @@ public class TypeOpenBox extends JFrame {
|
|||||||
public void valueChanged(ListSelectionEvent e) {
|
public void valueChanged(ListSelectionEvent e) {
|
||||||
String val = list.getSelectedValue();
|
String val = list.getSelectedValue();
|
||||||
if (val != null && !val.equals(Main.currentNodeName)) {
|
if (val != null && !val.equals(Main.currentNodeName)) {
|
||||||
Main.selectFile(val);
|
|
||||||
|
SingleThreadedExecutor.execute(() -> Main.selectFile(val));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -0,0 +1,153 @@
|
|||||||
|
package me.ByteEdit.decompiler;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.PrintWriter;
|
||||||
|
import java.io.StringWriter;
|
||||||
|
import java.lang.reflect.Field;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import org.benf.cfr.reader.PluginRunner;
|
||||||
|
import org.benf.cfr.reader.api.ClassFileSource;
|
||||||
|
import org.benf.cfr.reader.bytecode.analysis.parse.utils.Pair;
|
||||||
|
import org.benf.cfr.reader.entities.ClassFile;
|
||||||
|
import org.benf.cfr.reader.entities.Method;
|
||||||
|
import org.benf.cfr.reader.entities.constantpool.ConstantPool;
|
||||||
|
import org.benf.cfr.reader.state.ClassFileSourceImpl;
|
||||||
|
import org.benf.cfr.reader.state.DCCommonState;
|
||||||
|
import org.benf.cfr.reader.util.bytestream.BaseByteData;
|
||||||
|
import org.benf.cfr.reader.util.getopt.OptionsImpl;
|
||||||
|
import org.benf.cfr.reader.util.output.ToStringDumper;
|
||||||
|
import org.objectweb.asm.tree.ClassNode;
|
||||||
|
import org.objectweb.asm.tree.MethodNode;
|
||||||
|
|
||||||
|
public class CFRDecompiler implements IDecompiler {
|
||||||
|
|
||||||
|
public static final HashMap<String, String> options = new HashMap<>();
|
||||||
|
|
||||||
|
static {
|
||||||
|
options.put("aexagg", "false");
|
||||||
|
options.put("allowcorrecting", "true");
|
||||||
|
options.put("arrayiter", "true");
|
||||||
|
options.put("caseinsensitivefs", "false");
|
||||||
|
options.put("clobber", "false");
|
||||||
|
options.put("collectioniter", "true");
|
||||||
|
options.put("commentmonitors", "false");
|
||||||
|
options.put("decodeenumswitch", "true");
|
||||||
|
options.put("decodefinally", "true");
|
||||||
|
options.put("decodelambdas", "true");
|
||||||
|
options.put("decodestringswitch", "true");
|
||||||
|
options.put("dumpclasspath", "false");
|
||||||
|
options.put("eclipse", "true");
|
||||||
|
options.put("elidescala", "false");
|
||||||
|
options.put("forcecondpropagate", "false");
|
||||||
|
options.put("forceexceptionprune", "false");
|
||||||
|
options.put("forcereturningifs", "false");
|
||||||
|
options.put("forcetopsort", "false");
|
||||||
|
options.put("forcetopsortaggress", "false");
|
||||||
|
options.put("forloopaggcapture", "false");
|
||||||
|
options.put("hidebridgemethods", "false");
|
||||||
|
options.put("hidelangimports", "true");
|
||||||
|
options.put("hidelongstrings", "false");
|
||||||
|
options.put("hideutf", "true");
|
||||||
|
options.put("innerclasses", "true");
|
||||||
|
options.put("j14classobj", "false");
|
||||||
|
options.put("labelledblocks", "true");
|
||||||
|
options.put("lenient", "false");
|
||||||
|
options.put("liftconstructorinit", "true");
|
||||||
|
options.put("override", "true");
|
||||||
|
options.put("pullcodecase", "false");
|
||||||
|
options.put("recover", "true");
|
||||||
|
options.put("recovertypeclash", "false");
|
||||||
|
options.put("recovertypehints", "false");
|
||||||
|
options.put("relinkconststring", "true");
|
||||||
|
options.put("removebadgenerics", "true");
|
||||||
|
options.put("removeboilerplate", "true");
|
||||||
|
options.put("removedeadmethods", "true");
|
||||||
|
options.put("removeinnerclasssynthetics", "true");
|
||||||
|
options.put("rename", "false");
|
||||||
|
options.put("renamedupmembers", "false");
|
||||||
|
options.put("renameenumidents", "false");
|
||||||
|
options.put("renameillegalidents", "false");
|
||||||
|
options.put("showinferrable", "false");
|
||||||
|
options.put("silent", "false");
|
||||||
|
options.put("stringbuffer", "false");
|
||||||
|
options.put("stringbuilder", "true");
|
||||||
|
options.put("sugarasserts", "true");
|
||||||
|
options.put("sugarboxing", "true");
|
||||||
|
options.put("sugarenums", "true");
|
||||||
|
options.put("tidymonitors", "true");
|
||||||
|
options.put("usenametable", "true");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String decompile(ClassNode cn) {
|
||||||
|
return doDecompilation(cn, getBytes(cn), null);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String doDecompilation(ClassNode cn, byte[] b, MethodNode mn) {
|
||||||
|
try {
|
||||||
|
HashMap<String, String> ops = options;
|
||||||
|
ClassFileSource cfs = new ClassFileSource() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void informAnalysisRelativePathDetail(String a, String b) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getPossiblyRenamedPath(String path) {
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Pair<byte[], String> getClassFileContent(String path) throws IOException {
|
||||||
|
String name = path.substring(0, path.length() - 6);
|
||||||
|
if (name.equals(cn.name)) {
|
||||||
|
return Pair.make(b, name);
|
||||||
|
}
|
||||||
|
return null; // cfr loads unnecessary classes
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Collection<String> addJar(String arg0) {
|
||||||
|
throw new RuntimeException();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
PluginRunner runner = new PluginRunner(ops, cfs);
|
||||||
|
if (mn != null) {
|
||||||
|
BaseByteData data = new BaseByteData(b);
|
||||||
|
ClassFile cf = new ClassFile(data, "", initDCState(ops, cfs));
|
||||||
|
Field cpf = Method.class.getDeclaredField("cp");
|
||||||
|
Field descI = Method.class.getDeclaredField("descriptorIndex");
|
||||||
|
descI.setAccessible(true);
|
||||||
|
cpf.setAccessible(true);
|
||||||
|
for (Method m : cf.getMethodByName(mn.name)) {
|
||||||
|
ConstantPool cp = (ConstantPool) cpf.get(m);
|
||||||
|
if (cp.getUTF8Entry(descI.getInt(m)).getValue().equals(mn.desc)) {
|
||||||
|
ToStringDumper tsd = new ToStringDumper();
|
||||||
|
m.dump(tsd, true);
|
||||||
|
return tsd.toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
String decompilation = runner.getDecompilationFor(cn.name);
|
||||||
|
System.gc(); // cfr has a performance bug
|
||||||
|
return decompilation;
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
StringWriter sw = new StringWriter();
|
||||||
|
PrintWriter pw = new PrintWriter(sw);
|
||||||
|
e.printStackTrace(pw);
|
||||||
|
return sw.toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static DCCommonState initDCState(Map<String, String> optionsMap, ClassFileSource classFileSource) {
|
||||||
|
OptionsImpl options = new OptionsImpl(optionsMap);
|
||||||
|
if (classFileSource == null)
|
||||||
|
classFileSource = new ClassFileSourceImpl(options);
|
||||||
|
DCCommonState dcCommonState = new DCCommonState(options, classFileSource);
|
||||||
|
return dcCommonState;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,45 @@
|
|||||||
|
package me.ByteEdit.decompiler;
|
||||||
|
|
||||||
|
import org.fife.ui.rsyntaxtextarea.SyntaxConstants;
|
||||||
|
|
||||||
|
import me.ByteEdit.edit.Disassembler;
|
||||||
|
|
||||||
|
public enum EnumDecompiler {
|
||||||
|
BYTEEDIT("ByteEdit", new Disassembler(), false), PROCYON("Procyon", new ProcyonDecompiler()),
|
||||||
|
FERNFLOWER("FernFlower", new FernflowerDecompiler()), JD_GUI("JD-GUI", new JDDecompiler()),
|
||||||
|
CFR("CFR", new CFRDecompiler());
|
||||||
|
|
||||||
|
private final String name;
|
||||||
|
private final IDecompiler decompiler;
|
||||||
|
private final String syntaxStyle;
|
||||||
|
private final boolean isEditable;
|
||||||
|
|
||||||
|
private EnumDecompiler(String name, IDecompiler decompiler) {
|
||||||
|
this(name, decompiler, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
private EnumDecompiler(String name, IDecompiler decompiler, boolean isDecompiler) {
|
||||||
|
this.name = name;
|
||||||
|
this.decompiler = decompiler;
|
||||||
|
this.syntaxStyle = isDecompiler ? SyntaxConstants.SYNTAX_STYLE_JAVA
|
||||||
|
: SyntaxConstants.SYNTAX_STYLE_JAVA_DISASSEMBLE;
|
||||||
|
this.isEditable = !isDecompiler;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IDecompiler getDecompiler() {
|
||||||
|
return decompiler;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getSyntaxStyle() {
|
||||||
|
return syntaxStyle;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isEditable() {
|
||||||
|
return isEditable;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,142 @@
|
|||||||
|
package me.ByteEdit.decompiler;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.PrintWriter;
|
||||||
|
import java.io.StringWriter;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.jar.Manifest;
|
||||||
|
|
||||||
|
import org.jetbrains.java.decompiler.main.Fernflower;
|
||||||
|
import org.jetbrains.java.decompiler.main.extern.IBytecodeProvider;
|
||||||
|
import org.jetbrains.java.decompiler.main.extern.IFernflowerLogger;
|
||||||
|
import org.jetbrains.java.decompiler.main.extern.IResultSaver;
|
||||||
|
import org.jetbrains.java.decompiler.struct.ContextUnit;
|
||||||
|
import org.jetbrains.java.decompiler.struct.StructClass;
|
||||||
|
import org.jetbrains.java.decompiler.struct.StructContext;
|
||||||
|
import org.jetbrains.java.decompiler.struct.lazy.LazyLoader;
|
||||||
|
import org.objectweb.asm.tree.ClassNode;
|
||||||
|
import org.objectweb.asm.tree.MethodNode;
|
||||||
|
|
||||||
|
public class FernflowerDecompiler implements IBytecodeProvider, IResultSaver, IDecompiler {
|
||||||
|
|
||||||
|
private byte[] bytes;
|
||||||
|
private String returned;
|
||||||
|
|
||||||
|
public static final HashMap<String, Boolean> options = new HashMap<>();
|
||||||
|
|
||||||
|
static {
|
||||||
|
options.put("rbr", true);
|
||||||
|
options.put("rsy", false);
|
||||||
|
options.put("din", true);
|
||||||
|
options.put("dc4", true);
|
||||||
|
options.put("das", true);
|
||||||
|
options.put("hes", true);
|
||||||
|
options.put("hdc", true);
|
||||||
|
options.put("dgs", false);
|
||||||
|
options.put("ner", true);
|
||||||
|
options.put("den", true);
|
||||||
|
options.put("rgn", true);
|
||||||
|
options.put("lit", false);
|
||||||
|
options.put("asc", true);
|
||||||
|
options.put("bto", true);
|
||||||
|
options.put("nns", false);
|
||||||
|
options.put("uto", true);
|
||||||
|
options.put("udv", true);
|
||||||
|
options.put("rer", true);
|
||||||
|
options.put("fdi", true);
|
||||||
|
options.put("ren", false);
|
||||||
|
options.put("inn", true);
|
||||||
|
options.put("lac", false);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String decompile(ClassNode cn) {
|
||||||
|
return doDecompilation(cn, getBytes(cn), null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String doDecompilation(ClassNode cn, byte[] b, MethodNode mn) {
|
||||||
|
try {
|
||||||
|
// TODO decompile method only
|
||||||
|
this.bytes = b;
|
||||||
|
HashMap<String, Object> map = new HashMap<>();
|
||||||
|
for (String key : options.keySet()) {
|
||||||
|
map.put(key, options.get(key) ? "1" : "0");
|
||||||
|
}
|
||||||
|
Fernflower f = new Fernflower(this, this, map, new IFernflowerLogger() {
|
||||||
|
@Override
|
||||||
|
public void writeMessage(String message, Throwable t) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void writeMessage(String message, Severity severity) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean accepts(Severity severity) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
StructContext sc = f.getStructContext();
|
||||||
|
StructClass cl = new StructClass(b, true, sc.getLoader());
|
||||||
|
sc.getClasses().put(cn.name, cl);
|
||||||
|
// instead of loading a file use custom bridge, created a few getters
|
||||||
|
String fakePath = new File("none.class").getAbsolutePath();
|
||||||
|
ContextUnit unit = new ContextUnit(ContextUnit.TYPE_FOLDER, null, fakePath, true, sc.getSaver(),
|
||||||
|
sc.getDecompiledData());
|
||||||
|
sc.getUnits().put(fakePath, unit);
|
||||||
|
unit.addClass(cl, "none.class");
|
||||||
|
sc.getLoader().addClassLink(cn.name, new LazyLoader.Link(LazyLoader.Link.CLASS, fakePath, null));
|
||||||
|
|
||||||
|
f.decompileContext();
|
||||||
|
return returned;
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
StringWriter sw = new StringWriter();
|
||||||
|
PrintWriter pw = new PrintWriter(sw);
|
||||||
|
e.printStackTrace(pw);
|
||||||
|
return sw.toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public byte[] getBytecode(String externalPath, String internalPath) throws IOException {
|
||||||
|
return bytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
// we can ignore most of those methods because we do not want to save the output
|
||||||
|
// as a file
|
||||||
|
@Override
|
||||||
|
public void saveFolder(String path) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void copyFile(String source, String path, String entryName) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void saveClassFile(String path, String qualifiedName, String entryName, String content, int[] mapping) {
|
||||||
|
this.returned = content;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void createArchive(String path, String archiveName, Manifest manifest) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void saveDirEntry(String path, String archiveName, String entryName) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void copyEntry(String source, String path, String archiveName, String entry) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void saveClassEntry(String path, String archiveName, String qualifiedName, String entryName,
|
||||||
|
String content) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void closeArchive(String path, String archiveName) {
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
package me.ByteEdit.decompiler;
|
||||||
|
|
||||||
|
import org.objectweb.asm.ClassWriter;
|
||||||
|
import org.objectweb.asm.tree.ClassNode;
|
||||||
|
|
||||||
|
public interface IDecompiler {
|
||||||
|
|
||||||
|
String decompile(ClassNode cn);
|
||||||
|
|
||||||
|
default byte[] getBytes(ClassNode cn) {
|
||||||
|
ClassWriter classWriter = new ClassWriter(0);
|
||||||
|
cn.accept(classWriter);
|
||||||
|
return classWriter.toByteArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,130 @@
|
|||||||
|
package me.ByteEdit.decompiler;
|
||||||
|
|
||||||
|
import org.jd.core.v1.ClassFileToJavaSourceDecompiler;
|
||||||
|
import org.jd.core.v1.api.loader.Loader;
|
||||||
|
import org.jd.core.v1.api.loader.LoaderException;
|
||||||
|
import org.jd.core.v1.api.printer.Printer;
|
||||||
|
import org.objectweb.asm.ClassWriter;
|
||||||
|
import org.objectweb.asm.tree.ClassNode;
|
||||||
|
|
||||||
|
import me.ByteEdit.main.Main;
|
||||||
|
|
||||||
|
public class JDDecompiler implements Loader, Printer, IDecompiler {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String decompile(ClassNode cn) {
|
||||||
|
ClassFileToJavaSourceDecompiler decompiler = new ClassFileToJavaSourceDecompiler();
|
||||||
|
try {
|
||||||
|
decompiler.decompile(this, this, cn.name);
|
||||||
|
} catch (Throwable e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
String str = e.getClass().getName() + " - " + e.getMessage() + System.lineSeparator();
|
||||||
|
for (int i = 0; i < e.getStackTrace().length; i++) {
|
||||||
|
str += e.getStackTrace()[i].toString() + System.lineSeparator();
|
||||||
|
}
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
String decomp = toString();
|
||||||
|
indentationCount = 0;
|
||||||
|
sb = new StringBuilder();
|
||||||
|
return decomp;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean canLoad(String internalName) {
|
||||||
|
return Main.classNodes.containsKey(internalName + ".class");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public byte[] load(String internalName) throws LoaderException {
|
||||||
|
ClassNode cl = Main.classNodes.get(internalName + ".class");
|
||||||
|
ClassWriter cw = new ClassWriter(0);
|
||||||
|
cl.accept(cw);
|
||||||
|
return cw.toByteArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected static final String TAB = " ";
|
||||||
|
protected static final String NEWLINE = "\n";
|
||||||
|
|
||||||
|
protected int indentationCount = 0;
|
||||||
|
protected StringBuilder sb = new StringBuilder();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return sb.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void start(int maxLineNumber, int majorVersion, int minorVersion) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void end() {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void printText(String text) {
|
||||||
|
sb.append(text);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void printNumericConstant(String constant) {
|
||||||
|
sb.append(constant);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void printStringConstant(String constant, String ownerInternalName) {
|
||||||
|
sb.append(constant);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void printKeyword(String keyword) {
|
||||||
|
sb.append(keyword);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void printDeclaration(int type, String internalTypeName, String name, String descriptor) {
|
||||||
|
sb.append(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void printReference(int type, String internalTypeName, String name, String descriptor,
|
||||||
|
String ownerInternalName) {
|
||||||
|
sb.append(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void indent() {
|
||||||
|
this.indentationCount++;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void unindent() {
|
||||||
|
this.indentationCount--;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void startLine(int lineNumber) {
|
||||||
|
for (int i = 0; i < indentationCount; i++)
|
||||||
|
sb.append(TAB);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void endLine() {
|
||||||
|
sb.append(NEWLINE);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void extraLine(int count) {
|
||||||
|
while (count-- > 0)
|
||||||
|
sb.append(NEWLINE);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void startMarker(int type) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void endMarker(int type) {
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,76 @@
|
|||||||
|
package me.ByteEdit.decompiler;
|
||||||
|
|
||||||
|
import java.io.PrintWriter;
|
||||||
|
import java.io.StringWriter;
|
||||||
|
import java.lang.reflect.Field;
|
||||||
|
|
||||||
|
import org.objectweb.asm.tree.ClassNode;
|
||||||
|
import org.objectweb.asm.tree.MethodNode;
|
||||||
|
|
||||||
|
import com.strobel.assembler.InputTypeLoader;
|
||||||
|
import com.strobel.assembler.metadata.Buffer;
|
||||||
|
import com.strobel.assembler.metadata.ITypeLoader;
|
||||||
|
import com.strobel.assembler.metadata.MetadataSystem;
|
||||||
|
import com.strobel.assembler.metadata.TypeDefinition;
|
||||||
|
import com.strobel.assembler.metadata.TypeReference;
|
||||||
|
import com.strobel.decompiler.DecompilationOptions;
|
||||||
|
import com.strobel.decompiler.DecompilerSettings;
|
||||||
|
import com.strobel.decompiler.PlainTextOutput;
|
||||||
|
|
||||||
|
public class ProcyonDecompiler implements IDecompiler {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String decompile(ClassNode cn) {
|
||||||
|
return doDecompilation(cn, getBytes(cn), null);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String doDecompilation(ClassNode cn, byte[] b, MethodNode mn) {
|
||||||
|
try {
|
||||||
|
// TODO decompile method only
|
||||||
|
DecompilerSettings settings = new DecompilerSettings();
|
||||||
|
try {
|
||||||
|
for (Field f : settings.getClass().getDeclaredFields()) {
|
||||||
|
if (f.getType() == boolean.class) {
|
||||||
|
f.setAccessible(true);
|
||||||
|
f.setBoolean(settings, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (Throwable t) {
|
||||||
|
t.printStackTrace();
|
||||||
|
}
|
||||||
|
settings.setShowSyntheticMembers(true);
|
||||||
|
MetadataSystem metadataSystem = new MetadataSystem(new ITypeLoader() {
|
||||||
|
private InputTypeLoader backLoader = new InputTypeLoader();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean tryLoadType(String s, Buffer buffer) {
|
||||||
|
if (s.equals(cn.name)) {
|
||||||
|
buffer.putByteArray(b, 0, b.length);
|
||||||
|
buffer.position(0);
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return backLoader.tryLoadType(s, buffer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
TypeReference type = metadataSystem.lookupType(cn.name);
|
||||||
|
DecompilationOptions decompilationOptions = new DecompilationOptions();
|
||||||
|
decompilationOptions.setSettings(DecompilerSettings.javaDefaults());
|
||||||
|
decompilationOptions.setFullDecompilation(true);
|
||||||
|
TypeDefinition resolvedType = null;
|
||||||
|
if (type == null || ((resolvedType = type.resolve()) == null)) {
|
||||||
|
return "error";
|
||||||
|
}
|
||||||
|
StringWriter stringwriter = new StringWriter();
|
||||||
|
settings.getLanguage().decompileType(resolvedType, new PlainTextOutput(stringwriter), decompilationOptions);
|
||||||
|
String decompiledSource = stringwriter.toString();
|
||||||
|
return decompiledSource;
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
StringWriter sw = new StringWriter();
|
||||||
|
PrintWriter pw = new PrintWriter(sw);
|
||||||
|
e.printStackTrace(pw);
|
||||||
|
return sw.toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
package me.ByteEdit.decompiler;
|
||||||
|
|
||||||
|
import java.util.concurrent.LinkedBlockingQueue;
|
||||||
|
|
||||||
|
public class SingleThreadedExecutor {
|
||||||
|
|
||||||
|
private static final LinkedBlockingQueue<Runnable> queue = new LinkedBlockingQueue<>();
|
||||||
|
|
||||||
|
private static final Thread thread = new Thread(() -> {
|
||||||
|
while (true) {
|
||||||
|
try {
|
||||||
|
queue.take().run();
|
||||||
|
} catch (Throwable e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, "SingleThreadedExecutor");
|
||||||
|
|
||||||
|
static {
|
||||||
|
thread.start();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void execute(Runnable r) {
|
||||||
|
queue.add(r);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -27,7 +27,6 @@ import java.util.concurrent.ExecutorService;
|
|||||||
import java.util.concurrent.Executors;
|
import java.util.concurrent.Executors;
|
||||||
import java.util.concurrent.Future;
|
import java.util.concurrent.Future;
|
||||||
import java.util.concurrent.FutureTask;
|
import java.util.concurrent.FutureTask;
|
||||||
import java.util.concurrent.atomic.AtomicInteger;
|
|
||||||
|
|
||||||
import org.objectweb.asm.Handle;
|
import org.objectweb.asm.Handle;
|
||||||
import org.objectweb.asm.Label;
|
import org.objectweb.asm.Label;
|
||||||
@@ -58,52 +57,29 @@ import org.objectweb.asm.tree.TryCatchBlockNode;
|
|||||||
import org.objectweb.asm.tree.TypeInsnNode;
|
import org.objectweb.asm.tree.TypeInsnNode;
|
||||||
import org.objectweb.asm.tree.VarInsnNode;
|
import org.objectweb.asm.tree.VarInsnNode;
|
||||||
|
|
||||||
|
import me.ByteEdit.decompiler.IDecompiler;
|
||||||
import me.ByteEdit.main.Main;
|
import me.ByteEdit.main.Main;
|
||||||
import me.ByteEdit.utils.ClassUtil;
|
import me.ByteEdit.utils.ClassUtil;
|
||||||
import me.ByteEdit.utils.OpcodesReverse;
|
import me.ByteEdit.utils.OpcodesReverse;
|
||||||
import me.ByteEdit.utils.UnicodeUtils;
|
import me.ByteEdit.utils.UnicodeUtils;
|
||||||
|
|
||||||
public class Disassembler {
|
public class Disassembler implements IDecompiler {
|
||||||
|
|
||||||
private static final ExecutorService exec = Executors
|
private static final ExecutorService exec = Executors
|
||||||
.newFixedThreadPool((Runtime.getRuntime().availableProcessors() + 1) / 2);
|
.newFixedThreadPool((Runtime.getRuntime().availableProcessors() + 1) / 2);
|
||||||
|
|
||||||
public static String disassemble(ClassNode classNode) {
|
@Override
|
||||||
return disassemble(classNode, null).getDisassembly();
|
public String decompile(ClassNode cn) {
|
||||||
|
return disassemble(cn);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class DisassembleTuple {
|
private static String disassemble(ClassNode classNode) {
|
||||||
|
|
||||||
private final String dis;
|
|
||||||
private final int line;
|
|
||||||
|
|
||||||
public DisassembleTuple(String dis) {
|
|
||||||
this.dis = dis;
|
|
||||||
this.line = -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
public DisassembleTuple(String dis, int line) {
|
|
||||||
this.dis = dis;
|
|
||||||
this.line = line;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getDisassembly() {
|
|
||||||
return dis;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getLine() {
|
|
||||||
return line;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public static DisassembleTuple disassemble(ClassNode classNode, Object nodeToFind) {
|
|
||||||
if (classNode == null) {
|
if (classNode == null) {
|
||||||
return new DisassembleTuple("ClassNode is null! This is not a valid java class file!");
|
return "ClassNode is null! This is not a valid java class file!";
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
HugeStrings hs = new HugeStrings();
|
HugeStrings hs = new HugeStrings();
|
||||||
AtomicInteger lineFound = new AtomicInteger(-1);
|
|
||||||
StringContext ctx = new StringContext(18);
|
StringContext ctx = new StringContext(18);
|
||||||
ctx.next("// #Annotations:\n");
|
ctx.next("// #Annotations:\n");
|
||||||
ctx.next(doAnnotations(classNode.visibleAnnotations, hs, ""));
|
ctx.next(doAnnotations(classNode.visibleAnnotations, hs, ""));
|
||||||
@@ -149,19 +125,18 @@ public class Disassembler {
|
|||||||
+ (classNode.sourceFile == null ? "null" : UnicodeUtils.escape(hs, classNode.sourceFile)) + "\n");
|
+ (classNode.sourceFile == null ? "null" : UnicodeUtils.escape(hs, classNode.sourceFile)) + "\n");
|
||||||
int hugeIdx = ctx.next("");
|
int hugeIdx = ctx.next("");
|
||||||
ctx.next("\n// #Fields\n");
|
ctx.next("\n// #Fields\n");
|
||||||
ctx.next(doFields(classNode.fields, nodeToFind, lineFound, hs));
|
ctx.next(doFields(classNode.fields, hs));
|
||||||
ctx.next("\n// #Methods\n");
|
ctx.next("\n// #Methods\n");
|
||||||
ctx.next(doMethods(classNode.methods, classNode.name, nodeToFind, lineFound, hs));
|
ctx.next(doMethods(classNode.methods, classNode.name, hs));
|
||||||
ctx.next("}\n");
|
ctx.next("}\n");
|
||||||
|
|
||||||
if (!hs.isEmpty())
|
if (!hs.isEmpty())
|
||||||
ctx.set(hugeIdx, hs.makeStringsList());
|
ctx.set(hugeIdx, hs.makeStringsList());
|
||||||
return new DisassembleTuple(ctx.finish(), lineFound.get());
|
return ctx.finish();
|
||||||
} catch (Throwable e) {
|
} catch (Throwable e) {
|
||||||
return new DisassembleTuple("Class couldn't be decompiled:\n" + e.getClass().getName() + ": "
|
return "Class couldn't be decompiled:\n" + e.getClass().getName() + ": " + e.getMessage() + "\n"
|
||||||
+ e.getMessage() + "\n"
|
|
||||||
+ Arrays.toString(e.getStackTrace()).replace(", ", "\n\tat ").replace("[", "\tat ").replace("]", "")
|
+ Arrays.toString(e.getStackTrace()).replace(", ", "\n\tat ").replace("[", "\tat ").replace("]", "")
|
||||||
+ "\n");
|
+ "\n";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -232,8 +207,8 @@ public class Disassembler {
|
|||||||
return ctx.finish();
|
return ctx.finish();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static String doMethods(List<MethodNode> methods, String className, Object nodeToFind,
|
private static String doMethods(List<MethodNode> methods, String className, HugeStrings hs)
|
||||||
AtomicInteger lineFound, HugeStrings hs) throws InterruptedException, ExecutionException {
|
throws InterruptedException, ExecutionException {
|
||||||
boolean multithreaded = Main.INSTANCE.mntmMultithreaded.isSelected();
|
boolean multithreaded = Main.INSTANCE.mntmMultithreaded.isSelected();
|
||||||
Future<String>[] futures = new Future[methods.size()];
|
Future<String>[] futures = new Future[methods.size()];
|
||||||
for (int i = 0; i < futures.length; i++) {
|
for (int i = 0; i < futures.length; i++) {
|
||||||
@@ -251,9 +226,6 @@ public class Disassembler {
|
|||||||
ms += dis[1];
|
ms += dis[1];
|
||||||
if (mn.visibleAnnotations != null && !mn.visibleAnnotations.isEmpty())
|
if (mn.visibleAnnotations != null && !mn.visibleAnnotations.isEmpty())
|
||||||
ms += doAnnotations(mn.visibleAnnotations, hs, "\t");
|
ms += doAnnotations(mn.visibleAnnotations, hs, "\t");
|
||||||
if (mn.equals(nodeToFind)) {
|
|
||||||
lineFound.set(ms.split("\\n").length);
|
|
||||||
}
|
|
||||||
ms += "\t" + ClassUtil.getAccessFlagsFull(mn.access)
|
ms += "\t" + ClassUtil.getAccessFlagsFull(mn.access)
|
||||||
+ UnicodeUtils.escapeWithSpaces(hs, mn.name) + " "
|
+ UnicodeUtils.escapeWithSpaces(hs, mn.name) + " "
|
||||||
+ UnicodeUtils.escapeWithSpaces(hs, mn.desc) + " ";
|
+ UnicodeUtils.escapeWithSpaces(hs, mn.desc) + " ";
|
||||||
@@ -295,7 +267,7 @@ public class Disassembler {
|
|||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static String doFields(List<FieldNode> fields, Object nodeToFind, AtomicInteger lineFound, HugeStrings hs) {
|
private static String doFields(List<FieldNode> fields, HugeStrings hs) {
|
||||||
StringContext ctx = new StringContext(fields.size());
|
StringContext ctx = new StringContext(fields.size());
|
||||||
for (FieldNode fn : fields) {
|
for (FieldNode fn : fields) {
|
||||||
String s = "";
|
String s = "";
|
||||||
@@ -303,9 +275,6 @@ public class Disassembler {
|
|||||||
s += "\t// #Signature: " + UnicodeUtils.escapeWithSpaces(hs, fn.signature) + "\n";
|
s += "\t// #Signature: " + UnicodeUtils.escapeWithSpaces(hs, fn.signature) + "\n";
|
||||||
if (fn.visibleAnnotations != null && !fn.visibleAnnotations.isEmpty())
|
if (fn.visibleAnnotations != null && !fn.visibleAnnotations.isEmpty())
|
||||||
s += doAnnotations(fn.visibleAnnotations, hs, "\t");
|
s += doAnnotations(fn.visibleAnnotations, hs, "\t");
|
||||||
if (fn.equals(nodeToFind)) {
|
|
||||||
lineFound.set(s.split("\\n").length);
|
|
||||||
}
|
|
||||||
s += "\t" + ClassUtil.getAccessFlagsFull(fn.access).replace("varargs", "transient")
|
s += "\t" + ClassUtil.getAccessFlagsFull(fn.access).replace("varargs", "transient")
|
||||||
+ UnicodeUtils.escapeWithSpaces(hs, fn.desc) + " " + UnicodeUtils.escapeWithSpaces(hs, fn.name);
|
+ UnicodeUtils.escapeWithSpaces(hs, fn.desc) + " " + UnicodeUtils.escapeWithSpaces(hs, fn.name);
|
||||||
if (fn.value != null) {
|
if (fn.value != null) {
|
||||||
@@ -578,5 +547,4 @@ public class Disassembler {
|
|||||||
}
|
}
|
||||||
return "null";
|
return "null";
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -114,7 +114,8 @@ public class SearchBox extends JFrame {
|
|||||||
: Main.txtByteEditView.getText().substring(startPos).toLowerCase();
|
: Main.txtByteEditView.getText().substring(startPos).toLowerCase();
|
||||||
int index = txt.indexOf(chckbxCaseSensitive.isSelected() ? toFind : toFind.toLowerCase());
|
int index = txt.indexOf(chckbxCaseSensitive.isSelected() ? toFind : toFind.toLowerCase());
|
||||||
if (index == -1) {
|
if (index == -1) {
|
||||||
txt = chckbxCaseSensitive.isSelected() ? Main.txtByteEditView.getText() : Main.txtByteEditView.getText().toLowerCase();
|
txt = chckbxCaseSensitive.isSelected() ? Main.txtByteEditView.getText()
|
||||||
|
: Main.txtByteEditView.getText().toLowerCase();
|
||||||
index = txt.indexOf(chckbxCaseSensitive.isSelected() ? toFind : toFind.toLowerCase());
|
index = txt.indexOf(chckbxCaseSensitive.isSelected() ? toFind : toFind.toLowerCase());
|
||||||
startPos = 0;
|
startPos = 0;
|
||||||
if (index == -1) {
|
if (index == -1) {
|
||||||
@@ -144,7 +145,8 @@ public class SearchBox extends JFrame {
|
|||||||
if (chckbxCaseSensitive.isSelected()) {
|
if (chckbxCaseSensitive.isSelected()) {
|
||||||
Main.txtByteEditView.replaceRange(txt.replace(toFind, toReplace), 0, txt.length());
|
Main.txtByteEditView.replaceRange(txt.replace(toFind, toReplace), 0, txt.length());
|
||||||
} else {
|
} else {
|
||||||
Main.txtByteEditView.replaceRange(txt.replaceAll("(?i)" + Pattern.quote(toFind), toReplace), 0, txt.length());
|
Main.txtByteEditView.replaceRange(txt.replaceAll("(?i)" + Pattern.quote(toFind), toReplace), 0,
|
||||||
|
txt.length());
|
||||||
}
|
}
|
||||||
Main.txtByteEditView.setCaretPosition(prev);
|
Main.txtByteEditView.setCaretPosition(prev);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ import javax.swing.event.DocumentListener;
|
|||||||
import javax.swing.event.ListSelectionEvent;
|
import javax.swing.event.ListSelectionEvent;
|
||||||
import javax.swing.event.ListSelectionListener;
|
import javax.swing.event.ListSelectionListener;
|
||||||
|
|
||||||
|
import me.ByteEdit.decompiler.SingleThreadedExecutor;
|
||||||
import me.ByteEdit.main.Main;
|
import me.ByteEdit.main.Main;
|
||||||
|
|
||||||
public class TypeOpenBox extends JFrame {
|
public class TypeOpenBox extends JFrame {
|
||||||
@@ -51,7 +52,8 @@ public class TypeOpenBox extends JFrame {
|
|||||||
public void valueChanged(ListSelectionEvent e) {
|
public void valueChanged(ListSelectionEvent e) {
|
||||||
String val = list.getSelectedValue();
|
String val = list.getSelectedValue();
|
||||||
if (val != null && !val.equals(Main.currentNodeName)) {
|
if (val != null && !val.equals(Main.currentNodeName)) {
|
||||||
Main.selectFile(val);
|
|
||||||
|
SingleThreadedExecutor.execute(() -> Main.selectFile(val));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
+69
-132
@@ -1,5 +1,6 @@
|
|||||||
package me.ByteEdit.main;
|
package me.ByteEdit.main;
|
||||||
|
|
||||||
|
import java.awt.BorderLayout;
|
||||||
import java.awt.Component;
|
import java.awt.Component;
|
||||||
import java.awt.EventQueue;
|
import java.awt.EventQueue;
|
||||||
import java.awt.Font;
|
import java.awt.Font;
|
||||||
@@ -15,6 +16,8 @@ import java.awt.dnd.DropTargetEvent;
|
|||||||
import java.awt.dnd.DropTargetListener;
|
import java.awt.dnd.DropTargetListener;
|
||||||
import java.awt.event.ActionEvent;
|
import java.awt.event.ActionEvent;
|
||||||
import java.awt.event.ActionListener;
|
import java.awt.event.ActionListener;
|
||||||
|
import java.awt.event.ItemEvent;
|
||||||
|
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.awt.event.MouseEvent;
|
||||||
@@ -26,6 +29,7 @@ import java.io.IOException;
|
|||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.io.StringReader;
|
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.Collections;
|
||||||
import java.util.Comparator;
|
import java.util.Comparator;
|
||||||
@@ -41,7 +45,9 @@ import java.util.zip.ZipFile;
|
|||||||
import java.util.zip.ZipOutputStream;
|
import java.util.zip.ZipOutputStream;
|
||||||
|
|
||||||
import javax.swing.ButtonGroup;
|
import javax.swing.ButtonGroup;
|
||||||
|
import javax.swing.DefaultComboBoxModel;
|
||||||
import javax.swing.JCheckBoxMenuItem;
|
import javax.swing.JCheckBoxMenuItem;
|
||||||
|
import javax.swing.JComboBox;
|
||||||
import javax.swing.JComponent;
|
import javax.swing.JComponent;
|
||||||
import javax.swing.JDialog;
|
import javax.swing.JDialog;
|
||||||
import javax.swing.JFileChooser;
|
import javax.swing.JFileChooser;
|
||||||
@@ -84,7 +90,6 @@ import org.fife.ui.rtextarea.ToolTipSupplier;
|
|||||||
import org.objectweb.asm.ClassReader;
|
import org.objectweb.asm.ClassReader;
|
||||||
import org.objectweb.asm.ClassWriter;
|
import org.objectweb.asm.ClassWriter;
|
||||||
import org.objectweb.asm.tree.ClassNode;
|
import org.objectweb.asm.tree.ClassNode;
|
||||||
import org.objectweb.asm.tree.FieldNode;
|
|
||||||
import org.objectweb.asm.tree.MethodNode;
|
import org.objectweb.asm.tree.MethodNode;
|
||||||
|
|
||||||
import me.ByteEdit.boxes.CompilationBox;
|
import me.ByteEdit.boxes.CompilationBox;
|
||||||
@@ -94,9 +99,9 @@ import me.ByteEdit.boxes.SearchBox;
|
|||||||
import me.ByteEdit.boxes.ThemeBox;
|
import me.ByteEdit.boxes.ThemeBox;
|
||||||
import me.ByteEdit.boxes.TypeOpenBox;
|
import me.ByteEdit.boxes.TypeOpenBox;
|
||||||
import me.ByteEdit.boxes.UnicodeBox;
|
import me.ByteEdit.boxes.UnicodeBox;
|
||||||
|
import me.ByteEdit.decompiler.EnumDecompiler;
|
||||||
|
import me.ByteEdit.decompiler.SingleThreadedExecutor;
|
||||||
import me.ByteEdit.edit.Assembler;
|
import me.ByteEdit.edit.Assembler;
|
||||||
import me.ByteEdit.edit.Disassembler;
|
|
||||||
import me.ByteEdit.edit.Disassembler.DisassembleTuple;
|
|
||||||
import me.ByteEdit.edit.HugeStrings;
|
import me.ByteEdit.edit.HugeStrings;
|
||||||
import me.ByteEdit.utils.ClassUtil;
|
import me.ByteEdit.utils.ClassUtil;
|
||||||
import me.ByteEdit.utils.OpcodesReverse;
|
import me.ByteEdit.utils.OpcodesReverse;
|
||||||
@@ -157,9 +162,7 @@ public class Main extends JFrame {
|
|||||||
* Launch the application.
|
* Launch the application.
|
||||||
*/
|
*/
|
||||||
public static void main(String[] args) {
|
public static void main(String[] args) {
|
||||||
EventQueue.invokeLater(new Runnable() {
|
EventQueue.invokeLater(() -> {
|
||||||
|
|
||||||
public void run() {
|
|
||||||
try {
|
try {
|
||||||
Main frame = new Main();
|
Main frame = new Main();
|
||||||
frame.setVisible(true);
|
frame.setVisible(true);
|
||||||
@@ -167,9 +170,7 @@ public class Main extends JFrame {
|
|||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -452,7 +453,6 @@ public class Main extends JFrame {
|
|||||||
tree.getSelectionModel().setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION);
|
tree.getSelectionModel().setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION);
|
||||||
tree.addTreeExpansionListener(new FurtherExpandingTreeExpansionListener());
|
tree.addTreeExpansionListener(new FurtherExpandingTreeExpansionListener());
|
||||||
tree.addKeyListener(new KeyAdapter() {
|
tree.addKeyListener(new KeyAdapter() {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void keyReleased(KeyEvent e) {
|
public void keyReleased(KeyEvent e) {
|
||||||
if (e.getKeyCode() == 116 && jarFile != null) { // F5
|
if (e.getKeyCode() == 116 && jarFile != null) { // F5
|
||||||
@@ -526,7 +526,8 @@ public class Main extends JFrame {
|
|||||||
public void valueChanged(TreeSelectionEvent e) {
|
public void valueChanged(TreeSelectionEvent e) {
|
||||||
synchronized (treeLock) {
|
synchronized (treeLock) {
|
||||||
if (!isChangingFile) {
|
if (!isChangingFile) {
|
||||||
selectFile(((ByteEditTreeNode) e.getPath().getLastPathComponent()).path);
|
SingleThreadedExecutor.execute(
|
||||||
|
() -> selectFile(((ByteEditTreeNode) e.getPath().getLastPathComponent()).path));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -546,7 +547,7 @@ public class Main extends JFrame {
|
|||||||
for (int i = 0; i < flavors.length; i++) {
|
for (int i = 0; i < flavors.length; i++) {
|
||||||
if (flavors[i].isFlavorJavaFileListType()) {
|
if (flavors[i].isFlavorJavaFileListType()) {
|
||||||
dtde.acceptDrop(dtde.getDropAction());
|
dtde.acceptDrop(dtde.getDropAction());
|
||||||
java.util.List<File> files = (java.util.List<File>) tr.getTransferData(flavors[i]);
|
List<File> files = (List<File>) tr.getTransferData(flavors[i]);
|
||||||
final File file = files.get(0);
|
final File file = files.get(0);
|
||||||
if (file.getName().endsWith(".jar")) {
|
if (file.getName().endsWith(".jar")) {
|
||||||
jarFile = file;
|
jarFile = file;
|
||||||
@@ -696,29 +697,10 @@ public class Main extends JFrame {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
txtByteEditView.addKeyListener(new KeyAdapter() {
|
txtByteEditView.addKeyListener(new KeyAdapter() {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void keyReleased(KeyEvent e) {
|
public void keyReleased(KeyEvent e) {
|
||||||
if (e.getKeyCode() == 116 && currentNodeName != null) { // F5
|
if (e.getKeyCode() == 116 && currentNodeName != null) { // F5
|
||||||
try {
|
SingleThreadedExecutor.execute(Main::decompileCurrentNode);
|
||||||
ClassNode classNode = classNodes.get(currentNodeName);
|
|
||||||
int prev = txtByteEditView.getCaretPosition();
|
|
||||||
String dis = Disassembler.disassemble(classNode);
|
|
||||||
String substr = currentNodeName.substring(0, currentNodeName.length() - 6);
|
|
||||||
for (String key : Main.classNodes.keySet()) {
|
|
||||||
if (key.contains("$")) {
|
|
||||||
String[] split = key.split("\\$");
|
|
||||||
if (split[0].equals(substr)) {
|
|
||||||
dis += "\n" + Disassembler.disassemble(classNodes.get(key));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
txtByteEditView.setText(dis);
|
|
||||||
if (dis.length() > prev)
|
|
||||||
txtByteEditView.setCaretPosition(prev);
|
|
||||||
} catch (Exception e2) {
|
|
||||||
e2.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -755,13 +737,6 @@ 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 -> {
|
|
||||||
try {
|
|
||||||
goToSelected();
|
|
||||||
} catch (BadLocationException e1) {
|
|
||||||
e1.printStackTrace();
|
|
||||||
}
|
|
||||||
}, ctrlG, JComponent.WHEN_FOCUSED);
|
|
||||||
txtByteEditView.registerKeyboardAction(e -> {
|
txtByteEditView.registerKeyboardAction(e -> {
|
||||||
try {
|
try {
|
||||||
renameSelected();
|
renameSelected();
|
||||||
@@ -774,82 +749,48 @@ public class Main extends JFrame {
|
|||||||
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());
|
||||||
|
|
||||||
splitPane.setRightComponent(scrollPane_ByteEdit);
|
panel.add(scrollPane_ByteEdit, BorderLayout.CENTER);
|
||||||
|
final JComboBox<String> decompilerMode = new JComboBox<>();
|
||||||
|
DefaultComboBoxModel model = new DefaultComboBoxModel();
|
||||||
|
Arrays.stream(EnumDecompiler.values()).forEach(model::addElement);
|
||||||
|
decompilerMode.setModel(model);
|
||||||
|
decompilerMode.addItemListener(new ItemListener() {
|
||||||
|
@Override
|
||||||
|
public void itemStateChanged(ItemEvent e) {
|
||||||
|
if (e.getStateChange() == ItemEvent.SELECTED) {
|
||||||
|
EnumDecompiler selected = (EnumDecompiler) e.getItem();
|
||||||
|
SingleThreadedExecutor.execute(() -> {
|
||||||
|
decompiler = selected;
|
||||||
|
if (currentNodeName != null) {
|
||||||
|
decompileCurrentNode();
|
||||||
|
try {
|
||||||
|
EventQueue.invokeAndWait(() -> {
|
||||||
|
txtByteEditView.setCaretPosition(0);
|
||||||
|
try {
|
||||||
|
txtByteEditView.setSyntaxEditingStyle(decompiler.getSyntaxStyle());
|
||||||
|
} catch (Throwable t) {
|
||||||
|
}
|
||||||
|
txtByteEditView.setEditable(decompiler.isEditable());
|
||||||
|
});
|
||||||
|
} catch (Exception e1) {
|
||||||
|
e1.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
panel.add(decompilerMode, BorderLayout.NORTH);
|
||||||
|
|
||||||
|
splitPane.setRightComponent(panel);
|
||||||
scrollPane_ByteEdit.setViewportView(txtByteEditView);
|
scrollPane_ByteEdit.setViewportView(txtByteEditView);
|
||||||
scrollPane_ByteEdit.setLineNumbersEnabled(true);
|
scrollPane_ByteEdit.setLineNumbersEnabled(true);
|
||||||
scrollPane_ByteEdit.setFoldIndicatorEnabled(true);
|
scrollPane_ByteEdit.setFoldIndicatorEnabled(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
private final Pattern jumpableInstructionPattern = Pattern.compile("^\t\t(?!//|\t+).+ .+");
|
public static EnumDecompiler decompiler = EnumDecompiler.BYTEEDIT;
|
||||||
|
|
||||||
public void goToSelected() throws BadLocationException {
|
|
||||||
int lineStart = txtByteEditView.getLineStartOffsetOfCurrentLine();
|
|
||||||
int lineEnd = txtByteEditView.getLineEndOffsetOfCurrentLine() - 1;
|
|
||||||
if (lineEnd < lineStart)
|
|
||||||
return;
|
|
||||||
String line = txtByteEditView.getText(lineStart, lineEnd - lineStart);
|
|
||||||
if (!jumpableInstructionPattern.matcher(line).matches()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
line = line.substring(2);
|
|
||||||
if (line.startsWith("invoke")) {
|
|
||||||
String[] split = line.split(" ");
|
|
||||||
String desc = UnicodeUtils.unescape(null, split[1], true);
|
|
||||||
String target = split[2];
|
|
||||||
int index = target.lastIndexOf("/");
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
for (MethodNode mn : classNode.methods) {
|
|
||||||
if (mn.name.equals(methodName) && mn.desc.equals(desc)) {
|
|
||||||
while (classNode.outerClass != null) {
|
|
||||||
classNode = classNodes.get(getFullName(classNode.outerClass));
|
|
||||||
}
|
|
||||||
int lineFound = selectFileWithSearch(getFullName(classNode.name), mn);
|
|
||||||
if (lineFound != -1) {
|
|
||||||
Main.txtByteEditView.setCaretPosition(Main.txtByteEditView.getLineStartOffset(lineFound));
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if (line.startsWith("new ")) {
|
|
||||||
String[] split = line.split(" ");
|
|
||||||
String className = UnicodeUtils.unescape(null, split[1], true);
|
|
||||||
ClassNode classNode = classNodes.get(getFullName(className));
|
|
||||||
if (classNode == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
selectFile(getFullName(className));
|
|
||||||
} else if (line.startsWith("getstatic ") || line.startsWith("putstatic ") || line.startsWith("getfield ")
|
|
||||||
|| line.startsWith("putfield ")) {
|
|
||||||
String[] split = line.split(" ");
|
|
||||||
String desc = UnicodeUtils.unescape(null, split[1], true);
|
|
||||||
String target = split[2];
|
|
||||||
int index = target.lastIndexOf("/");
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
for (FieldNode fn : classNode.fields) {
|
|
||||||
if (fn.name.equals(fieldName) && fn.desc.equals(desc)) {
|
|
||||||
while (classNode.outerClass != null) {
|
|
||||||
classNode = classNodes.get(getFullName(classNode.outerClass));
|
|
||||||
}
|
|
||||||
int lineFound = selectFileWithSearch(getFullName(classNode.name), fn);
|
|
||||||
if (lineFound != -1) {
|
|
||||||
Main.txtByteEditView.setCaretPosition(Main.txtByteEditView.getLineStartOffset(lineFound));
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private final Pattern renameableFieldPattern = Pattern
|
private final Pattern renameableFieldPattern = Pattern
|
||||||
.compile("^\t(?:[a-z]+ |0x[0-9a-fA-F]+ )*?(\\[*(?:V|Z|C|B|S|I|F|J|D|L.+?;)) ([^ ]+) ?.*");
|
.compile("^\t(?:[a-z]+ |0x[0-9a-fA-F]+ )*?(\\[*(?:V|Z|C|B|S|I|F|J|D|L.+?;)) ([^ ]+) ?.*");
|
||||||
@@ -940,41 +881,38 @@ public class Main extends JFrame {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static int selectFileWithSearch(String s, Object nodeToFind) {
|
public static void decompileCurrentNode() {
|
||||||
if (s != null && s.endsWith(".class")) {
|
try {
|
||||||
currentNodeName = s;
|
EnumDecompiler decompiler = Main.decompiler;
|
||||||
int lineFound = -1;
|
String current = currentNodeName;
|
||||||
ClassNode classNode = classNodes.get(s);
|
ClassNode classNode = classNodes.get(current);
|
||||||
if (classNode == null)
|
int prev = txtByteEditView.getCaretPosition();
|
||||||
return -1;
|
String dis = decompiler.getDecompiler().decompile(classNode);
|
||||||
String dis = "";
|
String substr = current.substring(0, current.length() - 6);
|
||||||
DisassembleTuple tuple = Disassembler.disassemble(classNode, nodeToFind);
|
synchronized (Main.classNodes) {
|
||||||
if (tuple.getLine() != -1) {
|
|
||||||
lineFound = dis.split("\\n").length + tuple.getLine() - 1;
|
|
||||||
}
|
|
||||||
dis += tuple.getDisassembly();
|
|
||||||
String substr = s.substring(0, s.length() - 6);
|
|
||||||
for (String key : Main.classNodes.keySet()) {
|
for (String key : Main.classNodes.keySet()) {
|
||||||
if (key.contains("$")) {
|
if (key.contains("$")) {
|
||||||
String[] split = key.split("\\$");
|
String[] split = key.split("\\$");
|
||||||
if (split[0].equals(substr)) {
|
if (split[0].equals(substr)) {
|
||||||
tuple = Disassembler.disassemble(classNodes.get(key), nodeToFind);
|
dis += "\n" + decompiler.getDecompiler().decompile(classNodes.get(key));
|
||||||
if (tuple.getLine() != -1) {
|
|
||||||
lineFound = dis.split("\\n").length + tuple.getLine() + 1;
|
|
||||||
}
|
}
|
||||||
dis += "\n" + tuple.getDisassembly();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
txtByteEditView.setText(dis);
|
txtByteEditView.setText(dis);
|
||||||
txtByteEditView.setCaretPosition(0);
|
if (dis.length() > prev)
|
||||||
return lineFound;
|
txtByteEditView.setCaretPosition(prev);
|
||||||
|
} catch (Exception e2) {
|
||||||
|
e2.printStackTrace();
|
||||||
}
|
}
|
||||||
return -1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static int selectFile(String s) {
|
public static void selectFile(String s) {
|
||||||
return selectFileWithSearch(s, null);
|
if (s != null && s.endsWith(".class")) {
|
||||||
|
currentNodeName = s;
|
||||||
|
decompileCurrentNode();
|
||||||
|
txtByteEditView.setCaretPosition(0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void save() {
|
public void save() {
|
||||||
@@ -1000,7 +938,6 @@ public class Main extends JFrame {
|
|||||||
int dialogResult = JOptionPane.showConfirmDialog(null, "This file already exists! Overwrite it?",
|
int dialogResult = JOptionPane.showConfirmDialog(null, "This file already exists! Overwrite it?",
|
||||||
"Warning", JOptionPane.YES_NO_OPTION);
|
"Warning", JOptionPane.YES_NO_OPTION);
|
||||||
if (dialogResult == JOptionPane.YES_OPTION) {
|
if (dialogResult == JOptionPane.YES_OPTION) {
|
||||||
save(file, classNodes.values());
|
|
||||||
shouldSave = true;
|
shouldSave = true;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -14,7 +14,7 @@
|
|||||||
<!-- General editor colors. -->
|
<!-- General editor colors. -->
|
||||||
<background color="2f2f2f"/>
|
<background color="2f2f2f"/>
|
||||||
<caret color="eeeeee"/>
|
<caret color="eeeeee"/>
|
||||||
<selection bg="111111" fg="eeeeee"/>
|
<selection bg="555555" fg="eeeeee"/>
|
||||||
<currentLineHighlight color="111111" fade="false"/>
|
<currentLineHighlight color="111111" fade="false"/>
|
||||||
<marginLine fg="4f4b46"/>
|
<marginLine fg="4f4b46"/>
|
||||||
<markAllHighlight color="947e76"/> <!-- TODO: Fix me -->
|
<markAllHighlight color="947e76"/> <!-- TODO: Fix me -->
|
||||||
@@ -36,23 +36,23 @@
|
|||||||
<!-- Syntax tokens. -->
|
<!-- Syntax tokens. -->
|
||||||
<tokenStyles>
|
<tokenStyles>
|
||||||
<style token="IDENTIFIER" fg="eeeeee"/>
|
<style token="IDENTIFIER" fg="eeeeee"/>
|
||||||
<style token="RESERVED_WORD" fg="dd02d6" bold="true"/>
|
<style token="RESERVED_WORD" fg="cc6c1d" bold="true"/>
|
||||||
<style token="RESERVED_WORD_2" fg="dd02d6" bold="true"/>
|
<style token="RESERVED_WORD_2" fg="cc6c1d" bold="true"/>
|
||||||
<style token="ANNOTATION" fg="808080"/>
|
<style token="ANNOTATION" fg="808080"/>
|
||||||
<style token="COMMENT_DOCUMENTATION" fg="279627"/>
|
<style token="COMMENT_DOCUMENTATION" fg="279627"/>
|
||||||
<style token="COMMENT_EOL" fg="279627"/>
|
<style token="COMMENT_EOL" fg="279627"/>
|
||||||
<style token="COMMENT_MULTILINE" fg="279627"/>
|
<style token="COMMENT_MULTILINE" fg="279627"/>
|
||||||
<style token="COMMENT_KEYWORD" fg="806040" bold="true"/>
|
<style token="COMMENT_KEYWORD" fg="806040" bold="true"/>
|
||||||
<style token="COMMENT_MARKUP" fg="808060"/>
|
<style token="COMMENT_MARKUP" fg="808060"/>
|
||||||
<style token="DATA_TYPE" fg="dd02d6" bold="true"/>
|
<style token="DATA_TYPE" fg="cc6c1d"/>
|
||||||
<style token="FUNCTION" fg="eeeeee"/>
|
<style token="FUNCTION" fg="eeeeee"/>
|
||||||
<style token="LITERAL_BOOLEAN" fg="dd02d6" bold="true"/>
|
<style token="LITERAL_BOOLEAN" fg="cc6c1d"/>
|
||||||
<style token="LITERAL_NUMBER_DECIMAL_INT" fg="eeeeee"/>
|
<style token="LITERAL_NUMBER_DECIMAL_INT" fg="6897bb"/>
|
||||||
<style token="LITERAL_NUMBER_FLOAT" fg="eeeeee"/>
|
<style token="LITERAL_NUMBER_FLOAT" fg="6897bb"/>
|
||||||
<style token="LITERAL_NUMBER_HEXADECIMAL" fg="eeeeee"/>
|
<style token="LITERAL_NUMBER_HEXADECIMAL" fg="6897bb"/>
|
||||||
<style token="LITERAL_STRING_DOUBLE_QUOTE" fg="00aeff"/>
|
<style token="LITERAL_STRING_DOUBLE_QUOTE" fg="17c6a3"/>
|
||||||
<style token="LITERAL_CHAR" fg="00aeff"/>
|
<style token="LITERAL_CHAR" fg="17c6a3"/>
|
||||||
<style token="LITERAL_BACKQUOTE" fg="00aeff"/>
|
<style token="LITERAL_BACKQUOTE" fg="17c6a3"/>
|
||||||
<style token="MARKUP_TAG_DELIMITER" fg="008080"/>
|
<style token="MARKUP_TAG_DELIMITER" fg="008080"/>
|
||||||
<style token="MARKUP_TAG_NAME" fg="3f7f7f"/>
|
<style token="MARKUP_TAG_NAME" fg="3f7f7f"/>
|
||||||
<style token="MARKUP_TAG_ATTRIBUTE" fg="7f007f"/>
|
<style token="MARKUP_TAG_ATTRIBUTE" fg="7f007f"/>
|
||||||
|
|||||||
@@ -102,6 +102,8 @@ class DefaultTokenFactory implements TokenFactory {
|
|||||||
@Override
|
@Override
|
||||||
public TokenImpl createToken(final char[] line, final int beg, final int end, final int startOffset,
|
public TokenImpl createToken(final char[] line, final int beg, final int end, final int startOffset,
|
||||||
final int type) {
|
final int type) {
|
||||||
|
// if (tokenList.length - 1 > currentFreeToken)
|
||||||
|
// return null;
|
||||||
TokenImpl token = tokenList[currentFreeToken];
|
TokenImpl token = tokenList[currentFreeToken];
|
||||||
token.set(line, beg, end, startOffset, type);
|
token.set(line, beg, end, startOffset, type);
|
||||||
currentFreeToken++;
|
currentFreeToken++;
|
||||||
|
|||||||
@@ -111,7 +111,7 @@ public interface SyntaxConstants {
|
|||||||
*/
|
*/
|
||||||
String SYNTAX_STYLE_JAVA = "text/java";
|
String SYNTAX_STYLE_JAVA = "text/java";
|
||||||
/**
|
/**
|
||||||
* Style for highlighting Java.
|
* Style for highlighting Java Disassembly.
|
||||||
*/
|
*/
|
||||||
String SYNTAX_STYLE_JAVA_DISASSEMBLE = "text/javaassembly";
|
String SYNTAX_STYLE_JAVA_DISASSEMBLE = "text/javaassembly";
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -108,6 +108,8 @@ public abstract class TokenMakerBase implements TokenMaker {
|
|||||||
currentToken = firstToken; // previous token is still null.
|
currentToken = firstToken; // previous token is still null.
|
||||||
} else {
|
} else {
|
||||||
TokenImpl next = tokenFactory.createToken(array, start, end, startOffset, tokenType);
|
TokenImpl next = tokenFactory.createToken(array, start, end, startOffset, tokenType);
|
||||||
|
if (currentToken == null || next == null)
|
||||||
|
return;
|
||||||
currentToken.setNextToken(next);
|
currentToken.setNextToken(next);
|
||||||
previousToken = currentToken;
|
previousToken = currentToken;
|
||||||
currentToken = next;
|
currentToken = next;
|
||||||
|
|||||||
@@ -3184,7 +3184,8 @@ public class JavaTokenMaker extends AbstractJFlexCTokenMaker {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
zzScanError(ZZ_NO_MATCH);
|
// zzScanError(ZZ_NO_MATCH);
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in new issue
Block a user