diff --git a/README.md b/README.md index 23d49b2..fb24b18 100644 --- a/README.md +++ b/README.md @@ -17,3 +17,5 @@ To go to the field/method definition in the selected line press CTRL + G. 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 quickly compile some java code, press CTRL + E. diff --git a/src/me/ByteEdit/boxes/CompilationBox.java b/src/me/ByteEdit/boxes/CompilationBox.java new file mode 100644 index 0000000..20db982 --- /dev/null +++ b/src/me/ByteEdit/boxes/CompilationBox.java @@ -0,0 +1,160 @@ +package me.ByteEdit.boxes; + +import java.awt.BorderLayout; +import java.awt.Color; +import java.awt.Toolkit; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.KeyEvent; +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.PrintWriter; +import java.io.StringWriter; +import java.net.URI; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.Arrays; +import java.util.Iterator; +import java.util.Set; + +import javax.swing.JComponent; +import javax.swing.JFrame; +import javax.swing.JPanel; +import javax.swing.KeyStroke; +import javax.swing.UIManager; +import javax.swing.border.EmptyBorder; +import javax.tools.FileObject; +import javax.tools.JavaCompiler; +import javax.tools.JavaCompiler.CompilationTask; +import javax.tools.JavaFileManager; +import javax.tools.JavaFileObject; +import javax.tools.JavaFileObject.Kind; +import javax.tools.SimpleJavaFileObject; +import javax.tools.StandardJavaFileManager; +import javax.tools.ToolProvider; + +import org.fife.ui.rsyntaxtextarea.RSyntaxTextArea; +import org.fife.ui.rsyntaxtextarea.SyntaxConstants; +import org.fife.ui.rtextarea.RTextScrollPane; +import org.objectweb.asm.ClassReader; +import org.objectweb.asm.tree.ClassNode; + +import me.ByteEdit.edit.Disassembler; +import me.ByteEdit.main.Main; + +public class CompilationBox extends JFrame { + + private JPanel contentPane; + private JavaCompiler compiler = ToolProvider.getSystemJavaCompiler(); + RSyntaxTextArea textArea = new RSyntaxTextArea(); + CompilationSuccess compSuccess; + + public CompilationBox() { + compSuccess = new CompilationSuccess(); + try { + UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); + } catch (Exception e) { + e.printStackTrace(); + } + setTitle("Java Compiler"); + setDefaultCloseOperation(JFrame.HIDE_ON_CLOSE); + setBounds((int) (Toolkit.getDefaultToolkit().getScreenSize().getWidth() / 2 - 400), + (int) (Toolkit.getDefaultToolkit().getScreenSize().getHeight() / 2 - 200), 800, 400); + contentPane = new JPanel(); + contentPane.setBackground(Color.GRAY); + contentPane.setBorder(new EmptyBorder(5, 5, 5, 5)); + setContentPane(contentPane); + contentPane.setLayout(new BorderLayout(0, 0)); + + Main.theme.apply(textArea); + textArea.setEditable(true); + textArea.setSyntaxEditingStyle(SyntaxConstants.SYNTAX_STYLE_JAVA); + textArea.setCodeFoldingEnabled(true); + textArea.setBackground(Color.LIGHT_GRAY); + + RTextScrollPane scrollPane = new RTextScrollPane(); + scrollPane.setViewportView(textArea); + scrollPane.setLineNumbersEnabled(true); + scrollPane.setFoldIndicatorEnabled(true); + scrollPane.getGutter().setBackground(Color.LIGHT_GRAY); + contentPane.add(scrollPane); + + KeyStroke ctrlS = KeyStroke.getKeyStroke(KeyEvent.VK_S, KeyEvent.CTRL_DOWN_MASK); + textArea.registerKeyboardAction(new ActionListener() { + + @Override + public void actionPerformed(ActionEvent e) { + if (compiler == null) { + Main.showError("No Java Compiler found!\nYou need JDK installed!"); + return; + } + try (StringWriter out = new StringWriter(); PrintWriter outWriter = new PrintWriter(out)) { + File tmpFolder = Files.createTempDirectory("compiled").toFile(); + + String source = textArea.getText(); + if (!source.contains("\npublic class Compiled {\n")) { + int importIndex = source.lastIndexOf("\nimport"); + if (importIndex == -1) { + if (source.startsWith("import")) { + importIndex = 0; + } + } else { + importIndex++; + } + if (importIndex != -1) { + int newLineIndex = source.indexOf('\n', importIndex); + source = source.substring(0, newLineIndex) + "\npublic class Compiled {\n" + + source.substring(newLineIndex) + "\n}"; + } else { + source = "public class Compiled {\n" + source + "\n}"; + } + } + + compiler.getTask(outWriter, null, null, Arrays.asList("-d", tmpFolder.getAbsolutePath()), null, + Arrays.asList(new JavaSourceFromString("Compiled", source))).call(); + String res = out.toString(); + File clazz = new File(tmpFolder, "Compiled.class"); + if (res.isEmpty()) { + 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); + compSuccess.textArea.setText(Disassembler.disassemble(node)); + compSuccess.setVisible(true); + } else { + Main.showError(res); + } + if (clazz.exists()) + Files.delete(clazz.toPath()); + Files.delete(tmpFolder.toPath()); + } catch (IOException e1) { + e1.printStackTrace(); + } + } + }, ctrlS, JComponent.WHEN_FOCUSED); + } + + class JavaSourceFromString extends SimpleJavaFileObject { + final String code; + + public JavaSourceFromString(String name, String code) { + super(URI.create("string:///" + name.replace('.', '/') + Kind.SOURCE.extension), Kind.SOURCE); + this.code = code; + } + + @Override + public CharSequence getCharContent(boolean ignoreEncodingErrors) { + return code; + } + } +} diff --git a/src/me/ByteEdit/boxes/CompilationSuccess.java b/src/me/ByteEdit/boxes/CompilationSuccess.java new file mode 100644 index 0000000..1e52d66 --- /dev/null +++ b/src/me/ByteEdit/boxes/CompilationSuccess.java @@ -0,0 +1,82 @@ +package me.ByteEdit.boxes; + +import java.awt.BorderLayout; +import java.awt.Color; +import java.awt.Toolkit; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.KeyEvent; +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.PrintWriter; +import java.io.StringWriter; +import java.net.URI; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.Arrays; +import java.util.Iterator; +import java.util.Set; + +import javax.swing.JComponent; +import javax.swing.JFrame; +import javax.swing.JPanel; +import javax.swing.KeyStroke; +import javax.swing.UIManager; +import javax.swing.border.EmptyBorder; +import javax.tools.FileObject; +import javax.tools.JavaCompiler; +import javax.tools.JavaCompiler.CompilationTask; +import javax.tools.JavaFileManager; +import javax.tools.JavaFileObject; +import javax.tools.JavaFileObject.Kind; +import javax.tools.SimpleJavaFileObject; +import javax.tools.StandardJavaFileManager; +import javax.tools.ToolProvider; + +import org.fife.ui.rsyntaxtextarea.RSyntaxTextArea; +import org.fife.ui.rsyntaxtextarea.SyntaxConstants; +import org.fife.ui.rtextarea.RTextScrollPane; +import org.objectweb.asm.ClassReader; +import org.objectweb.asm.tree.ClassNode; + +import me.ByteEdit.edit.Disassembler; +import me.ByteEdit.main.Main; + +public class CompilationSuccess extends JFrame { + + private JPanel contentPane; + RSyntaxTextArea textArea = new RSyntaxTextArea(); + + public CompilationSuccess() { + try { + UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); + } catch (Exception e) { + e.printStackTrace(); + } + setTitle("Java Compiler - Result"); + setDefaultCloseOperation(JFrame.HIDE_ON_CLOSE); + setBounds((int) (Toolkit.getDefaultToolkit().getScreenSize().getWidth() / 2 - 400), + (int) (Toolkit.getDefaultToolkit().getScreenSize().getHeight() / 2 - 200), 800, 400); + contentPane = new JPanel(); + contentPane.setBackground(Color.GRAY); + contentPane.setBorder(new EmptyBorder(5, 5, 5, 5)); + setContentPane(contentPane); + contentPane.setLayout(new BorderLayout(0, 0)); + + Main.theme.apply(textArea); + textArea.setEditable(true); + textArea.setSyntaxEditingStyle(SyntaxConstants.SYNTAX_STYLE_JAVA_DISASSEMBLE); + textArea.setCodeFoldingEnabled(true); + textArea.setBackground(Color.LIGHT_GRAY); + + RTextScrollPane scrollPane = new RTextScrollPane(); + scrollPane.setViewportView(textArea); + scrollPane.setLineNumbersEnabled(true); + scrollPane.setFoldIndicatorEnabled(true); + scrollPane.getGutter().setBackground(Color.LIGHT_GRAY); + contentPane.add(scrollPane); + } +} diff --git a/src/me/ByteEdit/main/Main.java b/src/me/ByteEdit/main/Main.java index 0ffc9db..3c559c4 100644 --- a/src/me/ByteEdit/main/Main.java +++ b/src/me/ByteEdit/main/Main.java @@ -71,6 +71,7 @@ import org.objectweb.asm.tree.ClassNode; import org.objectweb.asm.tree.FieldNode; import org.objectweb.asm.tree.MethodNode; +import me.ByteEdit.boxes.CompilationBox; import me.ByteEdit.boxes.OptionBox; import me.ByteEdit.boxes.RenameBox; import me.ByteEdit.boxes.SearchBox; @@ -98,6 +99,7 @@ public class Main extends JFrame { public static OptionBox optionBox; public static UnicodeBox unicodeBox; public static RenameBox renameBox; + public static CompilationBox compilationBox; public static JTree tree; public static RTextScrollPane scrollPane_ByteEdit; public static Theme theme; @@ -188,11 +190,17 @@ public class Main extends JFrame { */ public Main() { INSTANCE = this; + try { + theme = Theme.load(getClass().getClassLoader().getResourceAsStream("org/fife/eclipse.xml")); + } catch (IOException e2) { + e2.printStackTrace(); + } searchBox = new SearchBox(); typeOpenBox = new TypeOpenBox(); optionBox = new OptionBox(); unicodeBox = new UnicodeBox(); renameBox = new RenameBox(); + compilationBox = new CompilationBox(); setTitle("ByteEdit"); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); setBounds((int) (Toolkit.getDefaultToolkit().getScreenSize().getWidth() / 2 - 407), @@ -218,11 +226,6 @@ public class Main extends JFrame { ac.setShowDescWindow(true); FoldParserManager.get().addFoldParserMapping(SyntaxConstants.SYNTAX_STYLE_JAVA_DISASSEMBLE, new CurlyFoldParser(false, true)); - try { - Theme theme = Theme.load(getClass().getClassLoader().getResourceAsStream("org/fife/eclipse.xml")); - } catch (IOException e2) { - e2.printStackTrace(); - } tree = new JTree(new DefaultTreeModel(null)); tree.addKeyListener(new KeyAdapter() { @@ -301,6 +304,7 @@ public class Main extends JFrame { optionBox.setVisible(false); unicodeBox.setVisible(false); renameBox.setVisible(false); + compilationBox.setVisible(false); isChangingFile = false; } dtde.dropComplete(true); @@ -367,6 +371,7 @@ public class Main extends JFrame { KeyStroke ctrlO = KeyStroke.getKeyStroke(KeyEvent.VK_O, KeyEvent.CTRL_DOWN_MASK); KeyStroke ctrlU = KeyStroke.getKeyStroke(KeyEvent.VK_U, KeyEvent.CTRL_DOWN_MASK); KeyStroke ctrlR = KeyStroke.getKeyStroke(KeyEvent.VK_R, KeyEvent.CTRL_DOWN_MASK); + KeyStroke ctrlE = KeyStroke.getKeyStroke(KeyEvent.VK_E, KeyEvent.CTRL_DOWN_MASK); // global txtByteEditView.registerKeyboardAction(new ActionListener() { @@ -400,6 +405,13 @@ public class Main extends JFrame { unicodeBox.setVisible(true); } }, ctrlU, JComponent.WHEN_IN_FOCUSED_WINDOW); + txtByteEditView.registerKeyboardAction(new ActionListener() { + + @Override + public void actionPerformed(ActionEvent e) { + compilationBox.setVisible(true); + } + }, ctrlE, JComponent.WHEN_IN_FOCUSED_WINDOW); // specific tree.registerKeyboardAction(new ActionListener() { @@ -441,12 +453,7 @@ public class Main extends JFrame { txtByteEditView.setSyntaxEditingStyle(SyntaxConstants.SYNTAX_STYLE_JAVA_DISASSEMBLE); txtByteEditView.setCodeFoldingEnabled(true); scrollPane_ByteEdit = new RTextScrollPane(); - try { - theme = Theme.load(getClass().getClassLoader().getResourceAsStream("org/fife/eclipse.xml")); - theme.apply(txtByteEditView); - } catch (IOException e2) { - e2.printStackTrace(); - } + theme.apply(txtByteEditView); splitPane.setRightComponent(scrollPane_ByteEdit); txtByteEditView.setBackground(Color.LIGHT_GRAY);