mirror of
https://github.com/SuspiciousActivity/ByteEdit.git
synced 2026-08-13 17:56:17 +00:00
Merge pull request #1 from Outfluencer/master
Added some decompilers and decompile and disassemble async
This commit is contained in:
16 files changed
+775
-119
No files matched your search
@@ -15,6 +15,7 @@ import java.io.StringWriter;
|
||||
import java.net.URI;
|
||||
import java.nio.file.Files;
|
||||
import java.util.Arrays;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import javax.swing.JComponent;
|
||||
import javax.swing.JFrame;
|
||||
@@ -26,6 +27,7 @@ import javax.tools.JavaCompiler;
|
||||
import javax.tools.SimpleJavaFileObject;
|
||||
import javax.tools.ToolProvider;
|
||||
|
||||
import me.ByteEdit.decompiler.SingleThreadedExecutor;
|
||||
import org.fife.ui.rsyntaxtextarea.RSyntaxTextArea;
|
||||
import org.fife.ui.rsyntaxtextarea.SyntaxConstants;
|
||||
import org.fife.ui.rtextarea.RTextScrollPane;
|
||||
@@ -105,37 +107,48 @@ public class CompilationBox extends JFrame {
|
||||
null, Arrays.asList(new JavaSourceFromString("Compiled", source))).call();
|
||||
String res = out.toString();
|
||||
if (res.isEmpty()) {
|
||||
File clazz = new File(tmpFolder, "Compiled.class");
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
InputStream is = new FileInputStream(clazz);
|
||||
byte[] tmp = new byte[1024];
|
||||
int r;
|
||||
while ((r = is.read(tmp)) > 0) {
|
||||
baos.write(tmp, 0, r);
|
||||
}
|
||||
is.close();
|
||||
ClassReader read = new ClassReader(baos.toByteArray());
|
||||
ClassNode node = new ClassNode();
|
||||
read.accept(node, 0);
|
||||
String dis = Disassembler.disassemble(node);
|
||||
File[] files = tmpFolder.listFiles();
|
||||
if (files != null)
|
||||
for (File f : files) {
|
||||
if (f.getName().equals("Compiled.class"))
|
||||
continue;
|
||||
baos = new ByteArrayOutputStream();
|
||||
is = new FileInputStream(f);
|
||||
|
||||
|
||||
SingleThreadedExecutor.execute( () -> {
|
||||
try {
|
||||
File clazz = new File(tmpFolder, "Compiled.class");
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
InputStream is = new FileInputStream(clazz);
|
||||
byte[] tmp = new byte[1024];
|
||||
int r;
|
||||
while ((r = is.read(tmp)) > 0) {
|
||||
baos.write(tmp, 0, r);
|
||||
}
|
||||
is.close();
|
||||
read = new ClassReader(baos.toByteArray());
|
||||
node = new ClassNode();
|
||||
|
||||
|
||||
ClassReader read = new ClassReader(baos.toByteArray());
|
||||
ClassNode node = new ClassNode();
|
||||
read.accept(node, 0);
|
||||
dis += "\n" + Disassembler.disassemble(node);
|
||||
String dis = Disassembler.disassemble(node);
|
||||
File[] files = tmpFolder.listFiles();
|
||||
if (files != null)
|
||||
for (File f : files) {
|
||||
if (f.getName().equals("Compiled.class"))
|
||||
continue;
|
||||
baos = new ByteArrayOutputStream();
|
||||
is = new FileInputStream(f);
|
||||
while ((r = is.read(tmp)) > 0) {
|
||||
baos.write(tmp, 0, r);
|
||||
}
|
||||
is.close();
|
||||
read = new ClassReader(baos.toByteArray());
|
||||
node = new ClassNode();
|
||||
read.accept(node, 0);
|
||||
dis += "\n" + Disassembler.disassemble(node);
|
||||
}
|
||||
compSuccess.textArea.setText(dis);
|
||||
compSuccess.setVisible(true);
|
||||
}catch (IOException e2){
|
||||
e2.printStackTrace();
|
||||
}
|
||||
compSuccess.textArea.setText(dis);
|
||||
compSuccess.setVisible(true);
|
||||
});
|
||||
|
||||
} else {
|
||||
JOptionPane.showMessageDialog(CompilationBox.this, res, "Error!", JOptionPane.ERROR_MESSAGE);
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package me.ByteEdit.boxes;
|
||||
|
||||
import java.awt.Toolkit;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import javax.swing.DefaultListModel;
|
||||
import javax.swing.JFrame;
|
||||
@@ -13,6 +14,7 @@ import javax.swing.event.ListSelectionEvent;
|
||||
import javax.swing.event.ListSelectionListener;
|
||||
import javax.swing.text.BadLocationException;
|
||||
|
||||
import me.ByteEdit.decompiler.SingleThreadedExecutor;
|
||||
import org.objectweb.asm.tree.MethodNode;
|
||||
|
||||
import me.ByteEdit.main.Main;
|
||||
@@ -38,17 +40,21 @@ public class GlobalSearchOpenBox extends JFrame {
|
||||
list.addListSelectionListener(new ListSelectionListener() {
|
||||
|
||||
public void valueChanged(ListSelectionEvent e) {
|
||||
Info val = list.getSelectedValue();
|
||||
if (val != null && !val.owner.equals(Main.currentNodeName)) {
|
||||
int lineFound = Main.selectFileWithSearch(val.nodePath, val.mn);
|
||||
if (lineFound != -1) {
|
||||
try {
|
||||
Main.txtByteEditView.setCaretPosition(Main.txtByteEditView.getLineStartOffset(lineFound));
|
||||
} catch (BadLocationException e1) {
|
||||
e1.printStackTrace();
|
||||
|
||||
SingleThreadedExecutor.execute( () -> {
|
||||
Info val = list.getSelectedValue();
|
||||
if (val != null && !val.owner.equals(Main.currentNodeName)) {
|
||||
int lineFound = Main.selectFileWithSearch(val.nodePath, val.mn);
|
||||
if (lineFound != -1) {
|
||||
try {
|
||||
Main.txtByteEditView.setCaretPosition(Main.txtByteEditView.getLineStartOffset(lineFound));
|
||||
} catch (BadLocationException e1) {
|
||||
//e1.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@ import java.awt.Toolkit;
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.awt.event.ActionListener;
|
||||
import java.util.LinkedList;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import javax.swing.JButton;
|
||||
import javax.swing.JFrame;
|
||||
@@ -13,6 +14,7 @@ import javax.swing.JPanel;
|
||||
import javax.swing.JTextField;
|
||||
import javax.swing.border.EmptyBorder;
|
||||
|
||||
import me.ByteEdit.decompiler.SingleThreadedExecutor;
|
||||
import org.objectweb.asm.tree.AbstractInsnNode;
|
||||
import org.objectweb.asm.tree.ClassNode;
|
||||
import org.objectweb.asm.tree.FieldInsnNode;
|
||||
@@ -210,27 +212,31 @@ public class RenameBox extends JFrame {
|
||||
return;
|
||||
}
|
||||
}
|
||||
try { // refresh
|
||||
ClassNode classNode = Main.classNodes.get(Main.currentNodeName);
|
||||
int prev = Main.txtByteEditView.getCaretPosition();
|
||||
String dis = Disassembler.disassemble(classNode);
|
||||
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));
|
||||
|
||||
SingleThreadedExecutor.execute( () -> {
|
||||
try { // refresh
|
||||
ClassNode classNode = Main.classNodes.get(Main.currentNodeName);
|
||||
int prev = Main.txtByteEditView.getCaretPosition();
|
||||
String dis = Disassembler.disassemble(classNode);
|
||||
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();
|
||||
}
|
||||
Main.txtByteEditView.setText(dis);
|
||||
Main.txtByteEditView.setCaretPosition(prev);
|
||||
} catch (Exception e2) {
|
||||
e2.printStackTrace();
|
||||
}
|
||||
name = newName;
|
||||
desc = newDesc;
|
||||
RenameBox.this.setVisible(false);
|
||||
name = newName;
|
||||
desc = newDesc;
|
||||
RenameBox.this.setVisible(false);
|
||||
});
|
||||
|
||||
}
|
||||
});
|
||||
btnRename.setBounds(345, 237, 89, 23);
|
||||
|
||||
@@ -3,6 +3,7 @@ package me.ByteEdit.boxes;
|
||||
import java.awt.Toolkit;
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.awt.event.ActionListener;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import javax.swing.DefaultListModel;
|
||||
import javax.swing.JFrame;
|
||||
@@ -17,6 +18,7 @@ import javax.swing.event.DocumentListener;
|
||||
import javax.swing.event.ListSelectionEvent;
|
||||
import javax.swing.event.ListSelectionListener;
|
||||
|
||||
import me.ByteEdit.decompiler.SingleThreadedExecutor;
|
||||
import me.ByteEdit.main.Main;
|
||||
import me.ByteEdit.utils.UnicodeUtils;
|
||||
|
||||
@@ -43,7 +45,8 @@ public class TypeOpenBox extends JFrame {
|
||||
public void valueChanged(ListSelectionEvent e) {
|
||||
String val = list.getSelectedValue();
|
||||
if (val != null && !val.equals(Main.currentNodeName)) {
|
||||
Main.selectFile(val);
|
||||
|
||||
SingleThreadedExecutor.execute( () -> Main.selectFile(val));
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@@ -0,0 +1,165 @@
|
||||
package me.ByteEdit.decompiler;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
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;
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
public class CFRDecompiler {
|
||||
|
||||
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");
|
||||
}
|
||||
|
||||
public static String decompile(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.substring(37); // small hack to remove watermark
|
||||
} 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;
|
||||
}
|
||||
|
||||
protected Pair<byte[], String> getSystemClass(String name, String path) throws IOException {
|
||||
InputStream is = ClassLoader.getSystemClassLoader().getResourceAsStream(path);
|
||||
if (is != null) {
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
byte[] buffer = new byte[4096];
|
||||
int n;
|
||||
while ((n = is.read(buffer)) > 0) {
|
||||
baos.write(buffer, 0, n);
|
||||
}
|
||||
return Pair.make(baos.toByteArray(), name);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
package me.ByteEdit.decompiler;
|
||||
|
||||
public enum EnumDecompiler {
|
||||
BYTEEDIT("ByteEdit"), PROCYON("Procyon"), FERNFLOWER("FernFlower"), JD_GUI("JD-GUI"), CFR("CFR");
|
||||
|
||||
final String name;
|
||||
|
||||
EnumDecompiler(String name){
|
||||
this.name = name;
|
||||
}
|
||||
@Override
|
||||
public String toString() {
|
||||
return name;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,132 @@
|
||||
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 {
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
public String decompile(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) {
|
||||
}
|
||||
});
|
||||
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,126 @@
|
||||
package me.ByteEdit.decompiler;
|
||||
|
||||
import me.ByteEdit.main.Main;
|
||||
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;
|
||||
|
||||
|
||||
public class JDDecompiler implements Loader, Printer {
|
||||
|
||||
public String decompile(ClassNode cl) {
|
||||
ClassFileToJavaSourceDecompiler decompiler = new ClassFileToJavaSourceDecompiler();
|
||||
try {
|
||||
decompiler.decompile(this, this, cl.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;
|
||||
}
|
||||
return toString();
|
||||
}
|
||||
|
||||
@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,71 @@
|
||||
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 {
|
||||
|
||||
public static String decompile(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,27 @@
|
||||
package me.ByteEdit.decompiler;
|
||||
|
||||
import java.util.concurrent.LinkedBlockingQueue;
|
||||
|
||||
public class SingleThreadedExecutor {
|
||||
|
||||
|
||||
private static LinkedBlockingQueue<Runnable> queue = new LinkedBlockingQueue<>();
|
||||
|
||||
private static final Thread thread = new Thread(() -> {
|
||||
while(true){
|
||||
try {
|
||||
queue.take().run();
|
||||
} catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}, "Single");
|
||||
static {
|
||||
thread.start();
|
||||
}
|
||||
|
||||
|
||||
public static void execute(Runnable r){
|
||||
queue.add(r);
|
||||
}
|
||||
}
|
||||
@@ -29,10 +29,12 @@ import java.util.concurrent.Future;
|
||||
import java.util.concurrent.FutureTask;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
import org.objectweb.asm.Handle;
|
||||
import org.objectweb.asm.Label;
|
||||
import org.objectweb.asm.Opcodes;
|
||||
import org.objectweb.asm.Type;
|
||||
import com.strobel.decompiler.Decompiler;
|
||||
import me.ByteEdit.decompiler.CFRDecompiler;
|
||||
import me.ByteEdit.decompiler.FernflowerDecompiler;
|
||||
import me.ByteEdit.decompiler.JDDecompiler;
|
||||
import me.ByteEdit.decompiler.ProcyonDecompiler;
|
||||
import org.objectweb.asm.*;
|
||||
import org.objectweb.asm.tree.AbstractInsnNode;
|
||||
import org.objectweb.asm.tree.AnnotationNode;
|
||||
import org.objectweb.asm.tree.ClassNode;
|
||||
@@ -98,10 +100,34 @@ public class Disassembler {
|
||||
}
|
||||
|
||||
public static DisassembleTuple disassemble(ClassNode classNode, Object nodeToFind) {
|
||||
|
||||
if (classNode == null) {
|
||||
return new DisassembleTuple("ClassNode is null! This is not a valid java class file!");
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
try {
|
||||
System.out.println(Main.decompiler);
|
||||
ClassWriter classWriter = new ClassWriter(0);
|
||||
switch (Main.decompiler){
|
||||
case PROCYON:
|
||||
classNode.accept(classWriter);
|
||||
return new DisassembleTuple(ProcyonDecompiler.decompile(classNode, classWriter.toByteArray(), null));
|
||||
case FERNFLOWER:
|
||||
classNode.accept(classWriter);
|
||||
return new DisassembleTuple(new FernflowerDecompiler().decompile(classNode, classWriter.toByteArray(), null));
|
||||
case JD_GUI:
|
||||
classNode.accept(classWriter);
|
||||
return new DisassembleTuple(new JDDecompiler().decompile(classNode));
|
||||
case CFR:
|
||||
classNode.accept(classWriter);
|
||||
return new DisassembleTuple(CFRDecompiler.decompile(classNode, classWriter.toByteArray(), null));
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
HugeStrings hs = new HugeStrings();
|
||||
AtomicInteger lineFound = new AtomicInteger(-1);
|
||||
StringContext ctx = new StringContext(18);
|
||||
|
||||
@@ -3,6 +3,7 @@ package me.ByteEdit.edit;
|
||||
import java.awt.Toolkit;
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.awt.event.ActionListener;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import javax.swing.DefaultListModel;
|
||||
import javax.swing.JFrame;
|
||||
@@ -18,6 +19,7 @@ import javax.swing.event.DocumentListener;
|
||||
import javax.swing.event.ListSelectionEvent;
|
||||
import javax.swing.event.ListSelectionListener;
|
||||
|
||||
import me.ByteEdit.decompiler.SingleThreadedExecutor;
|
||||
import me.ByteEdit.main.Main;
|
||||
|
||||
public class TypeOpenBox extends JFrame {
|
||||
@@ -51,7 +53,8 @@ public class TypeOpenBox extends JFrame {
|
||||
public void valueChanged(ListSelectionEvent e) {
|
||||
String val = list.getSelectedValue();
|
||||
if (val != null && !val.equals(Main.currentNodeName)) {
|
||||
Main.selectFile(val);
|
||||
|
||||
SingleThreadedExecutor.execute( () -> Main.selectFile(val));
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
+119
-60
@@ -1,11 +1,6 @@
|
||||
package me.ByteEdit.main;
|
||||
|
||||
import java.awt.Component;
|
||||
import java.awt.EventQueue;
|
||||
import java.awt.Font;
|
||||
import java.awt.GridLayout;
|
||||
import java.awt.HeadlessException;
|
||||
import java.awt.Toolkit;
|
||||
import java.awt.*;
|
||||
import java.awt.datatransfer.DataFlavor;
|
||||
import java.awt.datatransfer.Transferable;
|
||||
import java.awt.dnd.DropTarget;
|
||||
@@ -13,11 +8,7 @@ import java.awt.dnd.DropTargetDragEvent;
|
||||
import java.awt.dnd.DropTargetDropEvent;
|
||||
import java.awt.dnd.DropTargetEvent;
|
||||
import java.awt.dnd.DropTargetListener;
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.awt.event.ActionListener;
|
||||
import java.awt.event.KeyAdapter;
|
||||
import java.awt.event.KeyEvent;
|
||||
import java.awt.event.MouseEvent;
|
||||
import java.awt.event.*;
|
||||
import java.io.BufferedReader;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.File;
|
||||
@@ -25,14 +16,13 @@ import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.StringReader;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.Enumeration;
|
||||
import java.util.HashMap;
|
||||
import java.util.*;
|
||||
import java.util.List;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.ThreadFactory;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.stream.Collectors;
|
||||
@@ -40,22 +30,7 @@ import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipFile;
|
||||
import java.util.zip.ZipOutputStream;
|
||||
|
||||
import javax.swing.ButtonGroup;
|
||||
import javax.swing.JCheckBoxMenuItem;
|
||||
import javax.swing.JComponent;
|
||||
import javax.swing.JDialog;
|
||||
import javax.swing.JFileChooser;
|
||||
import javax.swing.JFrame;
|
||||
import javax.swing.JMenu;
|
||||
import javax.swing.JMenuBar;
|
||||
import javax.swing.JMenuItem;
|
||||
import javax.swing.JOptionPane;
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.JRadioButtonMenuItem;
|
||||
import javax.swing.JScrollPane;
|
||||
import javax.swing.JSplitPane;
|
||||
import javax.swing.JTree;
|
||||
import javax.swing.KeyStroke;
|
||||
import javax.swing.*;
|
||||
import javax.swing.border.EmptyBorder;
|
||||
import javax.swing.event.TreeExpansionEvent;
|
||||
import javax.swing.event.TreeExpansionListener;
|
||||
@@ -69,6 +44,8 @@ import javax.swing.tree.TreeNode;
|
||||
import javax.swing.tree.TreePath;
|
||||
import javax.swing.tree.TreeSelectionModel;
|
||||
|
||||
import me.ByteEdit.decompiler.EnumDecompiler;
|
||||
import me.ByteEdit.decompiler.SingleThreadedExecutor;
|
||||
import org.fife.ui.autocomplete.AutoCompletion;
|
||||
import org.fife.ui.autocomplete.BasicCompletion;
|
||||
import org.fife.ui.autocomplete.CompletionProvider;
|
||||
@@ -104,6 +81,8 @@ import me.ByteEdit.utils.UnicodeUtils;
|
||||
|
||||
public class Main extends JFrame {
|
||||
|
||||
|
||||
|
||||
public static Main INSTANCE;
|
||||
private JPanel contentPane;
|
||||
private volatile boolean isChangingFile;
|
||||
@@ -526,7 +505,8 @@ public class Main extends JFrame {
|
||||
public void valueChanged(TreeSelectionEvent e) {
|
||||
synchronized (treeLock) {
|
||||
if (!isChangingFile) {
|
||||
selectFile(((ByteEditTreeNode) e.getPath().getLastPathComponent()).path);
|
||||
|
||||
SingleThreadedExecutor.execute( () -> selectFile(((ByteEditTreeNode) e.getPath().getLastPathComponent()).path));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -700,25 +680,30 @@ public class Main extends JFrame {
|
||||
@Override
|
||||
public void keyReleased(KeyEvent e) {
|
||||
if (e.getKeyCode() == 116 && currentNodeName != null) { // F5
|
||||
try {
|
||||
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));
|
||||
|
||||
SingleThreadedExecutor.execute( () -> {
|
||||
try {
|
||||
ClassNode classNode = classNodes.get(currentNodeName);
|
||||
int prev = txtByteEditView.getCaretPosition();
|
||||
String dis = Disassembler.disassemble(classNode);
|
||||
String substr = currentNodeName.substring(0, currentNodeName.length() - 6);
|
||||
synchronized (Main.classNodes){
|
||||
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();
|
||||
}
|
||||
txtByteEditView.setText(dis);
|
||||
if (dis.length() > prev)
|
||||
txtByteEditView.setCaretPosition(prev);
|
||||
} catch (Exception e2) {
|
||||
e2.printStackTrace();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -774,13 +759,66 @@ public class Main extends JFrame {
|
||||
txtByteEditView.setCodeFoldingEnabled(true);
|
||||
scrollPane_ByteEdit = new RTextScrollPane();
|
||||
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) {
|
||||
|
||||
SingleThreadedExecutor.execute( () -> {
|
||||
decompiler = (EnumDecompiler) e.getItem();
|
||||
try {
|
||||
txtByteEditView.setSyntaxEditingStyle(decompiler == EnumDecompiler.BYTEEDIT ? SyntaxConstants.SYNTAX_STYLE_JAVA_DISASSEMBLE : SyntaxConstants.SYNTAX_STYLE_JAVA);
|
||||
} catch (Throwable t){}
|
||||
txtByteEditView.setEditable(decompiler == EnumDecompiler.BYTEEDIT);
|
||||
if (currentNodeName != null) {
|
||||
|
||||
|
||||
try {
|
||||
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();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
});
|
||||
panel.add(decompilerMode, BorderLayout.NORTH);
|
||||
|
||||
|
||||
|
||||
splitPane.setRightComponent(panel);
|
||||
scrollPane_ByteEdit.setViewportView(txtByteEditView);
|
||||
scrollPane_ByteEdit.setLineNumbersEnabled(true);
|
||||
scrollPane_ByteEdit.setFoldIndicatorEnabled(true);
|
||||
}
|
||||
|
||||
|
||||
|
||||
public static EnumDecompiler decompiler = EnumDecompiler.BYTEEDIT;
|
||||
|
||||
private final Pattern jumpableInstructionPattern = Pattern.compile("^\t\t(?!//|\t+).+ .+");
|
||||
|
||||
public void goToSelected() throws BadLocationException {
|
||||
@@ -809,10 +847,20 @@ public class Main extends JFrame {
|
||||
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));
|
||||
}
|
||||
|
||||
|
||||
ClassNode finalClassNode = classNode;
|
||||
SingleThreadedExecutor.execute( () -> {
|
||||
int lineFound = selectFileWithSearch(getFullName(finalClassNode.name), mn);
|
||||
if (lineFound != -1) {
|
||||
try {
|
||||
Main.txtByteEditView.setCaretPosition(Main.txtByteEditView.getLineStartOffset(lineFound));
|
||||
} catch (BadLocationException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -823,7 +871,8 @@ public class Main extends JFrame {
|
||||
if (classNode == null) {
|
||||
return;
|
||||
}
|
||||
selectFile(getFullName(className));
|
||||
|
||||
SingleThreadedExecutor.execute( () -> selectFile(getFullName(className)));
|
||||
} else if (line.startsWith("getstatic ") || line.startsWith("putstatic ") || line.startsWith("getfield ")
|
||||
|| line.startsWith("putfield ")) {
|
||||
String[] split = line.split(" ");
|
||||
@@ -841,10 +890,20 @@ public class Main extends JFrame {
|
||||
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));
|
||||
}
|
||||
|
||||
ClassNode finalClassNode = classNode;
|
||||
ClassNode finalClassNode1 = classNode;
|
||||
SingleThreadedExecutor.execute( () -> {
|
||||
int lineFound = selectFileWithSearch(getFullName(finalClassNode1.name), fn);
|
||||
if (lineFound != -1) {
|
||||
try {
|
||||
Main.txtByteEditView.setCaretPosition(Main.txtByteEditView.getLineStartOffset(lineFound));
|
||||
} catch (BadLocationException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -102,6 +102,7 @@ class DefaultTokenFactory implements TokenFactory {
|
||||
@Override
|
||||
public TokenImpl createToken(final char[] line, final int beg, final int end, final int startOffset,
|
||||
final int type) {
|
||||
// if(tokenList.length - 1 > currentFreeToken) return null;
|
||||
TokenImpl token = tokenList[currentFreeToken];
|
||||
token.set(line, beg, end, startOffset, type);
|
||||
currentFreeToken++;
|
||||
|
||||
@@ -108,6 +108,7 @@ public abstract class TokenMakerBase implements TokenMaker {
|
||||
currentToken = firstToken; // previous token is still null.
|
||||
} else {
|
||||
TokenImpl next = tokenFactory.createToken(array, start, end, startOffset, tokenType);
|
||||
if(currentToken == null || next == null ) return;
|
||||
currentToken.setNextToken(next);
|
||||
previousToken = currentToken;
|
||||
currentToken = next;
|
||||
|
||||
@@ -3184,7 +3184,9 @@ public class JavaTokenMaker extends AbstractJFlexCTokenMaker {
|
||||
return null;
|
||||
}
|
||||
} else {
|
||||
zzScanError(ZZ_NO_MATCH);
|
||||
//zzScanError(ZZ_NO_MATCH);
|
||||
return null;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user