From cec2df468526786f2018e9f7b43425e7e72476ab Mon Sep 17 00:00:00 2001 From: Konloch Date: Fri, 25 Jun 2021 18:13:46 -0700 Subject: [PATCH] Code Cleanup + Refactored a lot of the GUI + Fixed a few bugs with the swing components and swing interaction + Includes #304 + Added LAF theme selection + Moved the Visual Settings from the Settings menu to the View menu + Added a simplified tab names option --- .../darcula/2017.11bcv/darcula-2017.11bcv.jar | Bin 0 -> 338307 bytes .../2017.11bcv/darcula-2017.11bcv.jar.md5 | 1 + .../2017.11bcv/darcula-2017.11bcv.jar.sha1 | 1 + .../darcula/2017.11bcv/darcula-2017.11bcv.pom | 8 + .../2017.11bcv/darcula-2017.11bcv.pom.md5 | 1 + .../2017.11bcv/darcula-2017.11bcv.pom.sha1 | 1 + libs/com/bulenkov/darcula/maven-metadata.xml | 12 + .../bulenkov/darcula/maven-metadata.xml.md5 | 1 + .../bulenkov/darcula/maven-metadata.xml.sha1 | 1 + pom.xml | 29 +- src/main/java/META-INF/MANIFEST.MF | 3 - .../club/bytecodeviewer/BytecodeViewer.java | 117 +- .../club/bytecodeviewer/CommandLineInput.java | 43 +- .../club/bytecodeviewer/Configuration.java | 11 +- .../club/bytecodeviewer/Constants.java | 3 + .../club/bytecodeviewer/Resources.java | 9 +- .../club/bytecodeviewer/Settings.java | 119 +- .../bytecodeviewer/api/BytecodeViewer.java | 53 +- .../bytecodeviewer/api/PluginConsole.java | 228 +- .../decompilers/ASMTextifierDecompiler.java | 3 +- .../decompilers/CFRDecompiler.java | 3 +- .../decompilers/Decompiler.java | 100 +- .../decompilers/Decompilers.java | 18 - .../decompilers/FernFlowerDecompiler.java | 3 +- .../decompilers/InternalDecompiler.java | 33 + .../decompilers/JADXDecompiler.java | 3 +- .../decompilers/JDGUIDecompiler.java | 4 +- .../decompilers/KrakatauDecompiler.java | 3 +- .../decompilers/KrakatauDisassembler.java | 3 +- .../decompilers/ProcyonDecompiler.java | 7 +- .../decompilers/SmaliDisassembler.java | 4 +- .../bytecode/ClassNodeDecompiler.java | 5 +- .../club/bytecodeviewer/gui/ClassViewer.java | 1908 ----------------- .../club/bytecodeviewer/gui/FileViewer.java | 328 --- .../bytecodeviewer/gui/MainViewerGUI.java | 97 +- .../club/bytecodeviewer/gui/TabbedPane.java | 352 --- .../club/bytecodeviewer/gui/WorkPane.java | 294 --- .../{extras => components}/AboutWindow.java | 2 +- .../gui/components/ButtonHoverAnimation.java | 35 + .../DecompilerViewComponent.java | 3 +- .../gui/{extras => components}/ExportJar.java | 2 +- .../gui/components/ImageJLabel.java | 18 + .../gui/components/JFrameConsole.java | 59 + .../components/JFrameConsolePrintStream.java | 62 + .../JTextAreaOutputStream.java | 2 +- .../gui/components/MaxWidthJLabel.java | 33 + .../gui/components/MethodsRenderer.java | 33 + .../{extras => components}/RunOptions.java | 2 +- .../gui/components/SearchableJTextArea.java | 92 + .../components/SearchableRSyntaxTextArea.java | 93 + .../gui/components/SystemErrConsole.java | 57 + .../gui/components/SystemOutConsole.java | 36 + .../{ => components}/VisibleComponent.java | 2 +- .../listeners/MouseClickedListener.java | 36 + .../listeners/PressKeyListener.java | 32 + .../listeners/ReleaseKeyListener.java | 32 + .../gui/extras/SystemErrConsole.java | 298 --- .../gui/resourcelist/ResourceListPane.java | 2 +- .../gui/resourcelist/ResourceTree.java | 2 +- .../gui/resourcesearch/PerformSearch.java | 54 + .../{ => resourcesearch}/SearchBoxPane.java | 68 +- .../gui/resourcesearch/SearchRadius.java | 10 + .../gui/resourcesearch/SearchType.java | 22 + .../DecompilerSelectionPane.java} | 9 +- .../ResourcePanelCompileMode.java | 12 + .../gui/resourceviewer/ResourceViewPanel.java | 107 + .../gui/resourceviewer/TabButton.java | 100 + .../gui/resourceviewer/TabRemovalEvent.java | 36 + .../gui/resourceviewer/TabbedPane.java | 250 +++ .../resourceviewer/WorkPaneMainComponent.java | 235 ++ .../gui/resourceviewer/WorkPaneRefresh.java | 65 + .../resourceviewer/viewer/ClassViewer.java | 569 +++++ .../gui/resourceviewer/viewer/FileViewer.java | 149 ++ .../viewer/ResourceViewer.java} | 10 +- .../viewer/synchronizedscroll/MethodData.java | 39 + .../bytecodeviewer/gui/theme/LAFTheme.java | 51 + .../bytecodeviewer/gui/theme/RSTATheme.java | 54 + .../gui/{ => util}/DelayTabbedPaneThread.java | 7 +- .../gui/{ => util}/PaneUpdaterThread.java | 145 +- .../{extras => util}/StringMetricsUtil.java | 2 +- .../preinstalled/CodeSequenceDiagram.java | 2 +- .../bytecodeviewer/util/JTextAreaUtils.java | 170 ++ .../club/bytecodeviewer/util/MiscUtils.java | 42 +- .../util/ResourceDecompiling.java | 35 +- .../util/ResourceExporting.java | 2 +- .../{Language.java => SyntaxLanguage.java} | 15 +- src/main/resources/META-INF/MANIFEST.MF | 3 - src/main/resources/jar.png | Bin 660 -> 1943 bytes 88 files changed, 3207 insertions(+), 3798 deletions(-) create mode 100644 libs/com/bulenkov/darcula/2017.11bcv/darcula-2017.11bcv.jar create mode 100644 libs/com/bulenkov/darcula/2017.11bcv/darcula-2017.11bcv.jar.md5 create mode 100644 libs/com/bulenkov/darcula/2017.11bcv/darcula-2017.11bcv.jar.sha1 create mode 100644 libs/com/bulenkov/darcula/2017.11bcv/darcula-2017.11bcv.pom create mode 100644 libs/com/bulenkov/darcula/2017.11bcv/darcula-2017.11bcv.pom.md5 create mode 100644 libs/com/bulenkov/darcula/2017.11bcv/darcula-2017.11bcv.pom.sha1 create mode 100644 libs/com/bulenkov/darcula/maven-metadata.xml create mode 100644 libs/com/bulenkov/darcula/maven-metadata.xml.md5 create mode 100644 libs/com/bulenkov/darcula/maven-metadata.xml.sha1 delete mode 100644 src/main/java/META-INF/MANIFEST.MF delete mode 100644 src/main/java/the/bytecode/club/bytecodeviewer/decompilers/Decompilers.java create mode 100644 src/main/java/the/bytecode/club/bytecodeviewer/decompilers/InternalDecompiler.java delete mode 100644 src/main/java/the/bytecode/club/bytecodeviewer/gui/ClassViewer.java delete mode 100644 src/main/java/the/bytecode/club/bytecodeviewer/gui/FileViewer.java delete mode 100644 src/main/java/the/bytecode/club/bytecodeviewer/gui/TabbedPane.java delete mode 100644 src/main/java/the/bytecode/club/bytecodeviewer/gui/WorkPane.java rename src/main/java/the/bytecode/club/bytecodeviewer/gui/{extras => components}/AboutWindow.java (99%) create mode 100644 src/main/java/the/bytecode/club/bytecodeviewer/gui/components/ButtonHoverAnimation.java rename src/main/java/the/bytecode/club/bytecodeviewer/gui/{ => components}/DecompilerViewComponent.java (95%) rename src/main/java/the/bytecode/club/bytecodeviewer/gui/{extras => components}/ExportJar.java (98%) create mode 100644 src/main/java/the/bytecode/club/bytecodeviewer/gui/components/ImageJLabel.java create mode 100644 src/main/java/the/bytecode/club/bytecodeviewer/gui/components/JFrameConsole.java create mode 100644 src/main/java/the/bytecode/club/bytecodeviewer/gui/components/JFrameConsolePrintStream.java rename src/main/java/the/bytecode/club/bytecodeviewer/gui/{extras => components}/JTextAreaOutputStream.java (90%) create mode 100644 src/main/java/the/bytecode/club/bytecodeviewer/gui/components/MaxWidthJLabel.java create mode 100644 src/main/java/the/bytecode/club/bytecodeviewer/gui/components/MethodsRenderer.java rename src/main/java/the/bytecode/club/bytecodeviewer/gui/{extras => components}/RunOptions.java (99%) create mode 100644 src/main/java/the/bytecode/club/bytecodeviewer/gui/components/SearchableJTextArea.java create mode 100644 src/main/java/the/bytecode/club/bytecodeviewer/gui/components/SearchableRSyntaxTextArea.java create mode 100644 src/main/java/the/bytecode/club/bytecodeviewer/gui/components/SystemErrConsole.java create mode 100644 src/main/java/the/bytecode/club/bytecodeviewer/gui/components/SystemOutConsole.java rename src/main/java/the/bytecode/club/bytecodeviewer/gui/{ => components}/VisibleComponent.java (96%) create mode 100644 src/main/java/the/bytecode/club/bytecodeviewer/gui/components/listeners/MouseClickedListener.java create mode 100644 src/main/java/the/bytecode/club/bytecodeviewer/gui/components/listeners/PressKeyListener.java create mode 100644 src/main/java/the/bytecode/club/bytecodeviewer/gui/components/listeners/ReleaseKeyListener.java delete mode 100644 src/main/java/the/bytecode/club/bytecodeviewer/gui/extras/SystemErrConsole.java create mode 100644 src/main/java/the/bytecode/club/bytecodeviewer/gui/resourcesearch/PerformSearch.java rename src/main/java/the/bytecode/club/bytecodeviewer/gui/{ => resourcesearch}/SearchBoxPane.java (74%) create mode 100644 src/main/java/the/bytecode/club/bytecodeviewer/gui/resourcesearch/SearchRadius.java create mode 100644 src/main/java/the/bytecode/club/bytecodeviewer/gui/resourcesearch/SearchType.java rename src/main/java/the/bytecode/club/bytecodeviewer/gui/{ViewPane.java => resourceviewer/DecompilerSelectionPane.java} (94%) create mode 100644 src/main/java/the/bytecode/club/bytecodeviewer/gui/resourceviewer/ResourcePanelCompileMode.java create mode 100644 src/main/java/the/bytecode/club/bytecodeviewer/gui/resourceviewer/ResourceViewPanel.java create mode 100644 src/main/java/the/bytecode/club/bytecodeviewer/gui/resourceviewer/TabButton.java create mode 100644 src/main/java/the/bytecode/club/bytecodeviewer/gui/resourceviewer/TabRemovalEvent.java create mode 100644 src/main/java/the/bytecode/club/bytecodeviewer/gui/resourceviewer/TabbedPane.java create mode 100644 src/main/java/the/bytecode/club/bytecodeviewer/gui/resourceviewer/WorkPaneMainComponent.java create mode 100644 src/main/java/the/bytecode/club/bytecodeviewer/gui/resourceviewer/WorkPaneRefresh.java create mode 100644 src/main/java/the/bytecode/club/bytecodeviewer/gui/resourceviewer/viewer/ClassViewer.java create mode 100644 src/main/java/the/bytecode/club/bytecodeviewer/gui/resourceviewer/viewer/FileViewer.java rename src/main/java/the/bytecode/club/bytecodeviewer/gui/{Viewer.java => resourceviewer/viewer/ResourceViewer.java} (90%) create mode 100644 src/main/java/the/bytecode/club/bytecodeviewer/gui/resourceviewer/viewer/synchronizedscroll/MethodData.java create mode 100644 src/main/java/the/bytecode/club/bytecodeviewer/gui/theme/LAFTheme.java create mode 100644 src/main/java/the/bytecode/club/bytecodeviewer/gui/theme/RSTATheme.java rename src/main/java/the/bytecode/club/bytecodeviewer/gui/{ => util}/DelayTabbedPaneThread.java (80%) rename src/main/java/the/bytecode/club/bytecodeviewer/gui/{ => util}/PaneUpdaterThread.java (68%) rename src/main/java/the/bytecode/club/bytecodeviewer/gui/{extras => util}/StringMetricsUtil.java (92%) create mode 100644 src/main/java/the/bytecode/club/bytecodeviewer/util/JTextAreaUtils.java rename src/main/java/the/bytecode/club/bytecodeviewer/util/{Language.java => SyntaxLanguage.java} (92%) delete mode 100644 src/main/resources/META-INF/MANIFEST.MF diff --git a/libs/com/bulenkov/darcula/2017.11bcv/darcula-2017.11bcv.jar b/libs/com/bulenkov/darcula/2017.11bcv/darcula-2017.11bcv.jar new file mode 100644 index 0000000000000000000000000000000000000000..13e0e1c82eeabb34fadf3eb26997ad26c5d062cb GIT binary patch literal 338307 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 z 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 + + 4.0.0 + com.bulenkov + darcula + 2017.11bcv + diff --git a/libs/com/bulenkov/darcula/2017.11bcv/darcula-2017.11bcv.pom.md5 b/libs/com/bulenkov/darcula/2017.11bcv/darcula-2017.11bcv.pom.md5 new file mode 100644 index 00000000..39fcf9d6 --- /dev/null +++ b/libs/com/bulenkov/darcula/2017.11bcv/darcula-2017.11bcv.pom.md5 @@ -0,0 +1 @@ +18d7207a865f9f1c7ac091ae2175c816 \ No newline at end of file diff --git a/libs/com/bulenkov/darcula/2017.11bcv/darcula-2017.11bcv.pom.sha1 b/libs/com/bulenkov/darcula/2017.11bcv/darcula-2017.11bcv.pom.sha1 new file mode 100644 index 00000000..fe3a5fdb --- /dev/null +++ b/libs/com/bulenkov/darcula/2017.11bcv/darcula-2017.11bcv.pom.sha1 @@ -0,0 +1 @@ +c24c87ad97daac49a716c8b1b35de813faa14315 \ No newline at end of file diff --git a/libs/com/bulenkov/darcula/maven-metadata.xml b/libs/com/bulenkov/darcula/maven-metadata.xml new file mode 100644 index 00000000..5e95470a --- /dev/null +++ b/libs/com/bulenkov/darcula/maven-metadata.xml @@ -0,0 +1,12 @@ + + + com.bulenkov + darcula + + 2017.11bcv + + 2017.11bcv + + 20210623081823 + + diff --git a/libs/com/bulenkov/darcula/maven-metadata.xml.md5 b/libs/com/bulenkov/darcula/maven-metadata.xml.md5 new file mode 100644 index 00000000..64ecffe2 --- /dev/null +++ b/libs/com/bulenkov/darcula/maven-metadata.xml.md5 @@ -0,0 +1 @@ +8c77ae68030a23cf5be1ad543a810476 \ No newline at end of file diff --git a/libs/com/bulenkov/darcula/maven-metadata.xml.sha1 b/libs/com/bulenkov/darcula/maven-metadata.xml.sha1 new file mode 100644 index 00000000..97be58a9 --- /dev/null +++ b/libs/com/bulenkov/darcula/maven-metadata.xml.sha1 @@ -0,0 +1 @@ +890769d1a55221b9f778bfb92a8af22bfd3439df \ No newline at end of file diff --git a/pom.xml b/pom.xml index fbc074af..cfe29d94 100644 --- a/pom.xml +++ b/pom.xml @@ -219,30 +219,15 @@ D2Jar-obf 1.0bcv + + com.bulenkov + darcula + 2017.11bcv + - - org.apache.maven.plugins - maven-dependency-plugin - 3.2.0 - - - unpack - - process-resources - - unpack-dependencies - - - system - ${basedir}/target/classes - - - - org.apache.maven.plugins maven-jar-plugin @@ -268,7 +253,7 @@ org.apache.maven.plugins maven-javadoc-plugin - 3.2.0 + 3.3.0 ${java.version} @@ -276,7 +261,7 @@ org.apache.maven.plugins maven-shade-plugin - 3.2.2 + 3.2.4 package diff --git a/src/main/java/META-INF/MANIFEST.MF b/src/main/java/META-INF/MANIFEST.MF deleted file mode 100644 index 919860b3..00000000 --- a/src/main/java/META-INF/MANIFEST.MF +++ /dev/null @@ -1,3 +0,0 @@ -Manifest-Version: 1.0 -Main-Class: the.bytecode.club.bytecodeviewer.BytecodeViewer - diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/BytecodeViewer.java b/src/main/java/the/bytecode/club/bytecodeviewer/BytecodeViewer.java index acb00f73..6f5c5b12 100644 --- a/src/main/java/the/bytecode/club/bytecodeviewer/BytecodeViewer.java +++ b/src/main/java/the/bytecode/club/bytecodeviewer/BytecodeViewer.java @@ -10,11 +10,7 @@ import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Objects; -import javax.swing.JDialog; -import javax.swing.JFileChooser; -import javax.swing.JMenuItem; -import javax.swing.JOptionPane; -import javax.swing.UIManager; +import javax.swing.*; import javax.swing.filechooser.FileFilter; import me.konloch.kontainer.io.DiskWriter; import me.konloch.kontainer.io.HTTPRequest; @@ -23,13 +19,15 @@ import org.objectweb.asm.tree.ClassNode; import the.bytecode.club.bootloader.Boot; import the.bytecode.club.bytecodeviewer.api.ClassNodeLoader; import the.bytecode.club.bytecodeviewer.compilers.Compilers; -import the.bytecode.club.bytecodeviewer.gui.ClassViewer; +import the.bytecode.club.bytecodeviewer.gui.components.DecompilerViewComponent; +import the.bytecode.club.bytecodeviewer.gui.resourceviewer.ResourcePanelCompileMode; +import the.bytecode.club.bytecodeviewer.gui.resourceviewer.viewer.ClassViewer; import the.bytecode.club.bytecodeviewer.gui.resourcelist.ResourceListPane; import the.bytecode.club.bytecodeviewer.gui.MainViewerGUI; -import the.bytecode.club.bytecodeviewer.gui.extras.RunOptions; -import the.bytecode.club.bytecodeviewer.gui.SearchBoxPane; -import the.bytecode.club.bytecodeviewer.gui.extras.SystemErrConsole; -import the.bytecode.club.bytecodeviewer.gui.WorkPane; +import the.bytecode.club.bytecodeviewer.gui.components.RunOptions; +import the.bytecode.club.bytecodeviewer.gui.resourcesearch.SearchBoxPane; +import the.bytecode.club.bytecodeviewer.gui.components.SystemErrConsole; +import the.bytecode.club.bytecodeviewer.gui.resourceviewer.WorkPaneMainComponent; import the.bytecode.club.bytecodeviewer.obfuscators.mapping.Refactorer; import the.bytecode.club.bytecodeviewer.plugin.PluginManager; import the.bytecode.club.bytecodeviewer.util.*; @@ -104,6 +102,7 @@ public class BytecodeViewer public static Refactorer refactorer = new Refactorer(); public static List files = new ArrayList<>(); //all of BCV's loaded files/classes/etc public static List createdProcesses = new ArrayList<>(); + public static final DecompilerViewComponent krakatau = new DecompilerViewComponent("Krakatau", true); public static final boolean EXPERIMENTAL_TAB_CODE = false; /** @@ -155,14 +154,16 @@ public class BytecodeViewer * @throws IOException */ public static byte[] getClassFile(Class clazz) throws IOException { - InputStream is = clazz.getResourceAsStream("/" + clazz.getName().replace('.', '/') + ".class"); - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - int r; - byte[] buffer = new byte[8192]; - while ((r = Objects.requireNonNull(is).read(buffer)) >= 0) { - baos.write(buffer, 0, r); + try (InputStream is = clazz.getResourceAsStream( + "/" + clazz.getName().replace('.', '/') + ".class"); + ByteArrayOutputStream baos = new ByteArrayOutputStream()) { + int r; + byte[] buffer = new byte[8192]; + while ((r = Objects.requireNonNull(is).read(buffer)) >= 0) { + baos.write(buffer, 0, r); + } + return baos.toByteArray(); } - return baos.toByteArray(); } /** @@ -176,8 +177,11 @@ public class BytecodeViewer System.setSecurityManager(sm); try { - UIManager.put("MenuItem.disabledAreNavigable", Boolean.FALSE); - UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); + //precache settings file + Settings.preloadSettingsFile(); + //setup look and feel + Configuration.lafTheme.setLAF(); + if (PREVIEW_COPY && !CommandLineInput.containsCommand(args)) showMessage("WARNING: This is a preview/dev copy, you WON'T be alerted when " + VERSION + " is " + "actually out if you use this." + nl + @@ -378,28 +382,36 @@ public class BytecodeViewer BytecodeViewer.viewer.updateBusyStatus(true); boolean actuallyTried = false; - for (java.awt.Component c : BytecodeViewer.viewer.workPane.getLoadedViewers()) { - if (c instanceof ClassViewer) { + for (java.awt.Component c : BytecodeViewer.viewer.workPane.getLoadedViewers()) + { + if (c instanceof ClassViewer) + { ClassViewer cv = (ClassViewer) c; - if (cv.smali1 != null && cv.smali1.isEditable() || - cv.smali2 != null && cv.smali2.isEditable() || - cv.smali3 != null && cv.smali3.isEditable()) { + + //compile smali assembly + if (cv.resourceViewPanel1.compileMode == ResourcePanelCompileMode.SMALI_ASSEMBLY && cv.resourceViewPanel1.textArea.isEditable() || + cv.resourceViewPanel2.compileMode == ResourcePanelCompileMode.SMALI_ASSEMBLY && cv.resourceViewPanel2.textArea.isEditable() || + cv.resourceViewPanel3.compileMode == ResourcePanelCompileMode.SMALI_ASSEMBLY && cv.resourceViewPanel3.textArea.isEditable()) + { actuallyTried = true; Object[] smali = cv.getSmali(); - if (smali != null) { + if (smali != null) + { ClassNode origNode = (ClassNode) smali[0]; String smaliText = (String) smali[1]; - byte[] smaliCompiled = - Compilers.smali.compile(smaliText, - origNode.name); - if (smaliCompiled != null) { + byte[] smaliCompiled = Compilers.smali.compile(smaliText, origNode.name); + + if (smaliCompiled != null) + { try { ClassNode newNode = JarUtils.getNode(smaliCompiled); BytecodeViewer.updateNode(origNode, newNode); } catch (Exception e) { e.printStackTrace(); } - } else { + } + else + { BytecodeViewer.showMessage("There has been an error with assembling your Smali code, " + "please check this. Class: " + origNode.name); BytecodeViewer.viewer.updateBusyStatus(false); @@ -408,26 +420,30 @@ public class BytecodeViewer } } - - if (cv.krakatau1 != null && cv.krakatau1.isEditable() || - cv.krakatau2 != null && cv.krakatau2.isEditable() || - cv.krakatau3 != null && cv.krakatau3.isEditable()) { + //compile krakatau assembly + if (cv.resourceViewPanel1.compileMode == ResourcePanelCompileMode.KRAKATAU_ASSEMBLY && cv.resourceViewPanel1.textArea.isEditable() || + cv.resourceViewPanel2.compileMode == ResourcePanelCompileMode.KRAKATAU_ASSEMBLY && cv.resourceViewPanel2.textArea.isEditable() || + cv.resourceViewPanel3.compileMode == ResourcePanelCompileMode.KRAKATAU_ASSEMBLY && cv.resourceViewPanel3.textArea.isEditable()) + { actuallyTried = true; Object[] krakatau = cv.getKrakatau(); - if (krakatau != null) { + if (krakatau != null) + { ClassNode origNode = (ClassNode) krakatau[0]; String krakatauText = (String) krakatau[1]; - byte[] krakatauCompiled = - Compilers.krakatau.compile(krakatauText, - origNode.name); - if (krakatauCompiled != null) { + byte[] krakatauCompiled = Compilers.krakatau.compile(krakatauText, origNode.name); + + if (krakatauCompiled != null) + { try { ClassNode newNode = JarUtils.getNode(krakatauCompiled); BytecodeViewer.updateNode(origNode, newNode); } catch (Exception e) { e.printStackTrace(); } - } else { + } + else + { BytecodeViewer.showMessage("There has been an error with assembling your Krakatau " + "Bytecode, please check this. Class: " + origNode.name); BytecodeViewer.viewer.updateBusyStatus(false); @@ -436,9 +452,11 @@ public class BytecodeViewer } } - if (cv.java1 != null && cv.java1.isEditable() || - cv.java2 != null && cv.java2.isEditable() || - cv.java3 != null && cv.java3.isEditable()) { + //default to java compiling + if (cv.resourceViewPanel1.textArea != null && cv.resourceViewPanel1.textArea.isEditable() || + cv.resourceViewPanel2.textArea != null && cv.resourceViewPanel2.textArea.isEditable() || + cv.resourceViewPanel3.textArea != null && cv.resourceViewPanel3.textArea.isEditable()) + { actuallyTried = true; Object[] java = cv.getJava(); if (java != null) { @@ -449,10 +467,9 @@ public class BytecodeViewer errConsole.setText("Error compiling class: " + origNode.name + nl + "Keep in mind most " + "decompilers cannot produce compilable classes" + nl + nl); - byte[] javaCompiled = - Compilers.java.compile(javaText, - origNode.name); - if (javaCompiled != null) { + byte[] javaCompiled = Compilers.java.compile(javaText, origNode.name); + if (javaCompiled != null) + { try { ClassNode newNode = JarUtils.getNode(javaCompiled); BytecodeViewer.updateNode(origNode, newNode); @@ -460,7 +477,9 @@ public class BytecodeViewer e.printStackTrace(); } errConsole.finished(); - } else { + } + else + { errConsole.pretty(); errConsole.setVisible(true); errConsole.finished(); @@ -554,7 +573,7 @@ public class BytecodeViewer files.clear(); LazyNameUtil.reset(); Objects.requireNonNull(MainViewerGUI.getComponent(ResourceListPane.class)).resetWorkspace(); - Objects.requireNonNull(MainViewerGUI.getComponent(WorkPane.class)).resetWorkspace(); + Objects.requireNonNull(MainViewerGUI.getComponent(WorkPaneMainComponent.class)).resetWorkspace(); Objects.requireNonNull(MainViewerGUI.getComponent(SearchBoxPane.class)).resetWorkspace(); the.bytecode.club.bytecodeviewer.api.BytecodeViewer.getClassNodeLoader().clear(); } diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/CommandLineInput.java b/src/main/java/the/bytecode/club/bytecodeviewer/CommandLineInput.java index 136b3b1d..68180888 100644 --- a/src/main/java/the/bytecode/club/bytecodeviewer/CommandLineInput.java +++ b/src/main/java/the/bytecode/club/bytecodeviewer/CommandLineInput.java @@ -8,7 +8,7 @@ import org.apache.commons.cli.DefaultParser; import org.apache.commons.cli.Options; import org.objectweb.asm.ClassWriter; import org.objectweb.asm.tree.ClassNode; -import the.bytecode.club.bytecodeviewer.decompilers.Decompilers; +import the.bytecode.club.bytecodeviewer.decompilers.Decompiler; import the.bytecode.club.bytecodeviewer.util.JarUtils; import the.bytecode.club.bytecodeviewer.util.MiscUtils; @@ -200,12 +200,12 @@ public class CommandLineInput { Thread.sleep(5 * 1000); if (target.equalsIgnoreCase("all")) { - Decompilers.procyon.decompileToZip(tempZip.getAbsolutePath(), output.getAbsolutePath()); + Decompiler.PROCYON.getDecompiler().decompileToZip(tempZip.getAbsolutePath(), output.getAbsolutePath()); } else { try { ClassNode cn = BytecodeViewer.getClassNode(target); final ClassWriter cw = accept(cn); - String contents = Decompilers.procyon.decompileClassNode(cn, cw.toByteArray()); + String contents = Decompiler.PROCYON.getDecompiler().decompileClassNode(cn, cw.toByteArray()); DiskWriter.replaceFile(output.getAbsolutePath(), contents, false); } catch (Exception e) { new the.bytecode.club.bytecodeviewer.api.ExceptionUI(e); @@ -218,12 +218,12 @@ public class CommandLineInput { Thread.sleep(5 * 1000); if (target.equalsIgnoreCase("all")) { - Decompilers.cfr.decompileToZip(tempZip.getAbsolutePath(), output.getAbsolutePath()); + Decompiler.CFR.getDecompiler().decompileToZip(tempZip.getAbsolutePath(), output.getAbsolutePath()); } else { try { ClassNode cn = BytecodeViewer.getClassNode(target); final ClassWriter cw = accept(cn); - String contents = Decompilers.cfr.decompileClassNode(cn, cw.toByteArray()); + String contents = Decompiler.CFR.getDecompiler().decompileClassNode(cn, cw.toByteArray()); DiskWriter.replaceFile(output.getAbsolutePath(), contents, false); } catch (Exception e) { new the.bytecode.club.bytecodeviewer.api.ExceptionUI(e); @@ -236,12 +236,12 @@ public class CommandLineInput { Thread.sleep(5 * 1000); if (target.equalsIgnoreCase("all")) { - Decompilers.fernflower.decompileToZip(tempZip.getAbsolutePath(), output.getAbsolutePath()); + Decompiler.FERNFLOWER.getDecompiler().decompileToZip(tempZip.getAbsolutePath(), output.getAbsolutePath()); } else { try { ClassNode cn = BytecodeViewer.getClassNode(target); final ClassWriter cw = accept(cn); - String contents = Decompilers.fernflower.decompileClassNode(cn, cw.toByteArray()); + String contents = Decompiler.FERNFLOWER.getDecompiler().decompileClassNode(cn, cw.toByteArray()); DiskWriter.replaceFile(output.getAbsolutePath(), contents, false); } catch (Exception e) { new the.bytecode.club.bytecodeviewer.api.ExceptionUI(e); @@ -254,12 +254,12 @@ public class CommandLineInput { Thread.sleep(5 * 1000); if (target.equalsIgnoreCase("all")) { - Decompilers.krakatau.decompileToZip(tempZip.getAbsolutePath(), output.getAbsolutePath()); + Decompiler.KRAKATAU.getDecompiler().decompileToZip(tempZip.getAbsolutePath(), output.getAbsolutePath()); } else { try { ClassNode cn = BytecodeViewer.getClassNode(target); final ClassWriter cw = accept(cn); - String contents = Decompilers.krakatau.decompileClassNode(cn, cw.toByteArray()); + String contents = Decompiler.KRAKATAU.getDecompiler().decompileClassNode(cn, cw.toByteArray()); DiskWriter.replaceFile(output.getAbsolutePath(), contents, false); } catch (Exception e) { new the.bytecode.club.bytecodeviewer.api.ExceptionUI(e); @@ -278,7 +278,7 @@ public class CommandLineInput { try { ClassNode cn = BytecodeViewer.getClassNode(target); final ClassWriter cw = accept(cn); - String contents = Decompilers.krakatauDA.decompileClassNode(cn, cw.toByteArray()); + String contents = Decompiler.KRAKATAU_BYTECODE.getDecompiler().decompileClassNode(cn, cw.toByteArray()); DiskWriter.replaceFile(output.getAbsolutePath(), contents, false); } catch (Exception e) { new the.bytecode.club.bytecodeviewer.api.ExceptionUI(e); @@ -297,7 +297,7 @@ public class CommandLineInput { try { ClassNode cn = BytecodeViewer.getClassNode(target); final ClassWriter cw = accept(cn); - String contents = Decompilers.jdgui.decompileClassNode(cn, cw.toByteArray()); + String contents = Decompiler.JDGUI.getDecompiler().decompileClassNode(cn, cw.toByteArray()); DiskWriter.replaceFile(output.getAbsolutePath(), contents, false); } catch (Exception e) { new the.bytecode.club.bytecodeviewer.api.ExceptionUI(e); @@ -316,7 +316,26 @@ public class CommandLineInput { try { ClassNode cn = BytecodeViewer.getClassNode(target); final ClassWriter cw = accept(cn); - String contents = Decompilers.smali.decompileClassNode(cn, cw.toByteArray()); + String contents = Decompiler.SMALI.getDecompiler().decompileClassNode(cn, cw.toByteArray()); + DiskWriter.replaceFile(output.getAbsolutePath(), contents, false); + } catch (Exception e) { + new the.bytecode.club.bytecodeviewer.api.ExceptionUI(e); + } + } + } else if (decompiler.equalsIgnoreCase("jadx")) { + System.out.println("Decompiling " + input.getAbsolutePath() + " with JADX"); + BytecodeViewer.openFiles(new File[]{input}, false); + + Thread.sleep(5 * 1000); + + if (target.equalsIgnoreCase("all")) { + System.out.println("Coming soon."); + //Decompiler.smali.decompileToZip(output.getAbsolutePath()); + } else { + try { + ClassNode cn = BytecodeViewer.getClassNode(target); + final ClassWriter cw = accept(cn); + String contents = Decompiler.JADX.getDecompiler().decompileClassNode(cn, cw.toByteArray()); DiskWriter.replaceFile(output.getAbsolutePath(), contents, false); } catch (Exception e) { new the.bytecode.club.bytecodeviewer.api.ExceptionUI(e); diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/Configuration.java b/src/main/java/the/bytecode/club/bytecodeviewer/Configuration.java index f39bfd84..10f52ea3 100644 --- a/src/main/java/the/bytecode/club/bytecodeviewer/Configuration.java +++ b/src/main/java/the/bytecode/club/bytecodeviewer/Configuration.java @@ -1,8 +1,13 @@ package the.bytecode.club.bytecodeviewer; +import the.bytecode.club.bytecodeviewer.gui.theme.LAFTheme; +import the.bytecode.club.bytecodeviewer.gui.theme.RSTATheme; + import java.io.File; /** + * A collection of variables that can be configured through the settings menu or some form of UI/plugin + * * @author Konloch * @since 6/21/2021 */ @@ -17,6 +22,7 @@ public class Configuration public static File krakatauTempDir; public static File krakatauTempJar; public static boolean displayParentInTab = false; //also change in the main GUI + public static boolean simplifiedTabNames = false; public static boolean currentlyDumping = false; public static boolean needsReDump = true; public static boolean warnForEditing = false; @@ -30,4 +36,7 @@ public class Configuration public static boolean verifyCorruptedStateOnBoot = false; //eventually may be a setting public static long lastHotKeyExecuted = System.currentTimeMillis(); -} + + public static LAFTheme lafTheme = LAFTheme.LIGHT; //lightmode by default since it uses the system theme + public static RSTATheme rstaTheme = lafTheme.getRSTATheme(); +} \ No newline at end of file diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/Constants.java b/src/main/java/the/bytecode/club/bytecodeviewer/Constants.java index 3d07d74a..f9bcbc30 100644 --- a/src/main/java/the/bytecode/club/bytecodeviewer/Constants.java +++ b/src/main/java/the/bytecode/club/bytecodeviewer/Constants.java @@ -10,6 +10,9 @@ import java.util.ArrayList; import java.util.List; /** + * General program constants, to use this class include everything as a wildcard static import: + * import static the.bytecode.club.bytecodeviewer.Constants.*; + * * @author Konloch * @since 6/21/2021 */ diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/Resources.java b/src/main/java/the/bytecode/club/bytecodeviewer/Resources.java index e78a0fcd..d4f05920 100644 --- a/src/main/java/the/bytecode/club/bytecodeviewer/Resources.java +++ b/src/main/java/the/bytecode/club/bytecodeviewer/Resources.java @@ -64,20 +64,17 @@ public class Resources { static { - icon = b642IMG( - "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"); + icon = b642IMG("iVBORw0KGgoAAAANSUhEUgAAADIAAAAyCAYAAAAeP4ixAAAUd0lEQVR42pWaWXRbVZaGq5iHqgaSeJZsy7YkD7KtwZItebblQfI8x/HseIodO3bixE5iZw4ZSBwyACkCXQ003dD0oigq1UBqFVQ1HSB0wkyvXt1VPNSiavHCC288/b3/I11ZSszQDzuRfO89Z39n/3uffST9BMBP17Dbgna72B1hdmfQ7hK7W+yeoN0btPvE7v8Rdl+Y3Rsc4+7guHcF5wif9/ag3fYd/v70J/zHWlGFcLPRKqth99Yoc1TVKssTc1b74Krxw1Vbh3yxAl+9Mre/QZmnrvFHG+/Xnud4alwxzpEXnJOm+UGfbEH/wv2NAHkwMQ4P6GLk/1hlDyXFKVuXFI/1yQnKolJ0yqLTEhFjTEKsKRlxZgPi01OQkJ6qTJeRBn2mEYlZpjWN13gP7+VzfJ7G8WjRqXo1xwZDQmhe+kBfHhR7QHz7O300fq6LUhYBQkJ1UxDkFggZdEMQIJoTCkCsAhDn6TgdpKMWE5KyzcqSc9JDZsjNCL3WridZAmA3Q3F8zhMVBFpHELGHxJcHk2KVPZAYE4K5BYSkD+hjQuR8kAMQYENKgkwgUTBJFMzJgQhkpIrzRnHKJA6axdl0pFgzkGrNRJotS5nRbokw7e8pco8GRygugk4ixYXhAnGhOF90ml7Nvd5AX7SoRMKsGRElK7mJD9E4SFSqTg1KgLh0wy0AdF5z2uTIRrozV1lmvg2ZBQHLyLfK33KQnifX8nJgFuO9fC5VQaWr8RhRXWaaWijO92NgbAGQ2whyG5NIu0FJag0IDs5JOBkBtJXXnKfjWW47LG4HcgqdyC1yKePrDAFItaSjrrkZlf5aZBXYA4AuawgqHIgLxQXjvFTB98GEg9zOivCglhffAcHBExkFmSyVEZDJzQQQhyyePOSI07aSAjjKPMgrL4SroliZvbgAxpwsxCcnYmFxCecvXESO3J9bnK8gCa8BMaoE4kJpMFRBOMw6gXkoOT6Q0wSRIJCBIHcQRCW43EDqDWEQISkpGUkUZLJwADpkF+ed4nS+twTu6jJ4aspR5KtU5iwrRGqmGdHxsThw6GH8540PYfU4FSShrQIfDqRJjtHRpHYzDP3UYOh7BIjKizCImLBIECItGIV0mYzyCQeg83S6xF+FsvoaVDT6UNHkQ2WzH56qMqRlmRGTEIdXXn0Nn/3XfyOvxKPu98hzrspiNQ6BuDAZIlGTRIdRZ/T1QZjwnFkfBhMEuUOBcPNR0dCqk0psyYkwCA6uRYGTEqCgqlQ5pJwXx6ta61HT1ghfRzPqulrh72xBcXUFjJnikCEZX/71b3j5lcvweMvU/XyOz3MhOJ6t1I1siQ7nYdTDYeLCCgAXW4PhhqmB3EkQXogS2mgJoQbBnOBg5iAEJ+FkXEXKp7SuWjlU3dqgnG7obkdzTyda+zYq87U2wlnkRoopDTc++Bh/+cuXKCorRXldDfwCW9VSr57nOIW1FaHoMN/CYbiY9Id+xQRh1gfzJS8AcidB7mJLsCEsGvGSF1piU043Q2hR8LbUqdVv3NShHO8c6kX35gFsHO5H48Y2FFaUIiM7C+9eu64glvYdQk6eHcXectS3NaO5u0M9z0iWN9SqcZln4TBUAnOT/hAmVvKFix0VlFgECPsbai9cUoSgpJiAlJOCqAhAcFJGgfJp6e1SAD2jg+gbG1IgzRs7UFpVia6Nm1Qk/ud//4yz5x6HMcOM6lofnrz0Dzh3/hfo6utF86ZO1As0x2NucXwtMlw85gwXU5MYFzk8KvSdDAS5mw2bqlJCy8RiLWcZ5P7AxGZZVRASfkaiRiZtkMkZhY2b+9E/sRlDk2MKpLGjFUXlpZjfvgs3PvwEH3/yOfbvPwxjuhm/fOYf8e9vvysgzwhQLfwivc7BXrT1dytZMr+4SJrMuHicfy2JMSrMlXCQe9jFxgabP1Yplj5TUFLc1LgvsMIQolpkUC+RaBMIrv7g5CjGtk1hZOsWtG/qQrFAbN+xC1ffuaZs8/AI0rMy8MaVN/H21fewY24n7K481DT40SPPD2wZQffIINoHNikYRobzMAdZAMIlZpAughILj0oQ5G4FwjY60H6kqd4nPBr2Ug8KRLclPi+8Uk7rJKnDIcbntmJqfhaD4yPw+mrQ2NiE16/8Hr9784/o6elDVrZFVao3//Af6O7ugaekGM0dbRjdOqGem9g+jeGpcSVNRoZyZe6xlLMqUmL0g2U/PCparlBNZCDIfTwXaF0smzmjndGwSzTy4SwvEklVKv3WtjUpTXcN94mcRjA+uxXTu3Zgascs2ro7kV/oxpGDD+OV37yGixefRq7VionxSbz2xu/x9N8/B19DHQZGhrF99y4sHlzGrn17sG1xXsEMTY2pxWmVnGNF43zFzBeJSq4WFVGJIawcMyr54SA85Kg9wxLIDbP0RtluSfASt0SjFKX+alUqlaT6N6F3bBgj01uwded2zC/txuT2GdSKkzaHHXsXlvDiS7/C0p59sOU51PuXX/ktnnn2BYxOTuDQsaM4fuYUDj9yHEtHDwrMXswszKtFYa6xcDQyX0RiLMtuRiWYK1QJ/WMOa70Y1cRTJkHuJ4g+2Ayy32GlYtuQJ+1FoWi1vKEGvvYmVaG6JbmZ2JM7tmHH3gXsObQf2xd3oqG1GQ6XE16vV5L6n3Di2CNwFeSju6sbz7/wr3j+n1/C/gNH8MjZM3j0icdw8uyKgtl75IBajKn5OWyWPNsk+dLau1Gi0qKiwvmZo/SHjSkrqdaLMR0iQArrm0K9VGAHt6vdmzW92FelcoPRYEL2jQ9jdNukksTCgSUcOH4Eew/vx/D4KMq9FXA4nVjYuRtPXHwK3qpquPLzsXLqLC6JtC499QwOHDyIxy5dFJgLOPHoaRw88TB2H9yH2d07g1EZQYdUMs5HFZTI/JSXVZpP+mVy5Cj5Mw14fmFaUFUE+VkAJF2BsNRlMcklyZhsJRJeVhKGm2Fngm9hNJYW1WoePX0Cx8WhveJM56aNKJRkZiQO7T+Co4eOocDjRkVlJc6dewLnH38SS4t7ce7i4wrm1PlHceTUcSwzKsu7VfIPSeIzB5tkk2U5LpUKRj8oc/pF2ROERYkgVJMG8nOCJNsyVGebLocgljx2pu6aMpQ2VKO2owlNvZ1SJgcwPD2BrbvmsFO0ve/oIRw6eQwPnzqJA0cPY3JmGg3NTSguLYGnqBB75hcxsnkMnsJC7J5fwKmV85id3YaVC+fEzmLPgWVMz2/Hlu3bML1zToFsnqa8BpSMKWfKmvKiP9myMbN6pQWrF8twEOT+EIjBlgmjyCpDwpcjna2zskhqeYXqhfydzWiV0tgzOoSRmUlMyaTbJEFp01KxRqcmML5nAVv2L2Fibhua21pRXlmhgFrkdUlpKZb278P8rnlMTm9V0DM75tAiZXho2zTmDu7H7IF9GJb9aLOU5V6Rb5vIuK6rRXXQ3CBVnhQ51WnT6LCoPOHmHQFS1NCMFLu06XIczZBzQW6pdLfeYhT6pew2+VVDyIF7mB+zUypHugf7pBVpx+Dhneh/dDtGji6iV2S3eWwU/UMD8NXXobS8DCXSJBaJ3Ljj1/p96B4dwYgk9qaJUSVBp0jPXVGOscO7MHZ8D/okR/rGN0s+9oRAWP6dFUVKKQGQ1ZblVhChNLnkwORxKBBXVUkARAbyy4BtgwIyIWVXIHqkspRJL0X9dqxsRd2ZLvScmsPwyUUMHV/ExCMSmZNLGDy2gMkTSxgVB2ljx/Zg4uG9GDu0G91Sasu90sIXiWSsufANSJtydExanj6BEZDBntDmWOT3KoXkFAtIgYDkfS+InDmENrMwEqSSHW4YyGbJkY1DfSiuKBMHcpQTnqoK+Po60TEzis7FKWxankPv8nZ0755F5/wU2qZG0CiFoqqlUUXHH9wYB8dGUFvvh1U64s6js2jcJ/f2daNXgYi0NkaC5JbkC4hNpQDbFX12JIiqWioi+bkKxFrmhrN6NSI+GbBFVmzT+BCGZyYwtHUMrbKTl1fLzuspkI1PHNklSbo8g3x3AdyFHpXshcVFyviaVlpThVZpRYYlp3bI7j4kJbuithrt+6ZRd3pMnK5Hx0BgwbhwfpmX89MPSj1HgdgVSHIkyGr5NUhEjAKSoSIiIIxInRcVLX7UdjULiPRXY4MKZGJ+BpPz2zAoeq6u96kmsPPELPLP1sK70o+qlSHUr4yj9/wONJ+eRN3KKGrPDKPqXDfKzrZh+MRuDEk0muQQ1rl3Kxr2TaBICkt9e7N0DUNqwVpl4agEzu8REEdFoQJJl4ikUVpSZfU5kSBqQzTkWWAU/WUUOZBTVgCHt0g2G2nbm+UE2Cnlt1/OHSP9GJBojAvI3NKCql6N7a0qKlaHDcWSM22LW1C9bwydJ+fQviI92LFtqFwaQc3iKHxjvaiRHbu5pwteiYQqrdKMukuL1EGrR1qf/qlRdI32o0mkWiNlv1yqpluqFkGyJUfS3QEQgz0TOqlcESB8Y8iTiBTkIt1jR3ZpPmyVhXDWlMLtkzJaL7t7Wx3quqXXosSCkWGj1yqnvKKyEqXzmr52lLf4VM/FPkszQlrtNtidDlRUV6G5vQ1V0inz2Ov1VauKxkgMz2xB36Ts7Jt7UbepTfLTL3tZOezlHpF7AbKk/JoFJJURsUtEcs3azr7aayULSJpIyywgFgGxlrtV0rNZe/rZX+K996/h2vX38f6N67j+wQ1lNz78ANdv3MB7167htddfx9DFnYifM+PUSxfxzqfX8f5nHyp757PruPr5+3j783dx7fMPcOPjj/DBRx8qY9fM/z/65GM8/9KL2CiLxHz0yrnHKXtHdVMdrr73jti72LZnF8yy2KmiHoLoRFrBXmu1jU/Ky0SKKxsmt1SuYicsYmbpa5IzTHjrj3/At99++4PGHT7N6/pR92rmcLtw6syKev31119jZHZSJXmBHORMVgt+9eqv1bU//flPqv8zyhaRIiCJtnToJCLhIPfyTaIjEwanBWmUl+QJJWaQ/ishLQmv/+4KvvnmG7wh/8clJkBnTkFcmZzWii3QS7/Da7TlfcvYEB0Ver+0zPfRyqJiohEdGwN9UqKcGDORK3LLkvKdYjYiK9+BL//2V/XMv115XQ5VXlhcUgl7u0NjDU+Oq+6DqmEaJNrFt1xTxHnkngBIBpKdWQrEVGhTkUmSDjPOkIhf/+ZVfPXVV3jzrbfglx27fcsAyqe8qJvtQNNEj7pGm5EdOz4lMfR+z/ISdGkGJKYbZXXZWUt5L3HBXOVBqt+DzMZiGCWC8bKyW+dmQs8NSDXkZ8U3RL58z/nV5wguWeh8UYmoR28VEJFW8IQYOLPzjU5CRZBUudEoECzF/FIm1qCXg9K/4IsvvvhBe/vaVaTU2ULvdz55GMZdXmQv+8XqkLfcCveODngmO+EZaUGWvwyJIhWdOKgvtOClV15Wz1195yoW9uwOjZNfXoxUh0VFI8WZjSRRj17Kb7xEJPJTFHlDkPCopIjMdNJdRicn4JnnnsWnn36KK1euYEqavsmtk9gytWpHjh5R12l1XW2h1wvHDqGorxFlo51wDrXAvaUTjplOlC0OoGR5ALZjnXDtakdavQdRqUnSrhSGntVsVhpN7uKEoF/0Ty+JnmA1Iy7XGAGiPteKt5mgE90lOSXp87PVBhlvNiAqMR6/uPQkrkllevKpS4hN0iFaH4/ohFisj4nCA+seUs0hr9N8sqlpr2ePLiOztxbZIw2wjNYjc7wettk2uKc7YOmqgbGhHGZpy3UpyYhL0quxF/buDj1PSWW4pNy6AipJEbUwl3XBaMTmpEV8QKc+Mo2zEkQSOE+i4pJ+X17HyZl4Q2Iczsr54S3Jj8u/vYwLjz8WsvOPXcDZ8+fw1NNPqes0drva6xdefAHn5Pq58+eD/59bfX/hvBojU/Imxy0V0p4NvSkFaZIbly9fVs+zDVJduUBQ8owGVUP1xIu/casgqx9iM0zxNnMQJpBM/HJynS5WDkSn8brsEz9kzz33HAymNJxeWflR99PUuaeuElbZswwWM2KT9eiSanX60TOBz55FHZQUKyohwmUVm50a8SH2HXzDMDEqCazP6maT+gBsnT4WD8VHY11CDNbr4pTUopMSVBFgRYsXbSeI6YwpSDKnKtMbDdCn3Wq61OSQ8R5GwSXdg6fBC7u3ULXn8cZkxBh0MNosSt6MhEGKAfc5vSMSIsaSEvG1gvrGihcYKoaModPxgcwUxPAbVhk4OkWH2NRENVGCSRyTQpAkVS1ZSnRKdjpM/CyM3xvy2yd5bRJHzLbskJlsgb8ZZZMz5sp+YM1SZ3BHVTHyastgqypCZlGe6mrVV3z8ZoxVSiKSREkJCBc4zmoUkDRZeClEqyC3h0BiLKkBGEqMkREQwuhpUueTRGps1FSXLMmXLg0mD2FZMjmbOVuFR/QqTkm77RC55NHktbMqYHzNv7H5s8n5O1daIBtfC4BVopFdXiB7jFPywaYqJsssO41wCEqfqqF6YrIJkhrx1Zv6MpQgNEZFg2FkqEmGleGlVpl43DA5qaUsHznigLXSA5s4Y68WZ0UqTllhl68M+f7ykPE9/87rvM8uAHyGz3McjmcutMPksQXKv0CoUuvQImG6BSJKIhIEuS309TTDFAETJrNwGE6gdn+ZkBNnFOchq9QVgsqtcIfAFJw4rDlN4zXel122CsCWiIujVSctJ1hqVXLbAnlBnwK5ETD6HP6tbghEg9HyRYPhQIENMzMExAk1IDqhQdExDWwt4zXNeS0C4QCMgkps+2qZ1UrtzRBRWQYNZPW3KPxjOEwE0BpS44RahDQoJbswsLVM9XFB5/nMzQCBDS9dLZ4CCEaCdjME7ZYf1WzINIQufh/MzUA3Q4WDrWW8pjmvSehmGYWi8B1y0vxcEyTiJ05r/Mwp7wd+5vRdP2XiMTrc1vqZE8dZ62dOed/zMyfbWj9z+n/+8OyuNX54ds/3/OjsZzfZzT8+uzdsjO/68dkP/vDs/wBUXNeRym9KEQAAAABJRU5ErkJggg=="); nextIcon = new ImageIcon(b642IMG("iVBORw0KGgoAAAANSUhEUgAAABAAAAAQBAMAAADt3eJSAAAAMFBMVEX" + "///8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAv3aB7AAAABnRSTlMANzlYqPBJSG" + "/ZAAAASUlEQVR42mNgwAbS0oAEE4yHyWBmYAzjYDC694OJ4f9" + "+BoY3H0BSbz6A2MxA6VciFyDqGAWQTWVkYEkCUrcOsDD8OwtkvMViMwAb8xEUHlHcFAAAAABJRU5ErkJggg==")); prevIcon = new ImageIcon(b642IMG("iVBORw0KGgoAAAANSUhEUgAAABAAAAAQBAMAAADt3eJSAAAAMFBMVEX" - + - "///8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAv3aB7AAAABnRSTlMANzlYgKhxpRi1AAAATElEQVR42mNgwAZYHIAEExA7qUAYLApMDmCGEwODCojByM/A8FEAyPi/moFh9QewYjCAM1iA+D2KqYwMrIlA6tUGFoa/Z4GMt1hsBgCe1wuKber+SwAAAABJRU5ErkJggg==")); + + "///8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAv3aB7AAAABnRSTlMANzlYgKhxpRi1AAAATElEQVR42mNgwAZYHIAEExA7qUAYLApMDmCGEwODCojByM/A8FEAyPi/moFh9QewYjCAM1iA+D2KqYwMrIlA6tUGFoa/Z4GMt1hsBgCe1wuKber+SwAAAABJRU5ErkJggg==")); busyIcon = new ImageIcon(Objects.requireNonNull(Resources.class.getResource("/1.gif"))); busyB64Icon = new ImageIcon(b642IMG("R0lGODlhEAALAPQAAP" + "///wAAANra2tDQ0Orq6gcHBwAAAC8vL4KCgmFhYbq6uiMjI0tLS4qKimVlZb6+vicnJwUFBU9PT" - + - "+bm5tjY2PT09Dk5Odzc3PLy8ra2tqCgoMrKyu7u7gAAAAAAAAAAACH5BAkLAAAAIf4aQ3JlYXRlZCB3aXRoIGFqYXhsb2FkLmluZm8AIf8LTkVUU0NBUEUyLjADAQAAACwAAAAAEAALAAAFLSAgjmRpnqSgCuLKAq5AEIM4zDVw03ve27ifDgfkEYe04kDIDC5zrtYKRa2WQgAh+QQJCwAAACwAAAAAEAALAAAFJGBhGAVgnqhpHIeRvsDawqns0qeN5+y967tYLyicBYE7EYkYAgAh+QQJCwAAACwAAAAAEAALAAAFNiAgjothLOOIJAkiGgxjpGKiKMkbz7SN6zIawJcDwIK9W/HISxGBzdHTuBNOmcJVCyoUlk7CEAAh+QQJCwAAACwAAAAAEAALAAAFNSAgjqQIRRFUAo3jNGIkSdHqPI8Tz3V55zuaDacDyIQ+YrBH+hWPzJFzOQQaeavWi7oqnVIhACH5BAkLAAAALAAAAAAQAAsAAAUyICCOZGme1rJY5kRRk7hI0mJSVUXJtF3iOl7tltsBZsNfUegjAY3I5sgFY55KqdX1GgIAIfkECQsAAAAsAAAAABAACwAABTcgII5kaZ4kcV2EqLJipmnZhWGXaOOitm2aXQ4g7P2Ct2ER4AMul00kj5g0Al8tADY2y6C+4FIIACH5BAkLAAAALAAAAAAQAAsAAAUvICCOZGme5ERRk6iy7qpyHCVStA3gNa/7txxwlwv2isSacYUc+l4tADQGQ1mvpBAAIfkECQsAAAAsAAAAABAACwAABS8gII5kaZ7kRFGTqLLuqnIcJVK0DeA1r/u3HHCXC/aKxJpxhRz6Xi0ANAZDWa+kEAA7")); + + "+bm5tjY2PT09Dk5Odzc3PLy8ra2tqCgoMrKyu7u7gAAAAAAAAAAACH5BAkLAAAAIf4aQ3JlYXRlZCB3aXRoIGFqYXhsb2FkLmluZm8AIf8LTkVUU0NBUEUyLjADAQAAACwAAAAAEAALAAAFLSAgjmRpnqSgCuLKAq5AEIM4zDVw03ve27ifDgfkEYe04kDIDC5zrtYKRa2WQgAh+QQJCwAAACwAAAAAEAALAAAFJGBhGAVgnqhpHIeRvsDawqns0qeN5+y967tYLyicBYE7EYkYAgAh+QQJCwAAACwAAAAAEAALAAAFNiAgjothLOOIJAkiGgxjpGKiKMkbz7SN6zIawJcDwIK9W/HISxGBzdHTuBNOmcJVCyoUlk7CEAAh+QQJCwAAACwAAAAAEAALAAAFNSAgjqQIRRFUAo3jNGIkSdHqPI8Tz3V55zuaDacDyIQ+YrBH+hWPzJFzOQQaeavWi7oqnVIhACH5BAkLAAAALAAAAAAQAAsAAAUyICCOZGme1rJY5kRRk7hI0mJSVUXJtF3iOl7tltsBZsNfUegjAY3I5sgFY55KqdX1GgIAIfkECQsAAAAsAAAAABAACwAABTcgII5kaZ4kcV2EqLJipmnZhWGXaOOitm2aXQ4g7P2Ct2ER4AMul00kj5g0Al8tADY2y6C+4FIIACH5BAkLAAAALAAAAAAQAAsAAAUvICCOZGme5ERRk6iy7qpyHCVStA3gNa/7txxwlwv2isSacYUc+l4tADQGQ1mvpBAAIfkECQsAAAAsAAAAABAACwAABS8gII5kaZ7kRFGTqLLuqnIcJVK0DeA1r/u3HHCXC/aKxJpxhRz6Xi0ANAZDWa+kEAA7")); batIcon = new ImageIcon(Objects.requireNonNull(Resources.class.getResource("/bat.png"))); shIcon = new ImageIcon(Objects.requireNonNull(Resources.class.getResource("/sh.png"))); diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/Settings.java b/src/main/java/the/bytecode/club/bytecodeviewer/Settings.java index 00e0f021..82e20bd3 100644 --- a/src/main/java/the/bytecode/club/bytecodeviewer/Settings.java +++ b/src/main/java/the/bytecode/club/bytecodeviewer/Settings.java @@ -3,6 +3,8 @@ package the.bytecode.club.bytecodeviewer; import javax.swing.JFrame; import me.konloch.kontainer.io.DiskReader; import me.konloch.kontainer.io.DiskWriter; +import the.bytecode.club.bytecodeviewer.gui.theme.LAFTheme; +import the.bytecode.club.bytecodeviewer.gui.theme.RSTATheme; import static the.bytecode.club.bytecodeviewer.Constants.*; @@ -291,23 +293,48 @@ public class Settings { String.valueOf(BytecodeViewer.viewer.ren.isSelected()), false); DiskWriter.writeNewLine(settingsName, String.valueOf(BytecodeViewer.viewer.viewPane1.getJADX().getEditable().isSelected()), false); + DiskWriter.writeNewLine(settingsName, + Configuration.lafTheme.name(), false); + DiskWriter.writeNewLine(settingsName, + Configuration.rstaTheme.name(), false); + DiskWriter.writeNewLine(settingsName, + String.valueOf(BytecodeViewer.viewer.simplifyNameInTabTitle.isSelected()), false); } catch (Exception e) { new the.bytecode.club.bytecodeviewer.api.ExceptionUI(e); } } - + + public static void preloadSettingsFile() + { + try + { + //precache the file + DiskReader.loadString(settingsName, 0, true); + + //process the cached file + Configuration.lafTheme = LAFTheme.valueOf(asString(127)); + Configuration.rstaTheme = RSTATheme.valueOf(asString(128)); + } + catch (Exception e) + { + //ignore because errors are expected, first start up and outdated settings. + //e.printStackTrace(); + } + } + public static void loadSettings() { //utilizes the Disk Reader's caching system. try { - BytecodeViewer.viewer.rbr.setSelected(Boolean.parseBoolean(DiskReader.loadString(settingsName, 1, true))); - BytecodeViewer.viewer.rsy.setSelected(Boolean.parseBoolean(DiskReader.loadString(settingsName, 2, false))); - BytecodeViewer.viewer.din.setSelected(Boolean.parseBoolean(DiskReader.loadString(settingsName, 3, false))); - BytecodeViewer.viewer.dc4.setSelected(Boolean.parseBoolean(DiskReader.loadString(settingsName, 4, false))); - BytecodeViewer.viewer.das.setSelected(Boolean.parseBoolean(DiskReader.loadString(settingsName, 5, false))); - BytecodeViewer.viewer.hes.setSelected(Boolean.parseBoolean(DiskReader.loadString(settingsName, 6, false))); - BytecodeViewer.viewer.hdc.setSelected(Boolean.parseBoolean(DiskReader.loadString(settingsName, 7, false))); - BytecodeViewer.viewer.dgs.setSelected(Boolean.parseBoolean(DiskReader.loadString(settingsName, 8, false))); - BytecodeViewer.viewer.ner.setSelected(Boolean.parseBoolean(DiskReader.loadString(settingsName, 9, false))); - BytecodeViewer.viewer.den.setSelected(Boolean.parseBoolean(DiskReader.loadString(settingsName, 10, false))); + //parse the cached file from memory + BytecodeViewer.viewer.rbr.setSelected(asBoolean(1)); + BytecodeViewer.viewer.rsy.setSelected(asBoolean(2)); + BytecodeViewer.viewer.din.setSelected(asBoolean(3)); + BytecodeViewer.viewer.dc4.setSelected(asBoolean(4)); + BytecodeViewer.viewer.das.setSelected(asBoolean(5)); + BytecodeViewer.viewer.hes.setSelected(asBoolean(6)); + BytecodeViewer.viewer.hdc.setSelected(asBoolean(7)); + BytecodeViewer.viewer.dgs.setSelected(asBoolean(8)); + BytecodeViewer.viewer.ner.setSelected(asBoolean(9)); + BytecodeViewer.viewer.den.setSelected(asBoolean(10)); BytecodeViewer.viewer.rgn.setSelected(Boolean.parseBoolean(DiskReader.loadString(settingsName, 11, false))); BytecodeViewer.viewer.bto.setSelected(Boolean.parseBoolean(DiskReader.loadString(settingsName, 12, false))); BytecodeViewer.viewer.nns.setSelected(Boolean.parseBoolean(DiskReader.loadString(settingsName, 13, false))); @@ -378,30 +405,30 @@ public class Settings { BytecodeViewer.viewer.debugHelpers.setSelected(Boolean.parseBoolean(DiskReader.loadString(settingsName, 78, false))); //79 is deprecated BytecodeViewer.viewer.updateCheck.setSelected(Boolean.parseBoolean(DiskReader.loadString(settingsName, 80, false))); - BytecodeViewer.viewer.viewPane1.setSelectedViewer(getInt(81)); - BytecodeViewer.viewer.viewPane2.setSelectedViewer(getInt(82)); - BytecodeViewer.viewer.viewPane3.setSelectedViewer(getInt(83)); + BytecodeViewer.viewer.viewPane1.setSelectedViewer(asInt(81)); + BytecodeViewer.viewer.viewPane2.setSelectedViewer(asInt(82)); + BytecodeViewer.viewer.viewPane3.setSelectedViewer(asInt(83)); - BytecodeViewer.viewer.refreshOnChange.setSelected(Boolean.parseBoolean(DiskReader.loadString(settingsName, 84, false))); + BytecodeViewer.viewer.refreshOnChange.setSelected(asBoolean(84)); - boolean bool = Boolean.parseBoolean(DiskReader.loadString(settingsName, 85, false)); + boolean bool = Boolean.parseBoolean(asString(85)); if (bool) { BytecodeViewer.viewer.setExtendedState(JFrame.MAXIMIZED_BOTH); BytecodeViewer.viewer.isMaximized = true; } //86 is deprecated //87 is deprecated - Configuration.lastDirectory = DiskReader.loadString(settingsName, 88, false); - Configuration.python = DiskReader.loadString(settingsName, 89, false); - Configuration.rt = DiskReader.loadString(settingsName, 90, false); - BytecodeViewer.viewer.viewPane1.getProcyon().getEditable().setSelected(Boolean.parseBoolean(DiskReader.loadString(settingsName, 91, false))); - BytecodeViewer.viewer.viewPane1.getCFR().getEditable().setSelected(Boolean.parseBoolean(DiskReader.loadString(settingsName, 92, false))); - BytecodeViewer.viewer.viewPane1.getFern().getEditable().setSelected(Boolean.parseBoolean(DiskReader.loadString(settingsName, 93, false))); - BytecodeViewer.viewer.viewPane1.getKrakatau().getEditable().setSelected(Boolean.parseBoolean(DiskReader.loadString(settingsName, 94, false))); - BytecodeViewer.viewer.viewPane1.getSmali().getEditable().setSelected(Boolean.parseBoolean(DiskReader.loadString(settingsName, 95, false))); - BytecodeViewer.viewer.viewPane2.getProcyon().getEditable().setSelected(Boolean.parseBoolean(DiskReader.loadString(settingsName, 96, false))); - BytecodeViewer.viewer.viewPane2.getCFR().getEditable().setSelected(Boolean.parseBoolean(DiskReader.loadString(settingsName, 97, false))); - BytecodeViewer.viewer.viewPane2.getFern().getEditable().setSelected(Boolean.parseBoolean(DiskReader.loadString(settingsName, 98, false))); + Configuration.lastDirectory = asString(88); + Configuration.python = asString(89); + Configuration.rt = asString(90); + BytecodeViewer.viewer.viewPane1.getProcyon().getEditable().setSelected(asBoolean(91)); + BytecodeViewer.viewer.viewPane1.getCFR().getEditable().setSelected(asBoolean(92)); + BytecodeViewer.viewer.viewPane1.getFern().getEditable().setSelected(asBoolean(93)); + BytecodeViewer.viewer.viewPane1.getKrakatau().getEditable().setSelected(asBoolean(94)); + BytecodeViewer.viewer.viewPane1.getSmali().getEditable().setSelected(asBoolean(95)); + BytecodeViewer.viewer.viewPane2.getProcyon().getEditable().setSelected(asBoolean(96)); + BytecodeViewer.viewer.viewPane2.getCFR().getEditable().setSelected(asBoolean(97)); + BytecodeViewer.viewer.viewPane2.getFern().getEditable().setSelected(asBoolean(98)); BytecodeViewer.viewer.viewPane2.getKrakatau().getEditable().setSelected(asBoolean(99)); BytecodeViewer.viewer.viewPane2.getSmali().getEditable().setSelected(asBoolean(100)); BytecodeViewer.viewer.viewPane3.getProcyon().getEditable().setSelected(asBoolean(101)); @@ -410,26 +437,31 @@ public class Settings { BytecodeViewer.viewer.viewPane3.getKrakatau().getEditable().setSelected(asBoolean(104)); BytecodeViewer.viewer.viewPane3.getSmali().getEditable().setSelected(asBoolean(105)); BytecodeViewer.viewer.decodeAPKResources.setSelected(asBoolean(106)); - Configuration.library = DiskReader.loadString(settingsName, 107, false); + Configuration.library = asString(107); Configuration.pingback = asBoolean(108); BytecodeViewer.viewer.viewPane1.getJD().getEditable().setSelected(asBoolean(109)); BytecodeViewer.viewer.viewPane2.getJD().getEditable().setSelected(asBoolean(110)); BytecodeViewer.viewer.viewPane3.getJD().getEditable().setSelected(asBoolean(111)); - BytecodeViewer.viewer.fontSpinner.setValue(getInt(112)); + BytecodeViewer.viewer.fontSpinner.setValue(asInt(112)); Configuration.deleteForeignLibraries = asBoolean(113); - int apkDecompiler = getInt(114); - if (apkDecompiler == 0) - BytecodeViewer.viewer.apkConversionGroup.setSelected(BytecodeViewer.viewer.apkConversionDex.getModel(), true); - else if (apkDecompiler == 1) - BytecodeViewer.viewer.apkConversionGroup.setSelected(BytecodeViewer.viewer.apkConversionEnjarify.getModel(), true); + //APK Decompiler + switch(asInt(114)) + { + case 0: + BytecodeViewer.viewer.apkConversionGroup.setSelected(BytecodeViewer.viewer.apkConversionDex.getModel(), true); + break; + case 1: + BytecodeViewer.viewer.apkConversionGroup.setSelected(BytecodeViewer.viewer.apkConversionEnjarify.getModel(), true); + break; + } - Configuration.python3 = DiskReader.loadString(settingsName, 115, false); - Configuration.javac = DiskReader.loadString(settingsName, 116, false); - Configuration.java = DiskReader.loadString(settingsName, 117, false); + Configuration.python3 = asString(115); + Configuration.javac = asString(116); + Configuration.java = asString(117); BytecodeViewer.viewer.compileOnSave.setSelected(asBoolean(118)); BytecodeViewer.viewer.autoCompileOnRefresh.setSelected(asBoolean(119)); - Configuration.warnForEditing = Boolean.parseBoolean(DiskReader.loadString(settingsName, 120, false)); + Configuration.warnForEditing = asBoolean(120); BytecodeViewer.viewer.showFileInTabTitle.setSelected(asBoolean(121)); Configuration.displayParentInTab = BytecodeViewer.viewer.showFileInTabTitle.isSelected(); BytecodeViewer.viewer.forcePureAsciiAsText.setSelected(asBoolean(122)); @@ -437,18 +469,27 @@ public class Settings { BytecodeViewer.viewer.showClassMethods.setSelected(asBoolean(124)); BytecodeViewer.viewer.ren.setSelected(asBoolean(125)); BytecodeViewer.viewer.viewPane1.getJADX().getEditable().setSelected(asBoolean(126)); + //line 127 is used for theme on preload + //line 128 is used for theme on preload + BytecodeViewer.viewer.simplifyNameInTabTitle.setSelected(asBoolean(129)); + Configuration.simplifiedTabNames = BytecodeViewer.viewer.simplifyNameInTabTitle.isSelected(); } catch (Exception e) { //ignore because errors are expected, first start up and outdated settings. //e.printStackTrace(); } } + public static String asString(int lineNumber) throws Exception + { + return DiskReader.loadString(settingsName, lineNumber, false); + } + public static boolean asBoolean(int lineNumber) throws Exception { return Boolean.parseBoolean(DiskReader.loadString(settingsName, lineNumber, false)); } - public static int getInt(int lineNumber) throws Exception + public static int asInt(int lineNumber) throws Exception { return Integer.parseInt(DiskReader.loadString(settingsName, lineNumber, false)); } diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/api/BytecodeViewer.java b/src/main/java/the/bytecode/club/bytecodeviewer/api/BytecodeViewer.java index 26e71837..9b167265 100644 --- a/src/main/java/the/bytecode/club/bytecodeviewer/api/BytecodeViewer.java +++ b/src/main/java/the/bytecode/club/bytecodeviewer/api/BytecodeViewer.java @@ -10,10 +10,11 @@ import java.util.jar.JarEntry; import java.util.jar.JarFile; import org.objectweb.asm.tree.ClassNode; import the.bytecode.club.bytecodeviewer.compilers.Compilers; +import the.bytecode.club.bytecodeviewer.decompilers.InternalDecompiler; import the.bytecode.club.bytecodeviewer.decompilers.Decompiler; -import the.bytecode.club.bytecodeviewer.decompilers.Decompilers; import the.bytecode.club.bytecodeviewer.plugin.preinstalled.EZInjection; import the.bytecode.club.bytecodeviewer.util.JarUtils; +import the.bytecode.club.bytecodeviewer.util.MiscUtils; import static the.bytecode.club.bytecodeviewer.Constants.*; @@ -41,7 +42,6 @@ import static the.bytecode.club.bytecodeviewer.Constants.*; * * @author Konloch */ - public class BytecodeViewer { private static URLClassLoader cl; @@ -72,7 +72,7 @@ public class BytecodeViewer { */ public static List> loadClassesIntoClassLoader() { try { - File f = new File(tempDirectory + fs + "loaded_temp.jar"); + File f = new File(tempDirectory + fs + MiscUtils.randomString(12) + "loaded_temp.jar"); JarUtils.saveAsJar(BytecodeViewer.getLoadedClasses(), f.getAbsolutePath()); JarFile jarFile = new JarFile("" + f.getAbsolutePath()); Enumeration e = jarFile.entries(); @@ -201,8 +201,8 @@ public class BytecodeViewer { * * @return The wrapped Krakatau Decompiler instance */ - public static Decompiler getKrakatauDecompiler() { - return Decompilers.krakatau; + public static InternalDecompiler getKrakatauDecompiler() { + return Decompiler.KRAKATAU.getDecompiler(); } /** @@ -210,8 +210,8 @@ public class BytecodeViewer { * * @return The wrapped Procyon Decompiler instance */ - public static Decompiler getProcyonDecompiler() { - return Decompilers.procyon; + public static InternalDecompiler getProcyonDecompiler() { + return Decompiler.PROCYON.getDecompiler(); } /** @@ -219,8 +219,8 @@ public class BytecodeViewer { * * @return The wrapped CFR Decompiler instance */ - public static Decompiler getCFRDecompiler() { - return Decompilers.cfr; + public static InternalDecompiler getCFRDecompiler() { + return Decompiler.CFR.getDecompiler(); } /** @@ -228,8 +228,8 @@ public class BytecodeViewer { * * @return The wrapped FernFlower Decompiler instance */ - public static Decompiler getFernFlowerDecompiler() { - return Decompilers.fernflower; + public static InternalDecompiler getFernFlowerDecompiler() { + return Decompiler.FERNFLOWER.getDecompiler(); } /** @@ -237,8 +237,26 @@ public class BytecodeViewer { * * @return The wrapped Krakatau Disassembler instance */ - public static Decompiler getKrakatauDisassembler() { - return Decompilers.krakatauDA; + public static InternalDecompiler getKrakatauDisassembler() { + return Decompiler.KRAKATAU_BYTECODE.getDecompiler(); + } + + /** + * Returns the wrapped JD-GUI Decompiler instance. + * + * @return The wrapped JD-GUI Decompiler instance + */ + public static InternalDecompiler getDJGUIDecompiler() { + return Decompiler.JDGUI.getDecompiler(); + } + + /** + * Returns the wrapped JADX Decompiler instance. + * + * @return The wrapped JADX Decompiler instance + */ + public static InternalDecompiler getJADXDecompiler() { + return Decompiler.JADX.getDecompiler(); } /** @@ -258,13 +276,4 @@ public class BytecodeViewer { public static the.bytecode.club.bytecodeviewer.compilers.Compiler getSmaliCompiler() { return Compilers.smali; } - - /** - * Returns the wrapped JD-GUI Decompiler instance. - * - * @return The wrapped JD-GUI Decompiler instance - */ - public static the.bytecode.club.bytecodeviewer.decompilers.Decompiler getDJGUIDecompiler() { - return Decompilers.jdgui; - } } diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/api/PluginConsole.java b/src/main/java/the/bytecode/club/bytecodeviewer/api/PluginConsole.java index 8d7f0f75..9eae20d4 100644 --- a/src/main/java/the/bytecode/club/bytecodeviewer/api/PluginConsole.java +++ b/src/main/java/the/bytecode/club/bytecodeviewer/api/PluginConsole.java @@ -1,7 +1,6 @@ package the.bytecode.club.bytecodeviewer.api; import java.awt.BorderLayout; -import java.awt.Color; import java.awt.Dimension; import java.awt.event.KeyEvent; import java.awt.event.KeyListener; @@ -10,13 +9,14 @@ import javax.swing.JCheckBox; import javax.swing.JFrame; import javax.swing.JPanel; import javax.swing.JScrollPane; -import javax.swing.JTextArea; import javax.swing.JTextField; -import javax.swing.text.DefaultHighlighter; -import javax.swing.text.Highlighter; -import javax.swing.text.JTextComponent; + import the.bytecode.club.bytecodeviewer.BytecodeViewer; import the.bytecode.club.bytecodeviewer.Resources; +import the.bytecode.club.bytecodeviewer.gui.components.JFrameConsole; +import the.bytecode.club.bytecodeviewer.gui.components.SearchableJTextArea; +import the.bytecode.club.bytecodeviewer.gui.components.listeners.PressKeyListener; +import the.bytecode.club.bytecodeviewer.gui.components.listeners.ReleaseKeyListener; /*************************************************************************** * Bytecode Viewer (BCV) - Java & Android Reverse Engineering Suite * @@ -42,219 +42,11 @@ import the.bytecode.club.bytecodeviewer.Resources; * @author Konloch */ -public class PluginConsole extends JFrame { - - JTextArea textArea = new JTextArea(); - JPanel panel = new JPanel(new BorderLayout()); - JScrollPane scrollPane = new JScrollPane(); - public JCheckBox check = new JCheckBox("Exact"); - final JTextField field = new JTextField(); - - public PluginConsole(String pluginName) { - this.setIconImages(Resources.iconList); - setTitle("Bytecode Viewer - Plugin Console - " + pluginName); - setSize(new Dimension(542, 316)); - - getContentPane().add(scrollPane, BorderLayout.CENTER); - - scrollPane.setViewportView(textArea); - textArea.addKeyListener(new KeyListener() { - @Override - public void keyPressed(KeyEvent e) { - if ((e.getKeyCode() == KeyEvent.VK_F) && ((e.getModifiers() & KeyEvent.CTRL_MASK) != 0)) { - field.requestFocus(); - } - - BytecodeViewer.checkHotKey(e); - } - - @Override - public void keyReleased(KeyEvent arg0) { - } - - @Override - public void keyTyped(KeyEvent arg0) { - } - }); - - JButton searchNext = new JButton(); - JButton searchPrev = new JButton(); - JPanel buttonPane = new JPanel(new BorderLayout()); - buttonPane.add(searchNext, BorderLayout.WEST); - buttonPane.add(searchPrev, BorderLayout.EAST); - searchNext.setIcon(Resources.nextIcon); - searchPrev.setIcon(Resources.prevIcon); - panel.add(buttonPane, BorderLayout.WEST); - panel.add(field, BorderLayout.CENTER); - panel.add(check, BorderLayout.EAST); - searchNext.addActionListener(arg0 -> search(field.getText(), true)); - searchPrev.addActionListener(arg0 -> search(field.getText(), false)); - field.addKeyListener(new KeyListener() { - @Override - public void keyReleased(KeyEvent arg0) { - if (arg0.getKeyCode() == KeyEvent.VK_ENTER) - search(field.getText(), true); - } - - @Override - public void keyPressed(KeyEvent arg0) { - } - - @Override - public void keyTyped(KeyEvent arg0) { - } - }); - scrollPane.setColumnHeaderView(panel); - this.setLocationRelativeTo(null); - } - - /** - * This was really interesting to write. - * - * @author Konloch - */ - public void search(String search, boolean next) { - try { - JTextArea area = textArea; - if (search.isEmpty()) { - highlight(area, ""); - return; - } - - int startLine = area.getDocument().getDefaultRootElement() - .getElementIndex(area.getCaretPosition()) + 1; - int currentLine = 1; - boolean canSearch = false; - String[] test; - if (area.getText().split("\n").length >= 2) - test = area.getText().split("\n"); - else - test = area.getText().split("\r"); - int lastGoodLine = -1; - int firstPos = -1; - boolean found = false; - - if (next) { - for (String s : test) { - if (!check.isSelected()) { - s = s.toLowerCase(); - search = search.toLowerCase(); - } - - if (currentLine == startLine) { - canSearch = true; - } else if (s.contains(search)) { - if (canSearch) { - area.setCaretPosition(area.getDocument() - .getDefaultRootElement() - .getElement(currentLine - 1) - .getStartOffset()); - canSearch = false; - found = true; - } - - if (firstPos == -1) - firstPos = currentLine; - } - - currentLine++; - } - - if (!found && firstPos != -1) { - area.setCaretPosition(area.getDocument() - .getDefaultRootElement().getElement(firstPos - 1) - .getStartOffset()); - } - } else { - canSearch = true; - for (String s : test) { - if (!check.isSelected()) { - s = s.toLowerCase(); - search = search.toLowerCase(); - } - - if (s.contains(search)) { - if (lastGoodLine != -1 && canSearch) - area.setCaretPosition(area.getDocument() - .getDefaultRootElement() - .getElement(lastGoodLine - 1) - .getStartOffset()); - - lastGoodLine = currentLine; - - if (currentLine >= startLine) - canSearch = false; - } - currentLine++; - } - - if (lastGoodLine != -1 - && area.getDocument().getDefaultRootElement() - .getElementIndex(area.getCaretPosition()) + 1 == startLine) { - area.setCaretPosition(area.getDocument() - .getDefaultRootElement() - .getElement(lastGoodLine - 1).getStartOffset()); - } - } - highlight(area, search); - } catch (Exception e) { - new the.bytecode.club.bytecodeviewer.api.ExceptionUI(e); - } - } - - private final DefaultHighlighter.DefaultHighlightPainter painter = new DefaultHighlighter.DefaultHighlightPainter( - new Color(255, 62, 150)); - - public void highlight(JTextComponent textComp, String pattern) { - if (pattern.isEmpty()) { - textComp.getHighlighter().removeAllHighlights(); - return; - } - - try { - Highlighter hilite = textComp.getHighlighter(); - hilite.removeAllHighlights(); - javax.swing.text.Document doc = textComp.getDocument(); - String text = doc.getText(0, doc.getLength()); - int pos = 0; - - if (!check.isSelected()) { - pattern = pattern.toLowerCase(); - text = text.toLowerCase(); - } - - // Search for pattern - while ((pos = text.indexOf(pattern, pos)) >= 0) { - // Create highlighter using private painter and apply around - // pattern - hilite.addHighlight(pos, pos + pattern.length(), painter); - pos += pattern.length(); - } - } catch (Exception e) { - new the.bytecode.club.bytecodeviewer.api.ExceptionUI(e); - } - } - - /** - * Appends \r\n to the end of your string, then it puts it on the top. - * - * @param t the string you want to append - */ - public void appendText(String t) { - textArea.setText((textArea.getText().isEmpty() ? "" : textArea - .getText() + "\r\n") - + t); - textArea.setCaretPosition(0); - } - - /** - * Sets the text - * - * @param t the text you want set - */ - public void setText(String t) { - textArea.setText(t); - textArea.setCaretPosition(0); +public class PluginConsole extends JFrameConsole +{ + public PluginConsole(String pluginName) + { + super("Bytecode Viewer - Plugin Console - " + pluginName); } private static final long serialVersionUID = -6556940545421437508L; diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/decompilers/ASMTextifierDecompiler.java b/src/main/java/the/bytecode/club/bytecodeviewer/decompilers/ASMTextifierDecompiler.java index 17abfe95..cc46551c 100644 --- a/src/main/java/the/bytecode/club/bytecodeviewer/decompilers/ASMTextifierDecompiler.java +++ b/src/main/java/the/bytecode/club/bytecodeviewer/decompilers/ASMTextifierDecompiler.java @@ -29,7 +29,8 @@ import org.objectweb.asm.util.TraceClassVisitor; * * @author Thiakil */ -public class ASMTextifierDecompiler extends Decompiler { +public class ASMTextifierDecompiler extends InternalDecompiler +{ @Override public String decompileClassNode(ClassNode cn, byte[] b) { StringWriter writer = new StringWriter(); diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/decompilers/CFRDecompiler.java b/src/main/java/the/bytecode/club/bytecodeviewer/decompilers/CFRDecompiler.java index 7ef3070c..e830e65c 100644 --- a/src/main/java/the/bytecode/club/bytecodeviewer/decompilers/CFRDecompiler.java +++ b/src/main/java/the/bytecode/club/bytecodeviewer/decompilers/CFRDecompiler.java @@ -46,7 +46,8 @@ import static the.bytecode.club.bytecodeviewer.Constants.*; * @author Konloch */ -public class CFRDecompiler extends Decompiler { +public class CFRDecompiler extends InternalDecompiler +{ private static final String[] WINDOWS_IS_GREAT = new String[] { diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/decompilers/Decompiler.java b/src/main/java/the/bytecode/club/bytecodeviewer/decompilers/Decompiler.java index 55d87b33..0e9abb80 100644 --- a/src/main/java/the/bytecode/club/bytecodeviewer/decompilers/Decompiler.java +++ b/src/main/java/the/bytecode/club/bytecodeviewer/decompilers/Decompiler.java @@ -1,6 +1,11 @@ package the.bytecode.club.bytecodeviewer.decompilers; -import org.objectweb.asm.tree.ClassNode; +import the.bytecode.club.bytecodeviewer.BytecodeViewer; +import the.bytecode.club.bytecodeviewer.decompilers.bytecode.ClassNodeDecompiler; +import the.bytecode.club.bytecodeviewer.gui.components.DecompilerViewComponent; + +import javax.swing.*; +import java.util.HashMap; /*************************************************************************** * Bytecode Viewer (BCV) - Java & Android Reverse Engineering Suite * @@ -21,15 +26,90 @@ import org.objectweb.asm.tree.ClassNode; ***************************************************************************/ /** - * Used to represent all of the decompilers/disassemblers BCV contains. + * All of the decompilers/disassemblers BCV uses * * @author Konloch */ - -public abstract class Decompiler { - - public abstract String decompileClassNode(ClassNode cn, byte[] b); - - public abstract void decompileToZip(String sourceJar, String zipName); - -} +public enum Decompiler +{ + NONE(0, "None", null, (JRadioButtonMenuItem) null), + PROCYON(1, "Procyon Decompiler", new ProcyonDecompiler(), new DecompilerViewComponent("Procyon")), + CFR(2, "CFR Decompiler", new CFRDecompiler(), new DecompilerViewComponent("Procyon")), + FERNFLOWER(3, "FernFlower Decompiler", new FernFlowerDecompiler(), new DecompilerViewComponent("Procyon")), + BYTECODE(4, "Bytecode Disassembler", new ClassNodeDecompiler(), new JRadioButtonMenuItem("Bytecode")), + HEXCODE(5, "Hexcode Viewer", null, new JRadioButtonMenuItem("Hexcode")), + SMALI(6, "Smali Decompiler", new SmaliDisassembler(), new DecompilerViewComponent("Smali")), + KRAKATAU(7, "Krakatau Decompiler", new KrakatauDecompiler(), BytecodeViewer.krakatau), + KRAKATAU_BYTECODE(8, "Krakatau Disassembler", new KrakatauDisassembler(), BytecodeViewer.krakatau), + JDGUI(9, "JD-GUI Decompiler", new JDGUIDecompiler(), new DecompilerViewComponent("Bytecode")), + JADX(10, "JADX Decompiler", new JADXDecompiler(), new DecompilerViewComponent("JADX")), + ASMTextify(11, "ASM Disassembler", new ASMTextifierDecompiler(), new DecompilerViewComponent("ASM Textify")), + ; + + private final int decompilerIndex; + private final String decompilerName; + private final InternalDecompiler decompiler; + private final DecompilerViewComponent decompilerSelectComponent; + private final JRadioButtonMenuItem basicSelectComponent; + + public static final HashMap decompilersByIndex = new HashMap<>(); + + static + { + for(Decompiler d : values()) + decompilersByIndex.put(d.decompilerIndex, d); + } + + Decompiler(int decompilerIndex, String decompilerName, InternalDecompiler decompiler, DecompilerViewComponent decompilerSelectComponent) { + this.decompilerIndex = decompilerIndex; + this.decompilerName = decompilerName; + this.decompiler = decompiler; + this.decompilerSelectComponent = decompilerSelectComponent; + this.basicSelectComponent = null; + } + + Decompiler(int decompilerIndex, String decompilerName, InternalDecompiler decompiler, JRadioButtonMenuItem basicSelectComponent) + { + this.decompilerIndex = decompilerIndex; + this.decompilerName = decompilerName; + this.decompiler = decompiler; + this.decompilerSelectComponent = null; + this.basicSelectComponent = basicSelectComponent; + } + + public void addDecompilerToGroup(ButtonGroup group) + { + if(decompilerSelectComponent != null) + decompilerSelectComponent.addToGroup(group); + else if(basicSelectComponent != null) + group.add(basicSelectComponent); + } + + public int getDecompilerIndex() + { + return decompilerIndex; + } + + public String getDecompilerName() + { + return decompilerName; + } + + public InternalDecompiler getDecompiler() + { + return decompiler; + } + + public DecompilerViewComponent getDecompilerSelectComponent() + { + return decompilerSelectComponent; + } + + public JMenuItem getMenu() + { + if(decompilerSelectComponent != null) + return decompilerSelectComponent.getMenu(); + + return basicSelectComponent; + } +} \ No newline at end of file diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/decompilers/Decompilers.java b/src/main/java/the/bytecode/club/bytecodeviewer/decompilers/Decompilers.java deleted file mode 100644 index d33eacb1..00000000 --- a/src/main/java/the/bytecode/club/bytecodeviewer/decompilers/Decompilers.java +++ /dev/null @@ -1,18 +0,0 @@ -package the.bytecode.club.bytecodeviewer.decompilers; - -import the.bytecode.club.bytecodeviewer.decompilers.bytecode.ClassNodeDecompiler; - -public class Decompilers { - - public final static Decompiler bytecode = new ClassNodeDecompiler(); - public final static Decompiler fernflower = new FernFlowerDecompiler(); - public final static Decompiler procyon = new ProcyonDecompiler(); - public final static Decompiler cfr = new CFRDecompiler(); - public final static KrakatauDecompiler krakatau = new KrakatauDecompiler(); - public final static KrakatauDisassembler krakatauDA = new KrakatauDisassembler(); - public final static SmaliDisassembler smali = new SmaliDisassembler(); - public final static Decompiler jdgui = new JDGUIDecompiler(); - public final static Decompiler jadx = new JADXDecompiler(); - public final static Decompiler textifier = new ASMTextifierDecompiler(); - -} diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/decompilers/FernFlowerDecompiler.java b/src/main/java/the/bytecode/club/bytecodeviewer/decompilers/FernFlowerDecompiler.java index ba2f5582..ca8cb359 100644 --- a/src/main/java/the/bytecode/club/bytecodeviewer/decompilers/FernFlowerDecompiler.java +++ b/src/main/java/the/bytecode/club/bytecodeviewer/decompilers/FernFlowerDecompiler.java @@ -38,7 +38,8 @@ import static the.bytecode.club.bytecodeviewer.Constants.*; * @author Konloch * @author WaterWolf */ -public class FernFlowerDecompiler extends Decompiler { +public class FernFlowerDecompiler extends InternalDecompiler +{ @Override public void decompileToZip(String sourceJar, String zipName) { diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/decompilers/InternalDecompiler.java b/src/main/java/the/bytecode/club/bytecodeviewer/decompilers/InternalDecompiler.java new file mode 100644 index 00000000..801e86a5 --- /dev/null +++ b/src/main/java/the/bytecode/club/bytecodeviewer/decompilers/InternalDecompiler.java @@ -0,0 +1,33 @@ +package the.bytecode.club.bytecodeviewer.decompilers; + +import org.objectweb.asm.tree.ClassNode; + +/*************************************************************************** + * Bytecode Viewer (BCV) - Java & Android Reverse Engineering Suite * + * Copyright (C) 2014 Kalen 'Konloch' Kinloch - http://bytecodeviewer.com * + * * + * This program is free software: you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation, either version 3 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program. If not, see . * + ***************************************************************************/ + +/** + * Used to represent a decompiler/disassembler + * + * @author Konloch + */ +public abstract class InternalDecompiler +{ + public abstract String decompileClassNode(ClassNode cn, byte[] b); + + public abstract void decompileToZip(String sourceJar, String zipName); +} diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/decompilers/JADXDecompiler.java b/src/main/java/the/bytecode/club/bytecodeviewer/decompilers/JADXDecompiler.java index 9fdbe977..b310b70f 100644 --- a/src/main/java/the/bytecode/club/bytecodeviewer/decompilers/JADXDecompiler.java +++ b/src/main/java/the/bytecode/club/bytecodeviewer/decompilers/JADXDecompiler.java @@ -38,7 +38,8 @@ import static the.bytecode.club.bytecodeviewer.Constants.*; * * @author Konloch */ -public class JADXDecompiler extends Decompiler { +public class JADXDecompiler extends InternalDecompiler +{ @Override public String decompileClassNode(ClassNode cn, byte[] b) { String fileStart = tempDirectory + fs; diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/decompilers/JDGUIDecompiler.java b/src/main/java/the/bytecode/club/bytecodeviewer/decompilers/JDGUIDecompiler.java index 184aad1f..5e45520b 100644 --- a/src/main/java/the/bytecode/club/bytecodeviewer/decompilers/JDGUIDecompiler.java +++ b/src/main/java/the/bytecode/club/bytecodeviewer/decompilers/JDGUIDecompiler.java @@ -13,7 +13,6 @@ import jd.cli.util.ClassFileUtil; import me.konloch.kontainer.io.DiskReader; import org.jd.core.v1.ClassFileToJavaSourceDecompiler; import org.objectweb.asm.tree.ClassNode; -import the.bytecode.club.bytecodeviewer.BytecodeViewer; import the.bytecode.club.bytecodeviewer.Constants; import the.bytecode.club.bytecodeviewer.util.MiscUtils; @@ -44,7 +43,8 @@ import static the.bytecode.club.bytecodeviewer.Constants.*; * @author JD-Core developers */ -public class JDGUIDecompiler extends Decompiler { +public class JDGUIDecompiler extends InternalDecompiler +{ @Override public String decompileClassNode(ClassNode cn, byte[] b) { diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/decompilers/KrakatauDecompiler.java b/src/main/java/the/bytecode/club/bytecodeviewer/decompilers/KrakatauDecompiler.java index c08523fb..6afd8a4d 100644 --- a/src/main/java/the/bytecode/club/bytecodeviewer/decompilers/KrakatauDecompiler.java +++ b/src/main/java/the/bytecode/club/bytecodeviewer/decompilers/KrakatauDecompiler.java @@ -42,7 +42,8 @@ import static the.bytecode.club.bytecodeviewer.Constants.*; * @author Konloch */ -public class KrakatauDecompiler extends Decompiler { +public class KrakatauDecompiler extends InternalDecompiler +{ public String quick() { if (Configuration.library.isEmpty()) diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/decompilers/KrakatauDisassembler.java b/src/main/java/the/bytecode/club/bytecodeviewer/decompilers/KrakatauDisassembler.java index 6ff44796..5e138c4f 100644 --- a/src/main/java/the/bytecode/club/bytecodeviewer/decompilers/KrakatauDisassembler.java +++ b/src/main/java/the/bytecode/club/bytecodeviewer/decompilers/KrakatauDisassembler.java @@ -41,7 +41,8 @@ import static the.bytecode.club.bytecodeviewer.Constants.*; * @author Konloch */ -public class KrakatauDisassembler extends Decompiler { +public class KrakatauDisassembler extends InternalDecompiler +{ public String decompileClassNode(File krakatauTempJar, File krakatauTempDir, ClassNode cn) { if (Configuration.python.isEmpty()) { diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/decompilers/ProcyonDecompiler.java b/src/main/java/the/bytecode/club/bytecodeviewer/decompilers/ProcyonDecompiler.java index 26897606..90a7553f 100644 --- a/src/main/java/the/bytecode/club/bytecodeviewer/decompilers/ProcyonDecompiler.java +++ b/src/main/java/the/bytecode/club/bytecodeviewer/decompilers/ProcyonDecompiler.java @@ -61,9 +61,10 @@ import static the.bytecode.club.bytecodeviewer.Constants.*; * @author Konloch * @author DeathMarine */ -public class ProcyonDecompiler extends Decompiler { - - public DecompilerSettings getDecompilerSettings() { +public class ProcyonDecompiler extends InternalDecompiler +{ + public DecompilerSettings getDecompilerSettings() + { DecompilerSettings settings = new DecompilerSettings(); settings.setAlwaysGenerateExceptionVariableForCatchBlocks(BytecodeViewer.viewer.alwaysGenerateExceptionVars.isSelected()); settings.setExcludeNestedTypes(BytecodeViewer.viewer.excludeNestedTypes.isSelected()); diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/decompilers/SmaliDisassembler.java b/src/main/java/the/bytecode/club/bytecodeviewer/decompilers/SmaliDisassembler.java index 4d7d4847..ad5ad15e 100644 --- a/src/main/java/the/bytecode/club/bytecodeviewer/decompilers/SmaliDisassembler.java +++ b/src/main/java/the/bytecode/club/bytecodeviewer/decompilers/SmaliDisassembler.java @@ -9,7 +9,6 @@ import java.util.Objects; import me.konloch.kontainer.io.DiskReader; import org.apache.commons.io.FileUtils; import org.objectweb.asm.tree.ClassNode; -import the.bytecode.club.bytecodeviewer.BytecodeViewer; import the.bytecode.club.bytecodeviewer.util.Dex2Jar; import the.bytecode.club.bytecodeviewer.util.FileContainer; import the.bytecode.club.bytecodeviewer.util.MiscUtils; @@ -40,7 +39,8 @@ import static the.bytecode.club.bytecodeviewer.Constants.*; * @author Konloch */ -public class SmaliDisassembler extends Decompiler { +public class SmaliDisassembler extends InternalDecompiler +{ public String decompileClassNode(FileContainer container, ClassNode cn, byte[] b) { String exception = ""; diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/decompilers/bytecode/ClassNodeDecompiler.java b/src/main/java/the/bytecode/club/bytecodeviewer/decompilers/bytecode/ClassNodeDecompiler.java index efd50ff6..71b5391d 100644 --- a/src/main/java/the/bytecode/club/bytecodeviewer/decompilers/bytecode/ClassNodeDecompiler.java +++ b/src/main/java/the/bytecode/club/bytecodeviewer/decompilers/bytecode/ClassNodeDecompiler.java @@ -9,7 +9,7 @@ import org.objectweb.asm.tree.FieldNode; import org.objectweb.asm.tree.InnerClassNode; import org.objectweb.asm.tree.MethodNode; import the.bytecode.club.bytecodeviewer.BytecodeViewer; -import the.bytecode.club.bytecodeviewer.decompilers.Decompiler; +import the.bytecode.club.bytecodeviewer.decompilers.InternalDecompiler; import static the.bytecode.club.bytecodeviewer.Constants.*; @@ -36,7 +36,8 @@ import static the.bytecode.club.bytecodeviewer.Constants.*; * @author Bibl */ -public class ClassNodeDecompiler extends Decompiler { +public class ClassNodeDecompiler extends InternalDecompiler +{ @Override public String decompileClassNode(ClassNode cn, byte[] b) { diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/gui/ClassViewer.java b/src/main/java/the/bytecode/club/bytecodeviewer/gui/ClassViewer.java deleted file mode 100644 index ef7b04f0..00000000 --- a/src/main/java/the/bytecode/club/bytecodeviewer/gui/ClassViewer.java +++ /dev/null @@ -1,1908 +0,0 @@ -package the.bytecode.club.bytecodeviewer.gui; - -import the.bytecode.club.bytecodeviewer.gui.hexviewer.JHexEditor; -import java.awt.BorderLayout; -import java.awt.Color; -import java.awt.Component; -import java.awt.Container; -import java.awt.Dimension; -import java.awt.Font; -import java.awt.Point; -import java.awt.event.ComponentAdapter; -import java.awt.event.ComponentEvent; -import java.awt.event.HierarchyEvent; -import java.awt.event.HierarchyListener; -import java.awt.event.KeyEvent; -import java.awt.event.KeyListener; -import java.io.File; -import java.util.Arrays; -import java.util.List; -import javax.swing.JButton; -import javax.swing.JCheckBox; -import javax.swing.JLabel; -import javax.swing.JPanel; -import javax.swing.JSplitPane; -import javax.swing.JTextField; -import javax.swing.JViewport; -import javax.swing.SwingUtilities; -import javax.swing.text.AbstractDocument; -import javax.swing.text.BadLocationException; -import javax.swing.text.BoxView; -import javax.swing.text.ComponentView; -import javax.swing.text.DefaultHighlighter; -import javax.swing.text.Element; -import javax.swing.text.Highlighter; -import javax.swing.text.IconView; -import javax.swing.text.JTextComponent; -import javax.swing.text.LabelView; -import javax.swing.text.StyleConstants; -import javax.swing.text.StyledEditorKit; -import javax.swing.text.View; -import javax.swing.text.ViewFactory; -import javax.swing.text.html.ParagraphView; -import org.fife.ui.rsyntaxtextarea.RSyntaxTextArea; -import org.fife.ui.rsyntaxtextarea.SyntaxConstants; -import org.fife.ui.rtextarea.RTextScrollPane; -import org.objectweb.asm.ClassWriter; -import org.objectweb.asm.Type; -import org.objectweb.asm.tree.ClassNode; -import the.bytecode.club.bytecodeviewer.BytecodeViewer; -import the.bytecode.club.bytecodeviewer.Configuration; -import the.bytecode.club.bytecodeviewer.Resources; -import the.bytecode.club.bytecodeviewer.Settings; -import the.bytecode.club.bytecodeviewer.decompilers.Decompilers; -import the.bytecode.club.bytecodeviewer.util.FileContainer; -import the.bytecode.club.bytecodeviewer.util.MethodParser; - -import static the.bytecode.club.bytecodeviewer.util.MethodParser.Method; - -/*************************************************************************** - * Bytecode Viewer (BCV) - Java & Android Reverse Engineering Suite * - * Copyright (C) 2014 Kalen 'Konloch' Kinloch - http://bytecodeviewer.com * - * * - * This program is free software: you can redistribute it and/or modify * - * it under the terms of the GNU General Public License as published by * - * the Free Software Foundation, either version 3 of the License, or * - * (at your option) any later version. * - * * - * This program is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program. If not, see . * - ***************************************************************************/ - -/** - * This represents the opened classfile. - * - * @author Konloch - * @author WaterWolf - */ - -public class ClassViewer extends Viewer { - private static final long serialVersionUID = -8650495368920680024L; - String name; - JSplitPane sp; - JSplitPane sp2; - public JPanel panel1Search = new JPanel(new BorderLayout()); - public JPanel panel2Search = new JPanel(new BorderLayout()); - public JPanel panel3Search = new JPanel(new BorderLayout()); - public JCheckBox check1 = new JCheckBox("Exact"); - public JCheckBox check2 = new JCheckBox("Exact"); - public JCheckBox check3 = new JCheckBox("Exact"); - public JPanel panel1 = new JPanel(new BorderLayout()); - public JPanel panel2 = new JPanel(new BorderLayout()); - public JPanel panel3 = new JPanel(new BorderLayout()); - int pane1 = -1; - int pane2 = -1; - int pane3 = -1; - public List methods = Arrays.asList(new MethodParser(), new MethodParser(), new MethodParser()); - public RSyntaxTextArea smali1 = null; - public RSyntaxTextArea smali2 = null; - public RSyntaxTextArea smali3 = null; - public RSyntaxTextArea krakatau1 = null; - public RSyntaxTextArea krakatau2 = null; - public RSyntaxTextArea krakatau3 = null; - public RSyntaxTextArea java1 = null; - public RSyntaxTextArea java2 = null; - public RSyntaxTextArea java3 = null; - public File[] tempFiles; - public ClassViewer THIS = this; - - /** - * This was really interesting to write. - * - * @author Konloch - */ - public void search(int pane, String search, boolean next) { - try { - Component[] com = null; - if (pane == 0) // bytecode - com = panel1.getComponents(); - else if (pane == 1) - com = panel2.getComponents(); - else if (pane == 2) - com = panel3.getComponents(); - - if (com == null) // someone fucked up, lets prevent a nullpointer. - return; - - for (Component c : com) { - if (c instanceof RTextScrollPane) { - RSyntaxTextArea area = (RSyntaxTextArea) ((RTextScrollPane) c) - .getViewport().getComponent(0); - - if (search.isEmpty()) { - highlight(pane, area, ""); - return; - } - - int startLine = area.getDocument().getDefaultRootElement() - .getElementIndex(area.getCaretPosition()) + 1; - - int currentLine = 1; - boolean canSearch = false; - String[] test; - - if (area.getText().split("\n").length >= 2) - test = area.getText().split("\n"); - else - test = area.getText().split("\r"); - - int lastGoodLine = -1; - int firstPos = -1; - boolean found = false; - - if (next) { - for (String s : test) { - if (pane == 0 && !check1.isSelected() || - pane == 1 && !check2.isSelected()) { - s = s.toLowerCase(); - search = search.toLowerCase(); - } - - if (currentLine == startLine) { - canSearch = true; - } else if (s.contains(search)) { - if (canSearch) { - area.setCaretPosition(area.getDocument() - .getDefaultRootElement() - .getElement(currentLine - 1) - .getStartOffset()); - canSearch = false; - found = true; - } - - if (firstPos == -1) - firstPos = currentLine; - } - - currentLine++; - } - - if (!found && firstPos != -1) { - area.setCaretPosition(area.getDocument() - .getDefaultRootElement() - .getElement(firstPos - 1).getStartOffset()); - } - } else { - canSearch = true; - for (String s : test) { - if (pane == 0 && !check1.isSelected() || pane == 1 - && !check2.isSelected() || pane == 2 - && !check3.isSelected()) { - s = s.toLowerCase(); - search = search.toLowerCase(); - } - - if (s.contains(search)) { - if (lastGoodLine != -1 && canSearch) - area.setCaretPosition(area.getDocument() - .getDefaultRootElement() - .getElement(lastGoodLine - 1) - .getStartOffset()); - - lastGoodLine = currentLine; - - if (currentLine >= startLine) - canSearch = false; - } - currentLine++; - } - - if (lastGoodLine != -1 - && area.getDocument() - .getDefaultRootElement() - .getElementIndex(area.getCaretPosition()) + 1 == startLine) { - area.setCaretPosition(area.getDocument() - .getDefaultRootElement() - .getElement(lastGoodLine - 1) - .getStartOffset()); - } - } - highlight(pane, area, search); - } - } - } catch (Exception e) { - new the.bytecode.club.bytecodeviewer.api.ExceptionUI(e); - } - } - - private final DefaultHighlighter.DefaultHighlightPainter painter = new DefaultHighlighter.DefaultHighlightPainter( - new Color(255, 62, 150)); - - public void highlight(int pane, JTextComponent textComp, String pattern) { - if (pattern.isEmpty()) { - textComp.getHighlighter().removeAllHighlights(); - return; - } - - try { - Highlighter hilite = textComp.getHighlighter(); - hilite.removeAllHighlights(); - javax.swing.text.Document doc = textComp.getDocument(); - String text = doc.getText(0, doc.getLength()); - int pos = 0; - - if ((pane == 0 && !check1.isSelected()) || pane == 1 - && !check2.isSelected() || pane == 2 - && !check3.isSelected()) { - pattern = pattern.toLowerCase(); - text = text.toLowerCase(); - } - - // Search for pattern - while ((pos = text.indexOf(pattern, pos)) >= 0) { - // Create highlighter using private painter and apply around - // pattern - hilite.addHighlight(pos, pos + pattern.length(), painter); - pos += pattern.length(); - } - } catch (Exception e) { - new the.bytecode.club.bytecodeviewer.api.ExceptionUI(e); - } - } - - final JTextField field1 = new JTextField(); - final JTextField field2 = new JTextField(); - final JTextField field3 = new JTextField(); - public TabbedPane tabbedPane; - - public ClassViewer(final FileContainer container, final String name, final ClassNode cn) { - this.container = container; - JButton byteSearchNext = new JButton(); - JButton byteSearchPrev = new JButton(); - JPanel byteButtonPane = new JPanel(new BorderLayout()); - byteButtonPane.add(byteSearchNext, BorderLayout.WEST); - byteButtonPane.add(byteSearchPrev, BorderLayout.EAST); - byteSearchNext.setIcon(Resources.nextIcon); - byteSearchPrev.setIcon(Resources.prevIcon); - panel1Search.add(byteButtonPane, BorderLayout.WEST); - panel1Search.add(field1, BorderLayout.CENTER); - panel1Search.add(check1, BorderLayout.EAST); - byteSearchNext.addActionListener(arg0 -> search(0, field1.getText(), true)); - byteSearchPrev.addActionListener(arg0 -> search(0, field1.getText(), false)); - field1.addKeyListener(new KeyListener() { - @Override - public void keyReleased(KeyEvent arg0) { - if (arg0.getKeyCode() == KeyEvent.VK_ENTER) - search(0, field1.getText(), true); - } - - @Override - public void keyPressed(KeyEvent arg0) { - } - - @Override - public void keyTyped(KeyEvent arg0) { - } - }); - - JButton searchNext2 = new JButton(); - JButton searchPrev2 = new JButton(); - JPanel buttonPane2 = new JPanel(new BorderLayout()); - buttonPane2.add(searchNext2, BorderLayout.WEST); - buttonPane2.add(searchPrev2, BorderLayout.EAST); - searchNext2.setIcon(Resources.nextIcon); - searchPrev2.setIcon(Resources.prevIcon); - panel2Search.add(buttonPane2, BorderLayout.WEST); - panel2Search.add(field2, BorderLayout.CENTER); - panel2Search.add(check2, BorderLayout.EAST); - searchNext2.addActionListener(arg0 -> search(1, field2.getText(), true)); - searchPrev2.addActionListener(arg0 -> search(1, field2.getText(), false)); - field2.addKeyListener(new KeyListener() { - @Override - public void keyReleased(KeyEvent arg0) { - if (arg0.getKeyCode() == KeyEvent.VK_ENTER) - search(1, field2.getText(), true); - } - - @Override - public void keyPressed(KeyEvent arg0) { - } - - @Override - public void keyTyped(KeyEvent arg0) { - } - }); - - JButton searchNext3 = new JButton(); - JButton searchPrev3 = new JButton(); - JPanel buttonPane3 = new JPanel(new BorderLayout()); - buttonPane3.add(searchNext3, BorderLayout.WEST); - buttonPane3.add(searchPrev3, BorderLayout.EAST); - searchNext3.setIcon(Resources.nextIcon); - searchPrev3.setIcon(Resources.prevIcon); - panel3Search.add(buttonPane3, BorderLayout.WEST); - panel3Search.add(field3, BorderLayout.CENTER); - panel3Search.add(check3, BorderLayout.EAST); - searchNext3.addActionListener(arg0 -> search(2, field3.getText(), true)); - searchPrev3.addActionListener(arg0 -> search(2, field3.getText(), false)); - field3.addKeyListener(new KeyListener() { - @Override - public void keyReleased(KeyEvent arg0) { - if (arg0.getKeyCode() == KeyEvent.VK_ENTER) - search(2, field3.getText(), true); - } - - @Override - public void keyPressed(KeyEvent arg0) { - } - - @Override - public void keyTyped(KeyEvent arg0) { - } - }); - - this.name = name; - this.cn = cn; - this.setName(name); - this.setLayout(new BorderLayout()); - - this.sp = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, panel1, panel2); - final ClassWriter cw = new ClassWriter(0); - cn.accept(cw); - JHexEditor hex = new JHexEditor(cw.toByteArray()); - this.sp2 = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, sp, panel3); - this.add(sp2, BorderLayout.CENTER); - - hex.setMaximumSize(new Dimension(0, Integer.MAX_VALUE)); - hex.setSize(0, Integer.MAX_VALUE); - - startPaneUpdater(null); - this.addComponentListener(new ComponentAdapter() { - @Override - public void componentResized(ComponentEvent e) { - resetDivider(); - } - }); - } - - public void resetDivider() { - sp.setResizeWeight(0.5); - if (pane2 != 0 && pane1 != 0) { - setDividerLocation(sp, 0.5); - } else if (pane1 != 0) { - setDividerLocation(sp, 1); - } else if (pane2 != 0) { - sp.setResizeWeight(1); - setDividerLocation(sp, 0); - } else { - setDividerLocation(sp, 0); - } - if (pane3 != 0) { - sp2.setResizeWeight(0.7); - setDividerLocation(sp2, 0.7); - if ((pane2 == 0 && pane1 != 0) || (pane1 == 0 && pane2 != 0)) { - setDividerLocation(sp2, 0.5); - } else if (pane1 == 0) { - setDividerLocation(sp2, 0); - } - } else { - sp.setResizeWeight(1); - sp2.setResizeWeight(0); - setDividerLocation(sp2, 1); - } - } - - PaneUpdaterThread t1; - PaneUpdaterThread t2; - PaneUpdaterThread t3; - - public void startPaneUpdater(final JButton button) { - this.cn = BytecodeViewer.getClassNode(container, cn.name); //update the classnode - setPanes(); - - panel1.removeAll(); - panel2.removeAll(); - panel3.removeAll(); - smali1 = null; - smali2 = null; - smali3 = null; - java1 = null; - java2 = null; - java3 = null; - - if (this.cn == null) { - panel1.add(new JLabel("This file has been removed from the reload.")); - panel2.add(new JLabel("This file has been removed from the reload.")); - panel3.add(new JLabel("This file has been removed from the reload.")); - return; - } - - if (pane1 != 0 && pane1 != 5) - panel1.add(panel1Search, BorderLayout.NORTH); - if (pane2 != 0 && pane2 != 5) - panel2.add(panel2Search, BorderLayout.NORTH); - if (pane3 != 0 && pane3 != 5) - panel3.add(panel3Search, BorderLayout.NORTH); - - final ClassWriter cw = new ClassWriter(0); - try { - cn.accept(cw); - } catch (Exception e) { - e.printStackTrace(); - try { - Thread.sleep(200); - cn.accept(cw); - } catch (InterruptedException ignored) { - } - } - - final byte[] b = cw.toByteArray(); - t1 = new PaneUpdaterThread() { - @Override - public void doShit() { - try { - paneId = 0; - viewer = THIS; - decompiler = pane1; - - BytecodeViewer.viewer.updateBusyStatus(true); - if (pane1 == 1) { // procyon - panelArea = new RSyntaxTextArea(); - panelArea.setSyntaxEditingStyle(SyntaxConstants.SYNTAX_STYLE_JAVA); - panelArea.setCodeFoldingEnabled(true); - panelArea.setAntiAliasingEnabled(true); - scrollPane = new RTextScrollPane(panelArea); - panelArea.setText(Decompilers.procyon.decompileClassNode(cn, b)); - - panelArea.setCaretPosition(0); - panelArea.setEditable(isPanel1Editable()); - panelArea.addKeyListener(new KeyListener() { - @Override - public void keyPressed(KeyEvent e) { - - if ((e.getKeyCode() == KeyEvent.VK_F) && ((e.getModifiers() & KeyEvent.CTRL_MASK) != 0)) { - field1.requestFocus(); - } - - BytecodeViewer.checkHotKey(e); - } - - @Override - public void keyReleased(KeyEvent arg0) { - } - - @Override - public void keyTyped(KeyEvent arg0) { - } - }); - scrollPane.setColumnHeaderView(new JLabel("Procyon Decompiler - Editable: " + panelArea.isEditable())); - panelArea.setFont(new Font(Font.MONOSPACED, Font.PLAIN, - (int) BytecodeViewer.viewer.fontSpinner.getValue())); - - SwingUtilities.invokeLater(() -> panel1.add(scrollPane)); - - java1 = panelArea; - } - - if (pane1 == 2) {// cfr - panelArea = new RSyntaxTextArea(); - panelArea.setSyntaxEditingStyle(SyntaxConstants.SYNTAX_STYLE_JAVA); - panelArea.setCodeFoldingEnabled(true); - panelArea.setAntiAliasingEnabled(true); - scrollPane = new RTextScrollPane(panelArea); - panelArea.setText(Decompilers.cfr.decompileClassNode(cn, b)); - panelArea.setCaretPosition(0); - panelArea.setEditable(isPanel1Editable()); - panelArea.addKeyListener(new KeyListener() { - @Override - public void keyPressed(KeyEvent e) { - if ((e.getKeyCode() == KeyEvent.VK_F) && ((e.getModifiers() & KeyEvent.CTRL_MASK) != 0)) { - field1.requestFocus(); - } - - BytecodeViewer.checkHotKey(e); - } - - @Override - public void keyReleased(KeyEvent arg0) { - } - - @Override - public void keyTyped(KeyEvent arg0) { - } - }); - scrollPane.setColumnHeaderView(new JLabel("CFR Decompiler - Editable: " + panelArea.isEditable())); - panelArea.setFont(new Font(Font.MONOSPACED, Font.PLAIN, - (int) BytecodeViewer.viewer.fontSpinner.getValue())); - - SwingUtilities.invokeLater(() -> panel1.add(scrollPane)); - - java1 = panelArea; - } - - if (pane1 == 3) {// fern - panelArea = new RSyntaxTextArea(); - panelArea.setSyntaxEditingStyle(SyntaxConstants.SYNTAX_STYLE_JAVA); - panelArea.setCodeFoldingEnabled(true); - panelArea.setAntiAliasingEnabled(true); - scrollPane = new RTextScrollPane(panelArea); - panelArea.setText(Decompilers.fernflower.decompileClassNode(cn, b)); - panelArea.setCaretPosition(0); - panelArea.setEditable(isPanel1Editable()); - panelArea.addKeyListener(new KeyListener() { - @Override - public void keyPressed(KeyEvent e) { - if ((e.getKeyCode() == KeyEvent.VK_F) && ((e.getModifiers() & KeyEvent.CTRL_MASK) != 0)) { - field1.requestFocus(); - } - - BytecodeViewer.checkHotKey(e); - } - - @Override - public void keyReleased(KeyEvent arg0) { - } - - @Override - public void keyTyped(KeyEvent arg0) { - } - }); - scrollPane.setColumnHeaderView(new JLabel("FernFlower Decompiler - Editable: " + panelArea.isEditable())); - panelArea.setFont(new Font(Font.MONOSPACED, Font.PLAIN, - (int) BytecodeViewer.viewer.fontSpinner.getValue())); - - SwingUtilities.invokeLater(() -> panel1.add(scrollPane)); - - java1 = panelArea; - } - - if (pane1 == 4) {// bytecode - panelArea = new RSyntaxTextArea(); - panelArea.setSyntaxEditingStyle(SyntaxConstants.SYNTAX_STYLE_JAVA); - panelArea.setCodeFoldingEnabled(true); - panelArea.setAntiAliasingEnabled(true); - scrollPane = new RTextScrollPane(panelArea); - panelArea.setText(Decompilers.bytecode.decompileClassNode(cn, b)); - panelArea.setCaretPosition(0); - panelArea.setEditable(false); - panelArea.addKeyListener(new KeyListener() { - @Override - public void keyPressed(KeyEvent e) { - if ((e.getKeyCode() == KeyEvent.VK_F) && ((e.getModifiers() & KeyEvent.CTRL_MASK) != 0)) { - field1.requestFocus(); - } - - BytecodeViewer.checkHotKey(e); - } - - @Override - public void keyReleased(KeyEvent arg0) { - } - - @Override - public void keyTyped(KeyEvent arg0) { - } - }); - scrollPane.setColumnHeaderView(new JLabel("Bytecode Decompiler - Editable: " + panelArea.isEditable())); - panelArea.setFont(new Font(Font.MONOSPACED, Font.PLAIN, - (int) BytecodeViewer.viewer.fontSpinner.getValue())); - - SwingUtilities.invokeLater(() -> panel1.add(scrollPane)); - } - - if (pane1 == 5) {// hex - final ClassWriter cw = new ClassWriter(0); - cn.accept(cw); - final JHexEditor hex = new JHexEditor(cw.toByteArray()); - hex.setFont(new Font(Font.MONOSPACED, Font.PLAIN, - (int) BytecodeViewer.viewer.fontSpinner.getValue())); - - SwingUtilities.invokeLater(() -> panel1.add(hex)); - } - - if (pane1 == 6) {//smali bytecode - panelArea = new RSyntaxTextArea(); - panelArea.setSyntaxEditingStyle(SyntaxConstants.SYNTAX_STYLE_JAVA); - panelArea.setCodeFoldingEnabled(true); - panelArea.setAntiAliasingEnabled(true); - scrollPane = new RTextScrollPane(panelArea); - panelArea.setText(Decompilers.smali.decompileClassNode(container, cn, b)); - panelArea.setCaretPosition(0); - panelArea.setEditable(isPanel1Editable()); - smali1 = panelArea; - smali1.addKeyListener(new KeyListener() { - @Override - public void keyPressed(KeyEvent e) { - if ((e.getKeyCode() == KeyEvent.VK_F) && ((e.getModifiers() & KeyEvent.CTRL_MASK) != 0)) { - field1.requestFocus(); - } - - BytecodeViewer.checkHotKey(e); - } - - @Override - public void keyReleased(KeyEvent arg0) { - } - - @Override - public void keyTyped(KeyEvent arg0) { - } - }); - scrollPane.setColumnHeaderView(new JLabel("Smali Decompiler - Editable: " + panelArea.isEditable())); - panelArea.setFont(new Font(Font.MONOSPACED, Font.PLAIN, - (int) BytecodeViewer.viewer.fontSpinner.getValue())); - - SwingUtilities.invokeLater(() -> panel1.add(scrollPane)); - } - - if (pane1 == 7) {// krakatau - panelArea = new RSyntaxTextArea(); - panelArea.setSyntaxEditingStyle(SyntaxConstants.SYNTAX_STYLE_JAVA); - panelArea.setCodeFoldingEnabled(true); - panelArea.setAntiAliasingEnabled(true); - scrollPane = new RTextScrollPane(panelArea); - panelArea.setText(Decompilers.krakatau.decompileClassNode(tempFiles[0], tempFiles[1], cn)); - panelArea.setCaretPosition(0); - panelArea.setEditable(isPanel1Editable()); - panelArea.addKeyListener(new KeyListener() { - @Override - public void keyPressed(KeyEvent e) { - if ((e.getKeyCode() == KeyEvent.VK_F) && ((e.getModifiers() & KeyEvent.CTRL_MASK) != 0)) { - field1.requestFocus(); - } - - BytecodeViewer.checkHotKey(e); - } - - @Override - public void keyReleased(KeyEvent arg0) { - } - - @Override - public void keyTyped(KeyEvent arg0) { - } - }); - scrollPane.setColumnHeaderView(new JLabel("Krakatau Decompiler - Editable: " + panelArea.isEditable())); - panelArea.setFont(new Font(Font.MONOSPACED, Font.PLAIN, - (int) BytecodeViewer.viewer.fontSpinner.getValue())); - - SwingUtilities.invokeLater(() -> panel1.add(scrollPane)); - - java1 = panelArea; - } - - - if (pane1 == 8) {// kraktau bytecode - panelArea = new RSyntaxTextArea(); - panelArea.setSyntaxEditingStyle(SyntaxConstants.SYNTAX_STYLE_JAVA); - panelArea.setCodeFoldingEnabled(true); - panelArea.setAntiAliasingEnabled(true); - scrollPane = new RTextScrollPane(panelArea); - panelArea.setText(Decompilers.krakatauDA.decompileClassNode(tempFiles[0], tempFiles[1], cn)); - panelArea.setCaretPosition(0); - panelArea.setEditable(isPanel1Editable()); - krakatau1 = panelArea; - krakatau1.addKeyListener(new KeyListener() { - @Override - public void keyPressed(KeyEvent e) { - if ((e.getKeyCode() == KeyEvent.VK_F) && ((e.getModifiers() & KeyEvent.CTRL_MASK) != 0)) { - field1.requestFocus(); - } - - BytecodeViewer.checkHotKey(e); - } - - @Override - public void keyReleased(KeyEvent arg0) { - } - - @Override - public void keyTyped(KeyEvent arg0) { - } - }); - scrollPane.setColumnHeaderView(new JLabel("Krakatau Disassembler - Editable: " + panelArea.isEditable())); - panelArea.setFont(new Font(Font.MONOSPACED, Font.PLAIN, - (int) BytecodeViewer.viewer.fontSpinner.getValue())); - - SwingUtilities.invokeLater(() -> panel1.add(scrollPane)); - } - - if (pane1 == 9) {// JD-GUI - panelArea = new RSyntaxTextArea(); - panelArea.setSyntaxEditingStyle(SyntaxConstants.SYNTAX_STYLE_JAVA); - panelArea.setCodeFoldingEnabled(true); - panelArea.setAntiAliasingEnabled(true); - scrollPane = new RTextScrollPane(panelArea); - panelArea.setText(Decompilers.jdgui.decompileClassNode(cn, b)); - panelArea.setCaretPosition(0); - panelArea.setEditable(isPanel1Editable()); - panelArea.addKeyListener(new KeyListener() { - @Override - public void keyPressed(KeyEvent e) { - if ((e.getKeyCode() == KeyEvent.VK_F) && ((e.getModifiers() & KeyEvent.CTRL_MASK) != 0)) { - field1.requestFocus(); - } - - BytecodeViewer.checkHotKey(e); - } - - @Override - public void keyReleased(KeyEvent arg0) { - } - - @Override - public void keyTyped(KeyEvent arg0) { - } - }); - scrollPane.setColumnHeaderView(new JLabel("JD-GUI Decompiler - Editable: " + panelArea.isEditable())); - panelArea.setFont(new Font(Font.MONOSPACED, Font.PLAIN, - (int) BytecodeViewer.viewer.fontSpinner.getValue())); - - SwingUtilities.invokeLater(() -> panel1.add(scrollPane)); - - java1 = panelArea; - } - - if (pane1 == 10) {// JADX - panelArea = new RSyntaxTextArea(); - panelArea.setSyntaxEditingStyle(SyntaxConstants.SYNTAX_STYLE_JAVA); - panelArea.setCodeFoldingEnabled(true); - panelArea.setAntiAliasingEnabled(true); - scrollPane = new RTextScrollPane(panelArea); - panelArea.setText(Decompilers.jadx.decompileClassNode(cn, b)); - panelArea.setCaretPosition(0); - panelArea.setEditable(isPanel1Editable()); - panelArea.addKeyListener(new KeyListener() { - @Override - public void keyPressed(KeyEvent e) { - if ((e.getKeyCode() == KeyEvent.VK_F) && ((e.getModifiers() & KeyEvent.CTRL_MASK) != 0)) { - field1.requestFocus(); - } - - BytecodeViewer.checkHotKey(e); - } - - @Override - public void keyReleased(KeyEvent arg0) { - } - - @Override - public void keyTyped(KeyEvent arg0) { - } - }); - scrollPane.setColumnHeaderView(new JLabel("JADX Decompiler - Editable: " + panelArea.isEditable())); - panelArea.setFont(new Font(Font.MONOSPACED, Font.PLAIN, - (int) BytecodeViewer.viewer.fontSpinner.getValue())); - - SwingUtilities.invokeLater(() -> panel1.add(scrollPane)); - - java1 = panelArea; - } - - if (pane1 == 11) {// asm text - panelArea = new RSyntaxTextArea(); - panelArea.setSyntaxEditingStyle(SyntaxConstants.SYNTAX_STYLE_JAVA); - panelArea.setAntiAliasingEnabled(true); - scrollPane = new RTextScrollPane(panelArea); - panelArea.setText(Decompilers.textifier.decompileClassNode(cn, b)); - panelArea.setCaretPosition(0); - panelArea.setEditable(false); - panelArea.addKeyListener(new KeyListener() { - @Override - public void keyPressed(KeyEvent e) { - if ((e.getKeyCode() == KeyEvent.VK_F) && ((e.getModifiers() & KeyEvent.CTRL_MASK) != 0)) { - field1.requestFocus(); - } - - BytecodeViewer.checkHotKey(e); - } - - @Override - public void keyReleased(KeyEvent arg0) { - } - - @Override - public void keyTyped(KeyEvent arg0) { - } - }); - scrollPane.setColumnHeaderView(new JLabel("ASM Textified - Editable: " + panelArea.isEditable())); - panelArea.setFont(new Font(Font.MONOSPACED, Font.PLAIN, - (int) BytecodeViewer.viewer.fontSpinner.getValue())); - - SwingUtilities.invokeLater(() -> panel1.add(scrollPane)); - java1 = panelArea; - } - - } catch (java.lang.IndexOutOfBoundsException | java.lang.NullPointerException e) { - //ignore - } catch (Exception e) { - new the.bytecode.club.bytecodeviewer.api.ExceptionUI(e); - } finally { - resetDivider(); - BytecodeViewer.viewer.updateBusyStatus(false); - if (button != null) - button.setEnabled(true); - } - } - }; - - - t2 = new PaneUpdaterThread() { - @Override - public void doShit() { - try { - paneId = 1; - viewer = THIS; - decompiler = pane2; - - BytecodeViewer.viewer.updateBusyStatus(true); - if (pane2 == 1) { - panelArea = new RSyntaxTextArea(); - panelArea.setSyntaxEditingStyle(SyntaxConstants.SYNTAX_STYLE_JAVA); - panelArea.setCodeFoldingEnabled(true); - panelArea.setAntiAliasingEnabled(true); - scrollPane = new RTextScrollPane(panelArea); - panelArea.setText(Decompilers.procyon.decompileClassNode(cn, b)); - panelArea.setCaretPosition(0); - panelArea.setEditable(isPanel2Editable()); - panelArea.addKeyListener(new KeyListener() { - @Override - public void keyPressed(KeyEvent e) { - if ((e.getKeyCode() == KeyEvent.VK_F) && ((e.getModifiers() & KeyEvent.CTRL_MASK) != 0)) { - field2.requestFocus(); - } - - BytecodeViewer.checkHotKey(e); - } - - @Override - public void keyReleased(KeyEvent arg0) { - } - - @Override - public void keyTyped(KeyEvent arg0) { - } - }); - scrollPane.setColumnHeaderView(new JLabel("Procyon Decompiler - Editable: " + panelArea.isEditable())); - panelArea.setFont(new Font(Font.MONOSPACED, Font.PLAIN, - (int) BytecodeViewer.viewer.fontSpinner.getValue())); - - SwingUtilities.invokeLater(() -> panel2.add(scrollPane)); - - java2 = panelArea; - } - - if (pane2 == 2) { - panelArea = new RSyntaxTextArea(); - panelArea.setSyntaxEditingStyle(SyntaxConstants.SYNTAX_STYLE_JAVA); - panelArea.setCodeFoldingEnabled(true); - panelArea.setAntiAliasingEnabled(true); - scrollPane = new RTextScrollPane(panelArea); - panelArea.setText(Decompilers.cfr.decompileClassNode(cn, b)); - panelArea.setCaretPosition(0); - panelArea.setEditable(isPanel2Editable()); - panelArea.addKeyListener(new KeyListener() { - @Override - public void keyPressed(KeyEvent e) { - if ((e.getKeyCode() == KeyEvent.VK_F) && ((e.getModifiers() & KeyEvent.CTRL_MASK) != 0)) { - field2.requestFocus(); - } - - BytecodeViewer.checkHotKey(e); - } - - @Override - public void keyReleased(KeyEvent arg0) { - } - - @Override - public void keyTyped(KeyEvent arg0) { - } - }); - scrollPane.setColumnHeaderView(new JLabel("CFR Decompiler - Editable: " + panelArea.isEditable())); - panelArea.setFont(new Font(Font.MONOSPACED, Font.PLAIN, - (int) BytecodeViewer.viewer.fontSpinner.getValue())); - - SwingUtilities.invokeLater(() -> panel2.add(scrollPane)); - - java2 = panelArea; - } - - if (pane2 == 3) { - panelArea = new RSyntaxTextArea(); - panelArea.setSyntaxEditingStyle(SyntaxConstants.SYNTAX_STYLE_JAVA); - panelArea.setCodeFoldingEnabled(true); - panelArea.setAntiAliasingEnabled(true); - scrollPane = new RTextScrollPane(panelArea); - panelArea.setText(Decompilers.fernflower.decompileClassNode(cn, b)); - panelArea.setCaretPosition(0); - panelArea.setEditable(isPanel2Editable()); - panelArea.addKeyListener(new KeyListener() { - @Override - public void keyPressed(KeyEvent e) { - if ((e.getKeyCode() == KeyEvent.VK_F) && ((e.getModifiers() & KeyEvent.CTRL_MASK) != 0)) { - field2.requestFocus(); - } - - BytecodeViewer.checkHotKey(e); - } - - @Override - public void keyReleased(KeyEvent arg0) { - } - - @Override - public void keyTyped(KeyEvent arg0) { - } - }); - scrollPane.setColumnHeaderView(new JLabel("FernFlower Decompiler - Editable: " + panelArea.isEditable())); - panelArea.setFont(new Font(Font.MONOSPACED, Font.PLAIN, - (int) BytecodeViewer.viewer.fontSpinner.getValue())); - - SwingUtilities.invokeLater(() -> panel2.add(scrollPane)); - - java2 = panelArea; - } - - if (pane2 == 4) { - panelArea = new RSyntaxTextArea(); - panelArea.setSyntaxEditingStyle(SyntaxConstants.SYNTAX_STYLE_JAVA); - panelArea.setCodeFoldingEnabled(true); - panelArea.setAntiAliasingEnabled(true); - scrollPane = new RTextScrollPane(panelArea); - panelArea.setText(Decompilers.bytecode.decompileClassNode(cn, b)); - panelArea.setCaretPosition(0); - panelArea.setEditable(false); - panelArea.addKeyListener(new KeyListener() { - @Override - public void keyPressed(KeyEvent e) { - if ((e.getKeyCode() == KeyEvent.VK_F) && ((e.getModifiers() & KeyEvent.CTRL_MASK) != 0)) { - field2.requestFocus(); - } - - BytecodeViewer.checkHotKey(e); - } - - @Override - public void keyReleased(KeyEvent arg0) { - } - - @Override - public void keyTyped(KeyEvent arg0) { - } - }); - scrollPane.setColumnHeaderView(new JLabel("Bytecode Decompiler - Editable: " + panelArea.isEditable())); - panelArea.setFont(new Font(Font.MONOSPACED, Font.PLAIN, - (int) BytecodeViewer.viewer.fontSpinner.getValue())); - - SwingUtilities.invokeLater(() -> panel2.add(scrollPane)); - - } - - if (pane2 == 5) { - final ClassWriter cw = new ClassWriter(0); - cn.accept(cw); - final JHexEditor hex = new JHexEditor(cw.toByteArray()); - hex.setFont(new Font(Font.MONOSPACED, Font.PLAIN, - (int) BytecodeViewer.viewer.fontSpinner.getValue())); - - SwingUtilities.invokeLater(() -> panel2.add(hex)); - } - - if (pane2 == 6) { - panelArea = new RSyntaxTextArea(); - panelArea.setSyntaxEditingStyle(SyntaxConstants.SYNTAX_STYLE_JAVA); - panelArea.setCodeFoldingEnabled(true); - panelArea.setAntiAliasingEnabled(true); - scrollPane = new RTextScrollPane(panelArea); - panelArea.setText(Decompilers.smali.decompileClassNode(container, cn, b)); - panelArea.setCaretPosition(0); - panelArea.setEditable(isPanel2Editable()); - smali2 = panelArea; - panelArea.addKeyListener(new KeyListener() { - @Override - public void keyPressed(KeyEvent e) { - if ((e.getKeyCode() == KeyEvent.VK_F) && ((e.getModifiers() & KeyEvent.CTRL_MASK) != 0)) { - field2.requestFocus(); - } - - BytecodeViewer.checkHotKey(e); - } - - @Override - public void keyReleased(KeyEvent arg0) { - } - - @Override - public void keyTyped(KeyEvent arg0) { - } - }); - scrollPane.setColumnHeaderView(new JLabel("Smali Decompiler - Editable: " + panelArea.isEditable())); - panelArea.setFont(new Font(Font.MONOSPACED, Font.PLAIN, - (int) BytecodeViewer.viewer.fontSpinner.getValue())); - - SwingUtilities.invokeLater(() -> panel2.add(scrollPane)); - - } - - if (pane2 == 7) {// krakatau - panelArea = new RSyntaxTextArea(); - panelArea.setSyntaxEditingStyle(SyntaxConstants.SYNTAX_STYLE_JAVA); - panelArea.setCodeFoldingEnabled(true); - panelArea.setAntiAliasingEnabled(true); - scrollPane = new RTextScrollPane(panelArea); - panelArea.setText(Decompilers.krakatau.decompileClassNode(tempFiles[0], tempFiles[1], cn)); - panelArea.setCaretPosition(0); - panelArea.setEditable(isPanel2Editable()); - panelArea.addKeyListener(new KeyListener() { - @Override - public void keyPressed(KeyEvent e) { - if ((e.getKeyCode() == KeyEvent.VK_F) && ((e.getModifiers() & KeyEvent.CTRL_MASK) != 0)) { - field2.requestFocus(); - } - - BytecodeViewer.checkHotKey(e); - } - - @Override - public void keyReleased(KeyEvent arg0) { - } - - @Override - public void keyTyped(KeyEvent arg0) { - } - }); - scrollPane.setColumnHeaderView(new JLabel("Krakatau Decompiler - Editable: " + panelArea.isEditable())); - panelArea.setFont(new Font(Font.MONOSPACED, Font.PLAIN, - (int) BytecodeViewer.viewer.fontSpinner.getValue())); - - SwingUtilities.invokeLater(() -> panel2.add(scrollPane)); - - java2 = panelArea; - } - - if (pane2 == 8) {// kraktau bytecode - panelArea = new RSyntaxTextArea(); - panelArea.setSyntaxEditingStyle(SyntaxConstants.SYNTAX_STYLE_JAVA); - panelArea.setCodeFoldingEnabled(true); - panelArea.setAntiAliasingEnabled(true); - scrollPane = new RTextScrollPane(panelArea); - panelArea.setText(Decompilers.krakatauDA.decompileClassNode(tempFiles[0], tempFiles[1], cn)); - panelArea.setCaretPosition(0); - panelArea.setEditable(isPanel2Editable()); - krakatau2 = panelArea; - krakatau2.addKeyListener(new KeyListener() { - @Override - public void keyPressed(KeyEvent e) { - if ((e.getKeyCode() == KeyEvent.VK_F) && ((e.getModifiers() & KeyEvent.CTRL_MASK) != 0)) { - field2.requestFocus(); - } - - BytecodeViewer.checkHotKey(e); - } - - @Override - public void keyReleased(KeyEvent arg0) { - } - - @Override - public void keyTyped(KeyEvent arg0) { - } - }); - scrollPane.setColumnHeaderView(new JLabel("Krakatau Disassembler")); - panelArea.setFont(new Font(Font.MONOSPACED, Font.PLAIN, - (int) BytecodeViewer.viewer.fontSpinner.getValue())); - - SwingUtilities.invokeLater(() -> panel2.add(scrollPane)); - - } - - if (pane2 == 9) {// JD-GUI - panelArea = new RSyntaxTextArea(); - panelArea.setSyntaxEditingStyle(SyntaxConstants.SYNTAX_STYLE_JAVA); - panelArea.setCodeFoldingEnabled(true); - panelArea.setAntiAliasingEnabled(true); - scrollPane = new RTextScrollPane(panelArea); - panelArea.setText(Decompilers.jdgui.decompileClassNode(cn, b)); - panelArea.setCaretPosition(0); - panelArea.setEditable(isPanel2Editable()); - panelArea.addKeyListener(new KeyListener() { - @Override - public void keyPressed(KeyEvent e) { - if ((e.getKeyCode() == KeyEvent.VK_F) && ((e.getModifiers() & KeyEvent.CTRL_MASK) != 0)) { - field2.requestFocus(); - } - - BytecodeViewer.checkHotKey(e); - } - - @Override - public void keyReleased(KeyEvent arg0) { - } - - @Override - public void keyTyped(KeyEvent arg0) { - } - }); - scrollPane.setColumnHeaderView(new JLabel("JD-GUI Decompiler - Editable: " + panelArea.isEditable())); - panelArea.setFont(new Font(Font.MONOSPACED, Font.PLAIN, - (int) BytecodeViewer.viewer.fontSpinner.getValue())); - - SwingUtilities.invokeLater(() -> panel2.add(scrollPane)); - - java2 = panelArea; - } - - if (pane2 == 10) {// JADX - panelArea = new RSyntaxTextArea(); - panelArea.setSyntaxEditingStyle(SyntaxConstants.SYNTAX_STYLE_JAVA); - panelArea.setCodeFoldingEnabled(true); - panelArea.setAntiAliasingEnabled(true); - scrollPane = new RTextScrollPane(panelArea); - panelArea.setText(Decompilers.jadx.decompileClassNode(cn, b)); - panelArea.setCaretPosition(0); - panelArea.setEditable(isPanel2Editable()); - panelArea.addKeyListener(new KeyListener() { - @Override - public void keyPressed(KeyEvent e) { - if ((e.getKeyCode() == KeyEvent.VK_F) && ((e.getModifiers() & KeyEvent.CTRL_MASK) != 0)) { - field1.requestFocus(); - } - - BytecodeViewer.checkHotKey(e); - } - - @Override - public void keyReleased(KeyEvent arg0) { - } - - @Override - public void keyTyped(KeyEvent arg0) { - } - }); - scrollPane.setColumnHeaderView(new JLabel("JADX Decompiler - Editable: " + panelArea.isEditable())); - panelArea.setFont(new Font(Font.MONOSPACED, Font.PLAIN, - (int) BytecodeViewer.viewer.fontSpinner.getValue())); - - SwingUtilities.invokeLater(() -> panel2.add(scrollPane)); - - java2 = panelArea; - } - - if (pane2 == 11) {// asm text - panelArea = new RSyntaxTextArea(); - panelArea.setSyntaxEditingStyle(SyntaxConstants.SYNTAX_STYLE_JAVA); - panelArea.setAntiAliasingEnabled(true); - scrollPane = new RTextScrollPane(panelArea); - panelArea.setText(Decompilers.textifier.decompileClassNode(cn, b)); - panelArea.setCaretPosition(0); - panelArea.setEditable(false); - panelArea.addKeyListener(new KeyListener() { - @Override - public void keyPressed(KeyEvent e) { - if ((e.getKeyCode() == KeyEvent.VK_F) && ((e.getModifiers() & KeyEvent.CTRL_MASK) != 0)) { - field2.requestFocus(); - } - - BytecodeViewer.checkHotKey(e); - } - - @Override - public void keyReleased(KeyEvent arg0) { - } - - @Override - public void keyTyped(KeyEvent arg0) { - } - }); - scrollPane.setColumnHeaderView(new JLabel("ASM Textified - Editable: " + panelArea.isEditable())); - panelArea.setFont(new Font(Font.MONOSPACED, Font.PLAIN, - (int) BytecodeViewer.viewer.fontSpinner.getValue())); - - SwingUtilities.invokeLater(() -> panel2.add(scrollPane)); - java2 = panelArea; - } - } catch (java.lang.IndexOutOfBoundsException | java.lang.NullPointerException e) { - //ignore - } catch (Exception e) { - new the.bytecode.club.bytecodeviewer.api.ExceptionUI(e); - } finally { - resetDivider(); - BytecodeViewer.viewer.updateBusyStatus(false); - if (button != null) - button.setEnabled(true); - } - } - }; - - - t3 = new PaneUpdaterThread() { - @Override - public void doShit() { - try { - paneId = 2; - viewer = THIS; - decompiler = pane3; - - BytecodeViewer.viewer.updateBusyStatus(true); - if (pane3 == 1) { - panelArea = new RSyntaxTextArea(); - panelArea.setSyntaxEditingStyle(SyntaxConstants.SYNTAX_STYLE_JAVA); - panelArea.setCodeFoldingEnabled(true); - panelArea.setAntiAliasingEnabled(true); - scrollPane = new RTextScrollPane(panelArea); - panelArea.setText(Decompilers.procyon.decompileClassNode(cn, b)); - panelArea.setCaretPosition(0); - panelArea.setEditable(isPanel3Editable()); - panelArea.addKeyListener(new KeyListener() { - @Override - public void keyPressed(KeyEvent e) { - if ((e.getKeyCode() == KeyEvent.VK_F) && ((e.getModifiers() & KeyEvent.CTRL_MASK) != 0)) { - field3.requestFocus(); - } - - BytecodeViewer.checkHotKey(e); - } - - @Override - public void keyReleased(KeyEvent arg0) { - } - - @Override - public void keyTyped(KeyEvent arg0) { - } - }); - scrollPane.setColumnHeaderView(new JLabel("Procyon Decompiler - Editable: " + panelArea.isEditable())); - panelArea.setFont(new Font(Font.MONOSPACED, Font.PLAIN, - (int) BytecodeViewer.viewer.fontSpinner.getValue())); - - SwingUtilities.invokeLater(() -> panel3.add(scrollPane)); - - java3 = panelArea; - } - - if (pane3 == 2) { - panelArea = new RSyntaxTextArea(); - panelArea - .setSyntaxEditingStyle(SyntaxConstants.SYNTAX_STYLE_JAVA); - panelArea.setCodeFoldingEnabled(true); - panelArea.setAntiAliasingEnabled(true); - scrollPane = new RTextScrollPane(panelArea); - panelArea.setText(Decompilers.cfr.decompileClassNode(cn, b)); - panelArea.setCaretPosition(0); - panelArea.setEditable(isPanel3Editable()); - panelArea.addKeyListener(new KeyListener() { - @Override - public void keyPressed(KeyEvent e) { - if ((e.getKeyCode() == KeyEvent.VK_F) && ((e.getModifiers() & KeyEvent.CTRL_MASK) != 0)) { - field3.requestFocus(); - } - - BytecodeViewer.checkHotKey(e); - } - - @Override - public void keyReleased(KeyEvent arg0) { - } - - @Override - public void keyTyped(KeyEvent arg0) { - } - }); - scrollPane.setColumnHeaderView(new JLabel("CFR Decompiler - Editable: " + panelArea.isEditable())); - panelArea.setFont(new Font(Font.MONOSPACED, Font.PLAIN, - (int) BytecodeViewer.viewer.fontSpinner.getValue())); - - SwingUtilities.invokeLater(() -> panel3.add(scrollPane)); - - java3 = panelArea; - } - - if (pane3 == 3) { - panelArea = new RSyntaxTextArea(); - panelArea - .setSyntaxEditingStyle(SyntaxConstants.SYNTAX_STYLE_JAVA); - panelArea.setCodeFoldingEnabled(true); - panelArea.setAntiAliasingEnabled(true); - scrollPane = new RTextScrollPane(panelArea); - panelArea.setText(Decompilers.fernflower.decompileClassNode(cn, b)); - panelArea.setCaretPosition(0); - panelArea.setEditable(isPanel3Editable()); - panelArea.addKeyListener(new KeyListener() { - @Override - public void keyPressed(KeyEvent e) { - if ((e.getKeyCode() == KeyEvent.VK_F) && ((e.getModifiers() & KeyEvent.CTRL_MASK) != 0)) { - field3.requestFocus(); - } - - BytecodeViewer.checkHotKey(e); - } - - @Override - public void keyReleased(KeyEvent arg0) { - } - - @Override - public void keyTyped(KeyEvent arg0) { - } - }); - scrollPane.setColumnHeaderView(new JLabel("FernFlower Decompiler - Editable: " + panelArea.isEditable())); - panelArea.setFont(new Font(Font.MONOSPACED, Font.PLAIN, - (int) BytecodeViewer.viewer.fontSpinner.getValue())); - - SwingUtilities.invokeLater(() -> panel3.add(scrollPane)); - - java3 = panelArea; - } - - if (pane3 == 4) { - panelArea = new RSyntaxTextArea(); - panelArea.setSyntaxEditingStyle(SyntaxConstants.SYNTAX_STYLE_JAVA); - panelArea.setCodeFoldingEnabled(true); - panelArea.setAntiAliasingEnabled(true); - scrollPane = new RTextScrollPane(panelArea); - panelArea.setText(Decompilers.bytecode.decompileClassNode(cn, b)); - panelArea.setCaretPosition(0); - panelArea.setEditable(false); - panelArea.addKeyListener(new KeyListener() { - @Override - public void keyPressed(KeyEvent e) { - if ((e.getKeyCode() == KeyEvent.VK_F) && ((e.getModifiers() & KeyEvent.CTRL_MASK) != 0)) { - field3.requestFocus(); - } - - BytecodeViewer.checkHotKey(e); - } - - @Override - public void keyReleased(KeyEvent arg0) { - } - - @Override - public void keyTyped(KeyEvent arg0) { - } - }); - scrollPane.setColumnHeaderView(new JLabel("Bytecode Decompiler - Editable: " + panelArea.isEditable())); - panelArea.setFont(new Font(Font.MONOSPACED, Font.PLAIN, - (int) BytecodeViewer.viewer.fontSpinner.getValue())); - - SwingUtilities.invokeLater(() -> panel3.add(scrollPane)); - } - - if (pane3 == 5) { - final ClassWriter cw = new ClassWriter(0); - cn.accept(cw); - final JHexEditor hex = new JHexEditor(cw.toByteArray()); - hex.setFont(new Font(Font.MONOSPACED, Font.PLAIN, - (int) BytecodeViewer.viewer.fontSpinner.getValue())); - - SwingUtilities.invokeLater(() -> panel3.add(hex)); - - } - - if (pane3 == 6) { - panelArea = new RSyntaxTextArea(); - panelArea.setSyntaxEditingStyle(SyntaxConstants.SYNTAX_STYLE_JAVA); - panelArea.setCodeFoldingEnabled(true); - panelArea.setAntiAliasingEnabled(true); - scrollPane = new RTextScrollPane(panelArea); - panelArea.setText(Decompilers.smali.decompileClassNode(container, cn, b)); - panelArea.setCaretPosition(0); - panelArea.setEditable(isPanel3Editable()); - smali3 = panelArea; - smali3.addKeyListener(new KeyListener() { - @Override - public void keyPressed(KeyEvent e) { - if ((e.getKeyCode() == KeyEvent.VK_F) && ((e.getModifiers() & KeyEvent.CTRL_MASK) != 0)) { - field3.requestFocus(); - } - - BytecodeViewer.checkHotKey(e); - } - - @Override - public void keyReleased(KeyEvent arg0) { - } - - @Override - public void keyTyped(KeyEvent arg0) { - } - }); - scrollPane.setColumnHeaderView(new JLabel("Smali Decompiler - Editable: " + panelArea.isEditable())); - panelArea.setFont(new Font(Font.MONOSPACED, Font.PLAIN, - (int) BytecodeViewer.viewer.fontSpinner.getValue())); - - SwingUtilities.invokeLater(() -> panel3.add(scrollPane)); - - } - - if (pane3 == 7) {// krakatau - panelArea = new RSyntaxTextArea(); - panelArea.setSyntaxEditingStyle(SyntaxConstants.SYNTAX_STYLE_JAVA); - panelArea.setCodeFoldingEnabled(true); - panelArea.setAntiAliasingEnabled(true); - scrollPane = new RTextScrollPane(panelArea); - panelArea.setText(Decompilers.krakatau.decompileClassNode(tempFiles[0], tempFiles[1], cn)); - panelArea.setCaretPosition(0); - panelArea.setEditable(isPanel3Editable()); - panelArea.addKeyListener(new KeyListener() { - @Override - public void keyPressed(KeyEvent e) { - if ((e.getKeyCode() == KeyEvent.VK_F) && ((e.getModifiers() & KeyEvent.CTRL_MASK) != 0)) { - field3.requestFocus(); - } - - BytecodeViewer.checkHotKey(e); - } - - @Override - public void keyReleased(KeyEvent arg0) { - } - - @Override - public void keyTyped(KeyEvent arg0) { - } - }); - scrollPane.setColumnHeaderView(new JLabel("Krakatau Decompiler - Editable: " + panelArea.isEditable())); - java3 = panelArea; - panelArea.setFont(new Font(Font.MONOSPACED, Font.PLAIN, - (int) BytecodeViewer.viewer.fontSpinner.getValue())); - - SwingUtilities.invokeLater(() -> panel3.add(scrollPane)); - } - - if (pane3 == 8) {// kraktau bytecode - panelArea = new RSyntaxTextArea(); - panelArea.setSyntaxEditingStyle(SyntaxConstants.SYNTAX_STYLE_JAVA); - panelArea.setCodeFoldingEnabled(true); - panelArea.setAntiAliasingEnabled(true); - scrollPane = new RTextScrollPane(panelArea); - panelArea.setText(Decompilers.krakatauDA.decompileClassNode(tempFiles[0], tempFiles[1], cn)); - panelArea.setCaretPosition(0); - panelArea.setEditable(isPanel3Editable()); - krakatau3 = panelArea; - krakatau3.addKeyListener(new KeyListener() { - @Override - public void keyPressed(KeyEvent e) { - if ((e.getKeyCode() == KeyEvent.VK_F) && ((e.getModifiers() & KeyEvent.CTRL_MASK) != 0)) { - field3.requestFocus(); - } - - BytecodeViewer.checkHotKey(e); - } - - @Override - public void keyReleased(KeyEvent arg0) { - } - - @Override - public void keyTyped(KeyEvent arg0) { - } - }); - scrollPane.setColumnHeaderView(new JLabel("Krakatau Disassembler")); - panelArea.setFont(new Font(Font.MONOSPACED, Font.PLAIN, - (int) BytecodeViewer.viewer.fontSpinner.getValue())); - - SwingUtilities.invokeLater(() -> panel3.add(scrollPane)); - - } - - if (pane3 == 9) {// JD-GUI - panelArea = new RSyntaxTextArea(); - panelArea.setSyntaxEditingStyle(SyntaxConstants.SYNTAX_STYLE_JAVA); - panelArea.setCodeFoldingEnabled(true); - panelArea.setAntiAliasingEnabled(true); - scrollPane = new RTextScrollPane(panelArea); - panelArea.setText(Decompilers.jdgui.decompileClassNode(cn, b)); - panelArea.setCaretPosition(0); - panelArea.setEditable(isPanel3Editable()); - panelArea.addKeyListener(new KeyListener() { - @Override - public void keyPressed(KeyEvent e) { - if ((e.getKeyCode() == KeyEvent.VK_F) && ((e.getModifiers() & KeyEvent.CTRL_MASK) != 0)) { - field3.requestFocus(); - } - - BytecodeViewer.checkHotKey(e); - } - - @Override - public void keyReleased(KeyEvent arg0) { - } - - @Override - public void keyTyped(KeyEvent arg0) { - } - }); - scrollPane.setColumnHeaderView(new JLabel("JD-GUI Decompiler - Editable: " + panelArea.isEditable())); - java3 = panelArea; - panelArea.setFont(new Font(Font.MONOSPACED, Font.PLAIN, - (int) BytecodeViewer.viewer.fontSpinner.getValue())); - - SwingUtilities.invokeLater(() -> panel3.add(scrollPane)); - } - - if (pane3 == 10) {// JADX - panelArea = new RSyntaxTextArea(); - panelArea.setSyntaxEditingStyle(SyntaxConstants.SYNTAX_STYLE_JAVA); - panelArea.setCodeFoldingEnabled(true); - panelArea.setAntiAliasingEnabled(true); - scrollPane = new RTextScrollPane(panelArea); - panelArea.setText(Decompilers.jadx.decompileClassNode(cn, b)); - panelArea.setCaretPosition(0); - panelArea.setEditable(isPanel3Editable()); - panelArea.addKeyListener(new KeyListener() { - @Override - public void keyPressed(KeyEvent e) { - if ((e.getKeyCode() == KeyEvent.VK_F) && ((e.getModifiers() & KeyEvent.CTRL_MASK) != 0)) { - field1.requestFocus(); - } - - BytecodeViewer.checkHotKey(e); - } - - @Override - public void keyReleased(KeyEvent arg0) { - } - - @Override - public void keyTyped(KeyEvent arg0) { - } - }); - scrollPane.setColumnHeaderView(new JLabel("JADX Decompiler - Editable: " + panelArea.isEditable())); - panelArea.setFont(new Font(Font.MONOSPACED, Font.PLAIN, - (int) BytecodeViewer.viewer.fontSpinner.getValue())); - - SwingUtilities.invokeLater(() -> panel3.add(scrollPane)); - - java3 = panelArea; - } - - if (pane3 == 11) {// asm text - panelArea = new RSyntaxTextArea(); - panelArea.setSyntaxEditingStyle(SyntaxConstants.SYNTAX_STYLE_JAVA); - panelArea.setAntiAliasingEnabled(true); - scrollPane = new RTextScrollPane(panelArea); - panelArea.setText(Decompilers.textifier.decompileClassNode(cn, b)); - panelArea.setCaretPosition(0); - panelArea.setEditable(false); - panelArea.addKeyListener(new KeyListener() { - @Override - public void keyPressed(KeyEvent e) { - if ((e.getKeyCode() == KeyEvent.VK_F) && ((e.getModifiers() & KeyEvent.CTRL_MASK) != 0)) { - field3.requestFocus(); - } - - BytecodeViewer.checkHotKey(e); - } - - @Override - public void keyReleased(KeyEvent arg0) { - } - - @Override - public void keyTyped(KeyEvent arg0) { - } - }); - scrollPane.setColumnHeaderView(new JLabel("ASM Textified - Editable: " + panelArea.isEditable())); - panelArea.setFont(new Font(Font.MONOSPACED, Font.PLAIN, - (int) BytecodeViewer.viewer.fontSpinner.getValue())); - - SwingUtilities.invokeLater(() -> panel3.add(scrollPane)); - java3 = panelArea; - } - } catch (java.lang.IndexOutOfBoundsException | java.lang.NullPointerException e) { - //ignore - } catch (Exception e) { - //new the.bytecode.club.bytecodeviewer.api.ExceptionUI(e); - } finally { - resetDivider(); - BytecodeViewer.viewer.updateBusyStatus(false); - if (button != null) - button.setEnabled(true); - } - } - }; - - Thread t = new Thread(() -> { - BytecodeViewer.viewer.updateBusyStatus(true); - while (Configuration.currentlyDumping) { - //wait until it's not dumping - try { - Thread.sleep(100); - } catch (InterruptedException e) { - e.printStackTrace(); - } - } - tempFiles = BytecodeViewer.dumpTempFile(container); - - BytecodeViewer.viewer.updateBusyStatus(false); - - if (pane1 > 0) - t1.start(); - if (pane2 > 0) - t2.start(); - if (pane3 > 0) - t3.start(); - }); - t.start(); - - if (isPanel1Editable() || isPanel2Editable() || isPanel3Editable()) { - if (!Configuration.warnForEditing) { - Configuration.warnForEditing = true; - if (!BytecodeViewer.viewer.autoCompileOnRefresh.isSelected() && !BytecodeViewer.viewer.compileOnSave.isSelected()) { - BytecodeViewer.showMessage("Make sure to compile (File>Compile or Ctrl + T) whenever you want to " - + "test or export your changes.\nYou can set compile automatically on refresh or on save " - + "in the settings menu."); - Settings.saveSettings(); - } - } - } - } - - public Object[] getSmali() { - if (smali1 != null) - return new Object[]{cn, smali1.getText()}; - if (smali2 != null) - return new Object[]{cn, smali2.getText()}; - if (smali3 != null) - return new Object[]{cn, smali3.getText()}; - - return null; - } - - public Object[] getKrakatau() { - if (krakatau1 != null) - return new Object[]{cn, krakatau1.getText()}; - if (krakatau2 != null) - return new Object[]{cn, krakatau2.getText()}; - if (krakatau3 != null) - return new Object[]{cn, krakatau3.getText()}; - - return null; - } - - public Object[] getJava() { - if (java1 != null) - return new Object[]{cn, java1.getText()}; - if (java2 != null) - return new Object[]{cn, java2.getText()}; - if (java3 != null) - return new Object[]{cn, java3.getText()}; - - return null; - } - - public static class MethodData { - public String name, desc; - - @Override - public boolean equals(final Object o) { - return equals((MethodData) o); - } - - public boolean equals(final MethodData md) { - return this.name.equals(md.name) && this.desc.equals(md.desc); - } - - public String constructPattern() { - final StringBuilder pattern = new StringBuilder(); - pattern.append(name).append(" *\\("); - final org.objectweb.asm.Type[] types = org.objectweb.asm.Type - .getArgumentTypes(desc); - pattern.append("(.*)"); - Arrays.stream(types).map(Type::getClassName) - .forEach(clazzName -> pattern.append(clazzName.substring(clazzName.lastIndexOf(".") + 1)).append( - "(.*)")); - pattern.append("\\) *\\{"); - return pattern.toString(); - } - } - - class WrapEditorKit extends StyledEditorKit { - private static final long serialVersionUID = 1719109651258205346L; - ViewFactory defaultFactory = new WrapColumnFactory(); - - @Override - public ViewFactory getViewFactory() { - return defaultFactory; - } - } - - static class WrapColumnFactory implements ViewFactory { - @Override - public View create(final Element elem) { - final String kind = elem.getName(); - if (kind != null) { - switch (kind) { - case AbstractDocument.ParagraphElementName: - return new NoWrapParagraphView(elem); - case AbstractDocument.SectionElementName: - return new BoxView(elem, View.Y_AXIS); - case StyleConstants.ComponentElementName: - return new ComponentView(elem); - case StyleConstants.IconElementName: - return new IconView(elem); - } - } - - return new LabelView(elem); - } - } - - public static class NoWrapParagraphView extends ParagraphView { - public NoWrapParagraphView(final Element elem) { - super(elem); - } - - @Override - public void layout(final int width, final int height) { - super.layout(Short.MAX_VALUE, height); - } - - @Override - public float getMinimumSpan(final int axis) { - return super.getPreferredSpan(axis); - } - } - - - public void setPanes() { - pane1 = BytecodeViewer.viewer.viewPane1.getSelectedViewer(); - pane2 = BytecodeViewer.viewer.viewPane2.getSelectedViewer(); - pane3 = BytecodeViewer.viewer.viewPane3.getSelectedViewer(); - } - - public boolean isPanel1Editable() { - setPanes(); - - return BytecodeViewer.viewer.viewPane1.isPaneEditable(); - } - - public boolean isPanel2Editable() { - setPanes(); - - return BytecodeViewer.viewer.viewPane2.isPaneEditable(); - } - - public boolean isPanel3Editable() { - setPanes(); - - return BytecodeViewer.viewer.viewPane3.isPaneEditable(); - } - - /** - * Whoever wrote this function, THANK YOU! - * - * @param splitter - * @param proportion - * @return - */ - public static JSplitPane setDividerLocation(final JSplitPane splitter, - final double proportion) { - if (splitter.isShowing()) { - if (splitter.getWidth() > 0 && splitter.getHeight() > 0) { - splitter.setDividerLocation(proportion); - } else { - splitter.addComponentListener(new ComponentAdapter() { - @Override - public void componentResized(ComponentEvent ce) { - splitter.removeComponentListener(this); - setDividerLocation(splitter, proportion); - } - }); - } - } else { - splitter.addHierarchyListener(new HierarchyListener() { - @Override - public void hierarchyChanged(HierarchyEvent e) { - if ((e.getChangeFlags() & HierarchyEvent.SHOWING_CHANGED) != 0 - && splitter.isShowing()) { - splitter.removeHierarchyListener(this); - setDividerLocation(splitter, proportion); - } - } - }); - } - return splitter; - } - - - public static void selectMethod(RSyntaxTextArea area, int methodLine) { - if (methodLine != area.getCaretLineNumber()) { - setCaretLine(area, methodLine); - setViewLine(area, methodLine); - } - } - - public static void selectMethod(ClassViewer classViewer, int paneId, Method method) { - RSyntaxTextArea area = null; - switch (paneId) { - case 0: - area = classViewer.t1.panelArea; - break; - case 1: - area = classViewer.t2.panelArea; - break; - case 2: - area = classViewer.t3.panelArea; - break; - } - - if (area != null) { - MethodParser methods = classViewer.methods.get(paneId); - if (methods != null) { - int methodLine = methods.findMethod(method); - if (methodLine != -1) { - selectMethod(area, methodLine); - } - } - } - } - - public static String getLineText(RSyntaxTextArea area, int line) { - try { - if (line < area.getLineCount()) { - int start = area.getLineStartOffset(line); - int end = area.getLineEndOffset(line); - return area.getText(start, end - start).trim(); - } - } catch (BadLocationException ignored) { - } - return ""; - } - - public static int getMaxViewLine(RSyntaxTextArea area) { - Container parent = area.getParent(); - if (parent instanceof JViewport) { - JViewport viewport = (JViewport) parent; - int y = viewport.getViewSize().height - viewport.getExtentSize().height; - int lineHeight = area.getLineHeight(); - return y >= lineHeight ? y / lineHeight : 0; - } - return 0; - } - - public static int getViewLine(RSyntaxTextArea area) { - Container parent = area.getParent(); - if (parent instanceof JViewport) { - JViewport viewport = (JViewport) parent; - Point point = viewport.getViewPosition(); - int lineHeight = area.getLineHeight(); - return point.y >= lineHeight ? point.y / lineHeight : 0; - } - return 0; - } - - public static void setViewLine(RSyntaxTextArea area, int line) { - Container parent = area.getParent(); - if (parent instanceof JViewport) { - JViewport viewport = (JViewport) parent; - int maxLine = ClassViewer.getMaxViewLine(area); - line = Math.min(line, maxLine); - viewport.setViewPosition(new Point(0, line * area.getLineHeight())); - } - } - - public static void setCaretLine(RSyntaxTextArea area, int line) { - try { - area.setCaretPosition(area.getLineStartOffset(line)); - } catch (BadLocationException ignored) { - } - } -} diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/gui/FileViewer.java b/src/main/java/the/bytecode/club/bytecodeviewer/gui/FileViewer.java deleted file mode 100644 index b8226e74..00000000 --- a/src/main/java/the/bytecode/club/bytecodeviewer/gui/FileViewer.java +++ /dev/null @@ -1,328 +0,0 @@ -package the.bytecode.club.bytecodeviewer.gui; - -import java.awt.BorderLayout; -import java.awt.Color; -import java.awt.event.KeyEvent; -import java.awt.event.KeyListener; -import java.awt.image.BufferedImage; -import java.io.ByteArrayInputStream; -import java.io.IOException; -import java.nio.charset.CharsetEncoder; -import java.nio.charset.StandardCharsets; -import javax.imageio.ImageIO; -import javax.swing.ImageIcon; -import javax.swing.JButton; -import javax.swing.JCheckBox; -import javax.swing.JLabel; -import javax.swing.JPanel; -import javax.swing.JTextArea; -import javax.swing.JTextField; -import javax.swing.text.DefaultHighlighter; -import javax.swing.text.Highlighter; -import javax.swing.text.JTextComponent; -import org.fife.ui.rsyntaxtextarea.RSyntaxTextArea; -import org.fife.ui.rtextarea.RTextScrollPane; -import org.imgscalr.Scalr; -import the.bytecode.club.bytecodeviewer.BytecodeViewer; -import the.bytecode.club.bytecodeviewer.Resources; -import the.bytecode.club.bytecodeviewer.gui.hexviewer.JHexEditor; -import the.bytecode.club.bytecodeviewer.util.FileContainer; -import the.bytecode.club.bytecodeviewer.util.Language; - -/*************************************************************************** - * Bytecode Viewer (BCV) - Java & Android Reverse Engineering Suite * - * Copyright (C) 2014 Kalen 'Konloch' Kinloch - http://bytecodeviewer.com * - * * - * This program is free software: you can redistribute it and/or modify * - * it under the terms of the GNU General Public License as published by * - * the Free Software Foundation, either version 3 of the License, or * - * (at your option) any later version. * - * * - * This program is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program. If not, see . * - ***************************************************************************/ - -/** - * Represents any open non-class file. - * - * @author Konloch - */ - -public class FileViewer extends Viewer { - - private static final long serialVersionUID = 6103372882168257164L; - - String name; - private final byte[] contents; - RSyntaxTextArea panelArea = new RSyntaxTextArea(); - JPanel panel = new JPanel(new BorderLayout()); - JPanel panel2 = new JPanel(new BorderLayout()); - public JCheckBox check = new JCheckBox("Exact"); - final JTextField field = new JTextField(); - public BufferedImage image; - boolean canRefresh = false; - public TabbedPane tabbedPane; - - public void setContents() { - String name = this.name.toLowerCase(); - panelArea.setCodeFoldingEnabled(true); - panelArea.setAntiAliasingEnabled(true); - RTextScrollPane scrollPane = new RTextScrollPane(panelArea); - panelArea.addKeyListener(new KeyListener() { - @Override - public void keyPressed(KeyEvent e) { - if ((e.getKeyCode() == KeyEvent.VK_F) && ((e.getModifiers() & KeyEvent.CTRL_MASK) != 0)) { - field.requestFocus(); - } - - BytecodeViewer.checkHotKey(e); - } - - @Override - public void keyReleased(KeyEvent arg0) { - } - - @Override - public void keyTyped(KeyEvent arg0) { - } - }); - - String contentsS = new String(contents); - - if (!isPureAscii(contentsS)) { - if (name.endsWith(".png") || name.endsWith(".jpg") || name.endsWith(".jpeg") || - name.endsWith(".gif") || name.endsWith(".tif") || name.endsWith(".bmp")) { - canRefresh = true; - try { - image = ImageIO.read(new ByteArrayInputStream(contents)); //gifs fail cause of this - JLabel label = new JLabel("", new ImageIcon(image), JLabel.CENTER); - panel2.add(label, BorderLayout.CENTER); - panel2.addMouseWheelListener(e -> { - int notches = e.getWheelRotation(); - if (notches < 0) { - image = Scalr.resize(image, Scalr.Method.SPEED, image.getWidth() + 10, - image.getHeight() + 10); - } else { - image = Scalr.resize(image, Scalr.Method.SPEED, image.getWidth() - 10, - image.getHeight() - 10); - } - panel2.removeAll(); - JLabel label1 = new JLabel("", new ImageIcon(image), JLabel.CENTER); - panel2.add(label1, BorderLayout.CENTER); - panel2.updateUI(); - }); - return; - } catch (Exception e) { - new the.bytecode.club.bytecodeviewer.api.ExceptionUI(e); - } - } else if (BytecodeViewer.viewer.forcePureAsciiAsText.isSelected()) { - JHexEditor hex = new JHexEditor(contents); - panel2.add(hex); - return; - } - } - - panelArea.setSyntaxEditingStyle(Language.detectLanguage(name, contentsS).getSyntaxConstant()); - panelArea.setText(contentsS); - panelArea.setCaretPosition(0); - scrollPane.setColumnHeaderView(panel); - panel2.add(scrollPane); - } - - static CharsetEncoder asciiEncoder = StandardCharsets.US_ASCII.newEncoder(); // or "ISO-8859-1" for ISO Latin 1 - - public static boolean isPureAscii(String v) { - return asciiEncoder.canEncode(v); - } - - public FileViewer(final FileContainer container, final String name, final byte[] contents) { - this.name = name; - this.contents = contents; - this.container = container; - this.setName(name); - this.setLayout(new BorderLayout()); - - this.add(panel2, BorderLayout.CENTER); - - JButton searchNext = new JButton(); - JButton searchPrev = new JButton(); - JPanel buttonPane = new JPanel(new BorderLayout()); - buttonPane.add(searchNext, BorderLayout.WEST); - buttonPane.add(searchPrev, BorderLayout.EAST); - searchNext.setIcon(Resources.nextIcon); - searchPrev.setIcon(Resources.prevIcon); - panel.add(buttonPane, BorderLayout.WEST); - panel.add(field, BorderLayout.CENTER); - panel.add(check, BorderLayout.EAST); - searchNext.addActionListener(arg0 -> search(field.getText(), true)); - searchPrev.addActionListener(arg0 -> search(field.getText(), false)); - field.addKeyListener(new KeyListener() { - @Override - public void keyReleased(KeyEvent arg0) { - if (arg0.getKeyCode() == KeyEvent.VK_ENTER) - search(field.getText(), true); - } - - @Override - public void keyPressed(KeyEvent arg0) { - } - - @Override - public void keyTyped(KeyEvent arg0) { - } - }); - - setContents(); - } - - /** - * This was really interesting to write. - * - * @author Konloch - */ - public void search(String search, boolean next) { - try { - JTextArea area = panelArea; - if (search.isEmpty()) { - highlight(area, ""); - return; - } - - int startLine = area.getDocument().getDefaultRootElement() - .getElementIndex(area.getCaretPosition()) + 1; - int currentLine = 1; - boolean canSearch = false; - String[] test; - if (area.getText().split("\n").length >= 2) - test = area.getText().split("\n"); - else - test = area.getText().split("\r"); - int lastGoodLine = -1; - int firstPos = -1; - boolean found = false; - - if (next) { - for (String s : test) { - if (!check.isSelected()) { - s = s.toLowerCase(); - search = search.toLowerCase(); - } - - if (currentLine == startLine) { - canSearch = true; - } else if (s.contains(search)) { - if (canSearch) { - area.setCaretPosition(area.getDocument() - .getDefaultRootElement() - .getElement(currentLine - 1) - .getStartOffset()); - canSearch = false; - found = true; - } - - if (firstPos == -1) - firstPos = currentLine; - } - - currentLine++; - } - - if (!found && firstPos != -1) { - area.setCaretPosition(area.getDocument() - .getDefaultRootElement().getElement(firstPos - 1) - .getStartOffset()); - } - } else { - canSearch = true; - for (String s : test) { - if (!check.isSelected()) { - s = s.toLowerCase(); - search = search.toLowerCase(); - } - - if (s.contains(search)) { - if (lastGoodLine != -1 && canSearch) - area.setCaretPosition(area.getDocument() - .getDefaultRootElement() - .getElement(lastGoodLine - 1) - .getStartOffset()); - - lastGoodLine = currentLine; - - if (currentLine >= startLine) - canSearch = false; - } - currentLine++; - } - - if (lastGoodLine != -1 - && area.getDocument().getDefaultRootElement() - .getElementIndex(area.getCaretPosition()) + 1 == startLine) { - area.setCaretPosition(area.getDocument() - .getDefaultRootElement() - .getElement(lastGoodLine - 1).getStartOffset()); - } - } - highlight(area, search); - } catch (Exception e) { - new the.bytecode.club.bytecodeviewer.api.ExceptionUI(e); - } - } - - private final DefaultHighlighter.DefaultHighlightPainter painter = new DefaultHighlighter.DefaultHighlightPainter( - new Color(255, 62, 150)); - - public void highlight(JTextComponent textComp, String pattern) { - if (pattern.isEmpty()) { - textComp.getHighlighter().removeAllHighlights(); - return; - } - - try { - Highlighter hilite = textComp.getHighlighter(); - hilite.removeAllHighlights(); - javax.swing.text.Document doc = textComp.getDocument(); - String text = doc.getText(0, doc.getLength()); - int pos = 0; - - if (!check.isSelected()) { - pattern = pattern.toLowerCase(); - text = text.toLowerCase(); - } - - // Search for pattern - while ((pos = text.indexOf(pattern, pos)) >= 0) { - // Create highlighter using private painter and apply around - // pattern - hilite.addHighlight(pos, pos + pattern.length(), painter); - pos += pattern.length(); - } - } catch (Exception e) { - new the.bytecode.club.bytecodeviewer.api.ExceptionUI(e); - } - } - - public void refresh(JButton src) { - if (!canRefresh) { - src.setEnabled(true); - return; - } - - panel2.removeAll(); - try { - image = ImageIO.read(new ByteArrayInputStream(contents)); - } catch (IOException e) { - new the.bytecode.club.bytecodeviewer.api.ExceptionUI(e); - } - JLabel label = new JLabel("", new ImageIcon(image), JLabel.CENTER); - panel2.add(label, BorderLayout.CENTER); - panel2.updateUI(); - - src.setEnabled(true); - } -} diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/gui/MainViewerGUI.java b/src/main/java/the/bytecode/club/bytecodeviewer/gui/MainViewerGUI.java index b2112abf..306a5e01 100644 --- a/src/main/java/the/bytecode/club/bytecodeviewer/gui/MainViewerGUI.java +++ b/src/main/java/the/bytecode/club/bytecodeviewer/gui/MainViewerGUI.java @@ -4,22 +4,9 @@ import java.awt.Dimension; import java.awt.KeyboardFocusManager; import java.io.File; import java.util.ArrayList; -import javax.swing.BoxLayout; -import javax.swing.ButtonGroup; -import javax.swing.JCheckBoxMenuItem; -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.JRadioButtonMenuItem; -import javax.swing.JSeparator; -import javax.swing.JSpinner; -import javax.swing.JSplitPane; -import javax.swing.SpinnerNumberModel; -import javax.swing.SwingUtilities; +import java.util.HashMap; +import java.util.Map; +import javax.swing.*; import javax.swing.filechooser.FileFilter; import org.objectweb.asm.tree.ClassNode; @@ -28,11 +15,17 @@ import the.bytecode.club.bytecodeviewer.Configuration; import the.bytecode.club.bytecodeviewer.Resources; import the.bytecode.club.bytecodeviewer.Settings; import the.bytecode.club.bytecodeviewer.api.ExceptionUI; -import the.bytecode.club.bytecodeviewer.gui.extras.AboutWindow; -import the.bytecode.club.bytecodeviewer.gui.extras.RunOptions; +import the.bytecode.club.bytecodeviewer.gui.components.VisibleComponent; +import the.bytecode.club.bytecodeviewer.gui.components.AboutWindow; +import the.bytecode.club.bytecodeviewer.gui.components.RunOptions; import the.bytecode.club.bytecodeviewer.gui.plugins.MaliciousCodeScannerOptions; import the.bytecode.club.bytecodeviewer.gui.plugins.ReplaceStringsOptions; import the.bytecode.club.bytecodeviewer.gui.resourcelist.ResourceListPane; +import the.bytecode.club.bytecodeviewer.gui.resourcesearch.SearchBoxPane; +import the.bytecode.club.bytecodeviewer.gui.resourceviewer.DecompilerSelectionPane; +import the.bytecode.club.bytecodeviewer.gui.resourceviewer.WorkPaneMainComponent; +import the.bytecode.club.bytecodeviewer.gui.theme.LAFTheme; +import the.bytecode.club.bytecodeviewer.gui.theme.RSTATheme; import the.bytecode.club.bytecodeviewer.obfuscators.rename.RenameClasses; import the.bytecode.club.bytecodeviewer.obfuscators.rename.RenameFields; import the.bytecode.club.bytecodeviewer.obfuscators.rename.RenameMethods; @@ -80,7 +73,7 @@ public class MainViewerGUI extends JFrame { //main UI components private static final ArrayList uiComponents = new ArrayList<>(); - public final WorkPane workPane = new WorkPane(); + public final WorkPaneMainComponent workPane = new WorkPaneMainComponent(); public final ResourceListPane resourcePane = new ResourceListPane(); public final SearchBoxPane searchBoxPane = new SearchBoxPane(); public JSplitPane splitPane1; @@ -108,9 +101,9 @@ public class MainViewerGUI extends JFrame { //all of the view main menu components public final JMenu viewMainMenu = new JMenu("View"); - public final ViewPane viewPane1 = new ViewPane(1); - public final ViewPane viewPane2 = new ViewPane(2); - public final ViewPane viewPane3 = new ViewPane(3); + public final DecompilerSelectionPane viewPane1 = new DecompilerSelectionPane(1); + public final DecompilerSelectionPane viewPane2 = new DecompilerSelectionPane(2); + public final DecompilerSelectionPane viewPane3 = new DecompilerSelectionPane(3); //all of the plugins main menu components public final JMenu pluginsMainMenu = new JMenu("Plugins"); @@ -132,6 +125,8 @@ public class MainViewerGUI extends JFrame { public final JRadioButtonMenuItem apkConversionEnjarify = new JRadioButtonMenuItem("Enjarify"); public final JMenu fontSize = new JMenu("Font Size"); public final JSpinner fontSpinner = new JSpinner(); + public final JMenu rstaTheme = new JMenu("Text Area Theme"); + public final JMenu lafTheme = new JMenu("Window Theme"); //BCV settings public final JCheckBoxMenuItem refreshOnChange = new JCheckBoxMenuItem("Refresh On View Change"); private final JCheckBoxMenuItem deleteForeignOutdatedLibs = new JCheckBoxMenuItem("Delete Foreign/Outdated Libs"); @@ -147,11 +142,14 @@ public class MainViewerGUI extends JFrame { public final JMenuItem setOptionalLibrary = new JMenuItem("Set Optional Library Folder"); public final JCheckBoxMenuItem compileOnSave = new JCheckBoxMenuItem("Compile On Save"); public final JCheckBoxMenuItem showFileInTabTitle = new JCheckBoxMenuItem("Show File In Tab Title"); + public final JCheckBoxMenuItem simplifyNameInTabTitle = new JCheckBoxMenuItem("Simplify Name In Tab Title"); public final JCheckBoxMenuItem forcePureAsciiAsText = new JCheckBoxMenuItem("Force Pure Ascii As Text"); public final JCheckBoxMenuItem autoCompileOnRefresh = new JCheckBoxMenuItem("Compile On Refresh"); public final JCheckBoxMenuItem decodeAPKResources = new JCheckBoxMenuItem("Decode APK Resources"); public final JCheckBoxMenuItem synchronizedViewing = new JCheckBoxMenuItem("Synchronized Viewing"); public final JCheckBoxMenuItem showClassMethods = new JCheckBoxMenuItem("Show Class Methods"); + public final Map rstaThemes = new HashMap<>(); + public final Map lafThemes = new HashMap<>(); //CFIDE settings public final JCheckBoxMenuItem appendBracketsToLabels = new JCheckBoxMenuItem("Append Brackets To Labels"); public JCheckBoxMenuItem debugHelpers = new JCheckBoxMenuItem("Debug Helpers"); @@ -384,6 +382,7 @@ public class MainViewerGUI extends JFrame { public void buildViewMenu() { rootMenu.add(viewMainMenu); + viewMainMenu.add(visualSettings); viewMainMenu.add(viewPane1.menu); viewMainMenu.add(viewPane2.menu); viewMainMenu.add(viewPane3.menu); @@ -393,8 +392,8 @@ public class MainViewerGUI extends JFrame { { rootMenu.add(settingsMainMenu); - settingsMainMenu.add(visualSettings); - settingsMainMenu.add(new JSeparator()); + //settingsMainMenu.add(visualSettings); + //settingsMainMenu.add(new JSeparator()); settingsMainMenu.add(compileOnSave); settingsMainMenu.add(autoCompileOnRefresh); settingsMainMenu.add(refreshOnChange); @@ -420,8 +419,54 @@ public class MainViewerGUI extends JFrame { fontSpinner.setSize(new Dimension(42, 20)); fontSpinner.setModel(new SpinnerNumberModel(12, 1, null, 1)); fontSize.add(fontSpinner); + + ButtonGroup rstaGroup = new ButtonGroup(); + for (RSTATheme t : RSTATheme.values()) + { + JRadioButtonMenuItem item = new JRadioButtonMenuItem(t.getReadableName()); + if (Configuration.rstaTheme.equals(t)) + item.setSelected(true); + + rstaGroup.add(item); + + item.addActionListener(e -> + { + Configuration.rstaTheme = t; + item.setSelected(true); + Settings.saveSettings(); + }); + + rstaThemes.put(t, item); + rstaTheme.add(item); + } + + ButtonGroup lafGroup = new ButtonGroup(); + for (LAFTheme theme : LAFTheme.values()) + { + JRadioButtonMenuItem item = new JRadioButtonMenuItem(theme.getReadableName()); + if (Configuration.lafTheme.equals(theme)) + item.setSelected(true); + + lafGroup.add(item); + + item.addActionListener(e -> + { + Configuration.lafTheme = theme; + Configuration.rstaTheme = theme.getRSTATheme(); + rstaThemes.get(Configuration.rstaTheme).setSelected(true); + item.setSelected(true); + Settings.saveSettings(); + }); + + lafThemes.put(theme, item); + lafTheme.add(item); + } + + visualSettings.add(lafTheme); + visualSettings.add(rstaTheme); visualSettings.add(fontSize); visualSettings.add(showFileInTabTitle); + visualSettings.add(simplifyNameInTabTitle); visualSettings.add(synchronizedViewing); visualSettings.add(showClassMethods); @@ -527,6 +572,10 @@ public class MainViewerGUI extends JFrame { Configuration.displayParentInTab = BytecodeViewer.viewer.showFileInTabTitle.isSelected(); Settings.saveSettings(); }); + simplifyNameInTabTitle.addActionListener(arg0 -> { + Configuration.simplifiedTabNames = BytecodeViewer.viewer.simplifyNameInTabTitle.isSelected(); + Settings.saveSettings(); + }); } public void buildPluginMenu() diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/gui/TabbedPane.java b/src/main/java/the/bytecode/club/bytecodeviewer/gui/TabbedPane.java deleted file mode 100644 index b15a9b4b..00000000 --- a/src/main/java/the/bytecode/club/bytecodeviewer/gui/TabbedPane.java +++ /dev/null @@ -1,352 +0,0 @@ -package the.bytecode.club.bytecodeviewer.gui; - -import java.awt.BasicStroke; -import java.awt.Color; -import java.awt.Component; -import java.awt.Dimension; -import java.awt.FlowLayout; -import java.awt.Graphics; -import java.awt.Graphics2D; -import java.awt.Rectangle; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; -import java.awt.event.InputEvent; -import java.awt.event.MouseAdapter; -import java.awt.event.MouseEvent; -import java.awt.event.MouseListener; -import javax.swing.*; -import javax.swing.plaf.basic.BasicButtonUI; -import the.bytecode.club.bytecodeviewer.BytecodeViewer; - -/*************************************************************************** - * Bytecode Viewer (BCV) - Java & Android Reverse Engineering Suite * - * Copyright (C) 2014 Kalen 'Konloch' Kinloch - http://bytecodeviewer.com * - * * - * This program is free software: you can redistribute it and/or modify * - * it under the terms of the GNU General Public License as published by * - * the Free Software Foundation, either version 3 of the License, or * - * (at your option) any later version. * - * * - * This program is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program. If not, see . * - ***************************************************************************/ - -/** - * Component to be used as tabComponent; Contains a JLabel to show the text and a JButton to close the tab it belongs to - * - * @author Konloch - * @author WaterWolf - */ -public class TabbedPane extends JPanel { - - private static final long serialVersionUID = -4774885688297538774L; - public static final Color BLANK = new Color(0, 0, 0, 0); - private final JTabbedPane pane; - public final JLabel label; - private DelayTabbedPaneThread probablyABadIdea; - private long startedDragging = 0; - private static long zero = System.currentTimeMillis(); - public String tabName; - public String fileContainerName; - - public TabbedPane(String fileContainerName, String name, final JTabbedPane pane) { - // unset default FlowLayout' gaps - super(new FlowLayout(FlowLayout.LEFT, 0, 0)); - - this.tabName = name; - this.fileContainerName = fileContainerName; - - if (pane == null) - throw new NullPointerException("TabbedPane is null"); - - this.pane = pane; - setOpaque(false); - - // make JLabel read titles from JTabbedPane - label = new JLabel() { - private static final long serialVersionUID = -5511025206527893360L; - - @Override - public String getText() { - final int i = pane.indexOfTabComponent(TabbedPane.this); - if (i != -1) - return pane.getTitleAt(i); - return null; - } - - @Override - public Dimension getPreferredSize() { - Dimension realDimension = super.getPreferredSize(); - if (realDimension.getWidth() >= 400) - return new Dimension(400, 20); - else - return realDimension; - } - }; - - this.add(label); - // add more space between the label and the button - label.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 5)); - // tab button - JButton button = new TabButton(); - this.add(button); - // add more space to the top of the component - setBorder(BorderFactory.createEmptyBorder(2, 0, 0, 0)); - JPopupMenu pop_up = new JPopupMenu(); - JMenuItem closealltab = new JMenuItem("Close All But This: " + name); - JMenuItem closetab = new JMenuItem("Close Tab: " + name); - closetab.addActionListener(e -> { - String name1 = e.getActionCommand().split(": ")[1]; - final int i = pane.indexOfTab(name1); - if (i != -1) - pane.remove(i); - }); - closealltab.addActionListener(e -> { - String name12 = e.getActionCommand().split(": ")[1]; - while (true) { - int thisID = pane.indexOfTab(name12); - if (pane.getTabCount() <= 1) { - return; - } - if (thisID != 0) - pane.remove(0); - else - pane.remove(1); - } - }); - - pop_up.add(closealltab); - pop_up.add(closetab); - //setComponentPopupMenu(pop_up); - button.setComponentPopupMenu(pop_up); - - button.addMouseListener(new MouseListener() { - @Override - public void mouseClicked(MouseEvent e) { - if (e.getModifiers() == InputEvent.ALT_MASK) { - if (System.currentTimeMillis() - zero >= 100) { - zero = System.currentTimeMillis(); - final int i = pane.indexOfTabComponent(TabbedPane.this); - if (i != -1) - pane.remove(i); - } - } - } - - @Override - public void mouseEntered(MouseEvent arg0) { - } - - @Override - public void mouseExited(MouseEvent arg0) { - } - - @Override - public void mousePressed(MouseEvent arg0) { - } - - @Override - public void mouseReleased(MouseEvent e) { - } - }); - - //tab dragging - if(BytecodeViewer.EXPERIMENTAL_TAB_CODE) - { - /*label.addMouseListener(new MouseListener() { - @Override public void mouseClicked(MouseEvent e) {} - @Override public void mouseEntered(MouseEvent arg0) { - } - @Override public void mouseExited(MouseEvent arg0) { - } - @Override public void mousePressed(MouseEvent e) { - onMousePressed(e); - } - @Override public void mouseReleased(MouseEvent e) { - stopDragging(e.getX(), e.getY()); - } - });*/ - - this.addMouseListener(new MouseListener() { - @Override public void mouseClicked(MouseEvent e) {} - @Override public void mouseEntered(MouseEvent arg0) { - } - @Override public void mouseExited(MouseEvent arg0) { - } - @Override public void mousePressed(MouseEvent e) { - onMousePressed(e); - } - @Override public void mouseReleased(MouseEvent e) { - stopDragging(e.getX(), e.getY()); - } - }); - } - - //middle click close - if(BytecodeViewer.EXPERIMENTAL_TAB_CODE) - { - this.addMouseListener(new MouseAdapter() { - @Override - public void mouseReleased(MouseEvent e) { - if (e.getButton() == MouseEvent.BUTTON2) { - final int i = pane.indexOfTabComponent(TabbedPane.this); - if (i != -1) { - pane.remove(i); - } - } - } - }); - } - } - - private void stopDragging(int mouseX, int mouseY) { - if (System.currentTimeMillis() - startedDragging >= 210) { - Rectangle bounds = new Rectangle(1, 1, mouseX, mouseY); - System.out.println("debug-5: " + mouseX + ", " + mouseY); - int totalTabs = BytecodeViewer.viewer.workPane.tabs.getTabCount(); - int index = -1; - for (int i = 0; i < totalTabs; i++) { - Component c = BytecodeViewer.viewer.workPane.tabs.getTabComponentAt(i); - if (c != null && bounds.intersects(c.getBounds())) { - index = i; //replace this tabs position - } - } - - if (index == -1) { - for (int i = 0; i < totalTabs; i++) { - Component c = BytecodeViewer.viewer.workPane.tabs.getTabComponentAt(i); - //do some check to see if it's past the X or Y - if (c != null) { - System.out.println("debug-6: " + c.getBounds()); - } - } - } - - if (index != -1) { - BytecodeViewer.viewer.workPane.tabs.remove(this); - BytecodeViewer.viewer.workPane.tabs.setTabComponentAt(index, this); - } - } - SwingUtilities.invokeLater(() -> - { - label.setBackground(BLANK); - label.updateUI(); - }); - } - - public void onMousePressed(MouseEvent e) - { - BytecodeViewer.viewer.workPane.tabs.dispatchEvent(e); - - if(e.getButton() == 1) - { - startedDragging = System.currentTimeMillis(); - //dragging = true; - if (probablyABadIdea != null) - { - probablyABadIdea.stopped = true; - } - probablyABadIdea = new DelayTabbedPaneThread(TabbedPane.this); - probablyABadIdea.start(); - repaint(); - System.out.println(e.getX()+", "+e.getY()); - Rectangle bounds = new Rectangle(1, 1, e.getX(), e.getY()); - for(int i = 0; i < BytecodeViewer.viewer.workPane.tabs.getTabCount(); i++) - { - Component c = BytecodeViewer.viewer.workPane.tabs.getTabComponentAt(i); - if(c != null && bounds.intersects(c.getBounds())) - { - BytecodeViewer.viewer.workPane.tabs.setSelectedIndex(i); - } - } - } - else - { - stopDragging(e.getX(), e.getY()); - } - } - - private class TabButton extends JButton implements ActionListener { - private static final long serialVersionUID = -4492967978286454159L; - - public TabButton() { - final int size = 17; - setPreferredSize(new Dimension(size, size)); - setToolTipText("Close this tab"); - // Make the button looks the same for all Laf's - setUI(new BasicButtonUI()); - // Make it transparent - setContentAreaFilled(false); - // No need to be focusable - setFocusable(false); - setBorder(BorderFactory.createEtchedBorder()); - setBorderPainted(false); - // Making nice rollover effect - // we use the same listener for all buttons - addMouseListener(buttonMouseListener); - setRolloverEnabled(true); - // Close the proper tab by clicking the button - addActionListener(this); - } - - @Override - public void actionPerformed(final ActionEvent e) { - final int i = pane.indexOfTabComponent(TabbedPane.this); - if (i != -1) { - pane.remove(i); - } - } - - // we don't want to update UI for this button - @Override - public void updateUI() { - } - - // paint the cross - @Override - protected void paintComponent(final Graphics g) { - super.paintComponent(g); - final Graphics2D g2 = (Graphics2D) g.create(); - // shift the image for pressed buttons - if (getModel().isPressed()) { - g2.translate(1, 1); - } - g2.setStroke(new BasicStroke(2)); - g2.setColor(Color.BLACK); - if (getModel().isRollover()) { - g2.setColor(Color.MAGENTA); - } - final int delta = 6; - g2.drawLine(delta, delta, getWidth() - delta - 1, getHeight() - - delta - 1); - g2.drawLine(getWidth() - delta - 1, delta, delta, getHeight() - - delta - 1); - g2.dispose(); - } - } - - private final static MouseListener buttonMouseListener = new MouseAdapter() { - @Override - public void mouseEntered(final MouseEvent e) { - final Component component = e.getComponent(); - if (component instanceof AbstractButton) { - final AbstractButton button = (AbstractButton) component; - button.setBorderPainted(true); - } - } - - @Override - public void mouseExited(final MouseEvent e) { - final Component component = e.getComponent(); - if (component instanceof AbstractButton) { - final AbstractButton button = (AbstractButton) component; - button.setBorderPainted(false); - } - } - }; -} \ No newline at end of file diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/gui/WorkPane.java b/src/main/java/the/bytecode/club/bytecodeviewer/gui/WorkPane.java deleted file mode 100644 index af8955f9..00000000 --- a/src/main/java/the/bytecode/club/bytecodeviewer/gui/WorkPane.java +++ /dev/null @@ -1,294 +0,0 @@ -package the.bytecode.club.bytecodeviewer.gui; - -import java.awt.BorderLayout; -import java.awt.Component; -import java.awt.FlowLayout; -import java.awt.Point; -import java.awt.Rectangle; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; -import java.awt.event.ContainerEvent; -import java.awt.event.ContainerListener; -import java.awt.event.MouseEvent; -import java.awt.event.MouseListener; -import java.util.HashMap; -import javax.swing.JButton; -import javax.swing.JMenuItem; -import javax.swing.JPanel; -import javax.swing.JPopupMenu; -import javax.swing.JTabbedPane; -import org.objectweb.asm.tree.ClassNode; -import the.bytecode.club.bytecodeviewer.BytecodeViewer; -import the.bytecode.club.bytecodeviewer.Configuration; -import the.bytecode.club.bytecodeviewer.util.FileContainer; - -import static the.bytecode.club.bytecodeviewer.Constants.BLOCK_TAB_MENU; - -/*************************************************************************** - * Bytecode Viewer (BCV) - Java & Android Reverse Engineering Suite * - * Copyright (C) 2014 Kalen 'Konloch' Kinloch - http://bytecodeviewer.com * - * * - * This program is free software: you can redistribute it and/or modify * - * it under the terms of the GNU General Public License as published by * - * the Free Software Foundation, either version 3 of the License, or * - * (at your option) any later version. * - * * - * This program is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program. If not, see . * - ***************************************************************************/ - -/** - * The pane that contains all of the classes as tabs. - * - * @author Konloch - * @author WaterWolf - */ - -public class WorkPane extends VisibleComponent implements ActionListener { - - private static final long serialVersionUID = 6542337997679487946L; - - public JTabbedPane tabs; - - JPanel buttonPanel; - public JButton refreshClass; - - HashMap workingOn = new HashMap<>(); - - public WorkPane() { - super("WorkPanel"); - setTitle("Work Space"); - - this.tabs = new JTabbedPane(); - - - JPopupMenu pop_up = new JPopupMenu() { - @Override - public void setVisible(boolean b) { - super.setVisible(b); - } - }; - JMenuItem closealltab = new JMenuItem("Close All But This"); - JMenuItem closetab = new JMenuItem("Close Tab"); - closetab.addActionListener(e -> { - /*String name = e.getActionCommand().split(": ")[1]; - final int i = pane.indexOfTab(name); - if (i != -1) - pane.remove(i);*/ - }); - closealltab.addActionListener(e -> { - String name = e.getActionCommand().split(": ")[1]; - System.out.println("debug-3: " + name); - while (true) { - int thisID = tabs.indexOfTab(name); - if (tabs.getTabCount() <= 1) { - return; - } - if (thisID != 0) - tabs.remove(0); - else - tabs.remove(1); - } - }); - tabs.addMouseListener(new MouseListener() { - @Override - public void mouseClicked(MouseEvent e) { - } - - @Override - public void mouseEntered(MouseEvent arg0) { - } - - @Override - public void mouseExited(MouseEvent arg0) { - } - - @Override - public void mousePressed(MouseEvent e) { - if (e.getButton() == 3) { - if (BLOCK_TAB_MENU) - return; - - Rectangle bounds = new Rectangle(1, 1, e.getX(), e.getY()); - Point point = tabs.getMousePosition(); - System.out.println("debug-1: " + point); - for (int i = 0; i < BytecodeViewer.viewer.workPane.tabs.getTabCount(); i++) { - Component c = BytecodeViewer.viewer.workPane.tabs.getTabComponentAt(i); - if (c != null && bounds.intersects(c.getBounds())) { - pop_up.setVisible(true); - closealltab.setText("Close All But This: " + ((TabbedPane) c).tabName); - closetab.setText("Close Tab: " + ((TabbedPane) c).tabName); - //do something with this shit - //BytecodeViewer.viewer.workPane.tabs.setSelectedIndex(i); - } else { - pop_up.setVisible(false); - } - } - - System.out.println("debug-2: " + e.getX() + ", " + e.getY()); - } - } - - @Override - public void mouseReleased(MouseEvent e) { - } - }); - - pop_up.add(closealltab); - pop_up.add(closetab); - - - if (!BLOCK_TAB_MENU) - tabs.setComponentPopupMenu(pop_up); - - getContentPane().setLayout(new BorderLayout()); - - getContentPane().add(tabs, BorderLayout.CENTER); - - buttonPanel = new JPanel(new FlowLayout()); - - refreshClass = new JButton("Refresh"); - refreshClass.addActionListener(this); - - buttonPanel.add(refreshClass); - - buttonPanel.setVisible(false); - getContentPane().add(buttonPanel, BorderLayout.SOUTH); - - tabs.addContainerListener(new ContainerListener() { - - @Override - public void componentAdded(final ContainerEvent e) { - } - - @Override - public void componentRemoved(final ContainerEvent e) { - final Component c = e.getChild(); - if (c instanceof ClassViewer) { - String containerName = ((ClassViewer) c).container.name + ">"; - String fileName = ((ClassViewer) c).name; - - if (fileName.startsWith(containerName)) { - workingOn.remove(fileName); - } else { - workingOn.remove(containerName + fileName); - } - } - if (c instanceof FileViewer) { - String containerName = ((FileViewer) c).container.name + ">"; - String fileName = ((FileViewer) c).name; - - if (fileName.startsWith(containerName)) { - workingOn.remove(fileName); - } else { - workingOn.remove(containerName + fileName); - } - } - } - - }); - tabs.addChangeListener(arg0 -> buttonPanel.setVisible(tabs.getSelectedIndex() != -1)); - - this.setVisible(true); - - } - - public void addWorkingFile(final FileContainer container, String name, final ClassNode cn) { - String workingName = container.name + ">" + name; - String containerName = name; - - if (Configuration.displayParentInTab) - containerName = container.name + ">" + name; - - if (!workingOn.containsKey(workingName)) { - final ClassViewer tabComp = new ClassViewer(container, containerName, cn); - tabs.add(tabComp); - final int tabCount = tabs.indexOfComponent(tabComp); - workingOn.put(workingName, tabCount); - TabbedPane tabbedPane = new TabbedPane(container.name, name, tabs); - tabComp.tabbedPane = tabbedPane; - tabs.setTabComponentAt(tabCount, tabbedPane); - tabs.setSelectedIndex(tabCount); - } else { - tabs.setSelectedIndex(workingOn.get(workingName)); - } - } - - public void addFile(final FileContainer container, String name, byte[] contents) { - String workingName = container.name + ">" + name; - - if (Configuration.displayParentInTab) - name = container.name + ">" + name; - - if (contents == null) //a directory - return; - - if (!workingOn.containsKey(workingName)) { - final FileViewer tabComp = new FileViewer(container, name, contents); - tabs.add(tabComp); - final int tabCount = tabs.indexOfComponent(tabComp); - workingOn.put(workingName, tabCount); - - TabbedPane tabbedPane = new TabbedPane(null, name, tabs); - tabComp.tabbedPane = tabbedPane; - tabs.setTabComponentAt(tabCount, tabbedPane); - tabs.setSelectedIndex(tabCount); - } else { - try { - tabs.setSelectedIndex(workingOn.get(workingName)); - } catch (Exception e) { - //workingOn.remove(workingName); - e.printStackTrace(); - } - } - } - - public Viewer getCurrentViewer() { - return (Viewer) tabs.getSelectedComponent(); - } - - public java.awt.Component[] getLoadedViewers() { - return tabs.getComponents(); - } - - @Override - public void actionPerformed(final ActionEvent arg0) { - Thread t = new Thread(() -> { - if (BytecodeViewer.viewer.autoCompileOnRefresh.isSelected()) - try { - if (!BytecodeViewer.compile(false)) - return; - } catch (NullPointerException ignored) { - - } - final JButton src = (JButton) arg0.getSource(); - if (src == refreshClass) { - final Component tabComp = tabs.getSelectedComponent(); - if (tabComp != null) { - if (tabComp instanceof ClassViewer) { - src.setEnabled(false); - BytecodeViewer.viewer.updateBusyStatus(true); - ((ClassViewer) tabComp).startPaneUpdater(src); - BytecodeViewer.viewer.updateBusyStatus(false); - } else if (tabComp instanceof FileViewer) { - src.setEnabled(false); - BytecodeViewer.viewer.updateBusyStatus(true); - ((FileViewer) tabComp).refresh(src); - BytecodeViewer.viewer.updateBusyStatus(false); - } - } - } - }); - t.start(); - } - - public void resetWorkspace() { - tabs.removeAll(); - tabs.updateUI(); - } -} diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/gui/extras/AboutWindow.java b/src/main/java/the/bytecode/club/bytecodeviewer/gui/components/AboutWindow.java similarity index 99% rename from src/main/java/the/bytecode/club/bytecodeviewer/gui/extras/AboutWindow.java rename to src/main/java/the/bytecode/club/bytecodeviewer/gui/components/AboutWindow.java index 1d67e4a9..ee9ab5d9 100644 --- a/src/main/java/the/bytecode/club/bytecodeviewer/gui/extras/AboutWindow.java +++ b/src/main/java/the/bytecode/club/bytecodeviewer/gui/components/AboutWindow.java @@ -1,4 +1,4 @@ -package the.bytecode.club.bytecodeviewer.gui.extras; +package the.bytecode.club.bytecodeviewer.gui.components; import java.awt.CardLayout; import java.awt.Color; diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/gui/components/ButtonHoverAnimation.java b/src/main/java/the/bytecode/club/bytecodeviewer/gui/components/ButtonHoverAnimation.java new file mode 100644 index 00000000..da632c02 --- /dev/null +++ b/src/main/java/the/bytecode/club/bytecodeviewer/gui/components/ButtonHoverAnimation.java @@ -0,0 +1,35 @@ +package the.bytecode.club.bytecodeviewer.gui.components; + +import javax.swing.*; +import java.awt.*; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; + +/** + * @author Konloch + * @since 6/25/2021 + */ +public class ButtonHoverAnimation extends MouseAdapter +{ + @Override + public void mouseEntered(final MouseEvent e) + { + final Component component = e.getComponent(); + if (component instanceof AbstractButton) + { + final AbstractButton button = (AbstractButton) component; + button.setBorderPainted(true); + } + } + + @Override + public void mouseExited(final MouseEvent e) + { + final Component component = e.getComponent(); + if (component instanceof AbstractButton) + { + final AbstractButton button = (AbstractButton) component; + button.setBorderPainted(false); + } + } +} diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/gui/DecompilerViewComponent.java b/src/main/java/the/bytecode/club/bytecodeviewer/gui/components/DecompilerViewComponent.java similarity index 95% rename from src/main/java/the/bytecode/club/bytecodeviewer/gui/DecompilerViewComponent.java rename to src/main/java/the/bytecode/club/bytecodeviewer/gui/components/DecompilerViewComponent.java index dd649a0e..8acff12c 100644 --- a/src/main/java/the/bytecode/club/bytecodeviewer/gui/DecompilerViewComponent.java +++ b/src/main/java/the/bytecode/club/bytecodeviewer/gui/components/DecompilerViewComponent.java @@ -1,4 +1,4 @@ -package the.bytecode.club.bytecodeviewer.gui; +package the.bytecode.club.bytecodeviewer.gui.components; import the.bytecode.club.bytecodeviewer.util.RefreshWorkPane; @@ -33,6 +33,7 @@ public class DecompilerViewComponent menu.add(java); if(hasBytecodeOption) menu.add(bytecode); + menu.add(new JSeparator()); menu.add(editable); diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/gui/extras/ExportJar.java b/src/main/java/the/bytecode/club/bytecodeviewer/gui/components/ExportJar.java similarity index 98% rename from src/main/java/the/bytecode/club/bytecodeviewer/gui/extras/ExportJar.java rename to src/main/java/the/bytecode/club/bytecodeviewer/gui/components/ExportJar.java index 8cdf28cc..38004163 100644 --- a/src/main/java/the/bytecode/club/bytecodeviewer/gui/extras/ExportJar.java +++ b/src/main/java/the/bytecode/club/bytecodeviewer/gui/components/ExportJar.java @@ -1,4 +1,4 @@ -package the.bytecode.club.bytecodeviewer.gui.extras; +package the.bytecode.club.bytecodeviewer.gui.components; import java.awt.Dimension; import javax.swing.BoxLayout; diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/gui/components/ImageJLabel.java b/src/main/java/the/bytecode/club/bytecodeviewer/gui/components/ImageJLabel.java new file mode 100644 index 00000000..f318738d --- /dev/null +++ b/src/main/java/the/bytecode/club/bytecodeviewer/gui/components/ImageJLabel.java @@ -0,0 +1,18 @@ +package the.bytecode.club.bytecodeviewer.gui.components; + +import javax.swing.*; +import java.awt.*; + +/** + * Display an image on a JLabel element + * + * @author Konloch + * @since 6/25/2021 + */ +public class ImageJLabel extends JLabel +{ + public ImageJLabel(Image image) + { + super("", new ImageIcon(image), JLabel.CENTER); + } +} diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/gui/components/JFrameConsole.java b/src/main/java/the/bytecode/club/bytecodeviewer/gui/components/JFrameConsole.java new file mode 100644 index 00000000..8907326b --- /dev/null +++ b/src/main/java/the/bytecode/club/bytecodeviewer/gui/components/JFrameConsole.java @@ -0,0 +1,59 @@ +package the.bytecode.club.bytecodeviewer.gui.components; + +import the.bytecode.club.bytecodeviewer.Resources; + +import javax.swing.*; +import java.awt.*; + +/** + * A simple swing JFrame console + * + * @author Konloch + * @since 6/25/2021 + */ +public class JFrameConsole extends JFrame +{ + private final SearchableJTextArea textArea = new SearchableJTextArea(); + + public JFrameConsole(String title) + { + this.setIconImages(Resources.iconList); + setTitle(title); + setSize(new Dimension(542, 316)); + + getContentPane().add(textArea.getScrollPane(), BorderLayout.CENTER); + + this.setLocationRelativeTo(null); + } + + /** + * Appends \r\n to the end of your string, then it puts it on the top. + * + * @param t the string you want to append + */ + public void appendText(String t) + { + setText((textArea.getText().isEmpty() + ? "" + : textArea.getText() + "\r\n" + ) + t); + } + + /** + * Sets the text + * + * @param t the text you want set + */ + public void setText(String t) + { + textArea.setText(t); + textArea.setCaretPosition(0); + } + + public SearchableJTextArea getTextArea() + { + return textArea; + } + + private static final long serialVersionUID = -5056940543411437508L; +} diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/gui/components/JFrameConsolePrintStream.java b/src/main/java/the/bytecode/club/bytecodeviewer/gui/components/JFrameConsolePrintStream.java new file mode 100644 index 00000000..cf17e940 --- /dev/null +++ b/src/main/java/the/bytecode/club/bytecodeviewer/gui/components/JFrameConsolePrintStream.java @@ -0,0 +1,62 @@ +package the.bytecode.club.bytecodeviewer.gui.components; + +import java.io.PrintStream; + +import static the.bytecode.club.bytecodeviewer.Constants.nl; + +/** + * A swing console that can print out from PrintStreams + * + * @author Konloch + * @since 6/25/2021 + */ +public class JFrameConsolePrintStream extends JFrameConsole +{ + private final PrintStream originalOut; + private final PrintStream newPrintStream; + private final JTextAreaOutputStream s; + + public JFrameConsolePrintStream(String title, PrintStream originalOut) + { + super(title); + + this.originalOut = originalOut; + + s = new JTextAreaOutputStream(getTextArea()); + newPrintStream = new PrintStream(s); + } + + public void finished() + { + if (originalOut != null) + System.setErr(originalOut); + } + + public PrintStream getNewPrintStream() + { + return newPrintStream; + } + + public void pretty() + { + s.update(); + String[] test; + if (getTextArea().getText().split("\n").length >= 2) + test = getTextArea().getText().split("\n"); + else + test = getTextArea().getText().split("\r"); + + StringBuilder replace = new StringBuilder(); + for (String s : test) + { + if (s.startsWith("File '")) + { + String[] split = s.split("'"); + String start = split[0] + "'" + split[1] + "', "; + s = s.substring(start.length()); + } + replace.append(s).append(nl); + } + setText(replace.toString()); + } +} diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/gui/extras/JTextAreaOutputStream.java b/src/main/java/the/bytecode/club/bytecodeviewer/gui/components/JTextAreaOutputStream.java similarity index 90% rename from src/main/java/the/bytecode/club/bytecodeviewer/gui/extras/JTextAreaOutputStream.java rename to src/main/java/the/bytecode/club/bytecodeviewer/gui/components/JTextAreaOutputStream.java index b9575d13..efb5a506 100644 --- a/src/main/java/the/bytecode/club/bytecodeviewer/gui/extras/JTextAreaOutputStream.java +++ b/src/main/java/the/bytecode/club/bytecodeviewer/gui/components/JTextAreaOutputStream.java @@ -1,4 +1,4 @@ -package the.bytecode.club.bytecodeviewer.gui.extras; +package the.bytecode.club.bytecodeviewer.gui.components; import javax.swing.*; import java.io.IOException; diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/gui/components/MaxWidthJLabel.java b/src/main/java/the/bytecode/club/bytecodeviewer/gui/components/MaxWidthJLabel.java new file mode 100644 index 00000000..1d440643 --- /dev/null +++ b/src/main/java/the/bytecode/club/bytecodeviewer/gui/components/MaxWidthJLabel.java @@ -0,0 +1,33 @@ +package the.bytecode.club.bytecodeviewer.gui.components; + +import javax.swing.*; +import java.awt.*; + +/** + * @author Konloch + * @since 6/25/2021 + */ +public class MaxWidthJLabel extends JLabel +{ + private final int width; + private final int height; + + public MaxWidthJLabel(String title, int width, int height) + { + super(title); + this.width = width; + this.height = height; + } + + @Override + public Dimension getPreferredSize() + { + Dimension realDimension = super.getPreferredSize(); + if (realDimension.getWidth() >= width) + return new Dimension(width, height); + else + return realDimension; + } + + private static final long serialVersionUID = -5511025206527893360L; +} diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/gui/components/MethodsRenderer.java b/src/main/java/the/bytecode/club/bytecodeviewer/gui/components/MethodsRenderer.java new file mode 100644 index 00000000..a2720a29 --- /dev/null +++ b/src/main/java/the/bytecode/club/bytecodeviewer/gui/components/MethodsRenderer.java @@ -0,0 +1,33 @@ +package the.bytecode.club.bytecodeviewer.gui.components; + +import the.bytecode.club.bytecodeviewer.gui.util.PaneUpdaterThread; +import the.bytecode.club.bytecodeviewer.util.MethodParser; + +import javax.swing.*; +import java.awt.*; + +/** + * @author Konloch + * @author Waterwolf + * @since 6/24/2021 + */ +public class MethodsRenderer extends JLabel implements ListCellRenderer +{ + private final PaneUpdaterThread paneUpdaterThread; + + public MethodsRenderer(PaneUpdaterThread paneUpdaterThread) + { + this.paneUpdaterThread = paneUpdaterThread; + setOpaque(true); + } + + @Override + public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, + boolean cellHasFocus) + { + MethodParser methods = paneUpdaterThread.viewer.methods.get(paneUpdaterThread.decompilerViewIndex); + MethodParser.Method method = methods.getMethod((Integer) value); + setText(method.toString()); + return this; + } +} diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/gui/extras/RunOptions.java b/src/main/java/the/bytecode/club/bytecodeviewer/gui/components/RunOptions.java similarity index 99% rename from src/main/java/the/bytecode/club/bytecodeviewer/gui/extras/RunOptions.java rename to src/main/java/the/bytecode/club/bytecodeviewer/gui/components/RunOptions.java index 9600428f..ce203c00 100644 --- a/src/main/java/the/bytecode/club/bytecodeviewer/gui/extras/RunOptions.java +++ b/src/main/java/the/bytecode/club/bytecodeviewer/gui/components/RunOptions.java @@ -1,4 +1,4 @@ -package the.bytecode.club.bytecodeviewer.gui.extras; +package the.bytecode.club.bytecodeviewer.gui.components; import java.awt.Dimension; import javax.swing.JButton; diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/gui/components/SearchableJTextArea.java b/src/main/java/the/bytecode/club/bytecodeviewer/gui/components/SearchableJTextArea.java new file mode 100644 index 00000000..20f02f19 --- /dev/null +++ b/src/main/java/the/bytecode/club/bytecodeviewer/gui/components/SearchableJTextArea.java @@ -0,0 +1,92 @@ +package the.bytecode.club.bytecodeviewer.gui.components; + +import the.bytecode.club.bytecodeviewer.BytecodeViewer; +import the.bytecode.club.bytecodeviewer.Resources; +import the.bytecode.club.bytecodeviewer.gui.components.listeners.PressKeyListener; +import the.bytecode.club.bytecodeviewer.gui.components.listeners.ReleaseKeyListener; +import the.bytecode.club.bytecodeviewer.util.JTextAreaUtils; + +import javax.swing.*; +import java.awt.*; +import java.awt.event.KeyEvent; + +/** + * Searching on a JTextArea using swing highlighting + * + * @author Konloch + * @since 6/25/2021 + */ +public class SearchableJTextArea extends JTextArea +{ + private final JScrollPane scrollPane = new JScrollPane(); + private final JPanel searchPanel = new JPanel(new BorderLayout()); + private final JTextField searchInput = new JTextField(); + private final JCheckBox caseSensitiveSearch = new JCheckBox("Exact"); + + public SearchableJTextArea() + { + scrollPane.setViewportView(this); + scrollPane.setColumnHeaderView(searchPanel); + + JButton searchNext = new JButton(); + searchNext.setIcon(Resources.nextIcon); + + JButton searchPrev = new JButton(); + searchPrev.setIcon(Resources.prevIcon); + + JPanel buttonPane = new JPanel(new BorderLayout()); + buttonPane.add(searchNext, BorderLayout.WEST); + buttonPane.add(searchPrev, BorderLayout.EAST); + + searchPanel.add(buttonPane, BorderLayout.WEST); + searchPanel.add(searchInput, BorderLayout.CENTER); + searchPanel.add(caseSensitiveSearch, BorderLayout.EAST); + + searchNext.addActionListener(arg0 -> search(searchInput.getText(), true, caseSensitiveSearch.isSelected())); + searchPrev.addActionListener(arg0 -> search(searchInput.getText(), false, caseSensitiveSearch.isSelected())); + + searchInput.addKeyListener(new ReleaseKeyListener(keyEvent -> + { + if (keyEvent.getKeyCode() == KeyEvent.VK_ENTER) + search(searchInput.getText(), true, caseSensitiveSearch.isSelected()); + })); + + addKeyListener(new PressKeyListener(keyEvent -> + { + if ((keyEvent.getKeyCode() == KeyEvent.VK_F) && ((keyEvent.getModifiers() & KeyEvent.CTRL_MASK) != 0)) + searchInput.requestFocus(); + + BytecodeViewer.checkHotKey(keyEvent); + })); + } + + public void search(String search, boolean forwardSearchDirection, boolean caseSensitiveSearch) + { + JTextAreaUtils.search(this, search, forwardSearchDirection, caseSensitiveSearch); + } + + public void highlight(String pattern, boolean caseSensitiveSearch) + { + JTextAreaUtils.highlight(this, pattern, caseSensitiveSearch); + } + + public JScrollPane getScrollPane() + { + return scrollPane; + } + + public JPanel getSearchPanel() + { + return searchPanel; + } + + public JTextField getSearchInput() + { + return searchInput; + } + + public JCheckBox getCaseSensitiveSearch() + { + return caseSensitiveSearch; + } +} diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/gui/components/SearchableRSyntaxTextArea.java b/src/main/java/the/bytecode/club/bytecodeviewer/gui/components/SearchableRSyntaxTextArea.java new file mode 100644 index 00000000..d39e9217 --- /dev/null +++ b/src/main/java/the/bytecode/club/bytecodeviewer/gui/components/SearchableRSyntaxTextArea.java @@ -0,0 +1,93 @@ +package the.bytecode.club.bytecodeviewer.gui.components; + +import org.fife.ui.rsyntaxtextarea.RSyntaxTextArea; +import org.fife.ui.rtextarea.RTextScrollPane; +import the.bytecode.club.bytecodeviewer.BytecodeViewer; +import the.bytecode.club.bytecodeviewer.Resources; +import the.bytecode.club.bytecodeviewer.gui.components.listeners.PressKeyListener; +import the.bytecode.club.bytecodeviewer.gui.components.listeners.ReleaseKeyListener; +import the.bytecode.club.bytecodeviewer.util.JTextAreaUtils; + +import javax.swing.*; +import java.awt.*; +import java.awt.event.KeyEvent; + +/** + * Searching on an RSyntaxTextArea using swing highlighting + * + * @author Konloch + * @since 6/25/2021 + */ +public class SearchableRSyntaxTextArea extends RSyntaxTextArea +{ + private final RTextScrollPane scrollPane = new RTextScrollPane(this); + private final JPanel searchPanel = new JPanel(new BorderLayout()); + private final JTextField searchInput = new JTextField(); + private final JCheckBox caseSensitiveSearch = new JCheckBox("Exact"); + + public SearchableRSyntaxTextArea() + { + setAntiAliasingEnabled(true); + + scrollPane.setColumnHeaderView(searchPanel); + + JButton searchNext = new JButton(); + JButton searchPrev = new JButton(); + JPanel buttonPane = new JPanel(new BorderLayout()); + buttonPane.add(searchNext, BorderLayout.WEST); + buttonPane.add(searchPrev, BorderLayout.EAST); + searchNext.setIcon(Resources.nextIcon); + searchPrev.setIcon(Resources.prevIcon); + searchPanel.add(buttonPane, BorderLayout.WEST); + searchPanel.add(searchInput, BorderLayout.CENTER); + searchPanel.add(caseSensitiveSearch, BorderLayout.EAST); + + searchNext.addActionListener(arg0 -> search(searchInput.getText(), true, caseSensitiveSearch.isSelected())); + searchPrev.addActionListener(arg0 -> search(searchInput.getText(), false, caseSensitiveSearch.isSelected())); + + searchInput.addKeyListener(new ReleaseKeyListener(keyEvent -> + { + System.out.println("DEBUG: " + keyEvent.getKeyChar()); + if (keyEvent.getKeyCode() == KeyEvent.VK_ENTER) + search(searchInput.getText(), true, caseSensitiveSearch.isSelected()); + })); + + addKeyListener(new PressKeyListener(keyEvent -> + { + if ((keyEvent.getKeyCode() == KeyEvent.VK_F) && ((keyEvent.getModifiers() & KeyEvent.CTRL_MASK) != 0)) + searchInput.requestFocus(); + + BytecodeViewer.checkHotKey(keyEvent); + })); + } + + public void search(String search, boolean forwardSearchDirection, boolean caseSensitiveSearch) + { + JTextAreaUtils.search(this, search, forwardSearchDirection, caseSensitiveSearch); + } + + public void highlight(String pattern, boolean caseSensitiveSearch) + { + JTextAreaUtils.highlight(this, pattern, caseSensitiveSearch); + } + + public RTextScrollPane getScrollPane() + { + return scrollPane; + } + + public JPanel getSearchPanel() + { + return searchPanel; + } + + public JTextField getSearchInput() + { + return searchInput; + } + + public JCheckBox getCaseSensitiveSearch() + { + return caseSensitiveSearch; + } +} diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/gui/components/SystemErrConsole.java b/src/main/java/the/bytecode/club/bytecodeviewer/gui/components/SystemErrConsole.java new file mode 100644 index 00000000..9bbcb6fb --- /dev/null +++ b/src/main/java/the/bytecode/club/bytecodeviewer/gui/components/SystemErrConsole.java @@ -0,0 +1,57 @@ +package the.bytecode.club.bytecodeviewer.gui.components; + +import java.awt.BorderLayout; +import java.awt.Color; +import java.awt.Dimension; +import java.awt.event.KeyEvent; +import java.awt.event.KeyListener; +import java.io.PrintStream; +import javax.swing.JButton; +import javax.swing.JCheckBox; +import javax.swing.JFrame; +import javax.swing.JPanel; +import javax.swing.JScrollPane; +import javax.swing.JTextArea; +import javax.swing.JTextField; +import javax.swing.text.DefaultHighlighter; +import javax.swing.text.Highlighter; +import javax.swing.text.JTextComponent; +import the.bytecode.club.bytecodeviewer.BytecodeViewer; +import the.bytecode.club.bytecodeviewer.Resources; + +import static the.bytecode.club.bytecodeviewer.Constants.*; + +/*************************************************************************** + * Bytecode Viewer (BCV) - Java & Android Reverse Engineering Suite * + * Copyright (C) 2014 Kalen 'Konloch' Kinloch - http://bytecodeviewer.com * + * * + * This program is free software: you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation, either version 3 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program. If not, see . * + ***************************************************************************/ + +/** + * A simple console GUI. + * + * @author Konloch + */ + +public class SystemErrConsole extends JFrameConsolePrintStream +{ + public SystemErrConsole(String title) + { + super(title, System.err); + System.setErr(getNewPrintStream()); + } + + private static final long serialVersionUID = -6556940545421437508L; +} diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/gui/components/SystemOutConsole.java b/src/main/java/the/bytecode/club/bytecodeviewer/gui/components/SystemOutConsole.java new file mode 100644 index 00000000..06469b65 --- /dev/null +++ b/src/main/java/the/bytecode/club/bytecodeviewer/gui/components/SystemOutConsole.java @@ -0,0 +1,36 @@ +package the.bytecode.club.bytecodeviewer.gui.components; + +/*************************************************************************** + * Bytecode Viewer (BCV) - Java & Android Reverse Engineering Suite * + * Copyright (C) 2014 Kalen 'Konloch' Kinloch - http://bytecodeviewer.com * + * * + * This program is free software: you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation, either version 3 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program. If not, see . * + ***************************************************************************/ + +/** + * A simple console GUI. + * + * @author Konloch + */ + +public class SystemOutConsole extends JFrameConsolePrintStream +{ + public SystemOutConsole(String title) + { + super(title, System.out); + System.setOut(getNewPrintStream()); + } + + private static final long serialVersionUID = -6666940545499937508L; +} diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/gui/VisibleComponent.java b/src/main/java/the/bytecode/club/bytecodeviewer/gui/components/VisibleComponent.java similarity index 96% rename from src/main/java/the/bytecode/club/bytecodeviewer/gui/VisibleComponent.java rename to src/main/java/the/bytecode/club/bytecodeviewer/gui/components/VisibleComponent.java index bf59ff97..127e9286 100644 --- a/src/main/java/the/bytecode/club/bytecodeviewer/gui/VisibleComponent.java +++ b/src/main/java/the/bytecode/club/bytecodeviewer/gui/components/VisibleComponent.java @@ -1,4 +1,4 @@ -package the.bytecode.club.bytecodeviewer.gui; +package the.bytecode.club.bytecodeviewer.gui.components; import javax.swing.JInternalFrame; import org.objectweb.asm.tree.ClassNode; diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/gui/components/listeners/MouseClickedListener.java b/src/main/java/the/bytecode/club/bytecodeviewer/gui/components/listeners/MouseClickedListener.java new file mode 100644 index 00000000..498cfd75 --- /dev/null +++ b/src/main/java/the/bytecode/club/bytecodeviewer/gui/components/listeners/MouseClickedListener.java @@ -0,0 +1,36 @@ +package the.bytecode.club.bytecodeviewer.gui.components.listeners; + +import java.awt.event.*; + +/** + * @author Konloch + * @since 6/25/2021 + */ +public class MouseClickedListener implements MouseListener +{ + private final MouseClickedEvent mouseClickedEvent; + + public MouseClickedListener(MouseClickedEvent mouseClickedEvent) {this.mouseClickedEvent = mouseClickedEvent;} + + @Override + public void mouseClicked(MouseEvent e) { + mouseClickedEvent.mouseClicked(e); + } + + @Override + public void mouseEntered(MouseEvent arg0) { } + + @Override + public void mouseExited(MouseEvent arg0) { } + + @Override + public void mousePressed(MouseEvent arg0) { } + + @Override + public void mouseReleased(MouseEvent e) { } + + public interface MouseClickedEvent + { + void mouseClicked(MouseEvent e); + } +} diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/gui/components/listeners/PressKeyListener.java b/src/main/java/the/bytecode/club/bytecodeviewer/gui/components/listeners/PressKeyListener.java new file mode 100644 index 00000000..b65897bf --- /dev/null +++ b/src/main/java/the/bytecode/club/bytecodeviewer/gui/components/listeners/PressKeyListener.java @@ -0,0 +1,32 @@ +package the.bytecode.club.bytecodeviewer.gui.components.listeners; + +import java.awt.event.KeyEvent; +import java.awt.event.KeyListener; + +/** + * @author Konloch + * @since 6/25/2021 + */ +public class PressKeyListener implements KeyListener +{ + private final KeyPressedEvent keyPressedEvent; + + public PressKeyListener(KeyPressedEvent keyPressedEvent) {this.keyPressedEvent = keyPressedEvent;} + + @Override + public void keyTyped(KeyEvent e) { } + + @Override + public void keyPressed(KeyEvent e) + { + keyPressedEvent.keyReleased(e); + } + + @Override + public void keyReleased(KeyEvent e) {} + + public interface KeyPressedEvent + { + void keyReleased(KeyEvent e); + } +} diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/gui/components/listeners/ReleaseKeyListener.java b/src/main/java/the/bytecode/club/bytecodeviewer/gui/components/listeners/ReleaseKeyListener.java new file mode 100644 index 00000000..b110f22a --- /dev/null +++ b/src/main/java/the/bytecode/club/bytecodeviewer/gui/components/listeners/ReleaseKeyListener.java @@ -0,0 +1,32 @@ +package the.bytecode.club.bytecodeviewer.gui.components.listeners; + +import java.awt.event.KeyEvent; +import java.awt.event.KeyListener; + +/** + * @author Konloch + * @since 6/25/2021 + */ +public class ReleaseKeyListener implements KeyListener +{ + private final KeyReleasedEvent keyReleasedEvent; + + public ReleaseKeyListener(KeyReleasedEvent keyReleasedEvent) {this.keyReleasedEvent = keyReleasedEvent;} + + @Override + public void keyTyped(KeyEvent e) { } + + @Override + public void keyPressed(KeyEvent e) { } + + @Override + public void keyReleased(KeyEvent e) + { + keyReleasedEvent.keyReleased(e); + } + + public interface KeyReleasedEvent + { + void keyReleased(KeyEvent e); + } +} diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/gui/extras/SystemErrConsole.java b/src/main/java/the/bytecode/club/bytecodeviewer/gui/extras/SystemErrConsole.java deleted file mode 100644 index 744cee0a..00000000 --- a/src/main/java/the/bytecode/club/bytecodeviewer/gui/extras/SystemErrConsole.java +++ /dev/null @@ -1,298 +0,0 @@ -package the.bytecode.club.bytecodeviewer.gui.extras; - -import java.awt.BorderLayout; -import java.awt.Color; -import java.awt.Dimension; -import java.awt.event.KeyEvent; -import java.awt.event.KeyListener; -import java.io.PrintStream; -import javax.swing.JButton; -import javax.swing.JCheckBox; -import javax.swing.JFrame; -import javax.swing.JPanel; -import javax.swing.JScrollPane; -import javax.swing.JTextArea; -import javax.swing.JTextField; -import javax.swing.text.DefaultHighlighter; -import javax.swing.text.Highlighter; -import javax.swing.text.JTextComponent; -import the.bytecode.club.bytecodeviewer.BytecodeViewer; -import the.bytecode.club.bytecodeviewer.Resources; - -import static the.bytecode.club.bytecodeviewer.Constants.*; - -/*************************************************************************** - * Bytecode Viewer (BCV) - Java & Android Reverse Engineering Suite * - * Copyright (C) 2014 Kalen 'Konloch' Kinloch - http://bytecodeviewer.com * - * * - * This program is free software: you can redistribute it and/or modify * - * it under the terms of the GNU General Public License as published by * - * the Free Software Foundation, either version 3 of the License, or * - * (at your option) any later version. * - * * - * This program is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program. If not, see . * - ***************************************************************************/ - -/** - * A simple console GUI. - * - * @author Konloch - */ - -public class SystemErrConsole extends JFrame -{ - private final JTextArea textArea = new JTextArea(); - private final JPanel panel = new JPanel(new BorderLayout()); - private final JScrollPane scrollPane = new JScrollPane(); - private final JCheckBox check = new JCheckBox("Exact"); - private final JTextField field = new JTextField(); - private final PrintStream originalOut; - private final JTextAreaOutputStream s; - - public SystemErrConsole(String title) - { - this.setIconImages(Resources.iconList); - setTitle(title); - setSize(new Dimension(542, 316)); - - getContentPane().add(scrollPane, BorderLayout.CENTER); - - scrollPane.setViewportView(textArea); - textArea.addKeyListener(new KeyListener() - { - @Override - public void keyPressed(KeyEvent e) { - if ((e.getKeyCode() == KeyEvent.VK_F) && ((e.getModifiers() & KeyEvent.CTRL_MASK) != 0)) { - field.requestFocus(); - } - - BytecodeViewer.checkHotKey(e); - } - - @Override - public void keyReleased(KeyEvent arg0) { - } - - @Override - public void keyTyped(KeyEvent arg0) { - } - }); - - JButton searchNext = new JButton(); - JButton searchPrev = new JButton(); - JPanel buttonPane = new JPanel(new BorderLayout()); - buttonPane.add(searchNext, BorderLayout.WEST); - buttonPane.add(searchPrev, BorderLayout.EAST); - searchNext.setIcon(Resources.nextIcon); - searchPrev.setIcon(Resources.prevIcon); - panel.add(buttonPane, BorderLayout.WEST); - panel.add(field, BorderLayout.CENTER); - panel.add(check, BorderLayout.EAST); - searchNext.addActionListener(arg0 -> search(field.getText(), true)); - - searchPrev.addActionListener(arg0 -> search(field.getText(), false)); - field.addKeyListener(new KeyListener() { - @Override - public void keyReleased(KeyEvent arg0) { - if (arg0.getKeyCode() == KeyEvent.VK_ENTER) - search(field.getText(), true); - } - - @Override - public void keyPressed(KeyEvent arg0) { - } - - @Override - public void keyTyped(KeyEvent arg0) { - } - }); - scrollPane.setColumnHeaderView(panel); - this.setLocationRelativeTo(null); - s = new JTextAreaOutputStream(textArea); - PrintStream printStream = new PrintStream(s); - originalOut = System.err; - System.setErr(printStream); - } - - public void finished() { - if (originalOut != null) - System.setErr(originalOut); - } - - public void pretty() { - s.update(); - String[] test; - if (textArea.getText().split("\n").length >= 2) - test = textArea.getText().split("\n"); - else - test = textArea.getText().split("\r"); - - StringBuilder replace = new StringBuilder(); - for (String s : test) { - if (s.startsWith("File '")) { - String[] split = s.split("'"); - String start = split[0] + "'" + split[1] + "', "; - s = s.substring(start.length()); - } - replace.append(s).append(nl); - } - setText(replace.toString()); - } - - /** - * This was really interesting to write. - * - * @author Konloch - */ - public void search(String search, boolean next) { - try { - JTextArea area = textArea; - if (search.isEmpty()) { - highlight(area, ""); - return; - } - - int startLine = area.getDocument().getDefaultRootElement() - .getElementIndex(area.getCaretPosition()) + 1; - int currentLine = 1; - boolean canSearch = false; - String[] test; - if (area.getText().split("\n").length >= 2) - test = area.getText().split("\n"); - else - test = area.getText().split("\r"); - int lastGoodLine = -1; - int firstPos = -1; - boolean found = false; - - if (next) { - for (String s : test) { - if (!check.isSelected()) { - s = s.toLowerCase(); - search = search.toLowerCase(); - } - - if (currentLine == startLine) { - canSearch = true; - } else if (s.contains(search)) { - if (canSearch) { - area.setCaretPosition(area.getDocument() - .getDefaultRootElement() - .getElement(currentLine - 1) - .getStartOffset()); - canSearch = false; - found = true; - } - - if (firstPos == -1) - firstPos = currentLine; - } - - currentLine++; - } - - if (!found && firstPos != -1) { - area.setCaretPosition(area.getDocument() - .getDefaultRootElement().getElement(firstPos - 1) - .getStartOffset()); - } - } else { - canSearch = true; - for (String s : test) { - if (!check.isSelected()) { - s = s.toLowerCase(); - search = search.toLowerCase(); - } - - if (s.contains(search)) { - if (lastGoodLine != -1 && canSearch) - area.setCaretPosition(area.getDocument() - .getDefaultRootElement() - .getElement(lastGoodLine - 1) - .getStartOffset()); - - lastGoodLine = currentLine; - - if (currentLine >= startLine) - canSearch = false; - } - currentLine++; - } - - if (lastGoodLine != -1 - && area.getDocument().getDefaultRootElement() - .getElementIndex(area.getCaretPosition()) + 1 == startLine) { - area.setCaretPosition(area.getDocument() - .getDefaultRootElement() - .getElement(lastGoodLine - 1).getStartOffset()); - } - } - highlight(area, search); - } catch (Exception e) { - new the.bytecode.club.bytecodeviewer.api.ExceptionUI(e); - } - } - - private final DefaultHighlighter.DefaultHighlightPainter painter = new DefaultHighlighter.DefaultHighlightPainter( - new Color(255, 62, 150)); - - public void highlight(JTextComponent textComp, String pattern) { - if (pattern.isEmpty()) { - textComp.getHighlighter().removeAllHighlights(); - return; - } - - try { - Highlighter hilite = textComp.getHighlighter(); - hilite.removeAllHighlights(); - javax.swing.text.Document doc = textComp.getDocument(); - String text = doc.getText(0, doc.getLength()); - int pos = 0; - - if (!check.isSelected()) { - pattern = pattern.toLowerCase(); - text = text.toLowerCase(); - } - - // Search for pattern - while ((pos = text.indexOf(pattern, pos)) >= 0) { - // Create highlighter using private painter and apply around - // pattern - hilite.addHighlight(pos, pos + pattern.length(), painter); - pos += pattern.length(); - } - } catch (Exception e) { - new the.bytecode.club.bytecodeviewer.api.ExceptionUI(e); - } - } - - /** - * Appends \r\n to the end of your string, then it puts it on the top. - * - * @param t the string you want to append - */ - public void appendText(String t) { - textArea.setText((textArea.getText().isEmpty() ? "" : textArea - .getText() + "\r\n") - + t); - textArea.setCaretPosition(0); - } - - /** - * Sets the text - * - * @param t the text you want set - */ - public void setText(String t) { - textArea.setText(t); - textArea.setCaretPosition(0); - } - - private static final long serialVersionUID = -6556940545421437508L; -} diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/gui/resourcelist/ResourceListPane.java b/src/main/java/the/bytecode/club/bytecodeviewer/gui/resourcelist/ResourceListPane.java index b4f41128..0d4c9389 100644 --- a/src/main/java/the/bytecode/club/bytecodeviewer/gui/resourcelist/ResourceListPane.java +++ b/src/main/java/the/bytecode/club/bytecodeviewer/gui/resourcelist/ResourceListPane.java @@ -29,7 +29,7 @@ import javax.swing.tree.TreeNode; import javax.swing.tree.TreePath; import org.objectweb.asm.tree.ClassNode; import the.bytecode.club.bytecodeviewer.BytecodeViewer; -import the.bytecode.club.bytecodeviewer.gui.VisibleComponent; +import the.bytecode.club.bytecodeviewer.gui.components.VisibleComponent; import the.bytecode.club.bytecodeviewer.util.FileContainer; import the.bytecode.club.bytecodeviewer.util.FileDrop; import the.bytecode.club.bytecodeviewer.util.LazyNameUtil; diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/gui/resourcelist/ResourceTree.java b/src/main/java/the/bytecode/club/bytecodeviewer/gui/resourcelist/ResourceTree.java index 49fb4a80..e9390f41 100644 --- a/src/main/java/the/bytecode/club/bytecodeviewer/gui/resourcelist/ResourceTree.java +++ b/src/main/java/the/bytecode/club/bytecodeviewer/gui/resourcelist/ResourceTree.java @@ -1,6 +1,6 @@ package the.bytecode.club.bytecodeviewer.gui.resourcelist; -import the.bytecode.club.bytecodeviewer.gui.extras.StringMetricsUtil; +import the.bytecode.club.bytecodeviewer.gui.util.StringMetricsUtil; import javax.swing.*; import javax.swing.tree.DefaultMutableTreeNode; diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/gui/resourcesearch/PerformSearch.java b/src/main/java/the/bytecode/club/bytecodeviewer/gui/resourcesearch/PerformSearch.java new file mode 100644 index 00000000..1c9a9a60 --- /dev/null +++ b/src/main/java/the/bytecode/club/bytecodeviewer/gui/resourcesearch/PerformSearch.java @@ -0,0 +1,54 @@ +package the.bytecode.club.bytecodeviewer.gui.resourcesearch; + +import org.objectweb.asm.tree.ClassNode; +import the.bytecode.club.bytecodeviewer.BytecodeViewer; +import the.bytecode.club.bytecodeviewer.gui.MainViewerGUI; +import the.bytecode.club.bytecodeviewer.searching.BackgroundSearchThread; +import the.bytecode.club.bytecodeviewer.searching.RegexInsnFinder; +import the.bytecode.club.bytecodeviewer.searching.RegexSearch; +import the.bytecode.club.bytecodeviewer.searching.SearchResultNotifier; +import the.bytecode.club.bytecodeviewer.util.FileContainer; + +import javax.swing.tree.TreePath; +import java.util.Objects; +import java.util.regex.Pattern; +import java.util.regex.PatternSyntaxException; + +/** + * @author Konloch + * @since 6/25/2021 + */ +class PerformSearch extends BackgroundSearchThread +{ + private final SearchBoxPane searchBoxPane; + private final SearchResultNotifier srn; + + public PerformSearch(SearchBoxPane searchBoxPane, SearchResultNotifier srn) + { + this.searchBoxPane = searchBoxPane; + this.srn = srn; + } + + @Override + public void doSearch() + { + try + { + Pattern.compile(RegexInsnFinder.processRegex(RegexSearch.searchText.getText()), Pattern.MULTILINE); + } + catch (PatternSyntaxException ex) + { + BytecodeViewer.showMessage("You have an error in your regex syntax."); + } + + for (FileContainer container : BytecodeViewer.files) + for (ClassNode c : container.classes) + searchBoxPane.searchType.details.search(container, c, srn, searchBoxPane.exact.isSelected()); + + Objects.requireNonNull(MainViewerGUI.getComponent(SearchBoxPane.class)).search.setEnabled(true); + Objects.requireNonNull(MainViewerGUI.getComponent(SearchBoxPane.class)).search.setText("Search"); + + searchBoxPane.tree.expandPath(new TreePath(searchBoxPane.tree.getModel().getRoot())); + searchBoxPane.tree.updateUI(); + } +} diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/gui/SearchBoxPane.java b/src/main/java/the/bytecode/club/bytecodeviewer/gui/resourcesearch/SearchBoxPane.java similarity index 74% rename from src/main/java/the/bytecode/club/bytecodeviewer/gui/SearchBoxPane.java rename to src/main/java/the/bytecode/club/bytecodeviewer/gui/resourcesearch/SearchBoxPane.java index 62a33cb9..7b75ab0c 100644 --- a/src/main/java/the/bytecode/club/bytecodeviewer/gui/SearchBoxPane.java +++ b/src/main/java/the/bytecode/club/bytecodeviewer/gui/resourcesearch/SearchBoxPane.java @@ -1,11 +1,9 @@ -package the.bytecode.club.bytecodeviewer.gui; +package the.bytecode.club.bytecodeviewer.gui.resourcesearch; import java.awt.BorderLayout; import java.awt.GridLayout; import java.awt.event.ItemListener; import java.util.Objects; -import java.util.regex.Pattern; -import java.util.regex.PatternSyntaxException; import javax.swing.DefaultComboBoxModel; import javax.swing.JButton; import javax.swing.JCheckBox; @@ -15,18 +13,15 @@ import javax.swing.JPanel; import javax.swing.JScrollPane; import javax.swing.JTree; import javax.swing.tree.DefaultMutableTreeNode; -import javax.swing.tree.TreePath; + import org.objectweb.asm.tree.ClassNode; import the.bytecode.club.bytecodeviewer.BytecodeViewer; -import the.bytecode.club.bytecodeviewer.gui.resourcelist.ResourceListPane; +import the.bytecode.club.bytecodeviewer.gui.MainViewerGUI; +import the.bytecode.club.bytecodeviewer.gui.resourceviewer.WorkPaneMainComponent; +import the.bytecode.club.bytecodeviewer.gui.components.VisibleComponent; +import the.bytecode.club.bytecodeviewer.gui.resourceviewer.viewer.ResourceViewer; import the.bytecode.club.bytecodeviewer.searching.BackgroundSearchThread; -import the.bytecode.club.bytecodeviewer.searching.FieldCallSearch; -import the.bytecode.club.bytecodeviewer.searching.LDCSearch; -import the.bytecode.club.bytecodeviewer.searching.MethodCallSearch; -import the.bytecode.club.bytecodeviewer.searching.RegexInsnFinder; -import the.bytecode.club.bytecodeviewer.searching.RegexSearch; import the.bytecode.club.bytecodeviewer.searching.SearchResultNotifier; -import the.bytecode.club.bytecodeviewer.searching.SearchTypeDetails; import the.bytecode.club.bytecodeviewer.util.FileContainer; /*************************************************************************** @@ -55,8 +50,8 @@ import the.bytecode.club.bytecodeviewer.util.FileContainer; */ @SuppressWarnings("rawtypes") -public class SearchBoxPane extends VisibleComponent { - +public class SearchBoxPane extends VisibleComponent +{ private static final long serialVersionUID = -1098524689236993932L; public static final SearchRadius[] SEARCH_RADII = SearchRadius.values(); public static final SearchType[] SEARCH_TYPES = SearchType.values(); @@ -170,30 +165,7 @@ public class SearchBoxPane extends VisibleComponent { final SearchResultNotifier srn = debug -> treeRoot.add(new DefaultMutableTreeNode(debug)); if (radius == SearchRadius.All_Classes) { if (t.finished) { - t = new BackgroundSearchThread() { - @Override - public void doSearch() { - - try { - Pattern.compile(RegexInsnFinder.processRegex(RegexSearch.searchText.getText()), Pattern.MULTILINE); - } catch (PatternSyntaxException ex) { - BytecodeViewer.showMessage("You have an error in your regex syntax."); - } - - for (FileContainer container : BytecodeViewer.files) - for (ClassNode c : container.classes) - searchType.details.search(container, c, srn, exact.isSelected()); - - Objects.requireNonNull(MainViewerGUI.getComponent(SearchBoxPane.class)) - .search.setEnabled(true); - Objects.requireNonNull(MainViewerGUI.getComponent(SearchBoxPane.class)) - .search.setText("Search"); - - tree.expandPath(new TreePath(tree.getModel().getRoot())); - tree.updateUI(); - } - - }; + t = new PerformSearch(this, srn); Objects.requireNonNull(MainViewerGUI.getComponent(SearchBoxPane.class)) .search.setEnabled(false); Objects.requireNonNull(MainViewerGUI.getComponent(SearchBoxPane.class)) @@ -203,32 +175,16 @@ public class SearchBoxPane extends VisibleComponent { BytecodeViewer.showMessage("You currently have a search performing in the background, please wait for that to finish."); } } else if (radius == SearchRadius.Current_Class) { - final Viewer cv = Objects.requireNonNull(MainViewerGUI.getComponent(WorkPane.class)).getCurrentViewer(); + final ResourceViewer cv = Objects.requireNonNull(MainViewerGUI.getComponent(WorkPaneMainComponent.class)).getCurrentViewer(); if (cv != null) { searchType.details.search(cv.container, cv.cn, srn, exact.isSelected()); } } } - - public enum SearchType { - Strings(new LDCSearch()), - Regex(new RegexSearch()), - MethodCall(new MethodCallSearch()), - FieldCall(new FieldCallSearch()); - - public final SearchTypeDetails details; - - SearchType(final SearchTypeDetails details) { - this.details = details; - } - } - - public enum SearchRadius { - All_Classes, Current_Class - } - + public void resetWorkspace() { treeRoot.removeAllChildren(); tree.updateUI(); } + } diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/gui/resourcesearch/SearchRadius.java b/src/main/java/the/bytecode/club/bytecodeviewer/gui/resourcesearch/SearchRadius.java new file mode 100644 index 00000000..6076b74e --- /dev/null +++ b/src/main/java/the/bytecode/club/bytecodeviewer/gui/resourcesearch/SearchRadius.java @@ -0,0 +1,10 @@ +package the.bytecode.club.bytecodeviewer.gui.resourcesearch; + +/** + * @author Konloch + * @since 6/25/2021 + */ +public enum SearchRadius +{ + All_Classes, Current_Class +} diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/gui/resourcesearch/SearchType.java b/src/main/java/the/bytecode/club/bytecodeviewer/gui/resourcesearch/SearchType.java new file mode 100644 index 00000000..1c282517 --- /dev/null +++ b/src/main/java/the/bytecode/club/bytecodeviewer/gui/resourcesearch/SearchType.java @@ -0,0 +1,22 @@ +package the.bytecode.club.bytecodeviewer.gui.resourcesearch; + +import the.bytecode.club.bytecodeviewer.searching.*; + +/** + * @author Konloch + * @since 6/25/2021 + */ +public enum SearchType +{ + Strings(new LDCSearch()), + Regex(new RegexSearch()), + MethodCall(new MethodCallSearch()), + FieldCall(new FieldCallSearch()); + + public final SearchTypeDetails details; + + SearchType(final SearchTypeDetails details) + { + this.details = details; + } +} diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/gui/ViewPane.java b/src/main/java/the/bytecode/club/bytecodeviewer/gui/resourceviewer/DecompilerSelectionPane.java similarity index 94% rename from src/main/java/the/bytecode/club/bytecodeviewer/gui/ViewPane.java rename to src/main/java/the/bytecode/club/bytecodeviewer/gui/resourceviewer/DecompilerSelectionPane.java index c9252c53..d3f00d72 100644 --- a/src/main/java/the/bytecode/club/bytecodeviewer/gui/ViewPane.java +++ b/src/main/java/the/bytecode/club/bytecodeviewer/gui/resourceviewer/DecompilerSelectionPane.java @@ -1,4 +1,7 @@ -package the.bytecode.club.bytecodeviewer.gui; +package the.bytecode.club.bytecodeviewer.gui.resourceviewer; + +import the.bytecode.club.bytecodeviewer.decompilers.Decompiler; +import the.bytecode.club.bytecodeviewer.gui.components.DecompilerViewComponent; import javax.swing.*; @@ -6,7 +9,7 @@ import javax.swing.*; * @author Konloch * @since 6/21/2021 */ -public class ViewPane +public class DecompilerSelectionPane { public final int paneID; public final JMenu menu; @@ -23,7 +26,7 @@ public class ViewPane public final JRadioButtonMenuItem bytecode = new JRadioButtonMenuItem("Bytecode"); public final JRadioButtonMenuItem asmTextify = new JRadioButtonMenuItem("ASM Textify"); - public ViewPane(int paneID) { + public DecompilerSelectionPane(int paneID) { this.paneID = paneID; this.menu = new JMenu("Pane " + paneID); buildMenu(); diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/gui/resourceviewer/ResourcePanelCompileMode.java b/src/main/java/the/bytecode/club/bytecodeviewer/gui/resourceviewer/ResourcePanelCompileMode.java new file mode 100644 index 00000000..359ca762 --- /dev/null +++ b/src/main/java/the/bytecode/club/bytecodeviewer/gui/resourceviewer/ResourcePanelCompileMode.java @@ -0,0 +1,12 @@ +package the.bytecode.club.bytecodeviewer.gui.resourceviewer; + +/** + * @author Konloch + * @since 6/25/2021 + */ +public enum ResourcePanelCompileMode +{ + JAVA, + KRAKATAU_ASSEMBLY, + SMALI_ASSEMBLY, +} diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/gui/resourceviewer/ResourceViewPanel.java b/src/main/java/the/bytecode/club/bytecodeviewer/gui/resourceviewer/ResourceViewPanel.java new file mode 100644 index 00000000..030531fe --- /dev/null +++ b/src/main/java/the/bytecode/club/bytecodeviewer/gui/resourceviewer/ResourceViewPanel.java @@ -0,0 +1,107 @@ +package the.bytecode.club.bytecodeviewer.gui.resourceviewer; + +import org.fife.ui.rsyntaxtextarea.SyntaxConstants; +import org.objectweb.asm.ClassWriter; +import the.bytecode.club.bytecodeviewer.BytecodeViewer; +import the.bytecode.club.bytecodeviewer.Configuration; +import the.bytecode.club.bytecodeviewer.decompilers.Decompiler; +import the.bytecode.club.bytecodeviewer.gui.components.SearchableRSyntaxTextArea; +import the.bytecode.club.bytecodeviewer.gui.hexviewer.JHexEditor; +import the.bytecode.club.bytecodeviewer.gui.resourceviewer.viewer.ClassViewer; +import the.bytecode.club.bytecodeviewer.gui.util.PaneUpdaterThread; + +import javax.swing.*; +import java.awt.*; + +/** + * @author Konloch + * @since 6/24/2021 + */ +public class ResourceViewPanel +{ + public final JPanel panel = new JPanel(new BorderLayout()); + + public ClassViewer viewer; + public int decompilerViewIndex = -1; + public SearchableRSyntaxTextArea textArea; + public PaneUpdaterThread updateThread; + public final int panelIndex; + + //TODO change the compile mode for Krakatau and Smali assembly + public ResourcePanelCompileMode compileMode = ResourcePanelCompileMode.JAVA; + + public ResourceViewPanel(int panelIndex) {this.panelIndex = panelIndex;} + + public void createPane(ClassViewer viewer) + { + panel.removeAll(); + textArea = null; + + if(viewer.cn == null) + { + panel.add(new JLabel("This file has been removed from the reload.")); + } + } + + public void updatePane(ClassViewer cv, byte[] b, JButton button, boolean isPanelEditable) + { + updateThread = new PaneUpdaterThread(panelIndex, decompilerViewIndex) { + @Override + public void doShit() { + try { + BytecodeViewer.viewer.updateBusyStatus(true); + + if(ResourceViewPanel.this.decompilerViewIndex > 0) + { + //hex viewer + if (ResourceViewPanel.this.decompilerViewIndex == 5) + { + final ClassWriter cw = new ClassWriter(0); + cv.cn.accept(cw); + + final JHexEditor hex = new JHexEditor(cw.toByteArray()); + hex.setFont(new Font(Font.MONOSPACED, Font.PLAIN, (int) BytecodeViewer.viewer.fontSpinner.getValue())); + + SwingUtilities.invokeLater(() -> panel.add(hex)); + } + else + { + viewer = cv; + updateUpdaterTextArea = (SearchableRSyntaxTextArea) Configuration.rstaTheme.apply(new SearchableRSyntaxTextArea()); + + final Decompiler decompiler = Decompiler.decompilersByIndex.get(ResourceViewPanel.this.decompilerViewIndex); + final String decompiledSource = decompiler.getDecompiler().decompileClassNode(cv.cn, b); + //decompilerUpdate.update(decompiler.getDecompilerName(), cv.cn, b, decompiler.getDecompiler(), updateUpdaterTextArea); + + SwingUtilities.invokeLater(() -> + { + panel.add(updateUpdaterTextArea.getScrollPane()); + + textArea.setSyntaxEditingStyle(SyntaxConstants.SYNTAX_STYLE_JAVA); + textArea.setCodeFoldingEnabled(true); + textArea.setAntiAliasingEnabled(true); + textArea.setText(decompiledSource); + textArea.setCaretPosition(0); + textArea.setEditable(isPanelEditable); + + textArea.getScrollPane().setColumnHeaderView(new JLabel(decompiler.getDecompilerName() + " - Editable: " + textArea.isEditable())); + textArea.setFont(new Font(Font.MONOSPACED, Font.PLAIN, + (int) BytecodeViewer.viewer.fontSpinner.getValue())); + }); + textArea = updateUpdaterTextArea; + } + } + } catch (java.lang.IndexOutOfBoundsException | java.lang.NullPointerException e) { + //ignore + } catch (Exception e) { + new the.bytecode.club.bytecodeviewer.api.ExceptionUI(e); + } finally { + cv.resetDivider(); + BytecodeViewer.viewer.updateBusyStatus(false); + if (button != null) + button.setEnabled(true); + } + } + }; + } +} diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/gui/resourceviewer/TabButton.java b/src/main/java/the/bytecode/club/bytecodeviewer/gui/resourceviewer/TabButton.java new file mode 100644 index 00000000..f9aa0edb --- /dev/null +++ b/src/main/java/the/bytecode/club/bytecodeviewer/gui/resourceviewer/TabButton.java @@ -0,0 +1,100 @@ +package the.bytecode.club.bytecodeviewer.gui.resourceviewer; + +import javax.swing.*; +import javax.swing.plaf.basic.BasicButtonUI; +import java.awt.*; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; + +/** + * @author Konloch + * @since 6/25/2021 + */ +public class TabButton extends JButton implements ActionListener +{ + private final TabbedPane tabbedPane; + private final int tabIndex; + private final String tabWorkingName; + + public TabButton(TabbedPane tabbedPane, int tabIndex, String tabWorkingName) + { + this.tabbedPane = tabbedPane; + this.tabIndex = tabIndex; + this.tabWorkingName = tabWorkingName; + final int size = 17; + setPreferredSize(new Dimension(size, size)); + setToolTipText("Close this tab"); + // Make the button looks the same for all Laf's + setUI(new BasicButtonUI()); + // Make it transparent + setContentAreaFilled(false); + // No need to be focusable + setFocusable(false); + setBorder(BorderFactory.createEtchedBorder()); + setBorderPainted(false); + // Making nice rollover effect + // we use the same listener for all buttons + addMouseListener(TabbedPane.buttonHoverAnimation); + setRolloverEnabled(true); + // Close the proper tab by clicking the button + addActionListener(this); + } + + public int getTabIndex() + { + return tabIndex; + } + + @Override + public void actionPerformed(final ActionEvent e) + { + final int i = tabbedPane.tabs.indexOfTabComponent(tabbedPane); + if (i != -1) + { + tabbedPane.tabs.remove(i); + } + } + + // we don't want to update UI for this button + @Override + public void updateUI() { } + + // paint the cross + @Override + protected void paintComponent(final Graphics g) + { + super.paintComponent(g); + final Graphics2D g2 = (Graphics2D) g.create(); + // shift the image for pressed buttons + if (getModel().isPressed()) + g2.translate(1, 1); + + g2.setStroke(new BasicStroke(2)); + g2.setColor(Color.BLACK); + + if (getModel().isRollover()) + g2.setColor(Color.MAGENTA); + + final int delta = 6; + g2.drawLine(delta, delta, getWidth() - delta - 1, getHeight() - delta - 1); + g2.drawLine(getWidth() - delta - 1, delta, delta, getHeight() - delta - 1); + g2.dispose(); + } + + public TabbedPane getTabbedPane() + { + return tabbedPane; + } + + public String getTabWorkingName() + { + return tabWorkingName; + } + + public static long getSerialVersionUID() + { + return serialVersionUID; + } + + private static final long serialVersionUID = -4492967978286454159L; +} diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/gui/resourceviewer/TabRemovalEvent.java b/src/main/java/the/bytecode/club/bytecodeviewer/gui/resourceviewer/TabRemovalEvent.java new file mode 100644 index 00000000..ba93b15e --- /dev/null +++ b/src/main/java/the/bytecode/club/bytecodeviewer/gui/resourceviewer/TabRemovalEvent.java @@ -0,0 +1,36 @@ +package the.bytecode.club.bytecodeviewer.gui.resourceviewer; + +import the.bytecode.club.bytecodeviewer.BytecodeViewer; +import the.bytecode.club.bytecodeviewer.gui.resourceviewer.viewer.ClassViewer; +import the.bytecode.club.bytecodeviewer.gui.resourceviewer.viewer.FileViewer; + +import java.awt.*; +import java.awt.event.ContainerEvent; +import java.awt.event.ContainerListener; + +/** + * @author Konloch + * @since 6/24/2021 + */ +public class TabRemovalEvent implements ContainerListener +{ + @Override + public void componentAdded(ContainerEvent e) { } + + @Override + public void componentRemoved(ContainerEvent e) + { + final Component c = e.getChild(); + + if (c instanceof ClassViewer) + { + String workingName = ((ClassViewer) c).workingName; + BytecodeViewer.viewer.workPane.workingOn.remove(workingName); + } + else if (c instanceof FileViewer) + { + String workingName = ((FileViewer) c).workingName; + BytecodeViewer.viewer.workPane.workingOn.remove(workingName); + } + } +} diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/gui/resourceviewer/TabbedPane.java b/src/main/java/the/bytecode/club/bytecodeviewer/gui/resourceviewer/TabbedPane.java new file mode 100644 index 00000000..8cdd9e55 --- /dev/null +++ b/src/main/java/the/bytecode/club/bytecodeviewer/gui/resourceviewer/TabbedPane.java @@ -0,0 +1,250 @@ +package the.bytecode.club.bytecodeviewer.gui.resourceviewer; + +import java.awt.Color; +import java.awt.Component; +import java.awt.FlowLayout; +import java.awt.Rectangle; +import java.awt.event.InputEvent; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.awt.event.MouseListener; +import javax.swing.*; + +import the.bytecode.club.bytecodeviewer.BytecodeViewer; +import the.bytecode.club.bytecodeviewer.gui.components.ButtonHoverAnimation; +import the.bytecode.club.bytecodeviewer.gui.components.MaxWidthJLabel; +import the.bytecode.club.bytecodeviewer.gui.components.listeners.MouseClickedListener; +import the.bytecode.club.bytecodeviewer.gui.util.DelayTabbedPaneThread; + +/*************************************************************************** + * Bytecode Viewer (BCV) - Java & Android Reverse Engineering Suite * + * Copyright (C) 2014 Kalen 'Konloch' Kinloch - http://bytecodeviewer.com * + * * + * This program is free software: you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation, either version 3 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program. If not, see . * + ***************************************************************************/ + +/** + * Component to be used as tabComponent; Contains a JLabel to show the text and a JButton to close the tab it belongs to + * + * @author Konloch + * @author WaterWolf + */ +public class TabbedPane extends JPanel +{ + public final JTabbedPane tabs; + public final JLabel label; + private DelayTabbedPaneThread probablyABadIdea; + private long startedDragging = 0; + public final String tabName; + public final String fileContainerName; + private static long lastMouseClick = System.currentTimeMillis(); + public final static MouseListener buttonHoverAnimation = new ButtonHoverAnimation(); + public static final Color BLANK_COLOR = new Color(0, 0, 0, 0); + + public TabbedPane(int tabIndex, String tabWorkingName, String fileContainerName, String name, final JTabbedPane existingTabs) + { + // unset default FlowLayout' gaps + super(new FlowLayout(FlowLayout.LEFT, 0, 0)); + + this.tabName = name; + this.fileContainerName = fileContainerName; + + if (existingTabs == null) + throw new NullPointerException("TabbedPane is null"); + + this.tabs = existingTabs; + setOpaque(false); + + // make JLabel read titles from JTabbedPane + label = new MaxWidthJLabel(tabName, 400, 20); + + this.add(label); + // add more space between the label and the button + label.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 5)); + // tab button + JButton button = new TabButton(this, tabIndex, tabWorkingName); + this.add(button); + // add more space to the top of the component + setBorder(BorderFactory.createEmptyBorder(2, 0, 0, 0)); + + //define the right click pop-up menu + JPopupMenu rightClickMenu = new JPopupMenu(); + JMenuItem closeAllTabs = new JMenuItem("Close All But This: " + name); + JMenuItem closeTab = new JMenuItem("Close Tab: " + name); + + rightClickMenu.add(closeAllTabs); + rightClickMenu.add(closeTab); + //setComponentPopupMenu(rightClickMenu); + + button.setComponentPopupMenu(rightClickMenu); + button.addMouseListener(new MouseClickedListener(e -> + { + if (e.getModifiers() != InputEvent.ALT_MASK || System.currentTimeMillis() - lastMouseClick < 100) + return; + + lastMouseClick = System.currentTimeMillis(); + final int i = existingTabs.indexOfTabComponent(TabbedPane.this); + if (i != -1) + existingTabs.remove(i); + })); + + closeTab.addActionListener(e -> + { + TabButton tabButton = (TabButton) ((JPopupMenu)((JMenuItem) e.getSource()).getParent()).getInvoker(); + final int index = tabButton.getTabIndex(); + + if (index != -1) + existingTabs.remove(index); + }); + closeAllTabs.addActionListener(e -> + { + TabButton tabButton = (TabButton) ((JPopupMenu)((JMenuItem) e.getSource()).getParent()).getInvoker(); + final int index = tabButton.getTabIndex(); + + while (true) + { + if (existingTabs.getTabCount() <= 1) + return; + + if (index != 0) + existingTabs.remove(0); + else + existingTabs.remove(1); + } + }); + + //tab dragging + if(BytecodeViewer.EXPERIMENTAL_TAB_CODE) + { + /*label.addMouseListener(new MouseListener() { + @Override public void mouseClicked(MouseEvent e) {} + @Override public void mouseEntered(MouseEvent arg0) { + } + @Override public void mouseExited(MouseEvent arg0) { + } + @Override public void mousePressed(MouseEvent e) { + onMousePressed(e); + } + @Override public void mouseReleased(MouseEvent e) { + stopDragging(e.getX(), e.getY()); + } + });*/ + + this.addMouseListener(new MouseListener() { + @Override public void mouseClicked(MouseEvent e) {} + @Override public void mouseEntered(MouseEvent arg0) {} + @Override public void mouseExited(MouseEvent arg0) {} + @Override public void mousePressed(MouseEvent e) { + onMousePressed(e); + } + @Override public void mouseReleased(MouseEvent e) { + stopDragging(e.getX(), e.getY()); + } + }); + } + + //middle click close + if(BytecodeViewer.EXPERIMENTAL_TAB_CODE) + { + this.addMouseListener(new MouseAdapter() + { + @Override + public void mouseReleased(MouseEvent e) + { + if (e.getButton() != MouseEvent.BUTTON2) + return; + + final int i = existingTabs.indexOfTabComponent(TabbedPane.this); + if (i != -1) + existingTabs.remove(i); + } + }); + } + } + + private void stopDragging(int mouseX, int mouseY) + { + if (System.currentTimeMillis() - startedDragging >= 210) + { + Rectangle bounds = new Rectangle(1, 1, mouseX, mouseY); + System.out.println("debug-5: " + mouseX + ", " + mouseY); + + int totalTabs = BytecodeViewer.viewer.workPane.tabs.getTabCount(); + int index = -1; + for (int i = 0; i < totalTabs; i++) + { + Component c = BytecodeViewer.viewer.workPane.tabs.getTabComponentAt(i); + + if (c != null && bounds.intersects(c.getBounds())) + index = i; //replace this tabs position + } + + if (index == -1) + { + for (int i = 0; i < totalTabs; i++) + { + Component c = BytecodeViewer.viewer.workPane.tabs.getTabComponentAt(i); + //do some check to see if it's past the X or Y + if (c != null) { + System.out.println("debug-6: " + c.getBounds()); + } + } + } + + if (index != -1) + { + BytecodeViewer.viewer.workPane.tabs.remove(this); + BytecodeViewer.viewer.workPane.tabs.setTabComponentAt(index, this); + } + } + + SwingUtilities.invokeLater(() -> + { + label.setBackground(BLANK_COLOR); + label.updateUI(); + }); + } + + public void onMousePressed(MouseEvent e) + { + BytecodeViewer.viewer.workPane.tabs.dispatchEvent(e); + + if(e.getButton() == 1) + { + startedDragging = System.currentTimeMillis(); + //dragging = true; + if (probablyABadIdea != null) + probablyABadIdea.stopped = true; + + probablyABadIdea = new DelayTabbedPaneThread(TabbedPane.this); + probablyABadIdea.start(); + repaint(); + System.out.println(e.getX()+", "+e.getY()); + Rectangle bounds = new Rectangle(1, 1, e.getX(), e.getY()); + for(int i = 0; i < BytecodeViewer.viewer.workPane.tabs.getTabCount(); i++) + { + Component c = BytecodeViewer.viewer.workPane.tabs.getTabComponentAt(i); + if(c != null && bounds.intersects(c.getBounds())) + BytecodeViewer.viewer.workPane.tabs.setSelectedIndex(i); + } + } + else + { + stopDragging(e.getX(), e.getY()); + } + } + + private static final long serialVersionUID = -4774885688297538774L; + +} \ No newline at end of file diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/gui/resourceviewer/WorkPaneMainComponent.java b/src/main/java/the/bytecode/club/bytecodeviewer/gui/resourceviewer/WorkPaneMainComponent.java new file mode 100644 index 00000000..52bb9f35 --- /dev/null +++ b/src/main/java/the/bytecode/club/bytecodeviewer/gui/resourceviewer/WorkPaneMainComponent.java @@ -0,0 +1,235 @@ +package the.bytecode.club.bytecodeviewer.gui.resourceviewer; + +import java.awt.BorderLayout; +import java.awt.Component; +import java.awt.FlowLayout; +import java.awt.Rectangle; +import java.awt.event.MouseEvent; +import java.awt.event.MouseListener; +import java.util.HashMap; +import javax.swing.JButton; +import javax.swing.JMenuItem; +import javax.swing.JPanel; +import javax.swing.JPopupMenu; +import javax.swing.JTabbedPane; +import org.objectweb.asm.tree.ClassNode; +import the.bytecode.club.bytecodeviewer.BytecodeViewer; +import the.bytecode.club.bytecodeviewer.Configuration; +import the.bytecode.club.bytecodeviewer.gui.components.VisibleComponent; +import the.bytecode.club.bytecodeviewer.gui.resourceviewer.viewer.ClassViewer; +import the.bytecode.club.bytecodeviewer.gui.resourceviewer.viewer.FileViewer; +import the.bytecode.club.bytecodeviewer.gui.resourceviewer.viewer.ResourceViewer; +import the.bytecode.club.bytecodeviewer.util.FileContainer; +import the.bytecode.club.bytecodeviewer.util.MiscUtils; + +import static the.bytecode.club.bytecodeviewer.Constants.BLOCK_TAB_MENU; + +/*************************************************************************** + * Bytecode Viewer (BCV) - Java & Android Reverse Engineering Suite * + * Copyright (C) 2014 Kalen 'Konloch' Kinloch - http://bytecodeviewer.com * + * * + * This program is free software: you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation, either version 3 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program. If not, see . * + ***************************************************************************/ + +/** + * The pane that contains all of the resources as tabs. + * + * @author Konloch + * @author WaterWolf + */ +public class WorkPaneMainComponent extends VisibleComponent +{ + public final JTabbedPane tabs; + public final JPanel buttonPanel; + public final JButton refreshClass; + public final HashMap workingOn = new HashMap<>(); + + public WorkPaneMainComponent() + { + super("WorkPanel"); + setTitle("Work Space"); + + this.tabs = new JTabbedPane(); + + JPopupMenu popUp = new JPopupMenu(); + JMenuItem closeAllTabs = new JMenuItem("Close All But This"); + JMenuItem closeTab = new JMenuItem("Close Tab"); + closeTab.addActionListener(e -> + { + TabButton tabButton = (TabButton) ((JPopupMenu)((JMenuItem) e.getSource()).getParent()).getInvoker(); + final int index = tabButton.getTabIndex(); + + if (index != -1) + tabs.remove(index); + }); + closeAllTabs.addActionListener(e -> + { + TabButton tabButton = (TabButton) ((JPopupMenu)((JMenuItem) e.getSource()).getParent()).getInvoker(); + final int index = tabButton.getTabIndex(); + + while (true) + { + if (tabs.getTabCount() <= 1) + return; + + if (index != 0) + tabs.remove(0); + else + tabs.remove(1); + } + }); + tabs.addMouseListener(new MouseListener() + { + @Override + public void mouseClicked(MouseEvent e) { } + @Override + public void mouseEntered(MouseEvent arg0) { } + @Override + public void mouseExited(MouseEvent arg0) { } + + @Override + public void mousePressed(MouseEvent e) + { + if (BLOCK_TAB_MENU) + return; + + if (e.getButton() == 3) + { + Rectangle bounds = new Rectangle(1, 1, e.getX(), e.getY()); + + for (int i = 0; i < BytecodeViewer.viewer.workPane.tabs.getTabCount(); i++) + { + Component c = BytecodeViewer.viewer.workPane.tabs.getTabComponentAt(i); + if (c != null && bounds.intersects(c.getBounds())) + { + popUp.setVisible(true); + closeAllTabs.setText("Close All But This: " + ((TabbedPane) c).tabName); + closeTab.setText("Close Tab: " + ((TabbedPane) c).tabName); + } + else + { + popUp.setVisible(false); + } + } + } + } + + @Override + public void mouseReleased(MouseEvent e) { } + }); + + popUp.add(closeAllTabs); + popUp.add(closeTab); + + if (!BLOCK_TAB_MENU) + tabs.setComponentPopupMenu(popUp); + + getContentPane().setLayout(new BorderLayout()); + getContentPane().add(tabs, BorderLayout.CENTER); + + buttonPanel = new JPanel(new FlowLayout()); + + refreshClass = new JButton("Refresh"); + refreshClass.addActionListener((event)->{ + Thread t = new Thread(() -> new WorkPaneRefresh(event).run()); + t.start(); + }); + + buttonPanel.add(refreshClass); + + buttonPanel.setVisible(false); + getContentPane().add(buttonPanel, BorderLayout.SOUTH); + + tabs.addContainerListener(new TabRemovalEvent()); + tabs.addChangeListener(arg0 -> buttonPanel.setVisible(tabs.getSelectedIndex() != -1)); + + this.setVisible(true); + } + + public void addWorkingFile(final FileContainer container, String name, final ClassNode cn) + { + String workingName = container.name + ">" + name; + String containerName = name; + + if (Configuration.displayParentInTab) + containerName = container.name + ">" + name; + + if (!workingOn.containsKey(workingName)) + { + final ClassViewer tabComp = new ClassViewer(container, containerName, cn, workingName); + tabs.add(tabComp); + final int tabIndex = tabs.indexOfComponent(tabComp); + workingOn.put(workingName, tabIndex); + TabbedPane tabbedPane = new TabbedPane(tabIndex, workingName, container.name, name, tabs); + tabComp.tabbedPane = tabbedPane; + tabs.setTabComponentAt(tabIndex, tabbedPane); + tabs.setSelectedIndex(tabIndex); + } + else + { + tabs.setSelectedIndex(workingOn.get(workingName)); + } + } + + public void addFile(final FileContainer container, String name, byte[] contents) + { + if (contents == null) //a directory + return; + + final String workingName = container.name + ">" + name; + + if (Configuration.simplifiedTabNames) + name = MiscUtils.getChildFromPath(name); + if (Configuration.displayParentInTab) + name = container.name + ">" + name; + + if (!workingOn.containsKey(workingName)) + { + final FileViewer tabComp = new FileViewer(container, name, contents, workingName); + tabs.add(tabComp); + final int tabIndex = tabs.indexOfComponent(tabComp); + workingOn.put(workingName, tabIndex); + + TabbedPane tabbedPane = new TabbedPane(tabIndex, workingName, container.name, name, tabs); + tabComp.tabbedPane = tabbedPane; + tabs.setTabComponentAt(tabIndex, tabbedPane); + tabs.setSelectedIndex(tabIndex); + } + else + { + try { + tabs.setSelectedIndex(workingOn.get(workingName)); + } catch (Exception e) { + //workingOn.remove(workingName); + e.printStackTrace(); + } + } + } + + public ResourceViewer getCurrentViewer() { + return (ResourceViewer) tabs.getSelectedComponent(); + } + + public Component[] getLoadedViewers() { + return tabs.getComponents(); + } + + public void resetWorkspace() + { + tabs.removeAll(); + tabs.updateUI(); + } + + private static final long serialVersionUID = 6542337997679487946L; +} \ No newline at end of file diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/gui/resourceviewer/WorkPaneRefresh.java b/src/main/java/the/bytecode/club/bytecodeviewer/gui/resourceviewer/WorkPaneRefresh.java new file mode 100644 index 00000000..dcf518f2 --- /dev/null +++ b/src/main/java/the/bytecode/club/bytecodeviewer/gui/resourceviewer/WorkPaneRefresh.java @@ -0,0 +1,65 @@ +package the.bytecode.club.bytecodeviewer.gui.resourceviewer; + +import the.bytecode.club.bytecodeviewer.BytecodeViewer; +import the.bytecode.club.bytecodeviewer.gui.resourceviewer.viewer.ClassViewer; +import the.bytecode.club.bytecodeviewer.gui.resourceviewer.viewer.FileViewer; + +import javax.swing.*; +import java.awt.*; +import java.awt.event.ActionEvent; + +/** + * @author Konloch + * @since 6/24/2021 + */ +public class WorkPaneRefresh implements Runnable +{ + private final ActionEvent event; + + public WorkPaneRefresh(ActionEvent event) { + this.event = event; + } + + @Override + public void run() + { + if (BytecodeViewer.viewer.autoCompileOnRefresh.isSelected()) + try { + if (!BytecodeViewer.compile(false)) + return; + } catch (NullPointerException ignored) { + + } + + JButton src = null; + if(event != null && event.getSource() instanceof JButton) + src = (JButton) event.getSource(); + + //if (src == BytecodeViewer.viewer.workPane.refreshClass) + { + final Component tabComp = BytecodeViewer.viewer.workPane.tabs.getSelectedComponent(); + + if(tabComp == null) + return; + + if (tabComp instanceof ClassViewer) + { + if(src != null) + src.setEnabled(false); + + BytecodeViewer.viewer.updateBusyStatus(true); + ((ClassViewer) tabComp).startPaneUpdater(src); + BytecodeViewer.viewer.updateBusyStatus(false); + } + else if (tabComp instanceof FileViewer) + { + if(src != null) + src.setEnabled(false); + + BytecodeViewer.viewer.updateBusyStatus(true); + ((FileViewer) tabComp).refresh(src); + BytecodeViewer.viewer.updateBusyStatus(false); + } + } + } +} diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/gui/resourceviewer/viewer/ClassViewer.java b/src/main/java/the/bytecode/club/bytecodeviewer/gui/resourceviewer/viewer/ClassViewer.java new file mode 100644 index 00000000..84ef8bcf --- /dev/null +++ b/src/main/java/the/bytecode/club/bytecodeviewer/gui/resourceviewer/viewer/ClassViewer.java @@ -0,0 +1,569 @@ +package the.bytecode.club.bytecodeviewer.gui.resourceviewer.viewer; + +import the.bytecode.club.bytecodeviewer.gui.resourceviewer.ResourcePanelCompileMode; +import the.bytecode.club.bytecodeviewer.gui.resourceviewer.ResourceViewPanel; +import the.bytecode.club.bytecodeviewer.gui.resourceviewer.TabbedPane; +import the.bytecode.club.bytecodeviewer.gui.hexviewer.JHexEditor; +import java.awt.BorderLayout; +import java.awt.Color; +import java.awt.Component; +import java.awt.Container; +import java.awt.Dimension; +import java.awt.Point; +import java.awt.event.ComponentAdapter; +import java.awt.event.ComponentEvent; +import java.awt.event.HierarchyEvent; +import java.awt.event.HierarchyListener; +import java.io.File; +import java.util.Arrays; +import java.util.List; +import javax.swing.JButton; +import javax.swing.JSplitPane; +import javax.swing.JViewport; +import javax.swing.SwingUtilities; +import javax.swing.text.BadLocationException; +import javax.swing.text.DefaultHighlighter; +import javax.swing.text.Highlighter; +import javax.swing.text.JTextComponent; + +import org.fife.ui.rsyntaxtextarea.RSyntaxTextArea; +import org.fife.ui.rtextarea.RTextScrollPane; +import org.objectweb.asm.ClassWriter; +import org.objectweb.asm.tree.ClassNode; +import the.bytecode.club.bytecodeviewer.BytecodeViewer; +import the.bytecode.club.bytecodeviewer.Configuration; +import the.bytecode.club.bytecodeviewer.Settings; +import the.bytecode.club.bytecodeviewer.util.FileContainer; +import the.bytecode.club.bytecodeviewer.util.MethodParser; + +import static the.bytecode.club.bytecodeviewer.util.MethodParser.Method; + +/*************************************************************************** + * Bytecode Viewer (BCV) - Java & Android Reverse Engineering Suite * + * Copyright (C) 2014 Kalen 'Konloch' Kinloch - http://bytecodeviewer.com * + * * + * This program is free software: you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation, either version 3 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program. If not, see . * + ***************************************************************************/ + +/** + * This represents the opened classfile. + * + * @author Konloch + * @author WaterWolf + */ + +public class ClassViewer extends ResourceViewer +{ + private static final long serialVersionUID = -8650495368920680024L; + public String name; + public JSplitPane sp; + public JSplitPane sp2; + public TabbedPane tabbedPane; + public ResourceViewPanel resourceViewPanel1 = new ResourceViewPanel(0); + public ResourceViewPanel resourceViewPanel2 = new ResourceViewPanel(1); + public ResourceViewPanel resourceViewPanel3 = new ResourceViewPanel(2); + + public File[] tempFiles; + public ClassViewer THIS = this; + public List methods = Arrays.asList(new MethodParser(), new MethodParser(), new MethodParser()); + public final String workingName; + private final DefaultHighlighter.DefaultHighlightPainter painter = new DefaultHighlighter.DefaultHighlightPainter(new Color(255, 62, 150)); + + /** + * This was really interesting to write. + * + * @author Konloch + */ + public void search(int pane, String search, boolean next) + { + try + { + Component[] com = null; + if (pane == 0) // bytecode + com = resourceViewPanel1.panel.getComponents(); + else if (pane == 1) + com = resourceViewPanel2.panel.getComponents(); + else if (pane == 2) + com = resourceViewPanel3.panel.getComponents(); + + if (com == null) // someone fucked up, lets prevent a nullpointer. + return; + + for (Component c : com) + { + if (c instanceof RTextScrollPane) + { + RSyntaxTextArea area = (RSyntaxTextArea) ((RTextScrollPane) c).getViewport().getComponent(0); + + if (search.isEmpty()) + { + highlight(pane, area, ""); + return; + } + + int startLine = area.getDocument().getDefaultRootElement() + .getElementIndex(area.getCaretPosition()) + 1; + + int currentLine = 1; + boolean canSearch = false; + String[] test = (area.getText().split("\n").length >= 2 + ? area.getText().split("\n") + : area.getText().split("\r")); + + int lastGoodLine = -1; + int firstPos = -1; + boolean found = false; + + if (next) + { + for (String s : test) + { + if (pane == 0 && !resourceViewPanel1.textArea.getCaseSensitiveSearch().isSelected() || + pane == 1 && !resourceViewPanel2.textArea.getCaseSensitiveSearch().isSelected()) + { + //TODO should pane2 be here? - look into this later + s = s.toLowerCase(); + search = search.toLowerCase(); + } + + if (currentLine == startLine) + { + canSearch = true; + } + else if (s.contains(search)) + { + if (canSearch) + { + area.setCaretPosition(area.getDocument() + .getDefaultRootElement() + .getElement(currentLine - 1) + .getStartOffset()); + canSearch = false; + found = true; + } + + if (firstPos == -1) + firstPos = currentLine; + } + + currentLine++; + } + + if (!found && firstPos != -1) + { + area.setCaretPosition(area.getDocument() + .getDefaultRootElement() + .getElement(firstPos - 1).getStartOffset()); + } + } + else + { + canSearch = true; + for (String s : test) + { + if (pane == 0 && !resourceViewPanel1.textArea.getCaseSensitiveSearch().isSelected() || pane == 1 + && !resourceViewPanel2.textArea.getCaseSensitiveSearch().isSelected() || pane == 2 + && !resourceViewPanel3.textArea.getCaseSensitiveSearch().isSelected()) + { + s = s.toLowerCase(); + search = search.toLowerCase(); + } + + if (s.contains(search)) + { + if (lastGoodLine != -1 && canSearch) + area.setCaretPosition(area.getDocument() + .getDefaultRootElement() + .getElement(lastGoodLine - 1) + .getStartOffset()); + + lastGoodLine = currentLine; + + if (currentLine >= startLine) + canSearch = false; + } + currentLine++; + } + + if (lastGoodLine != -1 + && area.getDocument() + .getDefaultRootElement() + .getElementIndex(area.getCaretPosition()) + 1 == startLine) + { + area.setCaretPosition(area.getDocument() + .getDefaultRootElement() + .getElement(lastGoodLine - 1) + .getStartOffset()); + } + } + highlight(pane, area, search); + } + } + } + catch (Exception e) + { + new the.bytecode.club.bytecodeviewer.api.ExceptionUI(e); + } + } + + public void highlight(int pane, JTextComponent textComp, String pattern) + { + if (pattern.isEmpty()) + { + textComp.getHighlighter().removeAllHighlights(); + return; + } + + try + { + Highlighter hilite = textComp.getHighlighter(); + hilite.removeAllHighlights(); + javax.swing.text.Document doc = textComp.getDocument(); + String text = doc.getText(0, doc.getLength()); + int pos = 0; + + if ((pane == 0 && !resourceViewPanel1.textArea.getCaseSensitiveSearch().isSelected()) || pane == 1 + && !resourceViewPanel2.textArea.getCaseSensitiveSearch().isSelected() || pane == 2 + && !resourceViewPanel3.textArea.getCaseSensitiveSearch().isSelected()) + { + pattern = pattern.toLowerCase(); + text = text.toLowerCase(); + } + + // Search for pattern + while ((pos = text.indexOf(pattern, pos)) >= 0) + { + // Create highlighter using private painter and apply around + // pattern + hilite.addHighlight(pos, pos + pattern.length(), painter); + pos += pattern.length(); + } + } + catch (Exception e) + { + new the.bytecode.club.bytecodeviewer.api.ExceptionUI(e); + } + } + + public ClassViewer(final FileContainer container, final String name, final ClassNode cn, String workingName) + { + this.workingName = workingName; + this.container = container; + + this.name = name; + this.cn = cn; + this.setName(name); + this.setLayout(new BorderLayout()); + + this.sp = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, resourceViewPanel1.panel, resourceViewPanel2.panel); + final ClassWriter cw = new ClassWriter(0); + cn.accept(cw); + JHexEditor hex = new JHexEditor(cw.toByteArray()); + this.sp2 = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, sp, resourceViewPanel3.panel); + this.add(sp2, BorderLayout.CENTER); + + hex.setMaximumSize(new Dimension(0, Integer.MAX_VALUE)); + hex.setSize(0, Integer.MAX_VALUE); + + startPaneUpdater(null); + this.addComponentListener(new ComponentAdapter() { + @Override + public void componentResized(ComponentEvent e) { + resetDivider(); + } + }); + } + + public void resetDivider() { + SwingUtilities.invokeLater(() -> + { + sp.setResizeWeight(0.5); + + if (resourceViewPanel2.decompilerViewIndex != 0 && resourceViewPanel1.decompilerViewIndex != 0) { + setDividerLocation(sp, 0.5); + } else if (resourceViewPanel1.decompilerViewIndex != 0) { + setDividerLocation(sp, 1); + } else if (resourceViewPanel2.decompilerViewIndex != 0) { + sp.setResizeWeight(1); + setDividerLocation(sp, 0); + } else { + setDividerLocation(sp, 0); + } + + if (resourceViewPanel3.decompilerViewIndex != 0) { + sp2.setResizeWeight(0.7); + setDividerLocation(sp2, 0.7); + if ((resourceViewPanel2.decompilerViewIndex == 0 && resourceViewPanel1.decompilerViewIndex != 0) + || (resourceViewPanel1.decompilerViewIndex == 0 && resourceViewPanel2.decompilerViewIndex != 0)) { + setDividerLocation(sp2, 0.5); + } else if (resourceViewPanel1.decompilerViewIndex == 0) { + setDividerLocation(sp2, 0); + } + } else { + sp.setResizeWeight(1); + sp2.setResizeWeight(0); + setDividerLocation(sp2, 1); + } + }); + } + + public void startPaneUpdater(final JButton button) + { + this.cn = BytecodeViewer.getClassNode(container, cn.name); //update the classnode + setPanes(); + + resourceViewPanel1.createPane(this); + resourceViewPanel2.createPane(this); + resourceViewPanel3.createPane(this); + + final ClassWriter cw = new ClassWriter(0); + try { + cn.accept(cw); + } catch (Exception e) { + e.printStackTrace(); + try { + Thread.sleep(200); + cn.accept(cw); + } catch (InterruptedException ignored) { } + } + + final byte[] b = cw.toByteArray(); + resourceViewPanel1.updatePane(this, b, button, isPanel1Editable()); + resourceViewPanel2.updatePane(this, b, button, isPanel2Editable()); + resourceViewPanel3.updatePane(this, b, button, isPanel3Editable()); + + Thread t = new Thread(() -> + { + BytecodeViewer.viewer.updateBusyStatus(true); + while (Configuration.currentlyDumping) + { + //wait until it's not dumping + try { + Thread.sleep(100); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + tempFiles = BytecodeViewer.dumpTempFile(container); + + BytecodeViewer.viewer.updateBusyStatus(false); + + if (resourceViewPanel1.decompilerViewIndex > 0) + resourceViewPanel1.updateThread.startNewThread(); + if (resourceViewPanel2.decompilerViewIndex > 0) + resourceViewPanel2.updateThread.startNewThread(); + if (resourceViewPanel3.decompilerViewIndex > 0) + resourceViewPanel3.updateThread.startNewThread(); + }); + t.start(); + + if (isPanel1Editable() || isPanel2Editable() || isPanel3Editable()) + { + if (Configuration.warnForEditing) + return; + + Configuration.warnForEditing = true; + if (!BytecodeViewer.viewer.autoCompileOnRefresh.isSelected() + && !BytecodeViewer.viewer.compileOnSave.isSelected()) + { + BytecodeViewer.showMessage("Make sure to compile (File>Compile or Ctrl + T) whenever you want to " + + "test or export your changes.\nYou can set compile automatically on refresh or on save " + + "in the settings menu."); + + Settings.saveSettings(); + } + } + } + + public Object[] getSmali() { + if (resourceViewPanel1.compileMode == ResourcePanelCompileMode.SMALI_ASSEMBLY) + return new Object[]{cn, resourceViewPanel1.textArea.getText()}; + if (resourceViewPanel2.compileMode == ResourcePanelCompileMode.SMALI_ASSEMBLY) + return new Object[]{cn, resourceViewPanel2.textArea.getText()}; + if (resourceViewPanel3.compileMode == ResourcePanelCompileMode.SMALI_ASSEMBLY) + return new Object[]{cn, resourceViewPanel3.textArea.getText()}; + + return null; + } + + public Object[] getKrakatau() { + if (resourceViewPanel1.compileMode == ResourcePanelCompileMode.KRAKATAU_ASSEMBLY) + return new Object[]{cn, resourceViewPanel1.textArea.getText()}; + if (resourceViewPanel2.compileMode == ResourcePanelCompileMode.KRAKATAU_ASSEMBLY) + return new Object[]{cn, resourceViewPanel2.textArea.getText()}; + if (resourceViewPanel3.compileMode == ResourcePanelCompileMode.KRAKATAU_ASSEMBLY) + return new Object[]{cn, resourceViewPanel3.textArea.getText()}; + + return null; + } + + public Object[] getJava() { + if (resourceViewPanel1.textArea != null) + return new Object[]{cn, resourceViewPanel1.textArea.getText()}; + if (resourceViewPanel2.textArea != null) + return new Object[]{cn, resourceViewPanel2.textArea.getText()}; + if (resourceViewPanel3.textArea != null) + return new Object[]{cn, resourceViewPanel3.textArea.getText()}; + + return null; + } + + public void setPanes() { + resourceViewPanel1.decompilerViewIndex = BytecodeViewer.viewer.viewPane1.getSelectedViewer(); + resourceViewPanel2.decompilerViewIndex = BytecodeViewer.viewer.viewPane2.getSelectedViewer(); + resourceViewPanel3.decompilerViewIndex = BytecodeViewer.viewer.viewPane3.getSelectedViewer(); + } + + public boolean isPanel1Editable() { + setPanes(); + return BytecodeViewer.viewer.viewPane1.isPaneEditable(); + } + + public boolean isPanel2Editable() { + setPanes(); + return BytecodeViewer.viewer.viewPane2.isPaneEditable(); + } + + public boolean isPanel3Editable() { + setPanes(); + return BytecodeViewer.viewer.viewPane3.isPaneEditable(); + } + + /** + * Whoever wrote this function, THANK YOU! + * + * @param splitter + * @param proportion + * @return + */ + public static JSplitPane setDividerLocation(final JSplitPane splitter, + final double proportion) { + if (splitter.isShowing()) { + if (splitter.getWidth() > 0 && splitter.getHeight() > 0) { + splitter.setDividerLocation(proportion); + } else { + splitter.addComponentListener(new ComponentAdapter() { + @Override + public void componentResized(ComponentEvent ce) { + splitter.removeComponentListener(this); + setDividerLocation(splitter, proportion); + } + }); + } + } else { + splitter.addHierarchyListener(new HierarchyListener() { + @Override + public void hierarchyChanged(HierarchyEvent e) { + if ((e.getChangeFlags() & HierarchyEvent.SHOWING_CHANGED) != 0 + && splitter.isShowing()) { + splitter.removeHierarchyListener(this); + setDividerLocation(splitter, proportion); + } + } + }); + } + return splitter; + } + + + public static void selectMethod(RSyntaxTextArea area, int methodLine) { + if (methodLine != area.getCaretLineNumber()) { + setCaretLine(area, methodLine); + setViewLine(area, methodLine); + } + } + + public static void selectMethod(ClassViewer classViewer, int paneId, Method method) { + RSyntaxTextArea area = null; + switch (paneId) { + case 0: + area = classViewer.resourceViewPanel1.updateThread.updateUpdaterTextArea; + break; + case 1: + area = classViewer.resourceViewPanel2.updateThread.updateUpdaterTextArea; + break; + case 2: + area = classViewer.resourceViewPanel3.updateThread.updateUpdaterTextArea; + break; + } + + if (area != null) { + MethodParser methods = classViewer.methods.get(paneId); + if (methods != null) { + int methodLine = methods.findMethod(method); + if (methodLine != -1) { + selectMethod(area, methodLine); + } + } + } + } + + public static String getLineText(RSyntaxTextArea area, int line) { + try { + if (line < area.getLineCount()) { + int start = area.getLineStartOffset(line); + int end = area.getLineEndOffset(line); + return area.getText(start, end - start).trim(); + } + } catch (BadLocationException ignored) { } + return ""; + } + + public static int getMaxViewLine(RSyntaxTextArea area) + { + Container parent = area.getParent(); + if (parent instanceof JViewport) + { + JViewport viewport = (JViewport) parent; + int y = viewport.getViewSize().height - viewport.getExtentSize().height; + int lineHeight = area.getLineHeight(); + return y >= lineHeight ? y / lineHeight : 0; + } + + return 0; + } + + public static int getViewLine(RSyntaxTextArea area) + { + Container parent = area.getParent(); + if (parent instanceof JViewport) + { + JViewport viewport = (JViewport) parent; + Point point = viewport.getViewPosition(); + int lineHeight = area.getLineHeight(); + return point.y >= lineHeight ? point.y / lineHeight : 0; + } + + return 0; + } + + public static void setViewLine(RSyntaxTextArea area, int line) + { + Container parent = area.getParent(); + if (parent instanceof JViewport) + { + JViewport viewport = (JViewport) parent; + int maxLine = ClassViewer.getMaxViewLine(area); + line = Math.min(line, maxLine); + viewport.setViewPosition(new Point(0, line * area.getLineHeight())); + } + } + + public static void setCaretLine(RSyntaxTextArea area, int line) + { + try { + area.setCaretPosition(area.getLineStartOffset(line)); + } catch (BadLocationException ignored) { } + } +} diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/gui/resourceviewer/viewer/FileViewer.java b/src/main/java/the/bytecode/club/bytecodeviewer/gui/resourceviewer/viewer/FileViewer.java new file mode 100644 index 00000000..38d59464 --- /dev/null +++ b/src/main/java/the/bytecode/club/bytecodeviewer/gui/resourceviewer/viewer/FileViewer.java @@ -0,0 +1,149 @@ +package the.bytecode.club.bytecodeviewer.gui.resourceviewer.viewer; + +import java.awt.BorderLayout; +import java.awt.event.KeyEvent; +import java.awt.image.BufferedImage; +import javax.swing.ImageIcon; +import javax.swing.JButton; +import javax.swing.JCheckBox; +import javax.swing.JLabel; +import javax.swing.JPanel; +import javax.swing.JTextField; + +import org.fife.ui.rtextarea.RTextScrollPane; +import org.imgscalr.Scalr; +import the.bytecode.club.bytecodeviewer.BytecodeViewer; +import the.bytecode.club.bytecodeviewer.Configuration; +import the.bytecode.club.bytecodeviewer.Resources; +import the.bytecode.club.bytecodeviewer.gui.components.ImageJLabel; +import the.bytecode.club.bytecodeviewer.gui.components.SearchableRSyntaxTextArea; +import the.bytecode.club.bytecodeviewer.gui.components.listeners.PressKeyListener; +import the.bytecode.club.bytecodeviewer.gui.components.listeners.ReleaseKeyListener; +import the.bytecode.club.bytecodeviewer.gui.hexviewer.JHexEditor; +import the.bytecode.club.bytecodeviewer.gui.resourceviewer.TabbedPane; +import the.bytecode.club.bytecodeviewer.util.FileContainer; +import the.bytecode.club.bytecodeviewer.util.MiscUtils; +import the.bytecode.club.bytecodeviewer.util.SyntaxLanguage; + +/*************************************************************************** + * Bytecode Viewer (BCV) - Java & Android Reverse Engineering Suite * + * Copyright (C) 2014 Kalen 'Konloch' Kinloch - http://bytecodeviewer.com * + * * + * This program is free software: you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation, either version 3 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program. If not, see . * + ***************************************************************************/ + +/** + * Represents any open non-class file. + * + * @author Konloch + */ + +public class FileViewer extends ResourceViewer +{ + public final String name; + public final byte[] contents; + public final String workingName; + + public final SearchableRSyntaxTextArea textArea = (SearchableRSyntaxTextArea) + Configuration.rstaTheme.apply(new SearchableRSyntaxTextArea()); + + public final JPanel mainPanel = new JPanel(new BorderLayout()); + public TabbedPane tabbedPane; + public BufferedImage image; + public boolean canRefresh; + + public FileViewer(final FileContainer container, final String name, final byte[] contents, String workingName) + { + this.name = name; + this.contents = contents; + this.workingName = workingName; + this.container = container; + this.setName(name); + this.setLayout(new BorderLayout()); + + this.add(mainPanel, BorderLayout.CENTER); + + setContents(); + } + + public void setContents() + { + final String nameLowerCase = this.name.toLowerCase(); + final String contentsAsString = new String(contents); + + //image viewer + if (!MiscUtils.isPureAscii(contentsAsString)) + { + //TODO webp? + if (nameLowerCase.endsWith(".png") || nameLowerCase.endsWith(".jpg") || nameLowerCase.endsWith(".jpeg") || + nameLowerCase.endsWith(".gif") || nameLowerCase.endsWith(".tif") || nameLowerCase.endsWith(".bmp")) + { + canRefresh = true; + image = MiscUtils.loadImage(image, contents); //gifs fail because of this + mainPanel.add(new ImageJLabel(image), BorderLayout.CENTER); + mainPanel.addMouseWheelListener(e -> + { + int notches = e.getWheelRotation(); + + if (notches < 0) //zoom in + image = Scalr.resize(image, Scalr.Method.SPEED, image.getWidth() + 10, + image.getHeight() + 10); + else //zoom out + image = Scalr.resize(image, Scalr.Method.SPEED, image.getWidth() - 10, + image.getHeight() - 10); + + mainPanel.removeAll(); + mainPanel.add(new ImageJLabel(image), BorderLayout.CENTER); + mainPanel.updateUI(); + }); + return; + } + //hex viewer + else if (BytecodeViewer.viewer.forcePureAsciiAsText.isSelected()) + { + JHexEditor hex = new JHexEditor(contents); + mainPanel.add(hex); + return; + } + } + + textArea.setCodeFoldingEnabled(true); + textArea.setSyntaxEditingStyle(SyntaxLanguage.detectLanguage(nameLowerCase, contentsAsString).getSyntaxConstant()); + textArea.setText(contentsAsString); + textArea.setCaretPosition(0); + + mainPanel.add(textArea.getScrollPane()); + } + + public void refresh(JButton src) + { + if (!canRefresh) + { + src.setEnabled(true); + return; + } + + mainPanel.removeAll(); + + image = MiscUtils.loadImage(image, contents); + + JLabel label = new JLabel("", new ImageIcon(image), JLabel.CENTER); + mainPanel.add(label, BorderLayout.CENTER); + mainPanel.updateUI(); + + src.setEnabled(true); + } + + private static final long serialVersionUID = 6103372882168257164L; +} diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/gui/Viewer.java b/src/main/java/the/bytecode/club/bytecodeviewer/gui/resourceviewer/viewer/ResourceViewer.java similarity index 90% rename from src/main/java/the/bytecode/club/bytecodeviewer/gui/Viewer.java rename to src/main/java/the/bytecode/club/bytecodeviewer/gui/resourceviewer/viewer/ResourceViewer.java index b219cc36..2fdd70f4 100644 --- a/src/main/java/the/bytecode/club/bytecodeviewer/gui/Viewer.java +++ b/src/main/java/the/bytecode/club/bytecodeviewer/gui/resourceviewer/viewer/ResourceViewer.java @@ -1,4 +1,4 @@ -package the.bytecode.club.bytecodeviewer.gui; +package the.bytecode.club.bytecodeviewer.gui.resourceviewer.viewer; import javax.swing.JPanel; import org.objectweb.asm.tree.ClassNode; @@ -22,11 +22,11 @@ import the.bytecode.club.bytecodeviewer.util.FileContainer; * along with this program. If not, see . * ***************************************************************************/ -public abstract class Viewer extends JPanel { - +public abstract class ResourceViewer extends JPanel +{ public ClassNode cn; public String name; - FileContainer container; + public FileContainer container; private static final long serialVersionUID = -2965538493489119191L; -} +} \ No newline at end of file diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/gui/resourceviewer/viewer/synchronizedscroll/MethodData.java b/src/main/java/the/bytecode/club/bytecodeviewer/gui/resourceviewer/viewer/synchronizedscroll/MethodData.java new file mode 100644 index 00000000..f20ee149 --- /dev/null +++ b/src/main/java/the/bytecode/club/bytecodeviewer/gui/resourceviewer/viewer/synchronizedscroll/MethodData.java @@ -0,0 +1,39 @@ +package the.bytecode.club.bytecodeviewer.gui.resourceviewer.viewer.synchronizedscroll; + +import org.objectweb.asm.Type; + +import java.util.Arrays; + +/** + * @author Konloch + * @since 6/24/2021 + */ +public class MethodData +{ + public String name, desc; + + @Override + public boolean equals(final Object o) + { + return equals((MethodData) o); + } + + public boolean equals(final MethodData md) + { + return this.name.equals(md.name) && this.desc.equals(md.desc); + } + + public String constructPattern() + { + final StringBuilder pattern = new StringBuilder(); + pattern.append(name).append(" *\\("); + final org.objectweb.asm.Type[] types = org.objectweb.asm.Type + .getArgumentTypes(desc); + pattern.append("(.*)"); + Arrays.stream(types).map(Type::getClassName) + .forEach(clazzName -> pattern.append(clazzName.substring(clazzName.lastIndexOf(".") + 1)).append( + "(.*)")); + pattern.append("\\) *\\{"); + return pattern.toString(); + } +} diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/gui/theme/LAFTheme.java b/src/main/java/the/bytecode/club/bytecodeviewer/gui/theme/LAFTheme.java new file mode 100644 index 00000000..1f2bf343 --- /dev/null +++ b/src/main/java/the/bytecode/club/bytecodeviewer/gui/theme/LAFTheme.java @@ -0,0 +1,51 @@ +package the.bytecode.club.bytecodeviewer.gui.theme; + +import com.bulenkov.darcula.DarculaLaf; + +import javax.swing.*; + +/** + * @author Konloch + * @author ThexXTURBOXx + * @since 6/24/2021 + */ +public enum LAFTheme +{ + LIGHT("Light Theme (Requires restart)", RSTATheme.DEFAULT), //System theme + DARK("Dark Theme (Requires restart)", RSTATheme.DARK), //Darcula + ; + + private final String readableName; + private final RSTATheme rstaTheme; + + LAFTheme(String readableName, RSTATheme rstaTheme) + { + this.readableName = readableName; + this.rstaTheme = rstaTheme; + } + + public String getReadableName() + { + return readableName; + } + + public RSTATheme getRSTATheme() + { + return rstaTheme; + } + + public void setLAF() throws ClassNotFoundException, UnsupportedLookAndFeelException, InstantiationException, IllegalAccessException + { + switch(this) + { + default: + case LIGHT: + UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); + break; + + case DARK: + UIManager.setLookAndFeel(new DarculaLaf()); + break; + } + } +} diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/gui/theme/RSTATheme.java b/src/main/java/the/bytecode/club/bytecodeviewer/gui/theme/RSTATheme.java new file mode 100644 index 00000000..ad82b334 --- /dev/null +++ b/src/main/java/the/bytecode/club/bytecodeviewer/gui/theme/RSTATheme.java @@ -0,0 +1,54 @@ +package the.bytecode.club.bytecodeviewer.gui.theme; + +import org.fife.ui.rsyntaxtextarea.RSyntaxTextArea; +import org.fife.ui.rsyntaxtextarea.Theme; +import the.bytecode.club.bytecodeviewer.Constants; + +/** + * @author ThexXTURBOXx + * @since 6/23/2021 + */ +public enum RSTATheme +{ + DEFAULT("Default (Recommended Light)", null), + DARK("Dark (Recommended Dark)", "/org/fife/ui/rsyntaxtextarea/themes/dark.xml"), + DEFAULT_ALT( "Default-Alt", "/org/fife/ui/rsyntaxtextarea/themes/default-alt.xml"), + ECLIPSE("Eclipse", "/org/fife/ui/rsyntaxtextarea/themes/eclipse.xml"), + IDEA("IntelliJ", "/org/fife/ui/rsyntaxtextarea/themes/idea.xml"), + VS("Visual Studio", "/org/fife/ui/rsyntaxtextarea/themes/vs.xml"), + DRUID( "Druid (Dark)", "/org/fife/ui/rsyntaxtextarea/themes/druid.xml"), + MONOKAI( "Monokai (Dark)", "/org/fife/ui/rsyntaxtextarea/themes/monokai.xml"); + + private final String readableName; + private final String file; + + RSTATheme(String readableName, String file) + { + this.readableName = readableName; + this.file = file; + } + + public String getReadableName() { + return readableName; + } + + public RSyntaxTextArea apply(RSyntaxTextArea area) { + if (file != null) { + try { + Theme.load(Constants.class.getResourceAsStream(file)).apply(area); + } catch (Throwable ignored) { + } + } + return area; + } + + public static RSTATheme parse(String name) { + for (RSTATheme t : values()) { + if (t.name().equals(name)) { + return t; + } + } + return DEFAULT; + } + +} \ No newline at end of file diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/gui/DelayTabbedPaneThread.java b/src/main/java/the/bytecode/club/bytecodeviewer/gui/util/DelayTabbedPaneThread.java similarity index 80% rename from src/main/java/the/bytecode/club/bytecodeviewer/gui/DelayTabbedPaneThread.java rename to src/main/java/the/bytecode/club/bytecodeviewer/gui/util/DelayTabbedPaneThread.java index faf645e0..afddeb61 100644 --- a/src/main/java/the/bytecode/club/bytecodeviewer/gui/DelayTabbedPaneThread.java +++ b/src/main/java/the/bytecode/club/bytecodeviewer/gui/util/DelayTabbedPaneThread.java @@ -1,4 +1,6 @@ -package the.bytecode.club.bytecodeviewer.gui; +package the.bytecode.club.bytecodeviewer.gui.util; + +import the.bytecode.club.bytecodeviewer.gui.resourceviewer.TabbedPane; import java.awt.Color; import javax.swing.SwingUtilities; @@ -6,7 +8,8 @@ import javax.swing.SwingUtilities; /** * @author Konloch */ -public class DelayTabbedPaneThread extends Thread { +public class DelayTabbedPaneThread extends Thread +{ public boolean stopped = false; private final TabbedPane pane; diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/gui/PaneUpdaterThread.java b/src/main/java/the/bytecode/club/bytecodeviewer/gui/util/PaneUpdaterThread.java similarity index 68% rename from src/main/java/the/bytecode/club/bytecodeviewer/gui/PaneUpdaterThread.java rename to src/main/java/the/bytecode/club/bytecodeviewer/gui/util/PaneUpdaterThread.java index cf8537cf..ca8950a9 100644 --- a/src/main/java/the/bytecode/club/bytecodeviewer/gui/PaneUpdaterThread.java +++ b/src/main/java/the/bytecode/club/bytecodeviewer/gui/util/PaneUpdaterThread.java @@ -1,4 +1,4 @@ -package the.bytecode.club.bytecodeviewer.gui; +package the.bytecode.club.bytecodeviewer.gui.util; /*************************************************************************** * Bytecode Viewer (BCV) - Java & Android Reverse Engineering Suite * @@ -19,17 +19,13 @@ package the.bytecode.club.bytecodeviewer.gui; ***************************************************************************/ import java.awt.BorderLayout; -import java.awt.Component; import java.awt.Font; import java.awt.event.InputEvent; import java.util.Objects; import java.util.regex.Matcher; import javax.swing.JComboBox; -import javax.swing.JLabel; -import javax.swing.JList; import javax.swing.JPanel; import javax.swing.JViewport; -import javax.swing.ListCellRenderer; import javax.swing.event.CaretEvent; import javax.swing.event.CaretListener; import javax.swing.event.ChangeEvent; @@ -37,9 +33,12 @@ import javax.swing.event.ChangeListener; import org.fife.ui.rsyntaxtextarea.RSyntaxTextArea; import org.fife.ui.rtextarea.RTextScrollPane; import the.bytecode.club.bytecodeviewer.BytecodeViewer; +import the.bytecode.club.bytecodeviewer.gui.components.MethodsRenderer; +import the.bytecode.club.bytecodeviewer.gui.components.SearchableRSyntaxTextArea; +import the.bytecode.club.bytecodeviewer.gui.resourceviewer.viewer.ClassViewer; import the.bytecode.club.bytecodeviewer.util.MethodParser; -import static the.bytecode.club.bytecodeviewer.gui.TabbedPane.BLANK; +import static the.bytecode.club.bytecodeviewer.gui.resourceviewer.TabbedPane.BLANK_COLOR; /** * Allows us to run a background thread @@ -47,21 +46,40 @@ import static the.bytecode.club.bytecodeviewer.gui.TabbedPane.BLANK; * @author Konloch * @author DreamSworK */ -public abstract class PaneUpdaterThread extends Thread { +public abstract class PaneUpdaterThread implements Runnable +{ public ClassViewer viewer; - public RSyntaxTextArea panelArea; - public RTextScrollPane scrollPane; + public SearchableRSyntaxTextArea updateUpdaterTextArea; public JComboBox methodsList; - public int decompiler; - public int paneId; - + private Thread thread; + public int paneIndex; + public int decompilerViewIndex; + + public PaneUpdaterThread(int paneIndex, int decompilerViewIndex) + { + this.paneIndex = paneIndex; + this.decompilerViewIndex = decompilerViewIndex; + } + public abstract void doShit(); + + public void startNewThread() + { + thread = new Thread(this); + thread.start(); + } @Override - public void run() { + public void run() + { + if(decompilerViewIndex == 0) + return; + doShit(); + synchronizePane(); - attachCtrlMouseWheelZoom(scrollPane, panelArea); //freezes the UI for some reason + + attachCtrlMouseWheelZoom(updateUpdaterTextArea.getScrollPane(), updateUpdaterTextArea); //freezes the UI for some reason //probably cause BCV is doing dumb shit with the swing thread } @@ -89,9 +107,9 @@ public abstract class PaneUpdaterThread extends Thread { public final CaretListener caretListener = new CaretListener() { @Override public void caretUpdate(CaretEvent e) { - MethodParser methods = viewer.methods.get(paneId); + MethodParser methods = viewer.methods.get(paneIndex); if (methods != null) { - int methodLine = methods.findActiveMethod(panelArea.getCaretLineNumber()); + int methodLine = methods.findActiveMethod(updateUpdaterTextArea.getCaretLineNumber()); if (methodLine != -1) { if (BytecodeViewer.viewer.showClassMethods.isSelected()) { if (methodsList != null) { @@ -102,11 +120,11 @@ public abstract class PaneUpdaterThread extends Thread { } if (BytecodeViewer.viewer.synchronizedViewing.isSelected()) { int panes = 2; - if (viewer.panel3 != null) + if (viewer.resourceViewPanel3.panel != null) panes = 3; for (int i = 0; i < panes; i++) { - if (i != paneId) { + if (i != paneIndex) { ClassViewer.selectMethod(viewer, i, methods.getMethod(methodLine)); } } @@ -120,41 +138,41 @@ public abstract class PaneUpdaterThread extends Thread { @Override public void stateChanged(ChangeEvent e) { int panes = 2; - if (viewer.panel3 != null) + if (viewer.resourceViewPanel3.panel != null) panes = 3; if (BytecodeViewer.viewer.synchronizedViewing.isSelected()) { - if (panelArea.isShowing() && (panelArea.hasFocus() || panelArea.getMousePosition() != null)) { - int caretLine = panelArea.getCaretLineNumber(); - int maxViewLine = ClassViewer.getMaxViewLine(panelArea); - int activeViewLine = ClassViewer.getViewLine(panelArea); + if (updateUpdaterTextArea.isShowing() && (updateUpdaterTextArea.hasFocus() || updateUpdaterTextArea.getMousePosition() != null)) { + int caretLine = updateUpdaterTextArea.getCaretLineNumber(); + int maxViewLine = ClassViewer.getMaxViewLine(updateUpdaterTextArea); + int activeViewLine = ClassViewer.getViewLine(updateUpdaterTextArea); int activeLine = (activeViewLine == maxViewLine && caretLine > maxViewLine) ? caretLine : activeViewLine; int activeLineDelta = -1; MethodParser.Method activeMethod = null; - MethodParser activeMethods = viewer.methods.get(paneId); + MethodParser activeMethods = viewer.methods.get(paneIndex); if (activeMethods != null) { int activeMethodLine = activeMethods.findActiveMethod(activeLine); if (activeMethodLine != -1) { activeLineDelta = activeLine - activeMethodLine; activeMethod = activeMethods.getMethod(activeMethodLine); - ClassViewer.selectMethod(panelArea, activeMethodLine); + ClassViewer.selectMethod(updateUpdaterTextArea, activeMethodLine); } } for (int i = 0; i < panes; i++) { - if (i != paneId) { + if (i != paneIndex) { int setLine = -1; RSyntaxTextArea area = null; switch (i) { case 0: - area = viewer.t1.panelArea; + area = viewer.resourceViewPanel1.updateThread.updateUpdaterTextArea; break; case 1: - area = viewer.t2.panelArea; + area = viewer.resourceViewPanel2.updateThread.updateUpdaterTextArea; break; case 2: - area = viewer.t3.panelArea; + area = viewer.resourceViewPanel3.updateThread.updateUpdaterTextArea; break; } @@ -183,30 +201,19 @@ public abstract class PaneUpdaterThread extends Thread { } } }; - - class MethodsRenderer extends JLabel implements ListCellRenderer { - public MethodsRenderer() { - setOpaque(true); - } - - @Override - public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, - boolean cellHasFocus) { - MethodParser methods = viewer.methods.get(paneId); - MethodParser.Method method = methods.getMethod((Integer) value); - setText(method.toString()); - return this; - } - } - - public void synchronizePane() { - JViewport viewport = scrollPane.getViewport(); + + public void synchronizePane() + { + if(decompilerViewIndex == 5 || decompilerViewIndex < 0) + return; + + JViewport viewport = updateUpdaterTextArea.getScrollPane().getViewport(); viewport.addChangeListener(viewportListener); - panelArea.addCaretListener(caretListener); - - final MethodParser methods = viewer.methods.get(paneId); - for (int i = 0; i < panelArea.getLineCount(); i++) { - String lineText = ClassViewer.getLineText(panelArea, i); + updateUpdaterTextArea.addCaretListener(caretListener); + + final MethodParser methods = viewer.methods.get(paneIndex); + for (int i = 0; i < updateUpdaterTextArea.getLineCount(); i++) { + String lineText = ClassViewer.getLineText(updateUpdaterTextArea, i); Matcher regexMatcher = MethodParser.regex.matcher(lineText); if (regexMatcher.find()) { String methodName = regexMatcher.group("name"); @@ -221,21 +228,23 @@ public abstract class PaneUpdaterThread extends Thread { for (Integer line : methods.getMethodsLines()) { methodsList.addItem(line); } - methodsList.setRenderer(new PaneUpdaterThread.MethodsRenderer()); - methodsList.addActionListener(e -> { + methodsList.setRenderer(new MethodsRenderer(this)); + methodsList.addActionListener(e -> + { int line = (int) Objects.requireNonNull(methodsList.getSelectedItem()); RSyntaxTextArea area = null; - switch (paneId) { - case 0: - area = viewer.t1.panelArea; - break; - case 1: - area = viewer.t2.panelArea; - break; - case 2: - area = viewer.t3.panelArea; - break; + switch (paneIndex) + { + case 0: + area = viewer.resourceViewPanel1.updateThread.updateUpdaterTextArea; + break; + case 1: + area = viewer.resourceViewPanel2.updateThread.updateUpdaterTextArea; + break; + case 2: + area = viewer.resourceViewPanel3.updateThread.updateUpdaterTextArea; + break; } if (area != null) @@ -243,11 +252,11 @@ public abstract class PaneUpdaterThread extends Thread { }); JPanel panel = new JPanel(new BorderLayout()); - panel.add(scrollPane.getColumnHeader().getComponent(0), BorderLayout.NORTH); + panel.add(updateUpdaterTextArea.getScrollPane().getColumnHeader().getComponent(0), BorderLayout.NORTH); panel.add(methodsList, BorderLayout.SOUTH); - methodsList.setBackground(BLANK); - scrollPane.getColumnHeader().removeAll(); - scrollPane.getColumnHeader().add(panel); + methodsList.setBackground(BLANK_COLOR); + updateUpdaterTextArea.getScrollPane().getColumnHeader().removeAll(); + updateUpdaterTextArea.getScrollPane().getColumnHeader().add(panel); } } } diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/gui/extras/StringMetricsUtil.java b/src/main/java/the/bytecode/club/bytecodeviewer/gui/util/StringMetricsUtil.java similarity index 92% rename from src/main/java/the/bytecode/club/bytecodeviewer/gui/extras/StringMetricsUtil.java rename to src/main/java/the/bytecode/club/bytecodeviewer/gui/util/StringMetricsUtil.java index dd642aae..9f3177ef 100644 --- a/src/main/java/the/bytecode/club/bytecodeviewer/gui/extras/StringMetricsUtil.java +++ b/src/main/java/the/bytecode/club/bytecodeviewer/gui/util/StringMetricsUtil.java @@ -1,4 +1,4 @@ -package the.bytecode.club.bytecodeviewer.gui.extras; +package the.bytecode.club.bytecodeviewer.gui.util; import java.awt.*; import java.awt.font.FontRenderContext; diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/plugin/preinstalled/CodeSequenceDiagram.java b/src/main/java/the/bytecode/club/bytecodeviewer/plugin/preinstalled/CodeSequenceDiagram.java index 92fe26a9..e65b7719 100644 --- a/src/main/java/the/bytecode/club/bytecodeviewer/plugin/preinstalled/CodeSequenceDiagram.java +++ b/src/main/java/the/bytecode/club/bytecodeviewer/plugin/preinstalled/CodeSequenceDiagram.java @@ -15,7 +15,7 @@ import org.objectweb.asm.tree.MethodNode; import the.bytecode.club.bytecodeviewer.BytecodeViewer; import the.bytecode.club.bytecodeviewer.Resources; import the.bytecode.club.bytecodeviewer.api.Plugin; -import the.bytecode.club.bytecodeviewer.gui.ClassViewer; +import the.bytecode.club.bytecodeviewer.gui.resourceviewer.viewer.ClassViewer; import the.bytecode.club.bytecodeviewer.plugin.PluginManager; /*************************************************************************** diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/util/JTextAreaUtils.java b/src/main/java/the/bytecode/club/bytecodeviewer/util/JTextAreaUtils.java new file mode 100644 index 00000000..41b4ee6a --- /dev/null +++ b/src/main/java/the/bytecode/club/bytecodeviewer/util/JTextAreaUtils.java @@ -0,0 +1,170 @@ +package the.bytecode.club.bytecodeviewer.util; + +import javax.swing.*; +import javax.swing.text.DefaultHighlighter; +import javax.swing.text.Document; +import javax.swing.text.Highlighter; +import java.awt.*; + +/** + * This allows functionality to main the same between JTextArea and RSyntaxTextArea text panels + * + * @author Konloch + * @since 6/25/2021 + */ +public class JTextAreaUtils +{ + private static final DefaultHighlighter.DefaultHighlightPainter painter = new DefaultHighlighter.DefaultHighlightPainter(new Color(255, 62, 150)); + + /** + * This was really interesting to write. + * + * @author Konloch + */ + public static void search(JTextArea textArea, String search, boolean forwardSearchDirection, boolean caseSensitiveSearch) + { + try + { + if (search.isEmpty()) + { + highlight(textArea, "", caseSensitiveSearch); + return; + } + + int startLine = textArea.getDocument().getDefaultRootElement() + .getElementIndex(textArea.getCaretPosition()) + 1; + + int currentLine = 1; + boolean canSearch = false; + String[] test = (textArea.getText().split("\n").length >= 2 + ? textArea.getText().split("\n") + : textArea.getText().split("\r")); + + int lastGoodLine = -1; + int firstPos = -1; + boolean found = false; + + if (forwardSearchDirection) + { + for (String s : test) + { + if (!caseSensitiveSearch) + { + s = s.toLowerCase(); + search = search.toLowerCase(); + } + + if (currentLine == startLine) + { + canSearch = true; + } + else if (s.contains(search)) + { + if (canSearch) + { + textArea.setCaretPosition(textArea.getDocument() + .getDefaultRootElement() + .getElement(currentLine - 1) + .getStartOffset()); + + canSearch = false; + found = true; + } + + if (firstPos == -1) + firstPos = currentLine; + } + + currentLine++; + } + + if (!found && firstPos != -1) + { + textArea.setCaretPosition(textArea.getDocument() + .getDefaultRootElement().getElement(firstPos - 1) + .getStartOffset()); + } + } + else + { + canSearch = true; + for (String s : test) + { + if (!caseSensitiveSearch) + { + s = s.toLowerCase(); + search = search.toLowerCase(); + } + + if (s.contains(search)) + { + if (lastGoodLine != -1 && canSearch) + textArea.setCaretPosition(textArea.getDocument() + .getDefaultRootElement() + .getElement(lastGoodLine - 1) + .getStartOffset()); + + lastGoodLine = currentLine; + + if (currentLine >= startLine) + canSearch = false; + } + + currentLine++; + } + + if (lastGoodLine != -1 + && textArea.getDocument().getDefaultRootElement() + .getElementIndex(textArea.getCaretPosition()) + 1 == startLine) + { + textArea.setCaretPosition(textArea.getDocument() + .getDefaultRootElement() + .getElement(lastGoodLine - 1).getStartOffset()); + } + } + + highlight(textArea, search, caseSensitiveSearch); + } + catch (Exception e) + { + new the.bytecode.club.bytecodeviewer.api.ExceptionUI(e); + } + } + + public static void highlight(JTextArea textArea,String pattern, boolean caseSensitiveSearch) + { + if (pattern.isEmpty()) + { + textArea.getHighlighter().removeAllHighlights(); + return; + } + + try + { + Highlighter highlighter = textArea.getHighlighter(); + highlighter.removeAllHighlights(); + Document doc = textArea.getDocument(); + String text = doc.getText(0, doc.getLength()); + int pos = 0; + + if (!caseSensitiveSearch) + { + pattern = pattern.toLowerCase(); + text = text.toLowerCase(); + } + + // Search for pattern + while ((pos = text.indexOf(pattern, pos)) >= 0) + { + // Create highlighter using private painter and apply around + // pattern + highlighter.addHighlight(pos, pos + pattern.length(), painter); + pos += pattern.length(); + } + } + catch (Exception e) + { + new the.bytecode.club.bytecodeviewer.api.ExceptionUI(e); + } + } +} diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/util/MiscUtils.java b/src/main/java/the/bytecode/club/bytecodeviewer/util/MiscUtils.java index 2aa1c9d6..58e7bdbf 100644 --- a/src/main/java/the/bytecode/club/bytecodeviewer/util/MiscUtils.java +++ b/src/main/java/the/bytecode/club/bytecodeviewer/util/MiscUtils.java @@ -1,13 +1,17 @@ package the.bytecode.club.bytecodeviewer.util; +import org.apache.commons.lang3.StringUtils; import org.objectweb.asm.tree.ClassNode; -import java.io.BufferedReader; -import java.io.File; -import java.io.InputStream; -import java.io.InputStreamReader; +import javax.imageio.ImageIO; +import java.awt.*; +import java.awt.image.BufferedImage; +import java.io.*; import java.lang.reflect.Field; +import java.nio.charset.CharsetEncoder; +import java.nio.charset.StandardCharsets; import java.util.*; +import java.util.List; import static the.bytecode.club.bytecodeviewer.Constants.gson; @@ -35,7 +39,9 @@ import static the.bytecode.club.bytecodeviewer.Constants.gson; * @author Konloch */ -public class MiscUtils { +public class MiscUtils +{ + private static CharsetEncoder asciiEncoder = StandardCharsets.US_ASCII.newEncoder(); // or "ISO-8859-1" for ISO Latin 1 private static final String AB = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; private static final String AN = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; private static final Random rnd = new Random(); @@ -192,4 +198,30 @@ public class MiscUtils { field.setAccessible(true); ((Map) field.get(env)).put(name, val); } + + public static BufferedImage loadImage(BufferedImage defaultImage, byte[] contents) + { + try { + return ImageIO.read(new ByteArrayInputStream(contents)); + } catch (IOException e) { + new the.bytecode.club.bytecodeviewer.api.ExceptionUI(e); + } + + return defaultImage; + } + + public static boolean isPureAscii(String v) { + return asciiEncoder.canEncode(v); + } + + public static String getChildFromPath(String path) + { + if (path.contains("/")) + { + String[] pathParts = StringUtils.split(path, "/"); + return pathParts[pathParts.length-1]; + } + + return path; + } } diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/util/ResourceDecompiling.java b/src/main/java/the/bytecode/club/bytecodeviewer/util/ResourceDecompiling.java index dff45163..44f6cc3b 100644 --- a/src/main/java/the/bytecode/club/bytecodeviewer/util/ResourceDecompiling.java +++ b/src/main/java/the/bytecode/club/bytecodeviewer/util/ResourceDecompiling.java @@ -5,7 +5,7 @@ import org.objectweb.asm.ClassWriter; import org.objectweb.asm.tree.ClassNode; import the.bytecode.club.bytecodeviewer.BytecodeViewer; import the.bytecode.club.bytecodeviewer.api.ExceptionUI; -import the.bytecode.club.bytecodeviewer.decompilers.Decompilers; +import the.bytecode.club.bytecodeviewer.decompilers.Decompiler; import javax.swing.*; import javax.swing.filechooser.FileFilter; @@ -101,7 +101,7 @@ public class ResourceDecompiling if (result == 0) { Thread t12 = new Thread(() -> { try { - Decompilers.procyon.decompileToZip(tempZip.getAbsolutePath(), + Decompiler.PROCYON.getDecompiler().decompileToZip(tempZip.getAbsolutePath(), MiscUtils.append(javaSucks, "-proycon.zip")); BytecodeViewer.viewer.updateBusyStatus(false); } catch (Exception e) { @@ -112,7 +112,7 @@ public class ResourceDecompiling Thread t2 = new Thread(() -> { try { BytecodeViewer.viewer.updateBusyStatus(true); - Decompilers.cfr.decompileToZip(tempZip.getAbsolutePath(), + Decompiler.CFR.getDecompiler().decompileToZip(tempZip.getAbsolutePath(), MiscUtils.append(javaSucks, "-CFR.zip")); BytecodeViewer.viewer.updateBusyStatus(false); } catch (Exception e) { @@ -123,7 +123,7 @@ public class ResourceDecompiling Thread t3 = new Thread(() -> { try { BytecodeViewer.viewer.updateBusyStatus(true); - Decompilers.fernflower.decompileToZip(tempZip.getAbsolutePath(), + Decompiler.FERNFLOWER.getDecompiler().decompileToZip(tempZip.getAbsolutePath(), MiscUtils.append(javaSucks, "-fernflower.zip")); BytecodeViewer.viewer.updateBusyStatus(false); } catch (Exception e) { @@ -134,7 +134,7 @@ public class ResourceDecompiling Thread t4 = new Thread(() -> { try { BytecodeViewer.viewer.updateBusyStatus(true); - Decompilers.krakatau.decompileToZip(tempZip.getAbsolutePath(), + Decompiler.KRAKATAU.getDecompiler().decompileToZip(tempZip.getAbsolutePath(), MiscUtils.append(javaSucks, "-kraktau.zip")); BytecodeViewer.viewer.updateBusyStatus(false); } catch (Exception e) { @@ -146,7 +146,7 @@ public class ResourceDecompiling if (result == 1) { Thread t12 = new Thread(() -> { try { - Decompilers.procyon.decompileToZip(tempZip.getAbsolutePath(), path); + Decompiler.PROCYON.getDecompiler().decompileToZip(tempZip.getAbsolutePath(), path); BytecodeViewer.viewer.updateBusyStatus(false); } catch (Exception e) { new ExceptionUI(e); @@ -157,7 +157,7 @@ public class ResourceDecompiling if (result == 2) { Thread t12 = new Thread(() -> { try { - Decompilers.cfr.decompileToZip(tempZip.getAbsolutePath(), path); + Decompiler.CFR.getDecompiler().decompileToZip(tempZip.getAbsolutePath(), path); BytecodeViewer.viewer.updateBusyStatus(false); } catch (Exception e) { new ExceptionUI(e); @@ -168,7 +168,7 @@ public class ResourceDecompiling if (result == 3) { Thread t12 = new Thread(() -> { try { - Decompilers.fernflower.decompileToZip(tempZip.getAbsolutePath(), path); + Decompiler.FERNFLOWER.getDecompiler().decompileToZip(tempZip.getAbsolutePath(), path); BytecodeViewer.viewer.updateBusyStatus(false); } catch (Exception e) { new ExceptionUI(e); @@ -180,7 +180,7 @@ public class ResourceDecompiling if (result == 4) { Thread t12 = new Thread(() -> { try { - Decompilers.krakatau.decompileToZip(tempZip.getAbsolutePath(), path); + Decompiler.KRAKATAU.getDecompiler().decompileToZip(tempZip.getAbsolutePath(), path); BytecodeViewer.viewer.updateBusyStatus(false); } catch (Exception e) { new ExceptionUI(e); @@ -288,28 +288,28 @@ public class ResourceDecompiling try { DiskWriter.replaceFile(MiscUtils.append(file, "-proycon.java"), - Decompilers.procyon.decompileClassNode(cn, cw.toByteArray()), false); + Decompiler.PROCYON.getDecompiler().decompileClassNode(cn, cw.toByteArray()), false); } catch (Exception e) { e.printStackTrace(); } try { DiskWriter.replaceFile(MiscUtils.append(file, "-CFR.java"), - Decompilers.cfr.decompileClassNode(cn, cw.toByteArray()), false); + Decompiler.CFR.getDecompiler().decompileClassNode(cn, cw.toByteArray()), false); } catch (Exception e) { e.printStackTrace(); } try { DiskWriter.replaceFile(MiscUtils.append(file, "-fernflower.java"), - Decompilers.fernflower.decompileClassNode(cn, cw.toByteArray()), false); + Decompiler.FERNFLOWER.getDecompiler().decompileClassNode(cn, cw.toByteArray()), false); } catch (Exception e) { e.printStackTrace(); } try { DiskWriter.replaceFile(MiscUtils.append(file, "-kraktau.java"), - Decompilers.krakatau.decompileClassNode(cn, cw.toByteArray()), false); + Decompiler.KRAKATAU.getDecompiler().decompileClassNode(cn, cw.toByteArray()), false); } catch (Exception e) { e.printStackTrace(); } @@ -337,8 +337,7 @@ public class ResourceDecompiling } catch (InterruptedException ignored) { } } - String contents = Decompilers.procyon.decompileClassNode(cn, - cw.toByteArray()); + String contents = Decompiler.PROCYON.getDecompiler().decompileClassNode(cn, cw.toByteArray()); DiskWriter.replaceFile(path, contents, false); BytecodeViewer.viewer.updateBusyStatus(false); } catch (Exception e) { @@ -364,7 +363,7 @@ public class ResourceDecompiling } catch (InterruptedException ignored) { } } - String contents = Decompilers.cfr.decompileClassNode(cn, cw.toByteArray()); + String contents = Decompiler.CFR.getDecompiler().decompileClassNode(cn, cw.toByteArray()); DiskWriter.replaceFile(path, contents, false); BytecodeViewer.viewer.updateBusyStatus(false); } catch (Exception e) { @@ -391,7 +390,7 @@ public class ResourceDecompiling } catch (InterruptedException ignored) { } } - String contents = Decompilers.fernflower.decompileClassNode(cn, + String contents = Decompiler.FERNFLOWER.getDecompiler().decompileClassNode(cn, cw.toByteArray()); DiskWriter.replaceFile(path, contents, false); BytecodeViewer.viewer.updateBusyStatus(false); @@ -419,7 +418,7 @@ public class ResourceDecompiling } } - String contents = Decompilers.krakatau.decompileClassNode(cn, + String contents = Decompiler.KRAKATAU.getDecompiler().decompileClassNode(cn, cw.toByteArray()); DiskWriter.replaceFile(path, contents, false); BytecodeViewer.viewer.updateBusyStatus(false); diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/util/ResourceExporting.java b/src/main/java/the/bytecode/club/bytecodeviewer/util/ResourceExporting.java index 085de699..999c35f8 100644 --- a/src/main/java/the/bytecode/club/bytecodeviewer/util/ResourceExporting.java +++ b/src/main/java/the/bytecode/club/bytecodeviewer/util/ResourceExporting.java @@ -1,7 +1,7 @@ package the.bytecode.club.bytecodeviewer.util; import the.bytecode.club.bytecodeviewer.BytecodeViewer; -import the.bytecode.club.bytecodeviewer.gui.extras.ExportJar; +import the.bytecode.club.bytecodeviewer.gui.components.ExportJar; import javax.swing.*; import javax.swing.filechooser.FileFilter; diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/util/Language.java b/src/main/java/the/bytecode/club/bytecodeviewer/util/SyntaxLanguage.java similarity index 92% rename from src/main/java/the/bytecode/club/bytecodeviewer/util/Language.java rename to src/main/java/the/bytecode/club/bytecodeviewer/util/SyntaxLanguage.java index 79b78b7a..571cb9f1 100644 --- a/src/main/java/the/bytecode/club/bytecodeviewer/util/Language.java +++ b/src/main/java/the/bytecode/club/bytecodeviewer/util/SyntaxLanguage.java @@ -3,8 +3,8 @@ package the.bytecode.club.bytecodeviewer.util; import java.util.function.BiFunction; import org.fife.ui.rsyntaxtextarea.SyntaxConstants; -public enum Language { - +public enum SyntaxLanguage +{ XML(SyntaxConstants.SYNTAX_STYLE_XML, (n, c) -> n.endsWith(".xml") || c.startsWith(" n.endsWith(".py") || n.endsWith(".python")), @@ -42,13 +42,13 @@ public enum Language { TYPESCRIPT(SyntaxConstants.SYNTAX_STYLE_TYPESCRIPT, (n, c) -> n.endsWith(".ts")), NONE(SyntaxConstants.SYNTAX_STYLE_NONE, (n, c) -> false); - public static final Language[] VALUES = values(); + public static final SyntaxLanguage[] VALUES = values(); private final BiFunction criteria; private final String syntaxConstant; - Language(String syntaxConstant, BiFunction criteria) { + SyntaxLanguage(String syntaxConstant, BiFunction criteria) { this.criteria = criteria; this.syntaxConstant = syntaxConstant; } @@ -61,13 +61,12 @@ public enum Language { return syntaxConstant; } - public static Language detectLanguage(String fileName, String content) { - for (Language lang : VALUES) { + public static SyntaxLanguage detectLanguage(String fileName, String content) { + for (SyntaxLanguage lang : VALUES) { if (lang.isLanguage(fileName, content)) { return lang; } } return NONE; } - -} +} \ No newline at end of file diff --git a/src/main/resources/META-INF/MANIFEST.MF b/src/main/resources/META-INF/MANIFEST.MF deleted file mode 100644 index 919860b3..00000000 --- a/src/main/resources/META-INF/MANIFEST.MF +++ /dev/null @@ -1,3 +0,0 @@ -Manifest-Version: 1.0 -Main-Class: the.bytecode.club.bytecodeviewer.BytecodeViewer - diff --git a/src/main/resources/jar.png b/src/main/resources/jar.png index b1d0b57d9ea3b860a66f7ba0e045f3387a4eb7e1..5f9f44d4945b4e041e3202ac6f35337b8eda809d 100644 GIT binary patch literal 1943 zcmbVN3s4kg9A7dtmB$1*Fuqt9A1L1K)mJv7FqQ-Tn6ae&6r^ z`~ScH|G)2M*cOD289xSspioP?ITO4il>51n;JKvrgIw?$?MZ)Gf}pVPlsjl`eAomC z3Xb5i?Xumvkfa5-nqq_kR_%9t02+c)=K4JpUChdG0b9uN2IS^}W(4LK1CpCy#jG9^ z>*Uf)MK-I{mQ9xy(|QJ(I|okjlYqd@$`tH(yLgH88<2ip5{#8;6oLC8a)&3v=u;Rtm2J_ zG>I%F3u3k)xP}fYV@NV=GQn}V9M1?oY349EYo=t@fDjmgt1yj9gJt6hq&AV%B*bF` ziD3g!tH5xMlHpLDiqK@^8j{eG8to%ckT47-Q%?jlH0cmTHwE0~+*BcpdiX*F4g`@j z2`)hdhJiZG@Og{LlpzWZ&IJ~v%mt~iCC#M6^*W$PjrYs7T1g8p$rMks7PA2Xp;2=j zL*fn%OS2kGrPZ^z3U_E3l|E6g_?$%07*69!M8VL0vp{>51Q^=S{LlT1L=F@n<$7u! zr7V@qA=5btoN38m;bgJP2S+Xr?oSqyqLm^rAhdG&EQ1VAb59+C0a~Av1*HFx7XvU! zaL7JNWQ~O&T2IJ26i7#vVjb`T{ilQdYr_hA2oAc1G7PjS@DXTqEDySy2-?`V9YG-w z^h~_PY|Kuo+EHyO&RQJ(cJGMxeUhqg1mE7|>$2rF?4Q}au_-RcS^Q$?ndsfM`L3v1 zFEpw_YaG9J4g7J@nY9HG5t<+V*ir*W*7#5M8pA>x@@wDk>Xg2@W4NjB>YM_Zj+Up~ zU*2)AtSfvy*&H*Plyg4pJC6Dv&d;bn)8^EMeVMl-?8Jqa-q|@OZ`s4j)Y>;}b#L;G z$xv~~%uy@aiuR1`malEwu=$+&>Yb8?i@ycMEtxg$g}sxf2>STC^UXG}kC^LAJ?GV~ zI~nx-FNFBTiSq{%D>Jvgb?7Jc=o`CE*Vb25>XN^{FuS{Ff5nVb?Mtpnb&U0*7HPz0 z_mqX-kaOC$_k?C{U8C)}#Qk2gy1OH0by@hN{j;1!w}UU=ZYr93u=&BQ${+W~4F=xhPk3ON7?)p)T(ex-xQX>(ccp5y}Bv`8g)HJhH?7 S)wW~GuhWudGw)2zulO63|GE(X delta 635 zcmV->0)+jS50nLvB!2;OQb$4nuFf3k00004XF*Lt006O%3;baP00009a7bBm000id z000id0mpBsWB>pHDM>^@R5(wqkxOe+K^TVp0q)$nmi_@ZZrrn`N;d9>T@fe@@zDky9}K;CjjPH}LZ3|S>I zKXpRabu^pJfq#_CW#rzQv43X>rBVs|KU^Z~uahCGL`It(*=!c|dR>Jl(cD((b0=j@ z+cF}zFeLSU59?%=Xx91?sZ>gu`r&ExnG@>WA2aB zj?0`$CX>iyGAI^{vPM>kCQLR&A`$ruymvSpmavvGo_|8jF)w3EZZ18Cd2JJkL;|5u zNLVErpSMaem&?g+BQsWv8CG!Z?kXZa2m}K1@whAV zZs!}`?tGOv+@E{dgFhG+`10IJ?^Jepy4k63 zS-)ghhIDClQ^p>TM_45~KXDtuU{FpJjYj2~JmFzUr_<6)hO82uyK+kenx^6P_8v@6 zws3v%#i8N1