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
This commit is contained in:
parent
f1db4c2ea8
commit
cec2df4685
BIN
libs/com/bulenkov/darcula/2017.11bcv/darcula-2017.11bcv.jar
Normal file
BIN
libs/com/bulenkov/darcula/2017.11bcv/darcula-2017.11bcv.jar
Normal file
Binary file not shown.
|
@ -0,0 +1 @@
|
||||||
|
e1c0e9bdc5e1a9117385316e9953bf18
|
|
@ -0,0 +1 @@
|
||||||
|
1f1bd37eb6a58bcbeca533757b452fda2e3bf58a
|
|
@ -0,0 +1,8 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
<groupId>com.bulenkov</groupId>
|
||||||
|
<artifactId>darcula</artifactId>
|
||||||
|
<version>2017.11bcv</version>
|
||||||
|
</project>
|
|
@ -0,0 +1 @@
|
||||||
|
18d7207a865f9f1c7ac091ae2175c816
|
|
@ -0,0 +1 @@
|
||||||
|
c24c87ad97daac49a716c8b1b35de813faa14315
|
12
libs/com/bulenkov/darcula/maven-metadata.xml
Normal file
12
libs/com/bulenkov/darcula/maven-metadata.xml
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<metadata>
|
||||||
|
<groupId>com.bulenkov</groupId>
|
||||||
|
<artifactId>darcula</artifactId>
|
||||||
|
<versioning>
|
||||||
|
<release>2017.11bcv</release>
|
||||||
|
<versions>
|
||||||
|
<version>2017.11bcv</version>
|
||||||
|
</versions>
|
||||||
|
<lastUpdated>20210623081823</lastUpdated>
|
||||||
|
</versioning>
|
||||||
|
</metadata>
|
1
libs/com/bulenkov/darcula/maven-metadata.xml.md5
Normal file
1
libs/com/bulenkov/darcula/maven-metadata.xml.md5
Normal file
|
@ -0,0 +1 @@
|
||||||
|
8c77ae68030a23cf5be1ad543a810476
|
1
libs/com/bulenkov/darcula/maven-metadata.xml.sha1
Normal file
1
libs/com/bulenkov/darcula/maven-metadata.xml.sha1
Normal file
|
@ -0,0 +1 @@
|
||||||
|
890769d1a55221b9f778bfb92a8af22bfd3439df
|
29
pom.xml
29
pom.xml
|
@ -219,30 +219,15 @@
|
||||||
<artifactId>D2Jar-obf</artifactId>
|
<artifactId>D2Jar-obf</artifactId>
|
||||||
<version>1.0bcv</version>
|
<version>1.0bcv</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.bulenkov</groupId>
|
||||||
|
<artifactId>darcula</artifactId>
|
||||||
|
<version>2017.11bcv</version>
|
||||||
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
<build>
|
<build>
|
||||||
<plugins>
|
<plugins>
|
||||||
<plugin>
|
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
|
||||||
<artifactId>maven-dependency-plugin</artifactId>
|
|
||||||
<version>3.2.0</version>
|
|
||||||
<executions>
|
|
||||||
<execution>
|
|
||||||
<id>unpack</id>
|
|
||||||
<!-- In process resource phase such that it doesn't
|
|
||||||
override other dependencies or BCV's own files -->
|
|
||||||
<phase>process-resources</phase>
|
|
||||||
<goals>
|
|
||||||
<goal>unpack-dependencies</goal>
|
|
||||||
</goals>
|
|
||||||
<configuration>
|
|
||||||
<includeScope>system</includeScope>
|
|
||||||
<outputDirectory>${basedir}/target/classes</outputDirectory>
|
|
||||||
</configuration>
|
|
||||||
</execution>
|
|
||||||
</executions>
|
|
||||||
</plugin>
|
|
||||||
<plugin>
|
<plugin>
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
<artifactId>maven-jar-plugin</artifactId>
|
<artifactId>maven-jar-plugin</artifactId>
|
||||||
|
@ -268,7 +253,7 @@
|
||||||
<plugin>
|
<plugin>
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
<artifactId>maven-javadoc-plugin</artifactId>
|
<artifactId>maven-javadoc-plugin</artifactId>
|
||||||
<version>3.2.0</version>
|
<version>3.3.0</version>
|
||||||
<configuration>
|
<configuration>
|
||||||
<source>${java.version}</source>
|
<source>${java.version}</source>
|
||||||
</configuration>
|
</configuration>
|
||||||
|
@ -276,7 +261,7 @@
|
||||||
<plugin>
|
<plugin>
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
<artifactId>maven-shade-plugin</artifactId>
|
<artifactId>maven-shade-plugin</artifactId>
|
||||||
<version>3.2.2</version>
|
<version>3.2.4</version>
|
||||||
<executions>
|
<executions>
|
||||||
<execution>
|
<execution>
|
||||||
<phase>package</phase>
|
<phase>package</phase>
|
||||||
|
|
|
@ -1,3 +0,0 @@
|
||||||
Manifest-Version: 1.0
|
|
||||||
Main-Class: the.bytecode.club.bytecodeviewer.BytecodeViewer
|
|
||||||
|
|
|
@ -10,11 +10,7 @@ import java.util.ArrayList;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import javax.swing.JDialog;
|
import javax.swing.*;
|
||||||
import javax.swing.JFileChooser;
|
|
||||||
import javax.swing.JMenuItem;
|
|
||||||
import javax.swing.JOptionPane;
|
|
||||||
import javax.swing.UIManager;
|
|
||||||
import javax.swing.filechooser.FileFilter;
|
import javax.swing.filechooser.FileFilter;
|
||||||
import me.konloch.kontainer.io.DiskWriter;
|
import me.konloch.kontainer.io.DiskWriter;
|
||||||
import me.konloch.kontainer.io.HTTPRequest;
|
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.bootloader.Boot;
|
||||||
import the.bytecode.club.bytecodeviewer.api.ClassNodeLoader;
|
import the.bytecode.club.bytecodeviewer.api.ClassNodeLoader;
|
||||||
import the.bytecode.club.bytecodeviewer.compilers.Compilers;
|
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.resourcelist.ResourceListPane;
|
||||||
import the.bytecode.club.bytecodeviewer.gui.MainViewerGUI;
|
import the.bytecode.club.bytecodeviewer.gui.MainViewerGUI;
|
||||||
import the.bytecode.club.bytecodeviewer.gui.extras.RunOptions;
|
import the.bytecode.club.bytecodeviewer.gui.components.RunOptions;
|
||||||
import the.bytecode.club.bytecodeviewer.gui.SearchBoxPane;
|
import the.bytecode.club.bytecodeviewer.gui.resourcesearch.SearchBoxPane;
|
||||||
import the.bytecode.club.bytecodeviewer.gui.extras.SystemErrConsole;
|
import the.bytecode.club.bytecodeviewer.gui.components.SystemErrConsole;
|
||||||
import the.bytecode.club.bytecodeviewer.gui.WorkPane;
|
import the.bytecode.club.bytecodeviewer.gui.resourceviewer.WorkPaneMainComponent;
|
||||||
import the.bytecode.club.bytecodeviewer.obfuscators.mapping.Refactorer;
|
import the.bytecode.club.bytecodeviewer.obfuscators.mapping.Refactorer;
|
||||||
import the.bytecode.club.bytecodeviewer.plugin.PluginManager;
|
import the.bytecode.club.bytecodeviewer.plugin.PluginManager;
|
||||||
import the.bytecode.club.bytecodeviewer.util.*;
|
import the.bytecode.club.bytecodeviewer.util.*;
|
||||||
|
@ -104,6 +102,7 @@ public class BytecodeViewer
|
||||||
public static Refactorer refactorer = new Refactorer();
|
public static Refactorer refactorer = new Refactorer();
|
||||||
public static List<FileContainer> files = new ArrayList<>(); //all of BCV's loaded files/classes/etc
|
public static List<FileContainer> files = new ArrayList<>(); //all of BCV's loaded files/classes/etc
|
||||||
public static List<Process> createdProcesses = new ArrayList<>();
|
public static List<Process> createdProcesses = new ArrayList<>();
|
||||||
|
public static final DecompilerViewComponent krakatau = new DecompilerViewComponent("Krakatau", true);
|
||||||
public static final boolean EXPERIMENTAL_TAB_CODE = false;
|
public static final boolean EXPERIMENTAL_TAB_CODE = false;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -155,8 +154,9 @@ public class BytecodeViewer
|
||||||
* @throws IOException
|
* @throws IOException
|
||||||
*/
|
*/
|
||||||
public static byte[] getClassFile(Class<?> clazz) throws IOException {
|
public static byte[] getClassFile(Class<?> clazz) throws IOException {
|
||||||
InputStream is = clazz.getResourceAsStream("/" + clazz.getName().replace('.', '/') + ".class");
|
try (InputStream is = clazz.getResourceAsStream(
|
||||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
"/" + clazz.getName().replace('.', '/') + ".class");
|
||||||
|
ByteArrayOutputStream baos = new ByteArrayOutputStream()) {
|
||||||
int r;
|
int r;
|
||||||
byte[] buffer = new byte[8192];
|
byte[] buffer = new byte[8192];
|
||||||
while ((r = Objects.requireNonNull(is).read(buffer)) >= 0) {
|
while ((r = Objects.requireNonNull(is).read(buffer)) >= 0) {
|
||||||
|
@ -164,6 +164,7 @@ public class BytecodeViewer
|
||||||
}
|
}
|
||||||
return baos.toByteArray();
|
return baos.toByteArray();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Main startup
|
* Main startup
|
||||||
|
@ -176,8 +177,11 @@ public class BytecodeViewer
|
||||||
System.setSecurityManager(sm);
|
System.setSecurityManager(sm);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
UIManager.put("MenuItem.disabledAreNavigable", Boolean.FALSE);
|
//precache settings file
|
||||||
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
|
Settings.preloadSettingsFile();
|
||||||
|
//setup look and feel
|
||||||
|
Configuration.lafTheme.setLAF();
|
||||||
|
|
||||||
if (PREVIEW_COPY && !CommandLineInput.containsCommand(args))
|
if (PREVIEW_COPY && !CommandLineInput.containsCommand(args))
|
||||||
showMessage("WARNING: This is a preview/dev copy, you WON'T be alerted when " + VERSION + " is "
|
showMessage("WARNING: This is a preview/dev copy, you WON'T be alerted when " + VERSION + " is "
|
||||||
+ "actually out if you use this." + nl +
|
+ "actually out if you use this." + nl +
|
||||||
|
@ -378,28 +382,36 @@ public class BytecodeViewer
|
||||||
BytecodeViewer.viewer.updateBusyStatus(true);
|
BytecodeViewer.viewer.updateBusyStatus(true);
|
||||||
boolean actuallyTried = false;
|
boolean actuallyTried = false;
|
||||||
|
|
||||||
for (java.awt.Component c : BytecodeViewer.viewer.workPane.getLoadedViewers()) {
|
for (java.awt.Component c : BytecodeViewer.viewer.workPane.getLoadedViewers())
|
||||||
if (c instanceof ClassViewer) {
|
{
|
||||||
|
if (c instanceof ClassViewer)
|
||||||
|
{
|
||||||
ClassViewer cv = (ClassViewer) c;
|
ClassViewer cv = (ClassViewer) c;
|
||||||
if (cv.smali1 != null && cv.smali1.isEditable() ||
|
|
||||||
cv.smali2 != null && cv.smali2.isEditable() ||
|
//compile smali assembly
|
||||||
cv.smali3 != null && cv.smali3.isEditable()) {
|
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;
|
actuallyTried = true;
|
||||||
Object[] smali = cv.getSmali();
|
Object[] smali = cv.getSmali();
|
||||||
if (smali != null) {
|
if (smali != null)
|
||||||
|
{
|
||||||
ClassNode origNode = (ClassNode) smali[0];
|
ClassNode origNode = (ClassNode) smali[0];
|
||||||
String smaliText = (String) smali[1];
|
String smaliText = (String) smali[1];
|
||||||
byte[] smaliCompiled =
|
byte[] smaliCompiled = Compilers.smali.compile(smaliText, origNode.name);
|
||||||
Compilers.smali.compile(smaliText,
|
|
||||||
origNode.name);
|
if (smaliCompiled != null)
|
||||||
if (smaliCompiled != null) {
|
{
|
||||||
try {
|
try {
|
||||||
ClassNode newNode = JarUtils.getNode(smaliCompiled);
|
ClassNode newNode = JarUtils.getNode(smaliCompiled);
|
||||||
BytecodeViewer.updateNode(origNode, newNode);
|
BytecodeViewer.updateNode(origNode, newNode);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
BytecodeViewer.showMessage("There has been an error with assembling your Smali code, "
|
BytecodeViewer.showMessage("There has been an error with assembling your Smali code, "
|
||||||
+ "please check this. Class: " + origNode.name);
|
+ "please check this. Class: " + origNode.name);
|
||||||
BytecodeViewer.viewer.updateBusyStatus(false);
|
BytecodeViewer.viewer.updateBusyStatus(false);
|
||||||
|
@ -408,26 +420,30 @@ public class BytecodeViewer
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//compile krakatau assembly
|
||||||
if (cv.krakatau1 != null && cv.krakatau1.isEditable() ||
|
if (cv.resourceViewPanel1.compileMode == ResourcePanelCompileMode.KRAKATAU_ASSEMBLY && cv.resourceViewPanel1.textArea.isEditable() ||
|
||||||
cv.krakatau2 != null && cv.krakatau2.isEditable() ||
|
cv.resourceViewPanel2.compileMode == ResourcePanelCompileMode.KRAKATAU_ASSEMBLY && cv.resourceViewPanel2.textArea.isEditable() ||
|
||||||
cv.krakatau3 != null && cv.krakatau3.isEditable()) {
|
cv.resourceViewPanel3.compileMode == ResourcePanelCompileMode.KRAKATAU_ASSEMBLY && cv.resourceViewPanel3.textArea.isEditable())
|
||||||
|
{
|
||||||
actuallyTried = true;
|
actuallyTried = true;
|
||||||
Object[] krakatau = cv.getKrakatau();
|
Object[] krakatau = cv.getKrakatau();
|
||||||
if (krakatau != null) {
|
if (krakatau != null)
|
||||||
|
{
|
||||||
ClassNode origNode = (ClassNode) krakatau[0];
|
ClassNode origNode = (ClassNode) krakatau[0];
|
||||||
String krakatauText = (String) krakatau[1];
|
String krakatauText = (String) krakatau[1];
|
||||||
byte[] krakatauCompiled =
|
byte[] krakatauCompiled = Compilers.krakatau.compile(krakatauText, origNode.name);
|
||||||
Compilers.krakatau.compile(krakatauText,
|
|
||||||
origNode.name);
|
if (krakatauCompiled != null)
|
||||||
if (krakatauCompiled != null) {
|
{
|
||||||
try {
|
try {
|
||||||
ClassNode newNode = JarUtils.getNode(krakatauCompiled);
|
ClassNode newNode = JarUtils.getNode(krakatauCompiled);
|
||||||
BytecodeViewer.updateNode(origNode, newNode);
|
BytecodeViewer.updateNode(origNode, newNode);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
BytecodeViewer.showMessage("There has been an error with assembling your Krakatau "
|
BytecodeViewer.showMessage("There has been an error with assembling your Krakatau "
|
||||||
+ "Bytecode, please check this. Class: " + origNode.name);
|
+ "Bytecode, please check this. Class: " + origNode.name);
|
||||||
BytecodeViewer.viewer.updateBusyStatus(false);
|
BytecodeViewer.viewer.updateBusyStatus(false);
|
||||||
|
@ -436,9 +452,11 @@ public class BytecodeViewer
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cv.java1 != null && cv.java1.isEditable() ||
|
//default to java compiling
|
||||||
cv.java2 != null && cv.java2.isEditable() ||
|
if (cv.resourceViewPanel1.textArea != null && cv.resourceViewPanel1.textArea.isEditable() ||
|
||||||
cv.java3 != null && cv.java3.isEditable()) {
|
cv.resourceViewPanel2.textArea != null && cv.resourceViewPanel2.textArea.isEditable() ||
|
||||||
|
cv.resourceViewPanel3.textArea != null && cv.resourceViewPanel3.textArea.isEditable())
|
||||||
|
{
|
||||||
actuallyTried = true;
|
actuallyTried = true;
|
||||||
Object[] java = cv.getJava();
|
Object[] java = cv.getJava();
|
||||||
if (java != null) {
|
if (java != null) {
|
||||||
|
@ -449,10 +467,9 @@ public class BytecodeViewer
|
||||||
errConsole.setText("Error compiling class: " + origNode.name + nl + "Keep in mind most "
|
errConsole.setText("Error compiling class: " + origNode.name + nl + "Keep in mind most "
|
||||||
+ "decompilers cannot produce compilable classes" + nl + nl);
|
+ "decompilers cannot produce compilable classes" + nl + nl);
|
||||||
|
|
||||||
byte[] javaCompiled =
|
byte[] javaCompiled = Compilers.java.compile(javaText, origNode.name);
|
||||||
Compilers.java.compile(javaText,
|
if (javaCompiled != null)
|
||||||
origNode.name);
|
{
|
||||||
if (javaCompiled != null) {
|
|
||||||
try {
|
try {
|
||||||
ClassNode newNode = JarUtils.getNode(javaCompiled);
|
ClassNode newNode = JarUtils.getNode(javaCompiled);
|
||||||
BytecodeViewer.updateNode(origNode, newNode);
|
BytecodeViewer.updateNode(origNode, newNode);
|
||||||
|
@ -460,7 +477,9 @@ public class BytecodeViewer
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
errConsole.finished();
|
errConsole.finished();
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
errConsole.pretty();
|
errConsole.pretty();
|
||||||
errConsole.setVisible(true);
|
errConsole.setVisible(true);
|
||||||
errConsole.finished();
|
errConsole.finished();
|
||||||
|
@ -554,7 +573,7 @@ public class BytecodeViewer
|
||||||
files.clear();
|
files.clear();
|
||||||
LazyNameUtil.reset();
|
LazyNameUtil.reset();
|
||||||
Objects.requireNonNull(MainViewerGUI.getComponent(ResourceListPane.class)).resetWorkspace();
|
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();
|
Objects.requireNonNull(MainViewerGUI.getComponent(SearchBoxPane.class)).resetWorkspace();
|
||||||
the.bytecode.club.bytecodeviewer.api.BytecodeViewer.getClassNodeLoader().clear();
|
the.bytecode.club.bytecodeviewer.api.BytecodeViewer.getClassNodeLoader().clear();
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,7 +8,7 @@ import org.apache.commons.cli.DefaultParser;
|
||||||
import org.apache.commons.cli.Options;
|
import org.apache.commons.cli.Options;
|
||||||
import org.objectweb.asm.ClassWriter;
|
import org.objectweb.asm.ClassWriter;
|
||||||
import org.objectweb.asm.tree.ClassNode;
|
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.JarUtils;
|
||||||
import the.bytecode.club.bytecodeviewer.util.MiscUtils;
|
import the.bytecode.club.bytecodeviewer.util.MiscUtils;
|
||||||
|
|
||||||
|
@ -200,12 +200,12 @@ public class CommandLineInput {
|
||||||
Thread.sleep(5 * 1000);
|
Thread.sleep(5 * 1000);
|
||||||
|
|
||||||
if (target.equalsIgnoreCase("all")) {
|
if (target.equalsIgnoreCase("all")) {
|
||||||
Decompilers.procyon.decompileToZip(tempZip.getAbsolutePath(), output.getAbsolutePath());
|
Decompiler.PROCYON.getDecompiler().decompileToZip(tempZip.getAbsolutePath(), output.getAbsolutePath());
|
||||||
} else {
|
} else {
|
||||||
try {
|
try {
|
||||||
ClassNode cn = BytecodeViewer.getClassNode(target);
|
ClassNode cn = BytecodeViewer.getClassNode(target);
|
||||||
final ClassWriter cw = accept(cn);
|
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);
|
DiskWriter.replaceFile(output.getAbsolutePath(), contents, false);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
new the.bytecode.club.bytecodeviewer.api.ExceptionUI(e);
|
new the.bytecode.club.bytecodeviewer.api.ExceptionUI(e);
|
||||||
|
@ -218,12 +218,12 @@ public class CommandLineInput {
|
||||||
Thread.sleep(5 * 1000);
|
Thread.sleep(5 * 1000);
|
||||||
|
|
||||||
if (target.equalsIgnoreCase("all")) {
|
if (target.equalsIgnoreCase("all")) {
|
||||||
Decompilers.cfr.decompileToZip(tempZip.getAbsolutePath(), output.getAbsolutePath());
|
Decompiler.CFR.getDecompiler().decompileToZip(tempZip.getAbsolutePath(), output.getAbsolutePath());
|
||||||
} else {
|
} else {
|
||||||
try {
|
try {
|
||||||
ClassNode cn = BytecodeViewer.getClassNode(target);
|
ClassNode cn = BytecodeViewer.getClassNode(target);
|
||||||
final ClassWriter cw = accept(cn);
|
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);
|
DiskWriter.replaceFile(output.getAbsolutePath(), contents, false);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
new the.bytecode.club.bytecodeviewer.api.ExceptionUI(e);
|
new the.bytecode.club.bytecodeviewer.api.ExceptionUI(e);
|
||||||
|
@ -236,12 +236,12 @@ public class CommandLineInput {
|
||||||
Thread.sleep(5 * 1000);
|
Thread.sleep(5 * 1000);
|
||||||
|
|
||||||
if (target.equalsIgnoreCase("all")) {
|
if (target.equalsIgnoreCase("all")) {
|
||||||
Decompilers.fernflower.decompileToZip(tempZip.getAbsolutePath(), output.getAbsolutePath());
|
Decompiler.FERNFLOWER.getDecompiler().decompileToZip(tempZip.getAbsolutePath(), output.getAbsolutePath());
|
||||||
} else {
|
} else {
|
||||||
try {
|
try {
|
||||||
ClassNode cn = BytecodeViewer.getClassNode(target);
|
ClassNode cn = BytecodeViewer.getClassNode(target);
|
||||||
final ClassWriter cw = accept(cn);
|
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);
|
DiskWriter.replaceFile(output.getAbsolutePath(), contents, false);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
new the.bytecode.club.bytecodeviewer.api.ExceptionUI(e);
|
new the.bytecode.club.bytecodeviewer.api.ExceptionUI(e);
|
||||||
|
@ -254,12 +254,12 @@ public class CommandLineInput {
|
||||||
Thread.sleep(5 * 1000);
|
Thread.sleep(5 * 1000);
|
||||||
|
|
||||||
if (target.equalsIgnoreCase("all")) {
|
if (target.equalsIgnoreCase("all")) {
|
||||||
Decompilers.krakatau.decompileToZip(tempZip.getAbsolutePath(), output.getAbsolutePath());
|
Decompiler.KRAKATAU.getDecompiler().decompileToZip(tempZip.getAbsolutePath(), output.getAbsolutePath());
|
||||||
} else {
|
} else {
|
||||||
try {
|
try {
|
||||||
ClassNode cn = BytecodeViewer.getClassNode(target);
|
ClassNode cn = BytecodeViewer.getClassNode(target);
|
||||||
final ClassWriter cw = accept(cn);
|
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);
|
DiskWriter.replaceFile(output.getAbsolutePath(), contents, false);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
new the.bytecode.club.bytecodeviewer.api.ExceptionUI(e);
|
new the.bytecode.club.bytecodeviewer.api.ExceptionUI(e);
|
||||||
|
@ -278,7 +278,7 @@ public class CommandLineInput {
|
||||||
try {
|
try {
|
||||||
ClassNode cn = BytecodeViewer.getClassNode(target);
|
ClassNode cn = BytecodeViewer.getClassNode(target);
|
||||||
final ClassWriter cw = accept(cn);
|
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);
|
DiskWriter.replaceFile(output.getAbsolutePath(), contents, false);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
new the.bytecode.club.bytecodeviewer.api.ExceptionUI(e);
|
new the.bytecode.club.bytecodeviewer.api.ExceptionUI(e);
|
||||||
|
@ -297,7 +297,7 @@ public class CommandLineInput {
|
||||||
try {
|
try {
|
||||||
ClassNode cn = BytecodeViewer.getClassNode(target);
|
ClassNode cn = BytecodeViewer.getClassNode(target);
|
||||||
final ClassWriter cw = accept(cn);
|
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);
|
DiskWriter.replaceFile(output.getAbsolutePath(), contents, false);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
new the.bytecode.club.bytecodeviewer.api.ExceptionUI(e);
|
new the.bytecode.club.bytecodeviewer.api.ExceptionUI(e);
|
||||||
|
@ -316,7 +316,26 @@ public class CommandLineInput {
|
||||||
try {
|
try {
|
||||||
ClassNode cn = BytecodeViewer.getClassNode(target);
|
ClassNode cn = BytecodeViewer.getClassNode(target);
|
||||||
final ClassWriter cw = accept(cn);
|
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);
|
DiskWriter.replaceFile(output.getAbsolutePath(), contents, false);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
new the.bytecode.club.bytecodeviewer.api.ExceptionUI(e);
|
new the.bytecode.club.bytecodeviewer.api.ExceptionUI(e);
|
||||||
|
|
|
@ -1,8 +1,13 @@
|
||||||
package the.bytecode.club.bytecodeviewer;
|
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;
|
import java.io.File;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* A collection of variables that can be configured through the settings menu or some form of UI/plugin
|
||||||
|
*
|
||||||
* @author Konloch
|
* @author Konloch
|
||||||
* @since 6/21/2021
|
* @since 6/21/2021
|
||||||
*/
|
*/
|
||||||
|
@ -17,6 +22,7 @@ public class Configuration
|
||||||
public static File krakatauTempDir;
|
public static File krakatauTempDir;
|
||||||
public static File krakatauTempJar;
|
public static File krakatauTempJar;
|
||||||
public static boolean displayParentInTab = false; //also change in the main GUI
|
public static boolean displayParentInTab = false; //also change in the main GUI
|
||||||
|
public static boolean simplifiedTabNames = false;
|
||||||
public static boolean currentlyDumping = false;
|
public static boolean currentlyDumping = false;
|
||||||
public static boolean needsReDump = true;
|
public static boolean needsReDump = true;
|
||||||
public static boolean warnForEditing = false;
|
public static boolean warnForEditing = false;
|
||||||
|
@ -30,4 +36,7 @@ public class Configuration
|
||||||
public static boolean verifyCorruptedStateOnBoot = false; //eventually may be a setting
|
public static boolean verifyCorruptedStateOnBoot = false; //eventually may be a setting
|
||||||
|
|
||||||
public static long lastHotKeyExecuted = System.currentTimeMillis();
|
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();
|
||||||
}
|
}
|
|
@ -10,6 +10,9 @@ import java.util.ArrayList;
|
||||||
import java.util.List;
|
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
|
* @author Konloch
|
||||||
* @since 6/21/2021
|
* @since 6/21/2021
|
||||||
*/
|
*/
|
||||||
|
|
File diff suppressed because one or more lines are too long
|
@ -3,6 +3,8 @@ package the.bytecode.club.bytecodeviewer;
|
||||||
import javax.swing.JFrame;
|
import javax.swing.JFrame;
|
||||||
import me.konloch.kontainer.io.DiskReader;
|
import me.konloch.kontainer.io.DiskReader;
|
||||||
import me.konloch.kontainer.io.DiskWriter;
|
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.*;
|
import static the.bytecode.club.bytecodeviewer.Constants.*;
|
||||||
|
|
||||||
|
@ -291,23 +293,48 @@ public class Settings {
|
||||||
String.valueOf(BytecodeViewer.viewer.ren.isSelected()), false);
|
String.valueOf(BytecodeViewer.viewer.ren.isSelected()), false);
|
||||||
DiskWriter.writeNewLine(settingsName,
|
DiskWriter.writeNewLine(settingsName,
|
||||||
String.valueOf(BytecodeViewer.viewer.viewPane1.getJADX().getEditable().isSelected()), false);
|
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) {
|
} catch (Exception e) {
|
||||||
new the.bytecode.club.bytecodeviewer.api.ExceptionUI(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.
|
public static void loadSettings() { //utilizes the Disk Reader's caching system.
|
||||||
try {
|
try {
|
||||||
BytecodeViewer.viewer.rbr.setSelected(Boolean.parseBoolean(DiskReader.loadString(settingsName, 1, true)));
|
//parse the cached file from memory
|
||||||
BytecodeViewer.viewer.rsy.setSelected(Boolean.parseBoolean(DiskReader.loadString(settingsName, 2, false)));
|
BytecodeViewer.viewer.rbr.setSelected(asBoolean(1));
|
||||||
BytecodeViewer.viewer.din.setSelected(Boolean.parseBoolean(DiskReader.loadString(settingsName, 3, false)));
|
BytecodeViewer.viewer.rsy.setSelected(asBoolean(2));
|
||||||
BytecodeViewer.viewer.dc4.setSelected(Boolean.parseBoolean(DiskReader.loadString(settingsName, 4, false)));
|
BytecodeViewer.viewer.din.setSelected(asBoolean(3));
|
||||||
BytecodeViewer.viewer.das.setSelected(Boolean.parseBoolean(DiskReader.loadString(settingsName, 5, false)));
|
BytecodeViewer.viewer.dc4.setSelected(asBoolean(4));
|
||||||
BytecodeViewer.viewer.hes.setSelected(Boolean.parseBoolean(DiskReader.loadString(settingsName, 6, false)));
|
BytecodeViewer.viewer.das.setSelected(asBoolean(5));
|
||||||
BytecodeViewer.viewer.hdc.setSelected(Boolean.parseBoolean(DiskReader.loadString(settingsName, 7, false)));
|
BytecodeViewer.viewer.hes.setSelected(asBoolean(6));
|
||||||
BytecodeViewer.viewer.dgs.setSelected(Boolean.parseBoolean(DiskReader.loadString(settingsName, 8, false)));
|
BytecodeViewer.viewer.hdc.setSelected(asBoolean(7));
|
||||||
BytecodeViewer.viewer.ner.setSelected(Boolean.parseBoolean(DiskReader.loadString(settingsName, 9, false)));
|
BytecodeViewer.viewer.dgs.setSelected(asBoolean(8));
|
||||||
BytecodeViewer.viewer.den.setSelected(Boolean.parseBoolean(DiskReader.loadString(settingsName, 10, false)));
|
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.rgn.setSelected(Boolean.parseBoolean(DiskReader.loadString(settingsName, 11, false)));
|
||||||
BytecodeViewer.viewer.bto.setSelected(Boolean.parseBoolean(DiskReader.loadString(settingsName, 12, false)));
|
BytecodeViewer.viewer.bto.setSelected(Boolean.parseBoolean(DiskReader.loadString(settingsName, 12, false)));
|
||||||
BytecodeViewer.viewer.nns.setSelected(Boolean.parseBoolean(DiskReader.loadString(settingsName, 13, 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)));
|
BytecodeViewer.viewer.debugHelpers.setSelected(Boolean.parseBoolean(DiskReader.loadString(settingsName, 78, false)));
|
||||||
//79 is deprecated
|
//79 is deprecated
|
||||||
BytecodeViewer.viewer.updateCheck.setSelected(Boolean.parseBoolean(DiskReader.loadString(settingsName, 80, false)));
|
BytecodeViewer.viewer.updateCheck.setSelected(Boolean.parseBoolean(DiskReader.loadString(settingsName, 80, false)));
|
||||||
BytecodeViewer.viewer.viewPane1.setSelectedViewer(getInt(81));
|
BytecodeViewer.viewer.viewPane1.setSelectedViewer(asInt(81));
|
||||||
BytecodeViewer.viewer.viewPane2.setSelectedViewer(getInt(82));
|
BytecodeViewer.viewer.viewPane2.setSelectedViewer(asInt(82));
|
||||||
BytecodeViewer.viewer.viewPane3.setSelectedViewer(getInt(83));
|
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) {
|
if (bool) {
|
||||||
BytecodeViewer.viewer.setExtendedState(JFrame.MAXIMIZED_BOTH);
|
BytecodeViewer.viewer.setExtendedState(JFrame.MAXIMIZED_BOTH);
|
||||||
BytecodeViewer.viewer.isMaximized = true;
|
BytecodeViewer.viewer.isMaximized = true;
|
||||||
}
|
}
|
||||||
//86 is deprecated
|
//86 is deprecated
|
||||||
//87 is deprecated
|
//87 is deprecated
|
||||||
Configuration.lastDirectory = DiskReader.loadString(settingsName, 88, false);
|
Configuration.lastDirectory = asString(88);
|
||||||
Configuration.python = DiskReader.loadString(settingsName, 89, false);
|
Configuration.python = asString(89);
|
||||||
Configuration.rt = DiskReader.loadString(settingsName, 90, false);
|
Configuration.rt = asString(90);
|
||||||
BytecodeViewer.viewer.viewPane1.getProcyon().getEditable().setSelected(Boolean.parseBoolean(DiskReader.loadString(settingsName, 91, false)));
|
BytecodeViewer.viewer.viewPane1.getProcyon().getEditable().setSelected(asBoolean(91));
|
||||||
BytecodeViewer.viewer.viewPane1.getCFR().getEditable().setSelected(Boolean.parseBoolean(DiskReader.loadString(settingsName, 92, false)));
|
BytecodeViewer.viewer.viewPane1.getCFR().getEditable().setSelected(asBoolean(92));
|
||||||
BytecodeViewer.viewer.viewPane1.getFern().getEditable().setSelected(Boolean.parseBoolean(DiskReader.loadString(settingsName, 93, false)));
|
BytecodeViewer.viewer.viewPane1.getFern().getEditable().setSelected(asBoolean(93));
|
||||||
BytecodeViewer.viewer.viewPane1.getKrakatau().getEditable().setSelected(Boolean.parseBoolean(DiskReader.loadString(settingsName, 94, false)));
|
BytecodeViewer.viewer.viewPane1.getKrakatau().getEditable().setSelected(asBoolean(94));
|
||||||
BytecodeViewer.viewer.viewPane1.getSmali().getEditable().setSelected(Boolean.parseBoolean(DiskReader.loadString(settingsName, 95, false)));
|
BytecodeViewer.viewer.viewPane1.getSmali().getEditable().setSelected(asBoolean(95));
|
||||||
BytecodeViewer.viewer.viewPane2.getProcyon().getEditable().setSelected(Boolean.parseBoolean(DiskReader.loadString(settingsName, 96, false)));
|
BytecodeViewer.viewer.viewPane2.getProcyon().getEditable().setSelected(asBoolean(96));
|
||||||
BytecodeViewer.viewer.viewPane2.getCFR().getEditable().setSelected(Boolean.parseBoolean(DiskReader.loadString(settingsName, 97, false)));
|
BytecodeViewer.viewer.viewPane2.getCFR().getEditable().setSelected(asBoolean(97));
|
||||||
BytecodeViewer.viewer.viewPane2.getFern().getEditable().setSelected(Boolean.parseBoolean(DiskReader.loadString(settingsName, 98, false)));
|
BytecodeViewer.viewer.viewPane2.getFern().getEditable().setSelected(asBoolean(98));
|
||||||
BytecodeViewer.viewer.viewPane2.getKrakatau().getEditable().setSelected(asBoolean(99));
|
BytecodeViewer.viewer.viewPane2.getKrakatau().getEditable().setSelected(asBoolean(99));
|
||||||
BytecodeViewer.viewer.viewPane2.getSmali().getEditable().setSelected(asBoolean(100));
|
BytecodeViewer.viewer.viewPane2.getSmali().getEditable().setSelected(asBoolean(100));
|
||||||
BytecodeViewer.viewer.viewPane3.getProcyon().getEditable().setSelected(asBoolean(101));
|
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.getKrakatau().getEditable().setSelected(asBoolean(104));
|
||||||
BytecodeViewer.viewer.viewPane3.getSmali().getEditable().setSelected(asBoolean(105));
|
BytecodeViewer.viewer.viewPane3.getSmali().getEditable().setSelected(asBoolean(105));
|
||||||
BytecodeViewer.viewer.decodeAPKResources.setSelected(asBoolean(106));
|
BytecodeViewer.viewer.decodeAPKResources.setSelected(asBoolean(106));
|
||||||
Configuration.library = DiskReader.loadString(settingsName, 107, false);
|
Configuration.library = asString(107);
|
||||||
Configuration.pingback = asBoolean(108);
|
Configuration.pingback = asBoolean(108);
|
||||||
BytecodeViewer.viewer.viewPane1.getJD().getEditable().setSelected(asBoolean(109));
|
BytecodeViewer.viewer.viewPane1.getJD().getEditable().setSelected(asBoolean(109));
|
||||||
BytecodeViewer.viewer.viewPane2.getJD().getEditable().setSelected(asBoolean(110));
|
BytecodeViewer.viewer.viewPane2.getJD().getEditable().setSelected(asBoolean(110));
|
||||||
BytecodeViewer.viewer.viewPane3.getJD().getEditable().setSelected(asBoolean(111));
|
BytecodeViewer.viewer.viewPane3.getJD().getEditable().setSelected(asBoolean(111));
|
||||||
BytecodeViewer.viewer.fontSpinner.setValue(getInt(112));
|
BytecodeViewer.viewer.fontSpinner.setValue(asInt(112));
|
||||||
Configuration.deleteForeignLibraries = asBoolean(113);
|
Configuration.deleteForeignLibraries = asBoolean(113);
|
||||||
int apkDecompiler = getInt(114);
|
|
||||||
|
|
||||||
if (apkDecompiler == 0)
|
//APK Decompiler
|
||||||
|
switch(asInt(114))
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
BytecodeViewer.viewer.apkConversionGroup.setSelected(BytecodeViewer.viewer.apkConversionDex.getModel(), true);
|
BytecodeViewer.viewer.apkConversionGroup.setSelected(BytecodeViewer.viewer.apkConversionDex.getModel(), true);
|
||||||
else if (apkDecompiler == 1)
|
break;
|
||||||
|
case 1:
|
||||||
BytecodeViewer.viewer.apkConversionGroup.setSelected(BytecodeViewer.viewer.apkConversionEnjarify.getModel(), true);
|
BytecodeViewer.viewer.apkConversionGroup.setSelected(BytecodeViewer.viewer.apkConversionEnjarify.getModel(), true);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
Configuration.python3 = DiskReader.loadString(settingsName, 115, false);
|
Configuration.python3 = asString(115);
|
||||||
Configuration.javac = DiskReader.loadString(settingsName, 116, false);
|
Configuration.javac = asString(116);
|
||||||
Configuration.java = DiskReader.loadString(settingsName, 117, false);
|
Configuration.java = asString(117);
|
||||||
BytecodeViewer.viewer.compileOnSave.setSelected(asBoolean(118));
|
BytecodeViewer.viewer.compileOnSave.setSelected(asBoolean(118));
|
||||||
BytecodeViewer.viewer.autoCompileOnRefresh.setSelected(asBoolean(119));
|
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));
|
BytecodeViewer.viewer.showFileInTabTitle.setSelected(asBoolean(121));
|
||||||
Configuration.displayParentInTab = BytecodeViewer.viewer.showFileInTabTitle.isSelected();
|
Configuration.displayParentInTab = BytecodeViewer.viewer.showFileInTabTitle.isSelected();
|
||||||
BytecodeViewer.viewer.forcePureAsciiAsText.setSelected(asBoolean(122));
|
BytecodeViewer.viewer.forcePureAsciiAsText.setSelected(asBoolean(122));
|
||||||
|
@ -437,18 +469,27 @@ public class Settings {
|
||||||
BytecodeViewer.viewer.showClassMethods.setSelected(asBoolean(124));
|
BytecodeViewer.viewer.showClassMethods.setSelected(asBoolean(124));
|
||||||
BytecodeViewer.viewer.ren.setSelected(asBoolean(125));
|
BytecodeViewer.viewer.ren.setSelected(asBoolean(125));
|
||||||
BytecodeViewer.viewer.viewPane1.getJADX().getEditable().setSelected(asBoolean(126));
|
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) {
|
} catch (Exception e) {
|
||||||
//ignore because errors are expected, first start up and outdated settings.
|
//ignore because errors are expected, first start up and outdated settings.
|
||||||
//e.printStackTrace();
|
//e.printStackTrace();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static String asString(int lineNumber) throws Exception
|
||||||
|
{
|
||||||
|
return DiskReader.loadString(settingsName, lineNumber, false);
|
||||||
|
}
|
||||||
|
|
||||||
public static boolean asBoolean(int lineNumber) throws Exception
|
public static boolean asBoolean(int lineNumber) throws Exception
|
||||||
{
|
{
|
||||||
return Boolean.parseBoolean(DiskReader.loadString(settingsName, lineNumber, false));
|
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));
|
return Integer.parseInt(DiskReader.loadString(settingsName, lineNumber, false));
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,10 +10,11 @@ import java.util.jar.JarEntry;
|
||||||
import java.util.jar.JarFile;
|
import java.util.jar.JarFile;
|
||||||
import org.objectweb.asm.tree.ClassNode;
|
import org.objectweb.asm.tree.ClassNode;
|
||||||
import the.bytecode.club.bytecodeviewer.compilers.Compilers;
|
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.Decompiler;
|
||||||
import the.bytecode.club.bytecodeviewer.decompilers.Decompilers;
|
|
||||||
import the.bytecode.club.bytecodeviewer.plugin.preinstalled.EZInjection;
|
import the.bytecode.club.bytecodeviewer.plugin.preinstalled.EZInjection;
|
||||||
import the.bytecode.club.bytecodeviewer.util.JarUtils;
|
import the.bytecode.club.bytecodeviewer.util.JarUtils;
|
||||||
|
import the.bytecode.club.bytecodeviewer.util.MiscUtils;
|
||||||
|
|
||||||
import static the.bytecode.club.bytecodeviewer.Constants.*;
|
import static the.bytecode.club.bytecodeviewer.Constants.*;
|
||||||
|
|
||||||
|
@ -41,7 +42,6 @@ import static the.bytecode.club.bytecodeviewer.Constants.*;
|
||||||
*
|
*
|
||||||
* @author Konloch
|
* @author Konloch
|
||||||
*/
|
*/
|
||||||
|
|
||||||
public class BytecodeViewer {
|
public class BytecodeViewer {
|
||||||
|
|
||||||
private static URLClassLoader cl;
|
private static URLClassLoader cl;
|
||||||
|
@ -72,7 +72,7 @@ public class BytecodeViewer {
|
||||||
*/
|
*/
|
||||||
public static List<Class<?>> loadClassesIntoClassLoader() {
|
public static List<Class<?>> loadClassesIntoClassLoader() {
|
||||||
try {
|
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());
|
JarUtils.saveAsJar(BytecodeViewer.getLoadedClasses(), f.getAbsolutePath());
|
||||||
JarFile jarFile = new JarFile("" + f.getAbsolutePath());
|
JarFile jarFile = new JarFile("" + f.getAbsolutePath());
|
||||||
Enumeration<JarEntry> e = jarFile.entries();
|
Enumeration<JarEntry> e = jarFile.entries();
|
||||||
|
@ -201,8 +201,8 @@ public class BytecodeViewer {
|
||||||
*
|
*
|
||||||
* @return The wrapped Krakatau Decompiler instance
|
* @return The wrapped Krakatau Decompiler instance
|
||||||
*/
|
*/
|
||||||
public static Decompiler getKrakatauDecompiler() {
|
public static InternalDecompiler getKrakatauDecompiler() {
|
||||||
return Decompilers.krakatau;
|
return Decompiler.KRAKATAU.getDecompiler();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -210,8 +210,8 @@ public class BytecodeViewer {
|
||||||
*
|
*
|
||||||
* @return The wrapped Procyon Decompiler instance
|
* @return The wrapped Procyon Decompiler instance
|
||||||
*/
|
*/
|
||||||
public static Decompiler getProcyonDecompiler() {
|
public static InternalDecompiler getProcyonDecompiler() {
|
||||||
return Decompilers.procyon;
|
return Decompiler.PROCYON.getDecompiler();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -219,8 +219,8 @@ public class BytecodeViewer {
|
||||||
*
|
*
|
||||||
* @return The wrapped CFR Decompiler instance
|
* @return The wrapped CFR Decompiler instance
|
||||||
*/
|
*/
|
||||||
public static Decompiler getCFRDecompiler() {
|
public static InternalDecompiler getCFRDecompiler() {
|
||||||
return Decompilers.cfr;
|
return Decompiler.CFR.getDecompiler();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -228,8 +228,8 @@ public class BytecodeViewer {
|
||||||
*
|
*
|
||||||
* @return The wrapped FernFlower Decompiler instance
|
* @return The wrapped FernFlower Decompiler instance
|
||||||
*/
|
*/
|
||||||
public static Decompiler getFernFlowerDecompiler() {
|
public static InternalDecompiler getFernFlowerDecompiler() {
|
||||||
return Decompilers.fernflower;
|
return Decompiler.FERNFLOWER.getDecompiler();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -237,8 +237,26 @@ public class BytecodeViewer {
|
||||||
*
|
*
|
||||||
* @return The wrapped Krakatau Disassembler instance
|
* @return The wrapped Krakatau Disassembler instance
|
||||||
*/
|
*/
|
||||||
public static Decompiler getKrakatauDisassembler() {
|
public static InternalDecompiler getKrakatauDisassembler() {
|
||||||
return Decompilers.krakatauDA;
|
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() {
|
public static the.bytecode.club.bytecodeviewer.compilers.Compiler getSmaliCompiler() {
|
||||||
return Compilers.smali;
|
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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
package the.bytecode.club.bytecodeviewer.api;
|
package the.bytecode.club.bytecodeviewer.api;
|
||||||
|
|
||||||
import java.awt.BorderLayout;
|
import java.awt.BorderLayout;
|
||||||
import java.awt.Color;
|
|
||||||
import java.awt.Dimension;
|
import java.awt.Dimension;
|
||||||
import java.awt.event.KeyEvent;
|
import java.awt.event.KeyEvent;
|
||||||
import java.awt.event.KeyListener;
|
import java.awt.event.KeyListener;
|
||||||
|
@ -10,13 +9,14 @@ import javax.swing.JCheckBox;
|
||||||
import javax.swing.JFrame;
|
import javax.swing.JFrame;
|
||||||
import javax.swing.JPanel;
|
import javax.swing.JPanel;
|
||||||
import javax.swing.JScrollPane;
|
import javax.swing.JScrollPane;
|
||||||
import javax.swing.JTextArea;
|
|
||||||
import javax.swing.JTextField;
|
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.BytecodeViewer;
|
||||||
import the.bytecode.club.bytecodeviewer.Resources;
|
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 *
|
* Bytecode Viewer (BCV) - Java & Android Reverse Engineering Suite *
|
||||||
|
@ -42,219 +42,11 @@ import the.bytecode.club.bytecodeviewer.Resources;
|
||||||
* @author Konloch
|
* @author Konloch
|
||||||
*/
|
*/
|
||||||
|
|
||||||
public class PluginConsole extends JFrame {
|
public class PluginConsole extends JFrameConsole
|
||||||
|
{
|
||||||
JTextArea textArea = new JTextArea();
|
public PluginConsole(String pluginName)
|
||||||
JPanel panel = new JPanel(new BorderLayout());
|
{
|
||||||
JScrollPane scrollPane = new JScrollPane();
|
super("Bytecode Viewer - Plugin Console - " + pluginName);
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final long serialVersionUID = -6556940545421437508L;
|
private static final long serialVersionUID = -6556940545421437508L;
|
||||||
|
|
|
@ -29,7 +29,8 @@ import org.objectweb.asm.util.TraceClassVisitor;
|
||||||
*
|
*
|
||||||
* @author Thiakil
|
* @author Thiakil
|
||||||
*/
|
*/
|
||||||
public class ASMTextifierDecompiler extends Decompiler {
|
public class ASMTextifierDecompiler extends InternalDecompiler
|
||||||
|
{
|
||||||
@Override
|
@Override
|
||||||
public String decompileClassNode(ClassNode cn, byte[] b) {
|
public String decompileClassNode(ClassNode cn, byte[] b) {
|
||||||
StringWriter writer = new StringWriter();
|
StringWriter writer = new StringWriter();
|
||||||
|
|
|
@ -46,7 +46,8 @@ import static the.bytecode.club.bytecodeviewer.Constants.*;
|
||||||
* @author Konloch
|
* @author Konloch
|
||||||
*/
|
*/
|
||||||
|
|
||||||
public class CFRDecompiler extends Decompiler {
|
public class CFRDecompiler extends InternalDecompiler
|
||||||
|
{
|
||||||
|
|
||||||
private static final String[] WINDOWS_IS_GREAT = new String[]
|
private static final String[] WINDOWS_IS_GREAT = new String[]
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,6 +1,11 @@
|
||||||
package the.bytecode.club.bytecodeviewer.decompilers;
|
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 *
|
* 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
|
* @author Konloch
|
||||||
*/
|
*/
|
||||||
|
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")),
|
||||||
|
;
|
||||||
|
|
||||||
public abstract class Decompiler {
|
private final int decompilerIndex;
|
||||||
|
private final String decompilerName;
|
||||||
|
private final InternalDecompiler decompiler;
|
||||||
|
private final DecompilerViewComponent decompilerSelectComponent;
|
||||||
|
private final JRadioButtonMenuItem basicSelectComponent;
|
||||||
|
|
||||||
public abstract String decompileClassNode(ClassNode cn, byte[] b);
|
public static final HashMap<Integer, Decompiler> decompilersByIndex = new HashMap<>();
|
||||||
|
|
||||||
public abstract void decompileToZip(String sourceJar, String zipName);
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -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();
|
|
||||||
|
|
||||||
}
|
|
|
@ -38,7 +38,8 @@ import static the.bytecode.club.bytecodeviewer.Constants.*;
|
||||||
* @author Konloch
|
* @author Konloch
|
||||||
* @author WaterWolf
|
* @author WaterWolf
|
||||||
*/
|
*/
|
||||||
public class FernFlowerDecompiler extends Decompiler {
|
public class FernFlowerDecompiler extends InternalDecompiler
|
||||||
|
{
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void decompileToZip(String sourceJar, String zipName) {
|
public void decompileToZip(String sourceJar, String zipName) {
|
||||||
|
|
|
@ -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 <http://www.gnu.org/licenses/>. *
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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);
|
||||||
|
}
|
|
@ -38,7 +38,8 @@ import static the.bytecode.club.bytecodeviewer.Constants.*;
|
||||||
*
|
*
|
||||||
* @author Konloch
|
* @author Konloch
|
||||||
*/
|
*/
|
||||||
public class JADXDecompiler extends Decompiler {
|
public class JADXDecompiler extends InternalDecompiler
|
||||||
|
{
|
||||||
@Override
|
@Override
|
||||||
public String decompileClassNode(ClassNode cn, byte[] b) {
|
public String decompileClassNode(ClassNode cn, byte[] b) {
|
||||||
String fileStart = tempDirectory + fs;
|
String fileStart = tempDirectory + fs;
|
||||||
|
|
|
@ -13,7 +13,6 @@ import jd.cli.util.ClassFileUtil;
|
||||||
import me.konloch.kontainer.io.DiskReader;
|
import me.konloch.kontainer.io.DiskReader;
|
||||||
import org.jd.core.v1.ClassFileToJavaSourceDecompiler;
|
import org.jd.core.v1.ClassFileToJavaSourceDecompiler;
|
||||||
import org.objectweb.asm.tree.ClassNode;
|
import org.objectweb.asm.tree.ClassNode;
|
||||||
import the.bytecode.club.bytecodeviewer.BytecodeViewer;
|
|
||||||
import the.bytecode.club.bytecodeviewer.Constants;
|
import the.bytecode.club.bytecodeviewer.Constants;
|
||||||
import the.bytecode.club.bytecodeviewer.util.MiscUtils;
|
import the.bytecode.club.bytecodeviewer.util.MiscUtils;
|
||||||
|
|
||||||
|
@ -44,7 +43,8 @@ import static the.bytecode.club.bytecodeviewer.Constants.*;
|
||||||
* @author JD-Core developers
|
* @author JD-Core developers
|
||||||
*/
|
*/
|
||||||
|
|
||||||
public class JDGUIDecompiler extends Decompiler {
|
public class JDGUIDecompiler extends InternalDecompiler
|
||||||
|
{
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String decompileClassNode(ClassNode cn, byte[] b) {
|
public String decompileClassNode(ClassNode cn, byte[] b) {
|
||||||
|
|
|
@ -42,7 +42,8 @@ import static the.bytecode.club.bytecodeviewer.Constants.*;
|
||||||
* @author Konloch
|
* @author Konloch
|
||||||
*/
|
*/
|
||||||
|
|
||||||
public class KrakatauDecompiler extends Decompiler {
|
public class KrakatauDecompiler extends InternalDecompiler
|
||||||
|
{
|
||||||
|
|
||||||
public String quick() {
|
public String quick() {
|
||||||
if (Configuration.library.isEmpty())
|
if (Configuration.library.isEmpty())
|
||||||
|
|
|
@ -41,7 +41,8 @@ import static the.bytecode.club.bytecodeviewer.Constants.*;
|
||||||
* @author Konloch
|
* @author Konloch
|
||||||
*/
|
*/
|
||||||
|
|
||||||
public class KrakatauDisassembler extends Decompiler {
|
public class KrakatauDisassembler extends InternalDecompiler
|
||||||
|
{
|
||||||
|
|
||||||
public String decompileClassNode(File krakatauTempJar, File krakatauTempDir, ClassNode cn) {
|
public String decompileClassNode(File krakatauTempJar, File krakatauTempDir, ClassNode cn) {
|
||||||
if (Configuration.python.isEmpty()) {
|
if (Configuration.python.isEmpty()) {
|
||||||
|
|
|
@ -61,9 +61,10 @@ import static the.bytecode.club.bytecodeviewer.Constants.*;
|
||||||
* @author Konloch
|
* @author Konloch
|
||||||
* @author DeathMarine
|
* @author DeathMarine
|
||||||
*/
|
*/
|
||||||
public class ProcyonDecompiler extends Decompiler {
|
public class ProcyonDecompiler extends InternalDecompiler
|
||||||
|
{
|
||||||
public DecompilerSettings getDecompilerSettings() {
|
public DecompilerSettings getDecompilerSettings()
|
||||||
|
{
|
||||||
DecompilerSettings settings = new DecompilerSettings();
|
DecompilerSettings settings = new DecompilerSettings();
|
||||||
settings.setAlwaysGenerateExceptionVariableForCatchBlocks(BytecodeViewer.viewer.alwaysGenerateExceptionVars.isSelected());
|
settings.setAlwaysGenerateExceptionVariableForCatchBlocks(BytecodeViewer.viewer.alwaysGenerateExceptionVars.isSelected());
|
||||||
settings.setExcludeNestedTypes(BytecodeViewer.viewer.excludeNestedTypes.isSelected());
|
settings.setExcludeNestedTypes(BytecodeViewer.viewer.excludeNestedTypes.isSelected());
|
||||||
|
|
|
@ -9,7 +9,6 @@ import java.util.Objects;
|
||||||
import me.konloch.kontainer.io.DiskReader;
|
import me.konloch.kontainer.io.DiskReader;
|
||||||
import org.apache.commons.io.FileUtils;
|
import org.apache.commons.io.FileUtils;
|
||||||
import org.objectweb.asm.tree.ClassNode;
|
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.Dex2Jar;
|
||||||
import the.bytecode.club.bytecodeviewer.util.FileContainer;
|
import the.bytecode.club.bytecodeviewer.util.FileContainer;
|
||||||
import the.bytecode.club.bytecodeviewer.util.MiscUtils;
|
import the.bytecode.club.bytecodeviewer.util.MiscUtils;
|
||||||
|
@ -40,7 +39,8 @@ import static the.bytecode.club.bytecodeviewer.Constants.*;
|
||||||
* @author Konloch
|
* @author Konloch
|
||||||
*/
|
*/
|
||||||
|
|
||||||
public class SmaliDisassembler extends Decompiler {
|
public class SmaliDisassembler extends InternalDecompiler
|
||||||
|
{
|
||||||
|
|
||||||
public String decompileClassNode(FileContainer container, ClassNode cn, byte[] b) {
|
public String decompileClassNode(FileContainer container, ClassNode cn, byte[] b) {
|
||||||
String exception = "";
|
String exception = "";
|
||||||
|
|
|
@ -9,7 +9,7 @@ import org.objectweb.asm.tree.FieldNode;
|
||||||
import org.objectweb.asm.tree.InnerClassNode;
|
import org.objectweb.asm.tree.InnerClassNode;
|
||||||
import org.objectweb.asm.tree.MethodNode;
|
import org.objectweb.asm.tree.MethodNode;
|
||||||
import the.bytecode.club.bytecodeviewer.BytecodeViewer;
|
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.*;
|
import static the.bytecode.club.bytecodeviewer.Constants.*;
|
||||||
|
|
||||||
|
@ -36,7 +36,8 @@ import static the.bytecode.club.bytecodeviewer.Constants.*;
|
||||||
* @author Bibl
|
* @author Bibl
|
||||||
*/
|
*/
|
||||||
|
|
||||||
public class ClassNodeDecompiler extends Decompiler {
|
public class ClassNodeDecompiler extends InternalDecompiler
|
||||||
|
{
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String decompileClassNode(ClassNode cn, byte[] b) {
|
public String decompileClassNode(ClassNode cn, byte[] b) {
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -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 <http://www.gnu.org/licenses/>. *
|
|
||||||
***************************************************************************/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -4,22 +4,9 @@ import java.awt.Dimension;
|
||||||
import java.awt.KeyboardFocusManager;
|
import java.awt.KeyboardFocusManager;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import javax.swing.BoxLayout;
|
import java.util.HashMap;
|
||||||
import javax.swing.ButtonGroup;
|
import java.util.Map;
|
||||||
import javax.swing.JCheckBoxMenuItem;
|
import javax.swing.*;
|
||||||
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 javax.swing.filechooser.FileFilter;
|
import javax.swing.filechooser.FileFilter;
|
||||||
|
|
||||||
import org.objectweb.asm.tree.ClassNode;
|
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.Resources;
|
||||||
import the.bytecode.club.bytecodeviewer.Settings;
|
import the.bytecode.club.bytecodeviewer.Settings;
|
||||||
import the.bytecode.club.bytecodeviewer.api.ExceptionUI;
|
import the.bytecode.club.bytecodeviewer.api.ExceptionUI;
|
||||||
import the.bytecode.club.bytecodeviewer.gui.extras.AboutWindow;
|
import the.bytecode.club.bytecodeviewer.gui.components.VisibleComponent;
|
||||||
import the.bytecode.club.bytecodeviewer.gui.extras.RunOptions;
|
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.MaliciousCodeScannerOptions;
|
||||||
import the.bytecode.club.bytecodeviewer.gui.plugins.ReplaceStringsOptions;
|
import the.bytecode.club.bytecodeviewer.gui.plugins.ReplaceStringsOptions;
|
||||||
import the.bytecode.club.bytecodeviewer.gui.resourcelist.ResourceListPane;
|
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.RenameClasses;
|
||||||
import the.bytecode.club.bytecodeviewer.obfuscators.rename.RenameFields;
|
import the.bytecode.club.bytecodeviewer.obfuscators.rename.RenameFields;
|
||||||
import the.bytecode.club.bytecodeviewer.obfuscators.rename.RenameMethods;
|
import the.bytecode.club.bytecodeviewer.obfuscators.rename.RenameMethods;
|
||||||
|
@ -80,7 +73,7 @@ public class MainViewerGUI extends JFrame {
|
||||||
|
|
||||||
//main UI components
|
//main UI components
|
||||||
private static final ArrayList<VisibleComponent> uiComponents = new ArrayList<>();
|
private static final ArrayList<VisibleComponent> uiComponents = new ArrayList<>();
|
||||||
public final WorkPane workPane = new WorkPane();
|
public final WorkPaneMainComponent workPane = new WorkPaneMainComponent();
|
||||||
public final ResourceListPane resourcePane = new ResourceListPane();
|
public final ResourceListPane resourcePane = new ResourceListPane();
|
||||||
public final SearchBoxPane searchBoxPane = new SearchBoxPane();
|
public final SearchBoxPane searchBoxPane = new SearchBoxPane();
|
||||||
public JSplitPane splitPane1;
|
public JSplitPane splitPane1;
|
||||||
|
@ -108,9 +101,9 @@ public class MainViewerGUI extends JFrame {
|
||||||
|
|
||||||
//all of the view main menu components
|
//all of the view main menu components
|
||||||
public final JMenu viewMainMenu = new JMenu("View");
|
public final JMenu viewMainMenu = new JMenu("View");
|
||||||
public final ViewPane viewPane1 = new ViewPane(1);
|
public final DecompilerSelectionPane viewPane1 = new DecompilerSelectionPane(1);
|
||||||
public final ViewPane viewPane2 = new ViewPane(2);
|
public final DecompilerSelectionPane viewPane2 = new DecompilerSelectionPane(2);
|
||||||
public final ViewPane viewPane3 = new ViewPane(3);
|
public final DecompilerSelectionPane viewPane3 = new DecompilerSelectionPane(3);
|
||||||
|
|
||||||
//all of the plugins main menu components
|
//all of the plugins main menu components
|
||||||
public final JMenu pluginsMainMenu = new JMenu("Plugins");
|
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 JRadioButtonMenuItem apkConversionEnjarify = new JRadioButtonMenuItem("Enjarify");
|
||||||
public final JMenu fontSize = new JMenu("Font Size");
|
public final JMenu fontSize = new JMenu("Font Size");
|
||||||
public final JSpinner fontSpinner = new JSpinner();
|
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
|
//BCV settings
|
||||||
public final JCheckBoxMenuItem refreshOnChange = new JCheckBoxMenuItem("Refresh On View Change");
|
public final JCheckBoxMenuItem refreshOnChange = new JCheckBoxMenuItem("Refresh On View Change");
|
||||||
private final JCheckBoxMenuItem deleteForeignOutdatedLibs = new JCheckBoxMenuItem("Delete Foreign/Outdated Libs");
|
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 JMenuItem setOptionalLibrary = new JMenuItem("Set Optional Library Folder");
|
||||||
public final JCheckBoxMenuItem compileOnSave = new JCheckBoxMenuItem("Compile On Save");
|
public final JCheckBoxMenuItem compileOnSave = new JCheckBoxMenuItem("Compile On Save");
|
||||||
public final JCheckBoxMenuItem showFileInTabTitle = new JCheckBoxMenuItem("Show File In Tab Title");
|
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 forcePureAsciiAsText = new JCheckBoxMenuItem("Force Pure Ascii As Text");
|
||||||
public final JCheckBoxMenuItem autoCompileOnRefresh = new JCheckBoxMenuItem("Compile On Refresh");
|
public final JCheckBoxMenuItem autoCompileOnRefresh = new JCheckBoxMenuItem("Compile On Refresh");
|
||||||
public final JCheckBoxMenuItem decodeAPKResources = new JCheckBoxMenuItem("Decode APK Resources");
|
public final JCheckBoxMenuItem decodeAPKResources = new JCheckBoxMenuItem("Decode APK Resources");
|
||||||
public final JCheckBoxMenuItem synchronizedViewing = new JCheckBoxMenuItem("Synchronized Viewing");
|
public final JCheckBoxMenuItem synchronizedViewing = new JCheckBoxMenuItem("Synchronized Viewing");
|
||||||
public final JCheckBoxMenuItem showClassMethods = new JCheckBoxMenuItem("Show Class Methods");
|
public final JCheckBoxMenuItem showClassMethods = new JCheckBoxMenuItem("Show Class Methods");
|
||||||
|
public final Map<RSTATheme, JRadioButtonMenuItem> rstaThemes = new HashMap<>();
|
||||||
|
public final Map<LAFTheme, JRadioButtonMenuItem> lafThemes = new HashMap<>();
|
||||||
//CFIDE settings
|
//CFIDE settings
|
||||||
public final JCheckBoxMenuItem appendBracketsToLabels = new JCheckBoxMenuItem("Append Brackets To Labels");
|
public final JCheckBoxMenuItem appendBracketsToLabels = new JCheckBoxMenuItem("Append Brackets To Labels");
|
||||||
public JCheckBoxMenuItem debugHelpers = new JCheckBoxMenuItem("Debug Helpers");
|
public JCheckBoxMenuItem debugHelpers = new JCheckBoxMenuItem("Debug Helpers");
|
||||||
|
@ -384,6 +382,7 @@ public class MainViewerGUI extends JFrame {
|
||||||
public void buildViewMenu()
|
public void buildViewMenu()
|
||||||
{
|
{
|
||||||
rootMenu.add(viewMainMenu);
|
rootMenu.add(viewMainMenu);
|
||||||
|
viewMainMenu.add(visualSettings);
|
||||||
viewMainMenu.add(viewPane1.menu);
|
viewMainMenu.add(viewPane1.menu);
|
||||||
viewMainMenu.add(viewPane2.menu);
|
viewMainMenu.add(viewPane2.menu);
|
||||||
viewMainMenu.add(viewPane3.menu);
|
viewMainMenu.add(viewPane3.menu);
|
||||||
|
@ -393,8 +392,8 @@ public class MainViewerGUI extends JFrame {
|
||||||
{
|
{
|
||||||
rootMenu.add(settingsMainMenu);
|
rootMenu.add(settingsMainMenu);
|
||||||
|
|
||||||
settingsMainMenu.add(visualSettings);
|
//settingsMainMenu.add(visualSettings);
|
||||||
settingsMainMenu.add(new JSeparator());
|
//settingsMainMenu.add(new JSeparator());
|
||||||
settingsMainMenu.add(compileOnSave);
|
settingsMainMenu.add(compileOnSave);
|
||||||
settingsMainMenu.add(autoCompileOnRefresh);
|
settingsMainMenu.add(autoCompileOnRefresh);
|
||||||
settingsMainMenu.add(refreshOnChange);
|
settingsMainMenu.add(refreshOnChange);
|
||||||
|
@ -420,8 +419,54 @@ public class MainViewerGUI extends JFrame {
|
||||||
fontSpinner.setSize(new Dimension(42, 20));
|
fontSpinner.setSize(new Dimension(42, 20));
|
||||||
fontSpinner.setModel(new SpinnerNumberModel(12, 1, null, 1));
|
fontSpinner.setModel(new SpinnerNumberModel(12, 1, null, 1));
|
||||||
fontSize.add(fontSpinner);
|
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(fontSize);
|
||||||
visualSettings.add(showFileInTabTitle);
|
visualSettings.add(showFileInTabTitle);
|
||||||
|
visualSettings.add(simplifyNameInTabTitle);
|
||||||
visualSettings.add(synchronizedViewing);
|
visualSettings.add(synchronizedViewing);
|
||||||
visualSettings.add(showClassMethods);
|
visualSettings.add(showClassMethods);
|
||||||
|
|
||||||
|
@ -527,6 +572,10 @@ public class MainViewerGUI extends JFrame {
|
||||||
Configuration.displayParentInTab = BytecodeViewer.viewer.showFileInTabTitle.isSelected();
|
Configuration.displayParentInTab = BytecodeViewer.viewer.showFileInTabTitle.isSelected();
|
||||||
Settings.saveSettings();
|
Settings.saveSettings();
|
||||||
});
|
});
|
||||||
|
simplifyNameInTabTitle.addActionListener(arg0 -> {
|
||||||
|
Configuration.simplifiedTabNames = BytecodeViewer.viewer.simplifyNameInTabTitle.isSelected();
|
||||||
|
Settings.saveSettings();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public void buildPluginMenu()
|
public void buildPluginMenu()
|
||||||
|
|
|
@ -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 <http://www.gnu.org/licenses/>. *
|
|
||||||
***************************************************************************/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
|
@ -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 <http://www.gnu.org/licenses/>. *
|
|
||||||
***************************************************************************/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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<String, Integer> 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();
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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.CardLayout;
|
||||||
import java.awt.Color;
|
import java.awt.Color;
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,4 +1,4 @@
|
||||||
package the.bytecode.club.bytecodeviewer.gui;
|
package the.bytecode.club.bytecodeviewer.gui.components;
|
||||||
|
|
||||||
import the.bytecode.club.bytecodeviewer.util.RefreshWorkPane;
|
import the.bytecode.club.bytecodeviewer.util.RefreshWorkPane;
|
||||||
|
|
||||||
|
@ -33,6 +33,7 @@ public class DecompilerViewComponent
|
||||||
menu.add(java);
|
menu.add(java);
|
||||||
if(hasBytecodeOption)
|
if(hasBytecodeOption)
|
||||||
menu.add(bytecode);
|
menu.add(bytecode);
|
||||||
|
|
||||||
menu.add(new JSeparator());
|
menu.add(new JSeparator());
|
||||||
menu.add(editable);
|
menu.add(editable);
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
package the.bytecode.club.bytecodeviewer.gui.extras;
|
package the.bytecode.club.bytecodeviewer.gui.components;
|
||||||
|
|
||||||
import java.awt.Dimension;
|
import java.awt.Dimension;
|
||||||
import javax.swing.BoxLayout;
|
import javax.swing.BoxLayout;
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
|
@ -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;
|
||||||
|
}
|
|
@ -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());
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,4 +1,4 @@
|
||||||
package the.bytecode.club.bytecodeviewer.gui.extras;
|
package the.bytecode.club.bytecodeviewer.gui.components;
|
||||||
|
|
||||||
import javax.swing.*;
|
import javax.swing.*;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
|
@ -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;
|
||||||
|
}
|
|
@ -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<Object>
|
||||||
|
{
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,4 +1,4 @@
|
||||||
package the.bytecode.club.bytecodeviewer.gui.extras;
|
package the.bytecode.club.bytecodeviewer.gui.components;
|
||||||
|
|
||||||
import java.awt.Dimension;
|
import java.awt.Dimension;
|
||||||
import javax.swing.JButton;
|
import javax.swing.JButton;
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -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 <http://www.gnu.org/licenses/>. *
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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;
|
||||||
|
}
|
|
@ -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 <http://www.gnu.org/licenses/>. *
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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;
|
||||||
|
}
|
|
@ -1,4 +1,4 @@
|
||||||
package the.bytecode.club.bytecodeviewer.gui;
|
package the.bytecode.club.bytecodeviewer.gui.components;
|
||||||
|
|
||||||
import javax.swing.JInternalFrame;
|
import javax.swing.JInternalFrame;
|
||||||
import org.objectweb.asm.tree.ClassNode;
|
import org.objectweb.asm.tree.ClassNode;
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
|
@ -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 <http://www.gnu.org/licenses/>. *
|
|
||||||
***************************************************************************/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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;
|
|
||||||
}
|
|
|
@ -29,7 +29,7 @@ import javax.swing.tree.TreeNode;
|
||||||
import javax.swing.tree.TreePath;
|
import javax.swing.tree.TreePath;
|
||||||
import org.objectweb.asm.tree.ClassNode;
|
import org.objectweb.asm.tree.ClassNode;
|
||||||
import the.bytecode.club.bytecodeviewer.BytecodeViewer;
|
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.FileContainer;
|
||||||
import the.bytecode.club.bytecodeviewer.util.FileDrop;
|
import the.bytecode.club.bytecodeviewer.util.FileDrop;
|
||||||
import the.bytecode.club.bytecodeviewer.util.LazyNameUtil;
|
import the.bytecode.club.bytecodeviewer.util.LazyNameUtil;
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
package the.bytecode.club.bytecodeviewer.gui.resourcelist;
|
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.*;
|
||||||
import javax.swing.tree.DefaultMutableTreeNode;
|
import javax.swing.tree.DefaultMutableTreeNode;
|
||||||
|
|
|
@ -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();
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,11 +1,9 @@
|
||||||
package the.bytecode.club.bytecodeviewer.gui;
|
package the.bytecode.club.bytecodeviewer.gui.resourcesearch;
|
||||||
|
|
||||||
import java.awt.BorderLayout;
|
import java.awt.BorderLayout;
|
||||||
import java.awt.GridLayout;
|
import java.awt.GridLayout;
|
||||||
import java.awt.event.ItemListener;
|
import java.awt.event.ItemListener;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import java.util.regex.Pattern;
|
|
||||||
import java.util.regex.PatternSyntaxException;
|
|
||||||
import javax.swing.DefaultComboBoxModel;
|
import javax.swing.DefaultComboBoxModel;
|
||||||
import javax.swing.JButton;
|
import javax.swing.JButton;
|
||||||
import javax.swing.JCheckBox;
|
import javax.swing.JCheckBox;
|
||||||
|
@ -15,18 +13,15 @@ import javax.swing.JPanel;
|
||||||
import javax.swing.JScrollPane;
|
import javax.swing.JScrollPane;
|
||||||
import javax.swing.JTree;
|
import javax.swing.JTree;
|
||||||
import javax.swing.tree.DefaultMutableTreeNode;
|
import javax.swing.tree.DefaultMutableTreeNode;
|
||||||
import javax.swing.tree.TreePath;
|
|
||||||
import org.objectweb.asm.tree.ClassNode;
|
import org.objectweb.asm.tree.ClassNode;
|
||||||
import the.bytecode.club.bytecodeviewer.BytecodeViewer;
|
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.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.SearchResultNotifier;
|
||||||
import the.bytecode.club.bytecodeviewer.searching.SearchTypeDetails;
|
|
||||||
import the.bytecode.club.bytecodeviewer.util.FileContainer;
|
import the.bytecode.club.bytecodeviewer.util.FileContainer;
|
||||||
|
|
||||||
/***************************************************************************
|
/***************************************************************************
|
||||||
|
@ -55,8 +50,8 @@ import the.bytecode.club.bytecodeviewer.util.FileContainer;
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@SuppressWarnings("rawtypes")
|
@SuppressWarnings("rawtypes")
|
||||||
public class SearchBoxPane extends VisibleComponent {
|
public class SearchBoxPane extends VisibleComponent
|
||||||
|
{
|
||||||
private static final long serialVersionUID = -1098524689236993932L;
|
private static final long serialVersionUID = -1098524689236993932L;
|
||||||
public static final SearchRadius[] SEARCH_RADII = SearchRadius.values();
|
public static final SearchRadius[] SEARCH_RADII = SearchRadius.values();
|
||||||
public static final SearchType[] SEARCH_TYPES = SearchType.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));
|
final SearchResultNotifier srn = debug -> treeRoot.add(new DefaultMutableTreeNode(debug));
|
||||||
if (radius == SearchRadius.All_Classes) {
|
if (radius == SearchRadius.All_Classes) {
|
||||||
if (t.finished) {
|
if (t.finished) {
|
||||||
t = new BackgroundSearchThread() {
|
t = new PerformSearch(this, 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)
|
|
||||||
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();
|
|
||||||
}
|
|
||||||
|
|
||||||
};
|
|
||||||
Objects.requireNonNull(MainViewerGUI.getComponent(SearchBoxPane.class))
|
Objects.requireNonNull(MainViewerGUI.getComponent(SearchBoxPane.class))
|
||||||
.search.setEnabled(false);
|
.search.setEnabled(false);
|
||||||
Objects.requireNonNull(MainViewerGUI.getComponent(SearchBoxPane.class))
|
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.");
|
BytecodeViewer.showMessage("You currently have a search performing in the background, please wait for that to finish.");
|
||||||
}
|
}
|
||||||
} else if (radius == SearchRadius.Current_Class) {
|
} 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) {
|
if (cv != null) {
|
||||||
searchType.details.search(cv.container, cv.cn, srn, exact.isSelected());
|
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() {
|
public void resetWorkspace() {
|
||||||
treeRoot.removeAllChildren();
|
treeRoot.removeAllChildren();
|
||||||
tree.updateUI();
|
tree.updateUI();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -0,0 +1,10 @@
|
||||||
|
package the.bytecode.club.bytecodeviewer.gui.resourcesearch;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Konloch
|
||||||
|
* @since 6/25/2021
|
||||||
|
*/
|
||||||
|
public enum SearchRadius
|
||||||
|
{
|
||||||
|
All_Classes, Current_Class
|
||||||
|
}
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -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.*;
|
import javax.swing.*;
|
||||||
|
|
||||||
|
@ -6,7 +9,7 @@ import javax.swing.*;
|
||||||
* @author Konloch
|
* @author Konloch
|
||||||
* @since 6/21/2021
|
* @since 6/21/2021
|
||||||
*/
|
*/
|
||||||
public class ViewPane
|
public class DecompilerSelectionPane
|
||||||
{
|
{
|
||||||
public final int paneID;
|
public final int paneID;
|
||||||
public final JMenu menu;
|
public final JMenu menu;
|
||||||
|
@ -23,7 +26,7 @@ public class ViewPane
|
||||||
public final JRadioButtonMenuItem bytecode = new JRadioButtonMenuItem("Bytecode");
|
public final JRadioButtonMenuItem bytecode = new JRadioButtonMenuItem("Bytecode");
|
||||||
public final JRadioButtonMenuItem asmTextify = new JRadioButtonMenuItem("ASM Textify");
|
public final JRadioButtonMenuItem asmTextify = new JRadioButtonMenuItem("ASM Textify");
|
||||||
|
|
||||||
public ViewPane(int paneID) {
|
public DecompilerSelectionPane(int paneID) {
|
||||||
this.paneID = paneID;
|
this.paneID = paneID;
|
||||||
this.menu = new JMenu("Pane " + paneID);
|
this.menu = new JMenu("Pane " + paneID);
|
||||||
buildMenu();
|
buildMenu();
|
|
@ -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,
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
|
@ -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;
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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 <http://www.gnu.org/licenses/>. *
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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;
|
||||||
|
|
||||||
|
}
|
|
@ -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 <http://www.gnu.org/licenses/>. *
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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<String, Integer> 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;
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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 <http://www.gnu.org/licenses/>. *
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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<MethodParser> 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) { }
|
||||||
|
}
|
||||||
|
}
|
|
@ -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 <http://www.gnu.org/licenses/>. *
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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;
|
||||||
|
}
|
|
@ -1,4 +1,4 @@
|
||||||
package the.bytecode.club.bytecodeviewer.gui;
|
package the.bytecode.club.bytecodeviewer.gui.resourceviewer.viewer;
|
||||||
|
|
||||||
import javax.swing.JPanel;
|
import javax.swing.JPanel;
|
||||||
import org.objectweb.asm.tree.ClassNode;
|
import org.objectweb.asm.tree.ClassNode;
|
||||||
|
@ -22,11 +22,11 @@ import the.bytecode.club.bytecodeviewer.util.FileContainer;
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
|
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
|
||||||
***************************************************************************/
|
***************************************************************************/
|
||||||
|
|
||||||
public abstract class Viewer extends JPanel {
|
public abstract class ResourceViewer extends JPanel
|
||||||
|
{
|
||||||
public ClassNode cn;
|
public ClassNode cn;
|
||||||
public String name;
|
public String name;
|
||||||
FileContainer container;
|
public FileContainer container;
|
||||||
|
|
||||||
private static final long serialVersionUID = -2965538493489119191L;
|
private static final long serialVersionUID = -2965538493489119191L;
|
||||||
}
|
}
|
|
@ -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();
|
||||||
|
}
|
||||||
|
}
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -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 java.awt.Color;
|
||||||
import javax.swing.SwingUtilities;
|
import javax.swing.SwingUtilities;
|
||||||
|
@ -6,7 +8,8 @@ import javax.swing.SwingUtilities;
|
||||||
/**
|
/**
|
||||||
* @author Konloch
|
* @author Konloch
|
||||||
*/
|
*/
|
||||||
public class DelayTabbedPaneThread extends Thread {
|
public class DelayTabbedPaneThread extends Thread
|
||||||
|
{
|
||||||
public boolean stopped = false;
|
public boolean stopped = false;
|
||||||
private final TabbedPane pane;
|
private final TabbedPane pane;
|
||||||
|
|
|
@ -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 *
|
* 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.BorderLayout;
|
||||||
import java.awt.Component;
|
|
||||||
import java.awt.Font;
|
import java.awt.Font;
|
||||||
import java.awt.event.InputEvent;
|
import java.awt.event.InputEvent;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import java.util.regex.Matcher;
|
import java.util.regex.Matcher;
|
||||||
import javax.swing.JComboBox;
|
import javax.swing.JComboBox;
|
||||||
import javax.swing.JLabel;
|
|
||||||
import javax.swing.JList;
|
|
||||||
import javax.swing.JPanel;
|
import javax.swing.JPanel;
|
||||||
import javax.swing.JViewport;
|
import javax.swing.JViewport;
|
||||||
import javax.swing.ListCellRenderer;
|
|
||||||
import javax.swing.event.CaretEvent;
|
import javax.swing.event.CaretEvent;
|
||||||
import javax.swing.event.CaretListener;
|
import javax.swing.event.CaretListener;
|
||||||
import javax.swing.event.ChangeEvent;
|
import javax.swing.event.ChangeEvent;
|
||||||
|
@ -37,9 +33,12 @@ import javax.swing.event.ChangeListener;
|
||||||
import org.fife.ui.rsyntaxtextarea.RSyntaxTextArea;
|
import org.fife.ui.rsyntaxtextarea.RSyntaxTextArea;
|
||||||
import org.fife.ui.rtextarea.RTextScrollPane;
|
import org.fife.ui.rtextarea.RTextScrollPane;
|
||||||
import the.bytecode.club.bytecodeviewer.BytecodeViewer;
|
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 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
|
* Allows us to run a background thread
|
||||||
|
@ -47,21 +46,40 @@ import static the.bytecode.club.bytecodeviewer.gui.TabbedPane.BLANK;
|
||||||
* @author Konloch
|
* @author Konloch
|
||||||
* @author DreamSworK
|
* @author DreamSworK
|
||||||
*/
|
*/
|
||||||
public abstract class PaneUpdaterThread extends Thread {
|
public abstract class PaneUpdaterThread implements Runnable
|
||||||
|
{
|
||||||
public ClassViewer viewer;
|
public ClassViewer viewer;
|
||||||
public RSyntaxTextArea panelArea;
|
public SearchableRSyntaxTextArea updateUpdaterTextArea;
|
||||||
public RTextScrollPane scrollPane;
|
|
||||||
public JComboBox<Integer> methodsList;
|
public JComboBox<Integer> methodsList;
|
||||||
public int decompiler;
|
private Thread thread;
|
||||||
public int paneId;
|
public int paneIndex;
|
||||||
|
public int decompilerViewIndex;
|
||||||
|
|
||||||
|
public PaneUpdaterThread(int paneIndex, int decompilerViewIndex)
|
||||||
|
{
|
||||||
|
this.paneIndex = paneIndex;
|
||||||
|
this.decompilerViewIndex = decompilerViewIndex;
|
||||||
|
}
|
||||||
|
|
||||||
public abstract void doShit();
|
public abstract void doShit();
|
||||||
|
|
||||||
|
public void startNewThread()
|
||||||
|
{
|
||||||
|
thread = new Thread(this);
|
||||||
|
thread.start();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run()
|
||||||
|
{
|
||||||
|
if(decompilerViewIndex == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
doShit();
|
doShit();
|
||||||
|
|
||||||
synchronizePane();
|
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
|
//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() {
|
public final CaretListener caretListener = new CaretListener() {
|
||||||
@Override
|
@Override
|
||||||
public void caretUpdate(CaretEvent e) {
|
public void caretUpdate(CaretEvent e) {
|
||||||
MethodParser methods = viewer.methods.get(paneId);
|
MethodParser methods = viewer.methods.get(paneIndex);
|
||||||
if (methods != null) {
|
if (methods != null) {
|
||||||
int methodLine = methods.findActiveMethod(panelArea.getCaretLineNumber());
|
int methodLine = methods.findActiveMethod(updateUpdaterTextArea.getCaretLineNumber());
|
||||||
if (methodLine != -1) {
|
if (methodLine != -1) {
|
||||||
if (BytecodeViewer.viewer.showClassMethods.isSelected()) {
|
if (BytecodeViewer.viewer.showClassMethods.isSelected()) {
|
||||||
if (methodsList != null) {
|
if (methodsList != null) {
|
||||||
|
@ -102,11 +120,11 @@ public abstract class PaneUpdaterThread extends Thread {
|
||||||
}
|
}
|
||||||
if (BytecodeViewer.viewer.synchronizedViewing.isSelected()) {
|
if (BytecodeViewer.viewer.synchronizedViewing.isSelected()) {
|
||||||
int panes = 2;
|
int panes = 2;
|
||||||
if (viewer.panel3 != null)
|
if (viewer.resourceViewPanel3.panel != null)
|
||||||
panes = 3;
|
panes = 3;
|
||||||
|
|
||||||
for (int i = 0; i < panes; i++) {
|
for (int i = 0; i < panes; i++) {
|
||||||
if (i != paneId) {
|
if (i != paneIndex) {
|
||||||
ClassViewer.selectMethod(viewer, i, methods.getMethod(methodLine));
|
ClassViewer.selectMethod(viewer, i, methods.getMethod(methodLine));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -120,41 +138,41 @@ public abstract class PaneUpdaterThread extends Thread {
|
||||||
@Override
|
@Override
|
||||||
public void stateChanged(ChangeEvent e) {
|
public void stateChanged(ChangeEvent e) {
|
||||||
int panes = 2;
|
int panes = 2;
|
||||||
if (viewer.panel3 != null)
|
if (viewer.resourceViewPanel3.panel != null)
|
||||||
panes = 3;
|
panes = 3;
|
||||||
|
|
||||||
if (BytecodeViewer.viewer.synchronizedViewing.isSelected()) {
|
if (BytecodeViewer.viewer.synchronizedViewing.isSelected()) {
|
||||||
if (panelArea.isShowing() && (panelArea.hasFocus() || panelArea.getMousePosition() != null)) {
|
if (updateUpdaterTextArea.isShowing() && (updateUpdaterTextArea.hasFocus() || updateUpdaterTextArea.getMousePosition() != null)) {
|
||||||
int caretLine = panelArea.getCaretLineNumber();
|
int caretLine = updateUpdaterTextArea.getCaretLineNumber();
|
||||||
int maxViewLine = ClassViewer.getMaxViewLine(panelArea);
|
int maxViewLine = ClassViewer.getMaxViewLine(updateUpdaterTextArea);
|
||||||
int activeViewLine = ClassViewer.getViewLine(panelArea);
|
int activeViewLine = ClassViewer.getViewLine(updateUpdaterTextArea);
|
||||||
int activeLine = (activeViewLine == maxViewLine && caretLine > maxViewLine) ? caretLine :
|
int activeLine = (activeViewLine == maxViewLine && caretLine > maxViewLine) ? caretLine :
|
||||||
activeViewLine;
|
activeViewLine;
|
||||||
int activeLineDelta = -1;
|
int activeLineDelta = -1;
|
||||||
MethodParser.Method activeMethod = null;
|
MethodParser.Method activeMethod = null;
|
||||||
MethodParser activeMethods = viewer.methods.get(paneId);
|
MethodParser activeMethods = viewer.methods.get(paneIndex);
|
||||||
if (activeMethods != null) {
|
if (activeMethods != null) {
|
||||||
int activeMethodLine = activeMethods.findActiveMethod(activeLine);
|
int activeMethodLine = activeMethods.findActiveMethod(activeLine);
|
||||||
if (activeMethodLine != -1) {
|
if (activeMethodLine != -1) {
|
||||||
activeLineDelta = activeLine - activeMethodLine;
|
activeLineDelta = activeLine - activeMethodLine;
|
||||||
activeMethod = activeMethods.getMethod(activeMethodLine);
|
activeMethod = activeMethods.getMethod(activeMethodLine);
|
||||||
ClassViewer.selectMethod(panelArea, activeMethodLine);
|
ClassViewer.selectMethod(updateUpdaterTextArea, activeMethodLine);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (int i = 0; i < panes; i++) {
|
for (int i = 0; i < panes; i++) {
|
||||||
if (i != paneId) {
|
if (i != paneIndex) {
|
||||||
int setLine = -1;
|
int setLine = -1;
|
||||||
|
|
||||||
RSyntaxTextArea area = null;
|
RSyntaxTextArea area = null;
|
||||||
switch (i) {
|
switch (i) {
|
||||||
case 0:
|
case 0:
|
||||||
area = viewer.t1.panelArea;
|
area = viewer.resourceViewPanel1.updateThread.updateUpdaterTextArea;
|
||||||
break;
|
break;
|
||||||
case 1:
|
case 1:
|
||||||
area = viewer.t2.panelArea;
|
area = viewer.resourceViewPanel2.updateThread.updateUpdaterTextArea;
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
area = viewer.t3.panelArea;
|
area = viewer.resourceViewPanel3.updateThread.updateUpdaterTextArea;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -184,29 +202,18 @@ public abstract class PaneUpdaterThread extends Thread {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
class MethodsRenderer extends JLabel implements ListCellRenderer<Object> {
|
public void synchronizePane()
|
||||||
public MethodsRenderer() {
|
{
|
||||||
setOpaque(true);
|
if(decompilerViewIndex == 5 || decompilerViewIndex < 0)
|
||||||
}
|
return;
|
||||||
|
|
||||||
@Override
|
JViewport viewport = updateUpdaterTextArea.getScrollPane().getViewport();
|
||||||
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();
|
|
||||||
viewport.addChangeListener(viewportListener);
|
viewport.addChangeListener(viewportListener);
|
||||||
panelArea.addCaretListener(caretListener);
|
updateUpdaterTextArea.addCaretListener(caretListener);
|
||||||
|
|
||||||
final MethodParser methods = viewer.methods.get(paneId);
|
final MethodParser methods = viewer.methods.get(paneIndex);
|
||||||
for (int i = 0; i < panelArea.getLineCount(); i++) {
|
for (int i = 0; i < updateUpdaterTextArea.getLineCount(); i++) {
|
||||||
String lineText = ClassViewer.getLineText(panelArea, i);
|
String lineText = ClassViewer.getLineText(updateUpdaterTextArea, i);
|
||||||
Matcher regexMatcher = MethodParser.regex.matcher(lineText);
|
Matcher regexMatcher = MethodParser.regex.matcher(lineText);
|
||||||
if (regexMatcher.find()) {
|
if (regexMatcher.find()) {
|
||||||
String methodName = regexMatcher.group("name");
|
String methodName = regexMatcher.group("name");
|
||||||
|
@ -221,20 +228,22 @@ public abstract class PaneUpdaterThread extends Thread {
|
||||||
for (Integer line : methods.getMethodsLines()) {
|
for (Integer line : methods.getMethodsLines()) {
|
||||||
methodsList.addItem(line);
|
methodsList.addItem(line);
|
||||||
}
|
}
|
||||||
methodsList.setRenderer(new PaneUpdaterThread.MethodsRenderer());
|
methodsList.setRenderer(new MethodsRenderer(this));
|
||||||
methodsList.addActionListener(e -> {
|
methodsList.addActionListener(e ->
|
||||||
|
{
|
||||||
int line = (int) Objects.requireNonNull(methodsList.getSelectedItem());
|
int line = (int) Objects.requireNonNull(methodsList.getSelectedItem());
|
||||||
|
|
||||||
RSyntaxTextArea area = null;
|
RSyntaxTextArea area = null;
|
||||||
switch (paneId) {
|
switch (paneIndex)
|
||||||
|
{
|
||||||
case 0:
|
case 0:
|
||||||
area = viewer.t1.panelArea;
|
area = viewer.resourceViewPanel1.updateThread.updateUpdaterTextArea;
|
||||||
break;
|
break;
|
||||||
case 1:
|
case 1:
|
||||||
area = viewer.t2.panelArea;
|
area = viewer.resourceViewPanel2.updateThread.updateUpdaterTextArea;
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
area = viewer.t3.panelArea;
|
area = viewer.resourceViewPanel3.updateThread.updateUpdaterTextArea;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -243,11 +252,11 @@ public abstract class PaneUpdaterThread extends Thread {
|
||||||
});
|
});
|
||||||
|
|
||||||
JPanel panel = new JPanel(new BorderLayout());
|
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);
|
panel.add(methodsList, BorderLayout.SOUTH);
|
||||||
methodsList.setBackground(BLANK);
|
methodsList.setBackground(BLANK_COLOR);
|
||||||
scrollPane.getColumnHeader().removeAll();
|
updateUpdaterTextArea.getScrollPane().getColumnHeader().removeAll();
|
||||||
scrollPane.getColumnHeader().add(panel);
|
updateUpdaterTextArea.getScrollPane().getColumnHeader().add(panel);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,4 +1,4 @@
|
||||||
package the.bytecode.club.bytecodeviewer.gui.extras;
|
package the.bytecode.club.bytecodeviewer.gui.util;
|
||||||
|
|
||||||
import java.awt.*;
|
import java.awt.*;
|
||||||
import java.awt.font.FontRenderContext;
|
import java.awt.font.FontRenderContext;
|
|
@ -15,7 +15,7 @@ import org.objectweb.asm.tree.MethodNode;
|
||||||
import the.bytecode.club.bytecodeviewer.BytecodeViewer;
|
import the.bytecode.club.bytecodeviewer.BytecodeViewer;
|
||||||
import the.bytecode.club.bytecodeviewer.Resources;
|
import the.bytecode.club.bytecodeviewer.Resources;
|
||||||
import the.bytecode.club.bytecodeviewer.api.Plugin;
|
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;
|
import the.bytecode.club.bytecodeviewer.plugin.PluginManager;
|
||||||
|
|
||||||
/***************************************************************************
|
/***************************************************************************
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,13 +1,17 @@
|
||||||
package the.bytecode.club.bytecodeviewer.util;
|
package the.bytecode.club.bytecodeviewer.util;
|
||||||
|
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import org.objectweb.asm.tree.ClassNode;
|
import org.objectweb.asm.tree.ClassNode;
|
||||||
|
|
||||||
import java.io.BufferedReader;
|
import javax.imageio.ImageIO;
|
||||||
import java.io.File;
|
import java.awt.*;
|
||||||
import java.io.InputStream;
|
import java.awt.image.BufferedImage;
|
||||||
import java.io.InputStreamReader;
|
import java.io.*;
|
||||||
import java.lang.reflect.Field;
|
import java.lang.reflect.Field;
|
||||||
|
import java.nio.charset.CharsetEncoder;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
import static the.bytecode.club.bytecodeviewer.Constants.gson;
|
import static the.bytecode.club.bytecodeviewer.Constants.gson;
|
||||||
|
|
||||||
|
@ -35,7 +39,9 @@ import static the.bytecode.club.bytecodeviewer.Constants.gson;
|
||||||
* @author Konloch
|
* @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 AB = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
|
||||||
private static final String AN = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
|
private static final String AN = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
|
||||||
private static final Random rnd = new Random();
|
private static final Random rnd = new Random();
|
||||||
|
@ -192,4 +198,30 @@ public class MiscUtils {
|
||||||
field.setAccessible(true);
|
field.setAccessible(true);
|
||||||
((Map<String, String>) field.get(env)).put(name, val);
|
((Map<String, String>) 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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,7 +5,7 @@ import org.objectweb.asm.ClassWriter;
|
||||||
import org.objectweb.asm.tree.ClassNode;
|
import org.objectweb.asm.tree.ClassNode;
|
||||||
import the.bytecode.club.bytecodeviewer.BytecodeViewer;
|
import the.bytecode.club.bytecodeviewer.BytecodeViewer;
|
||||||
import the.bytecode.club.bytecodeviewer.api.ExceptionUI;
|
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.*;
|
||||||
import javax.swing.filechooser.FileFilter;
|
import javax.swing.filechooser.FileFilter;
|
||||||
|
@ -101,7 +101,7 @@ public class ResourceDecompiling
|
||||||
if (result == 0) {
|
if (result == 0) {
|
||||||
Thread t12 = new Thread(() -> {
|
Thread t12 = new Thread(() -> {
|
||||||
try {
|
try {
|
||||||
Decompilers.procyon.decompileToZip(tempZip.getAbsolutePath(),
|
Decompiler.PROCYON.getDecompiler().decompileToZip(tempZip.getAbsolutePath(),
|
||||||
MiscUtils.append(javaSucks, "-proycon.zip"));
|
MiscUtils.append(javaSucks, "-proycon.zip"));
|
||||||
BytecodeViewer.viewer.updateBusyStatus(false);
|
BytecodeViewer.viewer.updateBusyStatus(false);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
|
@ -112,7 +112,7 @@ public class ResourceDecompiling
|
||||||
Thread t2 = new Thread(() -> {
|
Thread t2 = new Thread(() -> {
|
||||||
try {
|
try {
|
||||||
BytecodeViewer.viewer.updateBusyStatus(true);
|
BytecodeViewer.viewer.updateBusyStatus(true);
|
||||||
Decompilers.cfr.decompileToZip(tempZip.getAbsolutePath(),
|
Decompiler.CFR.getDecompiler().decompileToZip(tempZip.getAbsolutePath(),
|
||||||
MiscUtils.append(javaSucks, "-CFR.zip"));
|
MiscUtils.append(javaSucks, "-CFR.zip"));
|
||||||
BytecodeViewer.viewer.updateBusyStatus(false);
|
BytecodeViewer.viewer.updateBusyStatus(false);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
|
@ -123,7 +123,7 @@ public class ResourceDecompiling
|
||||||
Thread t3 = new Thread(() -> {
|
Thread t3 = new Thread(() -> {
|
||||||
try {
|
try {
|
||||||
BytecodeViewer.viewer.updateBusyStatus(true);
|
BytecodeViewer.viewer.updateBusyStatus(true);
|
||||||
Decompilers.fernflower.decompileToZip(tempZip.getAbsolutePath(),
|
Decompiler.FERNFLOWER.getDecompiler().decompileToZip(tempZip.getAbsolutePath(),
|
||||||
MiscUtils.append(javaSucks, "-fernflower.zip"));
|
MiscUtils.append(javaSucks, "-fernflower.zip"));
|
||||||
BytecodeViewer.viewer.updateBusyStatus(false);
|
BytecodeViewer.viewer.updateBusyStatus(false);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
|
@ -134,7 +134,7 @@ public class ResourceDecompiling
|
||||||
Thread t4 = new Thread(() -> {
|
Thread t4 = new Thread(() -> {
|
||||||
try {
|
try {
|
||||||
BytecodeViewer.viewer.updateBusyStatus(true);
|
BytecodeViewer.viewer.updateBusyStatus(true);
|
||||||
Decompilers.krakatau.decompileToZip(tempZip.getAbsolutePath(),
|
Decompiler.KRAKATAU.getDecompiler().decompileToZip(tempZip.getAbsolutePath(),
|
||||||
MiscUtils.append(javaSucks, "-kraktau.zip"));
|
MiscUtils.append(javaSucks, "-kraktau.zip"));
|
||||||
BytecodeViewer.viewer.updateBusyStatus(false);
|
BytecodeViewer.viewer.updateBusyStatus(false);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
|
@ -146,7 +146,7 @@ public class ResourceDecompiling
|
||||||
if (result == 1) {
|
if (result == 1) {
|
||||||
Thread t12 = new Thread(() -> {
|
Thread t12 = new Thread(() -> {
|
||||||
try {
|
try {
|
||||||
Decompilers.procyon.decompileToZip(tempZip.getAbsolutePath(), path);
|
Decompiler.PROCYON.getDecompiler().decompileToZip(tempZip.getAbsolutePath(), path);
|
||||||
BytecodeViewer.viewer.updateBusyStatus(false);
|
BytecodeViewer.viewer.updateBusyStatus(false);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
new ExceptionUI(e);
|
new ExceptionUI(e);
|
||||||
|
@ -157,7 +157,7 @@ public class ResourceDecompiling
|
||||||
if (result == 2) {
|
if (result == 2) {
|
||||||
Thread t12 = new Thread(() -> {
|
Thread t12 = new Thread(() -> {
|
||||||
try {
|
try {
|
||||||
Decompilers.cfr.decompileToZip(tempZip.getAbsolutePath(), path);
|
Decompiler.CFR.getDecompiler().decompileToZip(tempZip.getAbsolutePath(), path);
|
||||||
BytecodeViewer.viewer.updateBusyStatus(false);
|
BytecodeViewer.viewer.updateBusyStatus(false);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
new ExceptionUI(e);
|
new ExceptionUI(e);
|
||||||
|
@ -168,7 +168,7 @@ public class ResourceDecompiling
|
||||||
if (result == 3) {
|
if (result == 3) {
|
||||||
Thread t12 = new Thread(() -> {
|
Thread t12 = new Thread(() -> {
|
||||||
try {
|
try {
|
||||||
Decompilers.fernflower.decompileToZip(tempZip.getAbsolutePath(), path);
|
Decompiler.FERNFLOWER.getDecompiler().decompileToZip(tempZip.getAbsolutePath(), path);
|
||||||
BytecodeViewer.viewer.updateBusyStatus(false);
|
BytecodeViewer.viewer.updateBusyStatus(false);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
new ExceptionUI(e);
|
new ExceptionUI(e);
|
||||||
|
@ -180,7 +180,7 @@ public class ResourceDecompiling
|
||||||
if (result == 4) {
|
if (result == 4) {
|
||||||
Thread t12 = new Thread(() -> {
|
Thread t12 = new Thread(() -> {
|
||||||
try {
|
try {
|
||||||
Decompilers.krakatau.decompileToZip(tempZip.getAbsolutePath(), path);
|
Decompiler.KRAKATAU.getDecompiler().decompileToZip(tempZip.getAbsolutePath(), path);
|
||||||
BytecodeViewer.viewer.updateBusyStatus(false);
|
BytecodeViewer.viewer.updateBusyStatus(false);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
new ExceptionUI(e);
|
new ExceptionUI(e);
|
||||||
|
@ -288,28 +288,28 @@ public class ResourceDecompiling
|
||||||
|
|
||||||
try {
|
try {
|
||||||
DiskWriter.replaceFile(MiscUtils.append(file, "-proycon.java"),
|
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) {
|
} catch (Exception e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
DiskWriter.replaceFile(MiscUtils.append(file, "-CFR.java"),
|
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) {
|
} catch (Exception e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
DiskWriter.replaceFile(MiscUtils.append(file, "-fernflower.java"),
|
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) {
|
} catch (Exception e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
DiskWriter.replaceFile(MiscUtils.append(file, "-kraktau.java"),
|
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) {
|
} catch (Exception e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
|
@ -337,8 +337,7 @@ public class ResourceDecompiling
|
||||||
} catch (InterruptedException ignored) {
|
} catch (InterruptedException ignored) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
String contents = Decompilers.procyon.decompileClassNode(cn,
|
String contents = Decompiler.PROCYON.getDecompiler().decompileClassNode(cn, cw.toByteArray());
|
||||||
cw.toByteArray());
|
|
||||||
DiskWriter.replaceFile(path, contents, false);
|
DiskWriter.replaceFile(path, contents, false);
|
||||||
BytecodeViewer.viewer.updateBusyStatus(false);
|
BytecodeViewer.viewer.updateBusyStatus(false);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
|
@ -364,7 +363,7 @@ public class ResourceDecompiling
|
||||||
} catch (InterruptedException ignored) {
|
} 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);
|
DiskWriter.replaceFile(path, contents, false);
|
||||||
BytecodeViewer.viewer.updateBusyStatus(false);
|
BytecodeViewer.viewer.updateBusyStatus(false);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
|
@ -391,7 +390,7 @@ public class ResourceDecompiling
|
||||||
} catch (InterruptedException ignored) {
|
} catch (InterruptedException ignored) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
String contents = Decompilers.fernflower.decompileClassNode(cn,
|
String contents = Decompiler.FERNFLOWER.getDecompiler().decompileClassNode(cn,
|
||||||
cw.toByteArray());
|
cw.toByteArray());
|
||||||
DiskWriter.replaceFile(path, contents, false);
|
DiskWriter.replaceFile(path, contents, false);
|
||||||
BytecodeViewer.viewer.updateBusyStatus(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());
|
cw.toByteArray());
|
||||||
DiskWriter.replaceFile(path, contents, false);
|
DiskWriter.replaceFile(path, contents, false);
|
||||||
BytecodeViewer.viewer.updateBusyStatus(false);
|
BytecodeViewer.viewer.updateBusyStatus(false);
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
package the.bytecode.club.bytecodeviewer.util;
|
package the.bytecode.club.bytecodeviewer.util;
|
||||||
|
|
||||||
import the.bytecode.club.bytecodeviewer.BytecodeViewer;
|
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.*;
|
||||||
import javax.swing.filechooser.FileFilter;
|
import javax.swing.filechooser.FileFilter;
|
||||||
|
|
|
@ -3,8 +3,8 @@ package the.bytecode.club.bytecodeviewer.util;
|
||||||
import java.util.function.BiFunction;
|
import java.util.function.BiFunction;
|
||||||
import org.fife.ui.rsyntaxtextarea.SyntaxConstants;
|
import org.fife.ui.rsyntaxtextarea.SyntaxConstants;
|
||||||
|
|
||||||
public enum Language {
|
public enum SyntaxLanguage
|
||||||
|
{
|
||||||
XML(SyntaxConstants.SYNTAX_STYLE_XML, (n, c) -> n.endsWith(".xml")
|
XML(SyntaxConstants.SYNTAX_STYLE_XML, (n, c) -> n.endsWith(".xml")
|
||||||
|| c.startsWith("<?xml") || c.startsWith("<xml")),
|
|| c.startsWith("<?xml") || c.startsWith("<xml")),
|
||||||
PYTHON(SyntaxConstants.SYNTAX_STYLE_PYTHON, (n, c) -> n.endsWith(".py") || n.endsWith(".python")),
|
PYTHON(SyntaxConstants.SYNTAX_STYLE_PYTHON, (n, c) -> n.endsWith(".py") || n.endsWith(".python")),
|
||||||
|
@ -42,13 +42,13 @@ public enum Language {
|
||||||
TYPESCRIPT(SyntaxConstants.SYNTAX_STYLE_TYPESCRIPT, (n, c) -> n.endsWith(".ts")),
|
TYPESCRIPT(SyntaxConstants.SYNTAX_STYLE_TYPESCRIPT, (n, c) -> n.endsWith(".ts")),
|
||||||
NONE(SyntaxConstants.SYNTAX_STYLE_NONE, (n, c) -> false);
|
NONE(SyntaxConstants.SYNTAX_STYLE_NONE, (n, c) -> false);
|
||||||
|
|
||||||
public static final Language[] VALUES = values();
|
public static final SyntaxLanguage[] VALUES = values();
|
||||||
|
|
||||||
private final BiFunction<String, String, Boolean> criteria;
|
private final BiFunction<String, String, Boolean> criteria;
|
||||||
|
|
||||||
private final String syntaxConstant;
|
private final String syntaxConstant;
|
||||||
|
|
||||||
Language(String syntaxConstant, BiFunction<String, String, Boolean> criteria) {
|
SyntaxLanguage(String syntaxConstant, BiFunction<String, String, Boolean> criteria) {
|
||||||
this.criteria = criteria;
|
this.criteria = criteria;
|
||||||
this.syntaxConstant = syntaxConstant;
|
this.syntaxConstant = syntaxConstant;
|
||||||
}
|
}
|
||||||
|
@ -61,13 +61,12 @@ public enum Language {
|
||||||
return syntaxConstant;
|
return syntaxConstant;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Language detectLanguage(String fileName, String content) {
|
public static SyntaxLanguage detectLanguage(String fileName, String content) {
|
||||||
for (Language lang : VALUES) {
|
for (SyntaxLanguage lang : VALUES) {
|
||||||
if (lang.isLanguage(fileName, content)) {
|
if (lang.isLanguage(fileName, content)) {
|
||||||
return lang;
|
return lang;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return NONE;
|
return NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -1,3 +0,0 @@
|
||||||
Manifest-Version: 1.0
|
|
||||||
Main-Class: the.bytecode.club.bytecodeviewer.BytecodeViewer
|
|
||||||
|
|
Binary file not shown.
Before Width: | Height: | Size: 660 B After Width: | Height: | Size: 1.9 KiB |
Loading…
Reference in New Issue
Block a user