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>
|
||||
<version>1.0bcv</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.bulenkov</groupId>
|
||||
<artifactId>darcula</artifactId>
|
||||
<version>2017.11bcv</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<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>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-jar-plugin</artifactId>
|
||||
|
@ -268,7 +253,7 @@
|
|||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-javadoc-plugin</artifactId>
|
||||
<version>3.2.0</version>
|
||||
<version>3.3.0</version>
|
||||
<configuration>
|
||||
<source>${java.version}</source>
|
||||
</configuration>
|
||||
|
@ -276,7 +261,7 @@
|
|||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-shade-plugin</artifactId>
|
||||
<version>3.2.2</version>
|
||||
<version>3.2.4</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<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.List;
|
||||
import java.util.Objects;
|
||||
import javax.swing.JDialog;
|
||||
import javax.swing.JFileChooser;
|
||||
import javax.swing.JMenuItem;
|
||||
import javax.swing.JOptionPane;
|
||||
import javax.swing.UIManager;
|
||||
import javax.swing.*;
|
||||
import javax.swing.filechooser.FileFilter;
|
||||
import me.konloch.kontainer.io.DiskWriter;
|
||||
import me.konloch.kontainer.io.HTTPRequest;
|
||||
|
@ -23,13 +19,15 @@ import org.objectweb.asm.tree.ClassNode;
|
|||
import the.bytecode.club.bootloader.Boot;
|
||||
import the.bytecode.club.bytecodeviewer.api.ClassNodeLoader;
|
||||
import the.bytecode.club.bytecodeviewer.compilers.Compilers;
|
||||
import the.bytecode.club.bytecodeviewer.gui.ClassViewer;
|
||||
import the.bytecode.club.bytecodeviewer.gui.components.DecompilerViewComponent;
|
||||
import the.bytecode.club.bytecodeviewer.gui.resourceviewer.ResourcePanelCompileMode;
|
||||
import the.bytecode.club.bytecodeviewer.gui.resourceviewer.viewer.ClassViewer;
|
||||
import the.bytecode.club.bytecodeviewer.gui.resourcelist.ResourceListPane;
|
||||
import the.bytecode.club.bytecodeviewer.gui.MainViewerGUI;
|
||||
import the.bytecode.club.bytecodeviewer.gui.extras.RunOptions;
|
||||
import the.bytecode.club.bytecodeviewer.gui.SearchBoxPane;
|
||||
import the.bytecode.club.bytecodeviewer.gui.extras.SystemErrConsole;
|
||||
import the.bytecode.club.bytecodeviewer.gui.WorkPane;
|
||||
import the.bytecode.club.bytecodeviewer.gui.components.RunOptions;
|
||||
import the.bytecode.club.bytecodeviewer.gui.resourcesearch.SearchBoxPane;
|
||||
import the.bytecode.club.bytecodeviewer.gui.components.SystemErrConsole;
|
||||
import the.bytecode.club.bytecodeviewer.gui.resourceviewer.WorkPaneMainComponent;
|
||||
import the.bytecode.club.bytecodeviewer.obfuscators.mapping.Refactorer;
|
||||
import the.bytecode.club.bytecodeviewer.plugin.PluginManager;
|
||||
import the.bytecode.club.bytecodeviewer.util.*;
|
||||
|
@ -104,6 +102,7 @@ public class BytecodeViewer
|
|||
public static Refactorer refactorer = new Refactorer();
|
||||
public static List<FileContainer> files = new ArrayList<>(); //all of BCV's loaded files/classes/etc
|
||||
public static List<Process> createdProcesses = new ArrayList<>();
|
||||
public static final DecompilerViewComponent krakatau = new DecompilerViewComponent("Krakatau", true);
|
||||
public static final boolean EXPERIMENTAL_TAB_CODE = false;
|
||||
|
||||
/**
|
||||
|
@ -155,8 +154,9 @@ public class BytecodeViewer
|
|||
* @throws IOException
|
||||
*/
|
||||
public static byte[] getClassFile(Class<?> clazz) throws IOException {
|
||||
InputStream is = clazz.getResourceAsStream("/" + clazz.getName().replace('.', '/') + ".class");
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
try (InputStream is = clazz.getResourceAsStream(
|
||||
"/" + clazz.getName().replace('.', '/') + ".class");
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream()) {
|
||||
int r;
|
||||
byte[] buffer = new byte[8192];
|
||||
while ((r = Objects.requireNonNull(is).read(buffer)) >= 0) {
|
||||
|
@ -164,6 +164,7 @@ public class BytecodeViewer
|
|||
}
|
||||
return baos.toByteArray();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Main startup
|
||||
|
@ -176,8 +177,11 @@ public class BytecodeViewer
|
|||
System.setSecurityManager(sm);
|
||||
|
||||
try {
|
||||
UIManager.put("MenuItem.disabledAreNavigable", Boolean.FALSE);
|
||||
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
|
||||
//precache settings file
|
||||
Settings.preloadSettingsFile();
|
||||
//setup look and feel
|
||||
Configuration.lafTheme.setLAF();
|
||||
|
||||
if (PREVIEW_COPY && !CommandLineInput.containsCommand(args))
|
||||
showMessage("WARNING: This is a preview/dev copy, you WON'T be alerted when " + VERSION + " is "
|
||||
+ "actually out if you use this." + nl +
|
||||
|
@ -378,28 +382,36 @@ public class BytecodeViewer
|
|||
BytecodeViewer.viewer.updateBusyStatus(true);
|
||||
boolean actuallyTried = false;
|
||||
|
||||
for (java.awt.Component c : BytecodeViewer.viewer.workPane.getLoadedViewers()) {
|
||||
if (c instanceof ClassViewer) {
|
||||
for (java.awt.Component c : BytecodeViewer.viewer.workPane.getLoadedViewers())
|
||||
{
|
||||
if (c instanceof ClassViewer)
|
||||
{
|
||||
ClassViewer cv = (ClassViewer) c;
|
||||
if (cv.smali1 != null && cv.smali1.isEditable() ||
|
||||
cv.smali2 != null && cv.smali2.isEditable() ||
|
||||
cv.smali3 != null && cv.smali3.isEditable()) {
|
||||
|
||||
//compile smali assembly
|
||||
if (cv.resourceViewPanel1.compileMode == ResourcePanelCompileMode.SMALI_ASSEMBLY && cv.resourceViewPanel1.textArea.isEditable() ||
|
||||
cv.resourceViewPanel2.compileMode == ResourcePanelCompileMode.SMALI_ASSEMBLY && cv.resourceViewPanel2.textArea.isEditable() ||
|
||||
cv.resourceViewPanel3.compileMode == ResourcePanelCompileMode.SMALI_ASSEMBLY && cv.resourceViewPanel3.textArea.isEditable())
|
||||
{
|
||||
actuallyTried = true;
|
||||
Object[] smali = cv.getSmali();
|
||||
if (smali != null) {
|
||||
if (smali != null)
|
||||
{
|
||||
ClassNode origNode = (ClassNode) smali[0];
|
||||
String smaliText = (String) smali[1];
|
||||
byte[] smaliCompiled =
|
||||
Compilers.smali.compile(smaliText,
|
||||
origNode.name);
|
||||
if (smaliCompiled != null) {
|
||||
byte[] smaliCompiled = Compilers.smali.compile(smaliText, origNode.name);
|
||||
|
||||
if (smaliCompiled != null)
|
||||
{
|
||||
try {
|
||||
ClassNode newNode = JarUtils.getNode(smaliCompiled);
|
||||
BytecodeViewer.updateNode(origNode, newNode);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
BytecodeViewer.showMessage("There has been an error with assembling your Smali code, "
|
||||
+ "please check this. Class: " + origNode.name);
|
||||
BytecodeViewer.viewer.updateBusyStatus(false);
|
||||
|
@ -408,26 +420,30 @@ public class BytecodeViewer
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
if (cv.krakatau1 != null && cv.krakatau1.isEditable() ||
|
||||
cv.krakatau2 != null && cv.krakatau2.isEditable() ||
|
||||
cv.krakatau3 != null && cv.krakatau3.isEditable()) {
|
||||
//compile krakatau assembly
|
||||
if (cv.resourceViewPanel1.compileMode == ResourcePanelCompileMode.KRAKATAU_ASSEMBLY && cv.resourceViewPanel1.textArea.isEditable() ||
|
||||
cv.resourceViewPanel2.compileMode == ResourcePanelCompileMode.KRAKATAU_ASSEMBLY && cv.resourceViewPanel2.textArea.isEditable() ||
|
||||
cv.resourceViewPanel3.compileMode == ResourcePanelCompileMode.KRAKATAU_ASSEMBLY && cv.resourceViewPanel3.textArea.isEditable())
|
||||
{
|
||||
actuallyTried = true;
|
||||
Object[] krakatau = cv.getKrakatau();
|
||||
if (krakatau != null) {
|
||||
if (krakatau != null)
|
||||
{
|
||||
ClassNode origNode = (ClassNode) krakatau[0];
|
||||
String krakatauText = (String) krakatau[1];
|
||||
byte[] krakatauCompiled =
|
||||
Compilers.krakatau.compile(krakatauText,
|
||||
origNode.name);
|
||||
if (krakatauCompiled != null) {
|
||||
byte[] krakatauCompiled = Compilers.krakatau.compile(krakatauText, origNode.name);
|
||||
|
||||
if (krakatauCompiled != null)
|
||||
{
|
||||
try {
|
||||
ClassNode newNode = JarUtils.getNode(krakatauCompiled);
|
||||
BytecodeViewer.updateNode(origNode, newNode);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
BytecodeViewer.showMessage("There has been an error with assembling your Krakatau "
|
||||
+ "Bytecode, please check this. Class: " + origNode.name);
|
||||
BytecodeViewer.viewer.updateBusyStatus(false);
|
||||
|
@ -436,9 +452,11 @@ public class BytecodeViewer
|
|||
}
|
||||
}
|
||||
|
||||
if (cv.java1 != null && cv.java1.isEditable() ||
|
||||
cv.java2 != null && cv.java2.isEditable() ||
|
||||
cv.java3 != null && cv.java3.isEditable()) {
|
||||
//default to java compiling
|
||||
if (cv.resourceViewPanel1.textArea != null && cv.resourceViewPanel1.textArea.isEditable() ||
|
||||
cv.resourceViewPanel2.textArea != null && cv.resourceViewPanel2.textArea.isEditable() ||
|
||||
cv.resourceViewPanel3.textArea != null && cv.resourceViewPanel3.textArea.isEditable())
|
||||
{
|
||||
actuallyTried = true;
|
||||
Object[] java = cv.getJava();
|
||||
if (java != null) {
|
||||
|
@ -449,10 +467,9 @@ public class BytecodeViewer
|
|||
errConsole.setText("Error compiling class: " + origNode.name + nl + "Keep in mind most "
|
||||
+ "decompilers cannot produce compilable classes" + nl + nl);
|
||||
|
||||
byte[] javaCompiled =
|
||||
Compilers.java.compile(javaText,
|
||||
origNode.name);
|
||||
if (javaCompiled != null) {
|
||||
byte[] javaCompiled = Compilers.java.compile(javaText, origNode.name);
|
||||
if (javaCompiled != null)
|
||||
{
|
||||
try {
|
||||
ClassNode newNode = JarUtils.getNode(javaCompiled);
|
||||
BytecodeViewer.updateNode(origNode, newNode);
|
||||
|
@ -460,7 +477,9 @@ public class BytecodeViewer
|
|||
e.printStackTrace();
|
||||
}
|
||||
errConsole.finished();
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
errConsole.pretty();
|
||||
errConsole.setVisible(true);
|
||||
errConsole.finished();
|
||||
|
@ -554,7 +573,7 @@ public class BytecodeViewer
|
|||
files.clear();
|
||||
LazyNameUtil.reset();
|
||||
Objects.requireNonNull(MainViewerGUI.getComponent(ResourceListPane.class)).resetWorkspace();
|
||||
Objects.requireNonNull(MainViewerGUI.getComponent(WorkPane.class)).resetWorkspace();
|
||||
Objects.requireNonNull(MainViewerGUI.getComponent(WorkPaneMainComponent.class)).resetWorkspace();
|
||||
Objects.requireNonNull(MainViewerGUI.getComponent(SearchBoxPane.class)).resetWorkspace();
|
||||
the.bytecode.club.bytecodeviewer.api.BytecodeViewer.getClassNodeLoader().clear();
|
||||
}
|
||||
|
|
|
@ -8,7 +8,7 @@ import org.apache.commons.cli.DefaultParser;
|
|||
import org.apache.commons.cli.Options;
|
||||
import org.objectweb.asm.ClassWriter;
|
||||
import org.objectweb.asm.tree.ClassNode;
|
||||
import the.bytecode.club.bytecodeviewer.decompilers.Decompilers;
|
||||
import the.bytecode.club.bytecodeviewer.decompilers.Decompiler;
|
||||
import the.bytecode.club.bytecodeviewer.util.JarUtils;
|
||||
import the.bytecode.club.bytecodeviewer.util.MiscUtils;
|
||||
|
||||
|
@ -200,12 +200,12 @@ public class CommandLineInput {
|
|||
Thread.sleep(5 * 1000);
|
||||
|
||||
if (target.equalsIgnoreCase("all")) {
|
||||
Decompilers.procyon.decompileToZip(tempZip.getAbsolutePath(), output.getAbsolutePath());
|
||||
Decompiler.PROCYON.getDecompiler().decompileToZip(tempZip.getAbsolutePath(), output.getAbsolutePath());
|
||||
} else {
|
||||
try {
|
||||
ClassNode cn = BytecodeViewer.getClassNode(target);
|
||||
final ClassWriter cw = accept(cn);
|
||||
String contents = Decompilers.procyon.decompileClassNode(cn, cw.toByteArray());
|
||||
String contents = Decompiler.PROCYON.getDecompiler().decompileClassNode(cn, cw.toByteArray());
|
||||
DiskWriter.replaceFile(output.getAbsolutePath(), contents, false);
|
||||
} catch (Exception e) {
|
||||
new the.bytecode.club.bytecodeviewer.api.ExceptionUI(e);
|
||||
|
@ -218,12 +218,12 @@ public class CommandLineInput {
|
|||
Thread.sleep(5 * 1000);
|
||||
|
||||
if (target.equalsIgnoreCase("all")) {
|
||||
Decompilers.cfr.decompileToZip(tempZip.getAbsolutePath(), output.getAbsolutePath());
|
||||
Decompiler.CFR.getDecompiler().decompileToZip(tempZip.getAbsolutePath(), output.getAbsolutePath());
|
||||
} else {
|
||||
try {
|
||||
ClassNode cn = BytecodeViewer.getClassNode(target);
|
||||
final ClassWriter cw = accept(cn);
|
||||
String contents = Decompilers.cfr.decompileClassNode(cn, cw.toByteArray());
|
||||
String contents = Decompiler.CFR.getDecompiler().decompileClassNode(cn, cw.toByteArray());
|
||||
DiskWriter.replaceFile(output.getAbsolutePath(), contents, false);
|
||||
} catch (Exception e) {
|
||||
new the.bytecode.club.bytecodeviewer.api.ExceptionUI(e);
|
||||
|
@ -236,12 +236,12 @@ public class CommandLineInput {
|
|||
Thread.sleep(5 * 1000);
|
||||
|
||||
if (target.equalsIgnoreCase("all")) {
|
||||
Decompilers.fernflower.decompileToZip(tempZip.getAbsolutePath(), output.getAbsolutePath());
|
||||
Decompiler.FERNFLOWER.getDecompiler().decompileToZip(tempZip.getAbsolutePath(), output.getAbsolutePath());
|
||||
} else {
|
||||
try {
|
||||
ClassNode cn = BytecodeViewer.getClassNode(target);
|
||||
final ClassWriter cw = accept(cn);
|
||||
String contents = Decompilers.fernflower.decompileClassNode(cn, cw.toByteArray());
|
||||
String contents = Decompiler.FERNFLOWER.getDecompiler().decompileClassNode(cn, cw.toByteArray());
|
||||
DiskWriter.replaceFile(output.getAbsolutePath(), contents, false);
|
||||
} catch (Exception e) {
|
||||
new the.bytecode.club.bytecodeviewer.api.ExceptionUI(e);
|
||||
|
@ -254,12 +254,12 @@ public class CommandLineInput {
|
|||
Thread.sleep(5 * 1000);
|
||||
|
||||
if (target.equalsIgnoreCase("all")) {
|
||||
Decompilers.krakatau.decompileToZip(tempZip.getAbsolutePath(), output.getAbsolutePath());
|
||||
Decompiler.KRAKATAU.getDecompiler().decompileToZip(tempZip.getAbsolutePath(), output.getAbsolutePath());
|
||||
} else {
|
||||
try {
|
||||
ClassNode cn = BytecodeViewer.getClassNode(target);
|
||||
final ClassWriter cw = accept(cn);
|
||||
String contents = Decompilers.krakatau.decompileClassNode(cn, cw.toByteArray());
|
||||
String contents = Decompiler.KRAKATAU.getDecompiler().decompileClassNode(cn, cw.toByteArray());
|
||||
DiskWriter.replaceFile(output.getAbsolutePath(), contents, false);
|
||||
} catch (Exception e) {
|
||||
new the.bytecode.club.bytecodeviewer.api.ExceptionUI(e);
|
||||
|
@ -278,7 +278,7 @@ public class CommandLineInput {
|
|||
try {
|
||||
ClassNode cn = BytecodeViewer.getClassNode(target);
|
||||
final ClassWriter cw = accept(cn);
|
||||
String contents = Decompilers.krakatauDA.decompileClassNode(cn, cw.toByteArray());
|
||||
String contents = Decompiler.KRAKATAU_BYTECODE.getDecompiler().decompileClassNode(cn, cw.toByteArray());
|
||||
DiskWriter.replaceFile(output.getAbsolutePath(), contents, false);
|
||||
} catch (Exception e) {
|
||||
new the.bytecode.club.bytecodeviewer.api.ExceptionUI(e);
|
||||
|
@ -297,7 +297,7 @@ public class CommandLineInput {
|
|||
try {
|
||||
ClassNode cn = BytecodeViewer.getClassNode(target);
|
||||
final ClassWriter cw = accept(cn);
|
||||
String contents = Decompilers.jdgui.decompileClassNode(cn, cw.toByteArray());
|
||||
String contents = Decompiler.JDGUI.getDecompiler().decompileClassNode(cn, cw.toByteArray());
|
||||
DiskWriter.replaceFile(output.getAbsolutePath(), contents, false);
|
||||
} catch (Exception e) {
|
||||
new the.bytecode.club.bytecodeviewer.api.ExceptionUI(e);
|
||||
|
@ -316,7 +316,26 @@ public class CommandLineInput {
|
|||
try {
|
||||
ClassNode cn = BytecodeViewer.getClassNode(target);
|
||||
final ClassWriter cw = accept(cn);
|
||||
String contents = Decompilers.smali.decompileClassNode(cn, cw.toByteArray());
|
||||
String contents = Decompiler.SMALI.getDecompiler().decompileClassNode(cn, cw.toByteArray());
|
||||
DiskWriter.replaceFile(output.getAbsolutePath(), contents, false);
|
||||
} catch (Exception e) {
|
||||
new the.bytecode.club.bytecodeviewer.api.ExceptionUI(e);
|
||||
}
|
||||
}
|
||||
} else if (decompiler.equalsIgnoreCase("jadx")) {
|
||||
System.out.println("Decompiling " + input.getAbsolutePath() + " with JADX");
|
||||
BytecodeViewer.openFiles(new File[]{input}, false);
|
||||
|
||||
Thread.sleep(5 * 1000);
|
||||
|
||||
if (target.equalsIgnoreCase("all")) {
|
||||
System.out.println("Coming soon.");
|
||||
//Decompiler.smali.decompileToZip(output.getAbsolutePath());
|
||||
} else {
|
||||
try {
|
||||
ClassNode cn = BytecodeViewer.getClassNode(target);
|
||||
final ClassWriter cw = accept(cn);
|
||||
String contents = Decompiler.JADX.getDecompiler().decompileClassNode(cn, cw.toByteArray());
|
||||
DiskWriter.replaceFile(output.getAbsolutePath(), contents, false);
|
||||
} catch (Exception e) {
|
||||
new the.bytecode.club.bytecodeviewer.api.ExceptionUI(e);
|
||||
|
|
|
@ -1,8 +1,13 @@
|
|||
package the.bytecode.club.bytecodeviewer;
|
||||
|
||||
import the.bytecode.club.bytecodeviewer.gui.theme.LAFTheme;
|
||||
import the.bytecode.club.bytecodeviewer.gui.theme.RSTATheme;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
/**
|
||||
* A collection of variables that can be configured through the settings menu or some form of UI/plugin
|
||||
*
|
||||
* @author Konloch
|
||||
* @since 6/21/2021
|
||||
*/
|
||||
|
@ -17,6 +22,7 @@ public class Configuration
|
|||
public static File krakatauTempDir;
|
||||
public static File krakatauTempJar;
|
||||
public static boolean displayParentInTab = false; //also change in the main GUI
|
||||
public static boolean simplifiedTabNames = false;
|
||||
public static boolean currentlyDumping = false;
|
||||
public static boolean needsReDump = true;
|
||||
public static boolean warnForEditing = false;
|
||||
|
@ -30,4 +36,7 @@ public class Configuration
|
|||
public static boolean verifyCorruptedStateOnBoot = false; //eventually may be a setting
|
||||
|
||||
public static long lastHotKeyExecuted = System.currentTimeMillis();
|
||||
|
||||
public static LAFTheme lafTheme = LAFTheme.LIGHT; //lightmode by default since it uses the system theme
|
||||
public static RSTATheme rstaTheme = lafTheme.getRSTATheme();
|
||||
}
|
|
@ -10,6 +10,9 @@ import java.util.ArrayList;
|
|||
import java.util.List;
|
||||
|
||||
/**
|
||||
* General program constants, to use this class include everything as a wildcard static import:
|
||||
* import static the.bytecode.club.bytecodeviewer.Constants.*;
|
||||
*
|
||||
* @author Konloch
|
||||
* @since 6/21/2021
|
||||
*/
|
||||
|
|
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 me.konloch.kontainer.io.DiskReader;
|
||||
import me.konloch.kontainer.io.DiskWriter;
|
||||
import the.bytecode.club.bytecodeviewer.gui.theme.LAFTheme;
|
||||
import the.bytecode.club.bytecodeviewer.gui.theme.RSTATheme;
|
||||
|
||||
import static the.bytecode.club.bytecodeviewer.Constants.*;
|
||||
|
||||
|
@ -291,23 +293,48 @@ public class Settings {
|
|||
String.valueOf(BytecodeViewer.viewer.ren.isSelected()), false);
|
||||
DiskWriter.writeNewLine(settingsName,
|
||||
String.valueOf(BytecodeViewer.viewer.viewPane1.getJADX().getEditable().isSelected()), false);
|
||||
DiskWriter.writeNewLine(settingsName,
|
||||
Configuration.lafTheme.name(), false);
|
||||
DiskWriter.writeNewLine(settingsName,
|
||||
Configuration.rstaTheme.name(), false);
|
||||
DiskWriter.writeNewLine(settingsName,
|
||||
String.valueOf(BytecodeViewer.viewer.simplifyNameInTabTitle.isSelected()), false);
|
||||
} catch (Exception e) {
|
||||
new the.bytecode.club.bytecodeviewer.api.ExceptionUI(e);
|
||||
}
|
||||
}
|
||||
|
||||
public static void preloadSettingsFile()
|
||||
{
|
||||
try
|
||||
{
|
||||
//precache the file
|
||||
DiskReader.loadString(settingsName, 0, true);
|
||||
|
||||
//process the cached file
|
||||
Configuration.lafTheme = LAFTheme.valueOf(asString(127));
|
||||
Configuration.rstaTheme = RSTATheme.valueOf(asString(128));
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
//ignore because errors are expected, first start up and outdated settings.
|
||||
//e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public static void loadSettings() { //utilizes the Disk Reader's caching system.
|
||||
try {
|
||||
BytecodeViewer.viewer.rbr.setSelected(Boolean.parseBoolean(DiskReader.loadString(settingsName, 1, true)));
|
||||
BytecodeViewer.viewer.rsy.setSelected(Boolean.parseBoolean(DiskReader.loadString(settingsName, 2, false)));
|
||||
BytecodeViewer.viewer.din.setSelected(Boolean.parseBoolean(DiskReader.loadString(settingsName, 3, false)));
|
||||
BytecodeViewer.viewer.dc4.setSelected(Boolean.parseBoolean(DiskReader.loadString(settingsName, 4, false)));
|
||||
BytecodeViewer.viewer.das.setSelected(Boolean.parseBoolean(DiskReader.loadString(settingsName, 5, false)));
|
||||
BytecodeViewer.viewer.hes.setSelected(Boolean.parseBoolean(DiskReader.loadString(settingsName, 6, false)));
|
||||
BytecodeViewer.viewer.hdc.setSelected(Boolean.parseBoolean(DiskReader.loadString(settingsName, 7, false)));
|
||||
BytecodeViewer.viewer.dgs.setSelected(Boolean.parseBoolean(DiskReader.loadString(settingsName, 8, false)));
|
||||
BytecodeViewer.viewer.ner.setSelected(Boolean.parseBoolean(DiskReader.loadString(settingsName, 9, false)));
|
||||
BytecodeViewer.viewer.den.setSelected(Boolean.parseBoolean(DiskReader.loadString(settingsName, 10, false)));
|
||||
//parse the cached file from memory
|
||||
BytecodeViewer.viewer.rbr.setSelected(asBoolean(1));
|
||||
BytecodeViewer.viewer.rsy.setSelected(asBoolean(2));
|
||||
BytecodeViewer.viewer.din.setSelected(asBoolean(3));
|
||||
BytecodeViewer.viewer.dc4.setSelected(asBoolean(4));
|
||||
BytecodeViewer.viewer.das.setSelected(asBoolean(5));
|
||||
BytecodeViewer.viewer.hes.setSelected(asBoolean(6));
|
||||
BytecodeViewer.viewer.hdc.setSelected(asBoolean(7));
|
||||
BytecodeViewer.viewer.dgs.setSelected(asBoolean(8));
|
||||
BytecodeViewer.viewer.ner.setSelected(asBoolean(9));
|
||||
BytecodeViewer.viewer.den.setSelected(asBoolean(10));
|
||||
BytecodeViewer.viewer.rgn.setSelected(Boolean.parseBoolean(DiskReader.loadString(settingsName, 11, false)));
|
||||
BytecodeViewer.viewer.bto.setSelected(Boolean.parseBoolean(DiskReader.loadString(settingsName, 12, false)));
|
||||
BytecodeViewer.viewer.nns.setSelected(Boolean.parseBoolean(DiskReader.loadString(settingsName, 13, false)));
|
||||
|
@ -378,30 +405,30 @@ public class Settings {
|
|||
BytecodeViewer.viewer.debugHelpers.setSelected(Boolean.parseBoolean(DiskReader.loadString(settingsName, 78, false)));
|
||||
//79 is deprecated
|
||||
BytecodeViewer.viewer.updateCheck.setSelected(Boolean.parseBoolean(DiskReader.loadString(settingsName, 80, false)));
|
||||
BytecodeViewer.viewer.viewPane1.setSelectedViewer(getInt(81));
|
||||
BytecodeViewer.viewer.viewPane2.setSelectedViewer(getInt(82));
|
||||
BytecodeViewer.viewer.viewPane3.setSelectedViewer(getInt(83));
|
||||
BytecodeViewer.viewer.viewPane1.setSelectedViewer(asInt(81));
|
||||
BytecodeViewer.viewer.viewPane2.setSelectedViewer(asInt(82));
|
||||
BytecodeViewer.viewer.viewPane3.setSelectedViewer(asInt(83));
|
||||
|
||||
BytecodeViewer.viewer.refreshOnChange.setSelected(Boolean.parseBoolean(DiskReader.loadString(settingsName, 84, false)));
|
||||
BytecodeViewer.viewer.refreshOnChange.setSelected(asBoolean(84));
|
||||
|
||||
boolean bool = Boolean.parseBoolean(DiskReader.loadString(settingsName, 85, false));
|
||||
boolean bool = Boolean.parseBoolean(asString(85));
|
||||
if (bool) {
|
||||
BytecodeViewer.viewer.setExtendedState(JFrame.MAXIMIZED_BOTH);
|
||||
BytecodeViewer.viewer.isMaximized = true;
|
||||
}
|
||||
//86 is deprecated
|
||||
//87 is deprecated
|
||||
Configuration.lastDirectory = DiskReader.loadString(settingsName, 88, false);
|
||||
Configuration.python = DiskReader.loadString(settingsName, 89, false);
|
||||
Configuration.rt = DiskReader.loadString(settingsName, 90, false);
|
||||
BytecodeViewer.viewer.viewPane1.getProcyon().getEditable().setSelected(Boolean.parseBoolean(DiskReader.loadString(settingsName, 91, false)));
|
||||
BytecodeViewer.viewer.viewPane1.getCFR().getEditable().setSelected(Boolean.parseBoolean(DiskReader.loadString(settingsName, 92, false)));
|
||||
BytecodeViewer.viewer.viewPane1.getFern().getEditable().setSelected(Boolean.parseBoolean(DiskReader.loadString(settingsName, 93, false)));
|
||||
BytecodeViewer.viewer.viewPane1.getKrakatau().getEditable().setSelected(Boolean.parseBoolean(DiskReader.loadString(settingsName, 94, false)));
|
||||
BytecodeViewer.viewer.viewPane1.getSmali().getEditable().setSelected(Boolean.parseBoolean(DiskReader.loadString(settingsName, 95, false)));
|
||||
BytecodeViewer.viewer.viewPane2.getProcyon().getEditable().setSelected(Boolean.parseBoolean(DiskReader.loadString(settingsName, 96, false)));
|
||||
BytecodeViewer.viewer.viewPane2.getCFR().getEditable().setSelected(Boolean.parseBoolean(DiskReader.loadString(settingsName, 97, false)));
|
||||
BytecodeViewer.viewer.viewPane2.getFern().getEditable().setSelected(Boolean.parseBoolean(DiskReader.loadString(settingsName, 98, false)));
|
||||
Configuration.lastDirectory = asString(88);
|
||||
Configuration.python = asString(89);
|
||||
Configuration.rt = asString(90);
|
||||
BytecodeViewer.viewer.viewPane1.getProcyon().getEditable().setSelected(asBoolean(91));
|
||||
BytecodeViewer.viewer.viewPane1.getCFR().getEditable().setSelected(asBoolean(92));
|
||||
BytecodeViewer.viewer.viewPane1.getFern().getEditable().setSelected(asBoolean(93));
|
||||
BytecodeViewer.viewer.viewPane1.getKrakatau().getEditable().setSelected(asBoolean(94));
|
||||
BytecodeViewer.viewer.viewPane1.getSmali().getEditable().setSelected(asBoolean(95));
|
||||
BytecodeViewer.viewer.viewPane2.getProcyon().getEditable().setSelected(asBoolean(96));
|
||||
BytecodeViewer.viewer.viewPane2.getCFR().getEditable().setSelected(asBoolean(97));
|
||||
BytecodeViewer.viewer.viewPane2.getFern().getEditable().setSelected(asBoolean(98));
|
||||
BytecodeViewer.viewer.viewPane2.getKrakatau().getEditable().setSelected(asBoolean(99));
|
||||
BytecodeViewer.viewer.viewPane2.getSmali().getEditable().setSelected(asBoolean(100));
|
||||
BytecodeViewer.viewer.viewPane3.getProcyon().getEditable().setSelected(asBoolean(101));
|
||||
|
@ -410,26 +437,31 @@ public class Settings {
|
|||
BytecodeViewer.viewer.viewPane3.getKrakatau().getEditable().setSelected(asBoolean(104));
|
||||
BytecodeViewer.viewer.viewPane3.getSmali().getEditable().setSelected(asBoolean(105));
|
||||
BytecodeViewer.viewer.decodeAPKResources.setSelected(asBoolean(106));
|
||||
Configuration.library = DiskReader.loadString(settingsName, 107, false);
|
||||
Configuration.library = asString(107);
|
||||
Configuration.pingback = asBoolean(108);
|
||||
BytecodeViewer.viewer.viewPane1.getJD().getEditable().setSelected(asBoolean(109));
|
||||
BytecodeViewer.viewer.viewPane2.getJD().getEditable().setSelected(asBoolean(110));
|
||||
BytecodeViewer.viewer.viewPane3.getJD().getEditable().setSelected(asBoolean(111));
|
||||
BytecodeViewer.viewer.fontSpinner.setValue(getInt(112));
|
||||
BytecodeViewer.viewer.fontSpinner.setValue(asInt(112));
|
||||
Configuration.deleteForeignLibraries = asBoolean(113);
|
||||
int apkDecompiler = getInt(114);
|
||||
|
||||
if (apkDecompiler == 0)
|
||||
//APK Decompiler
|
||||
switch(asInt(114))
|
||||
{
|
||||
case 0:
|
||||
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);
|
||||
break;
|
||||
}
|
||||
|
||||
Configuration.python3 = DiskReader.loadString(settingsName, 115, false);
|
||||
Configuration.javac = DiskReader.loadString(settingsName, 116, false);
|
||||
Configuration.java = DiskReader.loadString(settingsName, 117, false);
|
||||
Configuration.python3 = asString(115);
|
||||
Configuration.javac = asString(116);
|
||||
Configuration.java = asString(117);
|
||||
BytecodeViewer.viewer.compileOnSave.setSelected(asBoolean(118));
|
||||
BytecodeViewer.viewer.autoCompileOnRefresh.setSelected(asBoolean(119));
|
||||
Configuration.warnForEditing = Boolean.parseBoolean(DiskReader.loadString(settingsName, 120, false));
|
||||
Configuration.warnForEditing = asBoolean(120);
|
||||
BytecodeViewer.viewer.showFileInTabTitle.setSelected(asBoolean(121));
|
||||
Configuration.displayParentInTab = BytecodeViewer.viewer.showFileInTabTitle.isSelected();
|
||||
BytecodeViewer.viewer.forcePureAsciiAsText.setSelected(asBoolean(122));
|
||||
|
@ -437,18 +469,27 @@ public class Settings {
|
|||
BytecodeViewer.viewer.showClassMethods.setSelected(asBoolean(124));
|
||||
BytecodeViewer.viewer.ren.setSelected(asBoolean(125));
|
||||
BytecodeViewer.viewer.viewPane1.getJADX().getEditable().setSelected(asBoolean(126));
|
||||
//line 127 is used for theme on preload
|
||||
//line 128 is used for theme on preload
|
||||
BytecodeViewer.viewer.simplifyNameInTabTitle.setSelected(asBoolean(129));
|
||||
Configuration.simplifiedTabNames = BytecodeViewer.viewer.simplifyNameInTabTitle.isSelected();
|
||||
} catch (Exception e) {
|
||||
//ignore because errors are expected, first start up and outdated settings.
|
||||
//e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public static String asString(int lineNumber) throws Exception
|
||||
{
|
||||
return DiskReader.loadString(settingsName, lineNumber, false);
|
||||
}
|
||||
|
||||
public static boolean asBoolean(int lineNumber) throws Exception
|
||||
{
|
||||
return Boolean.parseBoolean(DiskReader.loadString(settingsName, lineNumber, false));
|
||||
}
|
||||
|
||||
public static int getInt(int lineNumber) throws Exception
|
||||
public static int asInt(int lineNumber) throws Exception
|
||||
{
|
||||
return Integer.parseInt(DiskReader.loadString(settingsName, lineNumber, false));
|
||||
}
|
||||
|
|
|
@ -10,10 +10,11 @@ import java.util.jar.JarEntry;
|
|||
import java.util.jar.JarFile;
|
||||
import org.objectweb.asm.tree.ClassNode;
|
||||
import the.bytecode.club.bytecodeviewer.compilers.Compilers;
|
||||
import the.bytecode.club.bytecodeviewer.decompilers.InternalDecompiler;
|
||||
import the.bytecode.club.bytecodeviewer.decompilers.Decompiler;
|
||||
import the.bytecode.club.bytecodeviewer.decompilers.Decompilers;
|
||||
import the.bytecode.club.bytecodeviewer.plugin.preinstalled.EZInjection;
|
||||
import the.bytecode.club.bytecodeviewer.util.JarUtils;
|
||||
import the.bytecode.club.bytecodeviewer.util.MiscUtils;
|
||||
|
||||
import static the.bytecode.club.bytecodeviewer.Constants.*;
|
||||
|
||||
|
@ -41,7 +42,6 @@ import static the.bytecode.club.bytecodeviewer.Constants.*;
|
|||
*
|
||||
* @author Konloch
|
||||
*/
|
||||
|
||||
public class BytecodeViewer {
|
||||
|
||||
private static URLClassLoader cl;
|
||||
|
@ -72,7 +72,7 @@ public class BytecodeViewer {
|
|||
*/
|
||||
public static List<Class<?>> loadClassesIntoClassLoader() {
|
||||
try {
|
||||
File f = new File(tempDirectory + fs + "loaded_temp.jar");
|
||||
File f = new File(tempDirectory + fs + MiscUtils.randomString(12) + "loaded_temp.jar");
|
||||
JarUtils.saveAsJar(BytecodeViewer.getLoadedClasses(), f.getAbsolutePath());
|
||||
JarFile jarFile = new JarFile("" + f.getAbsolutePath());
|
||||
Enumeration<JarEntry> e = jarFile.entries();
|
||||
|
@ -201,8 +201,8 @@ public class BytecodeViewer {
|
|||
*
|
||||
* @return The wrapped Krakatau Decompiler instance
|
||||
*/
|
||||
public static Decompiler getKrakatauDecompiler() {
|
||||
return Decompilers.krakatau;
|
||||
public static InternalDecompiler getKrakatauDecompiler() {
|
||||
return Decompiler.KRAKATAU.getDecompiler();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -210,8 +210,8 @@ public class BytecodeViewer {
|
|||
*
|
||||
* @return The wrapped Procyon Decompiler instance
|
||||
*/
|
||||
public static Decompiler getProcyonDecompiler() {
|
||||
return Decompilers.procyon;
|
||||
public static InternalDecompiler getProcyonDecompiler() {
|
||||
return Decompiler.PROCYON.getDecompiler();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -219,8 +219,8 @@ public class BytecodeViewer {
|
|||
*
|
||||
* @return The wrapped CFR Decompiler instance
|
||||
*/
|
||||
public static Decompiler getCFRDecompiler() {
|
||||
return Decompilers.cfr;
|
||||
public static InternalDecompiler getCFRDecompiler() {
|
||||
return Decompiler.CFR.getDecompiler();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -228,8 +228,8 @@ public class BytecodeViewer {
|
|||
*
|
||||
* @return The wrapped FernFlower Decompiler instance
|
||||
*/
|
||||
public static Decompiler getFernFlowerDecompiler() {
|
||||
return Decompilers.fernflower;
|
||||
public static InternalDecompiler getFernFlowerDecompiler() {
|
||||
return Decompiler.FERNFLOWER.getDecompiler();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -237,8 +237,26 @@ public class BytecodeViewer {
|
|||
*
|
||||
* @return The wrapped Krakatau Disassembler instance
|
||||
*/
|
||||
public static Decompiler getKrakatauDisassembler() {
|
||||
return Decompilers.krakatauDA;
|
||||
public static InternalDecompiler getKrakatauDisassembler() {
|
||||
return Decompiler.KRAKATAU_BYTECODE.getDecompiler();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the wrapped JD-GUI Decompiler instance.
|
||||
*
|
||||
* @return The wrapped JD-GUI Decompiler instance
|
||||
*/
|
||||
public static InternalDecompiler getDJGUIDecompiler() {
|
||||
return Decompiler.JDGUI.getDecompiler();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the wrapped JADX Decompiler instance.
|
||||
*
|
||||
* @return The wrapped JADX Decompiler instance
|
||||
*/
|
||||
public static InternalDecompiler getJADXDecompiler() {
|
||||
return Decompiler.JADX.getDecompiler();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -258,13 +276,4 @@ public class BytecodeViewer {
|
|||
public static the.bytecode.club.bytecodeviewer.compilers.Compiler getSmaliCompiler() {
|
||||
return Compilers.smali;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the wrapped JD-GUI Decompiler instance.
|
||||
*
|
||||
* @return The wrapped JD-GUI Decompiler instance
|
||||
*/
|
||||
public static the.bytecode.club.bytecodeviewer.decompilers.Decompiler getDJGUIDecompiler() {
|
||||
return Decompilers.jdgui;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
package the.bytecode.club.bytecodeviewer.api;
|
||||
|
||||
import java.awt.BorderLayout;
|
||||
import java.awt.Color;
|
||||
import java.awt.Dimension;
|
||||
import java.awt.event.KeyEvent;
|
||||
import java.awt.event.KeyListener;
|
||||
|
@ -10,13 +9,14 @@ import javax.swing.JCheckBox;
|
|||
import javax.swing.JFrame;
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.JScrollPane;
|
||||
import javax.swing.JTextArea;
|
||||
import javax.swing.JTextField;
|
||||
import javax.swing.text.DefaultHighlighter;
|
||||
import javax.swing.text.Highlighter;
|
||||
import javax.swing.text.JTextComponent;
|
||||
|
||||
import the.bytecode.club.bytecodeviewer.BytecodeViewer;
|
||||
import the.bytecode.club.bytecodeviewer.Resources;
|
||||
import the.bytecode.club.bytecodeviewer.gui.components.JFrameConsole;
|
||||
import the.bytecode.club.bytecodeviewer.gui.components.SearchableJTextArea;
|
||||
import the.bytecode.club.bytecodeviewer.gui.components.listeners.PressKeyListener;
|
||||
import the.bytecode.club.bytecodeviewer.gui.components.listeners.ReleaseKeyListener;
|
||||
|
||||
/***************************************************************************
|
||||
* Bytecode Viewer (BCV) - Java & Android Reverse Engineering Suite *
|
||||
|
@ -42,219 +42,11 @@ import the.bytecode.club.bytecodeviewer.Resources;
|
|||
* @author Konloch
|
||||
*/
|
||||
|
||||
public class PluginConsole extends JFrame {
|
||||
|
||||
JTextArea textArea = new JTextArea();
|
||||
JPanel panel = new JPanel(new BorderLayout());
|
||||
JScrollPane scrollPane = new JScrollPane();
|
||||
public JCheckBox check = new JCheckBox("Exact");
|
||||
final JTextField field = new JTextField();
|
||||
|
||||
public PluginConsole(String pluginName) {
|
||||
this.setIconImages(Resources.iconList);
|
||||
setTitle("Bytecode Viewer - Plugin Console - " + pluginName);
|
||||
setSize(new Dimension(542, 316));
|
||||
|
||||
getContentPane().add(scrollPane, BorderLayout.CENTER);
|
||||
|
||||
scrollPane.setViewportView(textArea);
|
||||
textArea.addKeyListener(new KeyListener() {
|
||||
@Override
|
||||
public void keyPressed(KeyEvent e) {
|
||||
if ((e.getKeyCode() == KeyEvent.VK_F) && ((e.getModifiers() & KeyEvent.CTRL_MASK) != 0)) {
|
||||
field.requestFocus();
|
||||
}
|
||||
|
||||
BytecodeViewer.checkHotKey(e);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void keyReleased(KeyEvent arg0) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void keyTyped(KeyEvent arg0) {
|
||||
}
|
||||
});
|
||||
|
||||
JButton searchNext = new JButton();
|
||||
JButton searchPrev = new JButton();
|
||||
JPanel buttonPane = new JPanel(new BorderLayout());
|
||||
buttonPane.add(searchNext, BorderLayout.WEST);
|
||||
buttonPane.add(searchPrev, BorderLayout.EAST);
|
||||
searchNext.setIcon(Resources.nextIcon);
|
||||
searchPrev.setIcon(Resources.prevIcon);
|
||||
panel.add(buttonPane, BorderLayout.WEST);
|
||||
panel.add(field, BorderLayout.CENTER);
|
||||
panel.add(check, BorderLayout.EAST);
|
||||
searchNext.addActionListener(arg0 -> search(field.getText(), true));
|
||||
searchPrev.addActionListener(arg0 -> search(field.getText(), false));
|
||||
field.addKeyListener(new KeyListener() {
|
||||
@Override
|
||||
public void keyReleased(KeyEvent arg0) {
|
||||
if (arg0.getKeyCode() == KeyEvent.VK_ENTER)
|
||||
search(field.getText(), true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void keyPressed(KeyEvent arg0) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void keyTyped(KeyEvent arg0) {
|
||||
}
|
||||
});
|
||||
scrollPane.setColumnHeaderView(panel);
|
||||
this.setLocationRelativeTo(null);
|
||||
}
|
||||
|
||||
/**
|
||||
* This was really interesting to write.
|
||||
*
|
||||
* @author Konloch
|
||||
*/
|
||||
public void search(String search, boolean next) {
|
||||
try {
|
||||
JTextArea area = textArea;
|
||||
if (search.isEmpty()) {
|
||||
highlight(area, "");
|
||||
return;
|
||||
}
|
||||
|
||||
int startLine = area.getDocument().getDefaultRootElement()
|
||||
.getElementIndex(area.getCaretPosition()) + 1;
|
||||
int currentLine = 1;
|
||||
boolean canSearch = false;
|
||||
String[] test;
|
||||
if (area.getText().split("\n").length >= 2)
|
||||
test = area.getText().split("\n");
|
||||
else
|
||||
test = area.getText().split("\r");
|
||||
int lastGoodLine = -1;
|
||||
int firstPos = -1;
|
||||
boolean found = false;
|
||||
|
||||
if (next) {
|
||||
for (String s : test) {
|
||||
if (!check.isSelected()) {
|
||||
s = s.toLowerCase();
|
||||
search = search.toLowerCase();
|
||||
}
|
||||
|
||||
if (currentLine == startLine) {
|
||||
canSearch = true;
|
||||
} else if (s.contains(search)) {
|
||||
if (canSearch) {
|
||||
area.setCaretPosition(area.getDocument()
|
||||
.getDefaultRootElement()
|
||||
.getElement(currentLine - 1)
|
||||
.getStartOffset());
|
||||
canSearch = false;
|
||||
found = true;
|
||||
}
|
||||
|
||||
if (firstPos == -1)
|
||||
firstPos = currentLine;
|
||||
}
|
||||
|
||||
currentLine++;
|
||||
}
|
||||
|
||||
if (!found && firstPos != -1) {
|
||||
area.setCaretPosition(area.getDocument()
|
||||
.getDefaultRootElement().getElement(firstPos - 1)
|
||||
.getStartOffset());
|
||||
}
|
||||
} else {
|
||||
canSearch = true;
|
||||
for (String s : test) {
|
||||
if (!check.isSelected()) {
|
||||
s = s.toLowerCase();
|
||||
search = search.toLowerCase();
|
||||
}
|
||||
|
||||
if (s.contains(search)) {
|
||||
if (lastGoodLine != -1 && canSearch)
|
||||
area.setCaretPosition(area.getDocument()
|
||||
.getDefaultRootElement()
|
||||
.getElement(lastGoodLine - 1)
|
||||
.getStartOffset());
|
||||
|
||||
lastGoodLine = currentLine;
|
||||
|
||||
if (currentLine >= startLine)
|
||||
canSearch = false;
|
||||
}
|
||||
currentLine++;
|
||||
}
|
||||
|
||||
if (lastGoodLine != -1
|
||||
&& area.getDocument().getDefaultRootElement()
|
||||
.getElementIndex(area.getCaretPosition()) + 1 == startLine) {
|
||||
area.setCaretPosition(area.getDocument()
|
||||
.getDefaultRootElement()
|
||||
.getElement(lastGoodLine - 1).getStartOffset());
|
||||
}
|
||||
}
|
||||
highlight(area, search);
|
||||
} catch (Exception e) {
|
||||
new the.bytecode.club.bytecodeviewer.api.ExceptionUI(e);
|
||||
}
|
||||
}
|
||||
|
||||
private final DefaultHighlighter.DefaultHighlightPainter painter = new DefaultHighlighter.DefaultHighlightPainter(
|
||||
new Color(255, 62, 150));
|
||||
|
||||
public void highlight(JTextComponent textComp, String pattern) {
|
||||
if (pattern.isEmpty()) {
|
||||
textComp.getHighlighter().removeAllHighlights();
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
Highlighter hilite = textComp.getHighlighter();
|
||||
hilite.removeAllHighlights();
|
||||
javax.swing.text.Document doc = textComp.getDocument();
|
||||
String text = doc.getText(0, doc.getLength());
|
||||
int pos = 0;
|
||||
|
||||
if (!check.isSelected()) {
|
||||
pattern = pattern.toLowerCase();
|
||||
text = text.toLowerCase();
|
||||
}
|
||||
|
||||
// Search for pattern
|
||||
while ((pos = text.indexOf(pattern, pos)) >= 0) {
|
||||
// Create highlighter using private painter and apply around
|
||||
// pattern
|
||||
hilite.addHighlight(pos, pos + pattern.length(), painter);
|
||||
pos += pattern.length();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
new the.bytecode.club.bytecodeviewer.api.ExceptionUI(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Appends \r\n to the end of your string, then it puts it on the top.
|
||||
*
|
||||
* @param t the string you want to append
|
||||
*/
|
||||
public void appendText(String t) {
|
||||
textArea.setText((textArea.getText().isEmpty() ? "" : textArea
|
||||
.getText() + "\r\n")
|
||||
+ t);
|
||||
textArea.setCaretPosition(0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the text
|
||||
*
|
||||
* @param t the text you want set
|
||||
*/
|
||||
public void setText(String t) {
|
||||
textArea.setText(t);
|
||||
textArea.setCaretPosition(0);
|
||||
public class PluginConsole extends JFrameConsole
|
||||
{
|
||||
public PluginConsole(String pluginName)
|
||||
{
|
||||
super("Bytecode Viewer - Plugin Console - " + pluginName);
|
||||
}
|
||||
|
||||
private static final long serialVersionUID = -6556940545421437508L;
|
||||
|
|
|
@ -29,7 +29,8 @@ import org.objectweb.asm.util.TraceClassVisitor;
|
|||
*
|
||||
* @author Thiakil
|
||||
*/
|
||||
public class ASMTextifierDecompiler extends Decompiler {
|
||||
public class ASMTextifierDecompiler extends InternalDecompiler
|
||||
{
|
||||
@Override
|
||||
public String decompileClassNode(ClassNode cn, byte[] b) {
|
||||
StringWriter writer = new StringWriter();
|
||||
|
|
|
@ -46,7 +46,8 @@ import static the.bytecode.club.bytecodeviewer.Constants.*;
|
|||
* @author Konloch
|
||||
*/
|
||||
|
||||
public class CFRDecompiler extends Decompiler {
|
||||
public class CFRDecompiler extends InternalDecompiler
|
||||
{
|
||||
|
||||
private static final String[] WINDOWS_IS_GREAT = new String[]
|
||||
{
|
||||
|
|
|
@ -1,6 +1,11 @@
|
|||
package the.bytecode.club.bytecodeviewer.decompilers;
|
||||
|
||||
import org.objectweb.asm.tree.ClassNode;
|
||||
import the.bytecode.club.bytecodeviewer.BytecodeViewer;
|
||||
import the.bytecode.club.bytecodeviewer.decompilers.bytecode.ClassNodeDecompiler;
|
||||
import the.bytecode.club.bytecodeviewer.gui.components.DecompilerViewComponent;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.util.HashMap;
|
||||
|
||||
/***************************************************************************
|
||||
* Bytecode Viewer (BCV) - Java & Android Reverse Engineering Suite *
|
||||
|
@ -21,15 +26,90 @@ import org.objectweb.asm.tree.ClassNode;
|
|||
***************************************************************************/
|
||||
|
||||
/**
|
||||
* Used to represent all of the decompilers/disassemblers BCV contains.
|
||||
* All of the decompilers/disassemblers BCV uses
|
||||
*
|
||||
* @author Konloch
|
||||
*/
|
||||
public 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 abstract void decompileToZip(String sourceJar, String zipName);
|
||||
public static final HashMap<Integer, Decompiler> decompilersByIndex = new HashMap<>();
|
||||
|
||||
static
|
||||
{
|
||||
for(Decompiler d : values())
|
||||
decompilersByIndex.put(d.decompilerIndex, d);
|
||||
}
|
||||
|
||||
Decompiler(int decompilerIndex, String decompilerName, InternalDecompiler decompiler, DecompilerViewComponent decompilerSelectComponent) {
|
||||
this.decompilerIndex = decompilerIndex;
|
||||
this.decompilerName = decompilerName;
|
||||
this.decompiler = decompiler;
|
||||
this.decompilerSelectComponent = decompilerSelectComponent;
|
||||
this.basicSelectComponent = null;
|
||||
}
|
||||
|
||||
Decompiler(int decompilerIndex, String decompilerName, InternalDecompiler decompiler, JRadioButtonMenuItem basicSelectComponent)
|
||||
{
|
||||
this.decompilerIndex = decompilerIndex;
|
||||
this.decompilerName = decompilerName;
|
||||
this.decompiler = decompiler;
|
||||
this.decompilerSelectComponent = null;
|
||||
this.basicSelectComponent = basicSelectComponent;
|
||||
}
|
||||
|
||||
public void addDecompilerToGroup(ButtonGroup group)
|
||||
{
|
||||
if(decompilerSelectComponent != null)
|
||||
decompilerSelectComponent.addToGroup(group);
|
||||
else if(basicSelectComponent != null)
|
||||
group.add(basicSelectComponent);
|
||||
}
|
||||
|
||||
public int getDecompilerIndex()
|
||||
{
|
||||
return decompilerIndex;
|
||||
}
|
||||
|
||||
public String getDecompilerName()
|
||||
{
|
||||
return decompilerName;
|
||||
}
|
||||
|
||||
public InternalDecompiler getDecompiler()
|
||||
{
|
||||
return decompiler;
|
||||
}
|
||||
|
||||
public DecompilerViewComponent getDecompilerSelectComponent()
|
||||
{
|
||||
return decompilerSelectComponent;
|
||||
}
|
||||
|
||||
public JMenuItem getMenu()
|
||||
{
|
||||
if(decompilerSelectComponent != null)
|
||||
return decompilerSelectComponent.getMenu();
|
||||
|
||||
return basicSelectComponent;
|
||||
}
|
||||
}
|
|
@ -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 WaterWolf
|
||||
*/
|
||||
public class FernFlowerDecompiler extends Decompiler {
|
||||
public class FernFlowerDecompiler extends InternalDecompiler
|
||||
{
|
||||
|
||||
@Override
|
||||
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
|
||||
*/
|
||||
public class JADXDecompiler extends Decompiler {
|
||||
public class JADXDecompiler extends InternalDecompiler
|
||||
{
|
||||
@Override
|
||||
public String decompileClassNode(ClassNode cn, byte[] b) {
|
||||
String fileStart = tempDirectory + fs;
|
||||
|
|
|
@ -13,7 +13,6 @@ import jd.cli.util.ClassFileUtil;
|
|||
import me.konloch.kontainer.io.DiskReader;
|
||||
import org.jd.core.v1.ClassFileToJavaSourceDecompiler;
|
||||
import org.objectweb.asm.tree.ClassNode;
|
||||
import the.bytecode.club.bytecodeviewer.BytecodeViewer;
|
||||
import the.bytecode.club.bytecodeviewer.Constants;
|
||||
import the.bytecode.club.bytecodeviewer.util.MiscUtils;
|
||||
|
||||
|
@ -44,7 +43,8 @@ import static the.bytecode.club.bytecodeviewer.Constants.*;
|
|||
* @author JD-Core developers
|
||||
*/
|
||||
|
||||
public class JDGUIDecompiler extends Decompiler {
|
||||
public class JDGUIDecompiler extends InternalDecompiler
|
||||
{
|
||||
|
||||
@Override
|
||||
public String decompileClassNode(ClassNode cn, byte[] b) {
|
||||
|
|
|
@ -42,7 +42,8 @@ import static the.bytecode.club.bytecodeviewer.Constants.*;
|
|||
* @author Konloch
|
||||
*/
|
||||
|
||||
public class KrakatauDecompiler extends Decompiler {
|
||||
public class KrakatauDecompiler extends InternalDecompiler
|
||||
{
|
||||
|
||||
public String quick() {
|
||||
if (Configuration.library.isEmpty())
|
||||
|
|
|
@ -41,7 +41,8 @@ import static the.bytecode.club.bytecodeviewer.Constants.*;
|
|||
* @author Konloch
|
||||
*/
|
||||
|
||||
public class KrakatauDisassembler extends Decompiler {
|
||||
public class KrakatauDisassembler extends InternalDecompiler
|
||||
{
|
||||
|
||||
public String decompileClassNode(File krakatauTempJar, File krakatauTempDir, ClassNode cn) {
|
||||
if (Configuration.python.isEmpty()) {
|
||||
|
|
|
@ -61,9 +61,10 @@ import static the.bytecode.club.bytecodeviewer.Constants.*;
|
|||
* @author Konloch
|
||||
* @author DeathMarine
|
||||
*/
|
||||
public class ProcyonDecompiler extends Decompiler {
|
||||
|
||||
public DecompilerSettings getDecompilerSettings() {
|
||||
public class ProcyonDecompiler extends InternalDecompiler
|
||||
{
|
||||
public DecompilerSettings getDecompilerSettings()
|
||||
{
|
||||
DecompilerSettings settings = new DecompilerSettings();
|
||||
settings.setAlwaysGenerateExceptionVariableForCatchBlocks(BytecodeViewer.viewer.alwaysGenerateExceptionVars.isSelected());
|
||||
settings.setExcludeNestedTypes(BytecodeViewer.viewer.excludeNestedTypes.isSelected());
|
||||
|
|
|
@ -9,7 +9,6 @@ import java.util.Objects;
|
|||
import me.konloch.kontainer.io.DiskReader;
|
||||
import org.apache.commons.io.FileUtils;
|
||||
import org.objectweb.asm.tree.ClassNode;
|
||||
import the.bytecode.club.bytecodeviewer.BytecodeViewer;
|
||||
import the.bytecode.club.bytecodeviewer.util.Dex2Jar;
|
||||
import the.bytecode.club.bytecodeviewer.util.FileContainer;
|
||||
import the.bytecode.club.bytecodeviewer.util.MiscUtils;
|
||||
|
@ -40,7 +39,8 @@ import static the.bytecode.club.bytecodeviewer.Constants.*;
|
|||
* @author Konloch
|
||||
*/
|
||||
|
||||
public class SmaliDisassembler extends Decompiler {
|
||||
public class SmaliDisassembler extends InternalDecompiler
|
||||
{
|
||||
|
||||
public String decompileClassNode(FileContainer container, ClassNode cn, byte[] b) {
|
||||
String exception = "";
|
||||
|
|
|
@ -9,7 +9,7 @@ import org.objectweb.asm.tree.FieldNode;
|
|||
import org.objectweb.asm.tree.InnerClassNode;
|
||||
import org.objectweb.asm.tree.MethodNode;
|
||||
import the.bytecode.club.bytecodeviewer.BytecodeViewer;
|
||||
import the.bytecode.club.bytecodeviewer.decompilers.Decompiler;
|
||||
import the.bytecode.club.bytecodeviewer.decompilers.InternalDecompiler;
|
||||
|
||||
import static the.bytecode.club.bytecodeviewer.Constants.*;
|
||||
|
||||
|
@ -36,7 +36,8 @@ import static the.bytecode.club.bytecodeviewer.Constants.*;
|
|||
* @author Bibl
|
||||
*/
|
||||
|
||||
public class ClassNodeDecompiler extends Decompiler {
|
||||
public class ClassNodeDecompiler extends InternalDecompiler
|
||||
{
|
||||
|
||||
@Override
|
||||
public String decompileClassNode(ClassNode cn, byte[] b) {
|
||||
|
|
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.io.File;
|
||||
import java.util.ArrayList;
|
||||
import javax.swing.BoxLayout;
|
||||
import javax.swing.ButtonGroup;
|
||||
import javax.swing.JCheckBoxMenuItem;
|
||||
import javax.swing.JDialog;
|
||||
import javax.swing.JFileChooser;
|
||||
import javax.swing.JFrame;
|
||||
import javax.swing.JMenu;
|
||||
import javax.swing.JMenuBar;
|
||||
import javax.swing.JMenuItem;
|
||||
import javax.swing.JOptionPane;
|
||||
import javax.swing.JRadioButtonMenuItem;
|
||||
import javax.swing.JSeparator;
|
||||
import javax.swing.JSpinner;
|
||||
import javax.swing.JSplitPane;
|
||||
import javax.swing.SpinnerNumberModel;
|
||||
import javax.swing.SwingUtilities;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import javax.swing.*;
|
||||
import javax.swing.filechooser.FileFilter;
|
||||
|
||||
import org.objectweb.asm.tree.ClassNode;
|
||||
|
@ -28,11 +15,17 @@ import the.bytecode.club.bytecodeviewer.Configuration;
|
|||
import the.bytecode.club.bytecodeviewer.Resources;
|
||||
import the.bytecode.club.bytecodeviewer.Settings;
|
||||
import the.bytecode.club.bytecodeviewer.api.ExceptionUI;
|
||||
import the.bytecode.club.bytecodeviewer.gui.extras.AboutWindow;
|
||||
import the.bytecode.club.bytecodeviewer.gui.extras.RunOptions;
|
||||
import the.bytecode.club.bytecodeviewer.gui.components.VisibleComponent;
|
||||
import the.bytecode.club.bytecodeviewer.gui.components.AboutWindow;
|
||||
import the.bytecode.club.bytecodeviewer.gui.components.RunOptions;
|
||||
import the.bytecode.club.bytecodeviewer.gui.plugins.MaliciousCodeScannerOptions;
|
||||
import the.bytecode.club.bytecodeviewer.gui.plugins.ReplaceStringsOptions;
|
||||
import the.bytecode.club.bytecodeviewer.gui.resourcelist.ResourceListPane;
|
||||
import the.bytecode.club.bytecodeviewer.gui.resourcesearch.SearchBoxPane;
|
||||
import the.bytecode.club.bytecodeviewer.gui.resourceviewer.DecompilerSelectionPane;
|
||||
import the.bytecode.club.bytecodeviewer.gui.resourceviewer.WorkPaneMainComponent;
|
||||
import the.bytecode.club.bytecodeviewer.gui.theme.LAFTheme;
|
||||
import the.bytecode.club.bytecodeviewer.gui.theme.RSTATheme;
|
||||
import the.bytecode.club.bytecodeviewer.obfuscators.rename.RenameClasses;
|
||||
import the.bytecode.club.bytecodeviewer.obfuscators.rename.RenameFields;
|
||||
import the.bytecode.club.bytecodeviewer.obfuscators.rename.RenameMethods;
|
||||
|
@ -80,7 +73,7 @@ public class MainViewerGUI extends JFrame {
|
|||
|
||||
//main UI components
|
||||
private static final ArrayList<VisibleComponent> uiComponents = new ArrayList<>();
|
||||
public final WorkPane workPane = new WorkPane();
|
||||
public final WorkPaneMainComponent workPane = new WorkPaneMainComponent();
|
||||
public final ResourceListPane resourcePane = new ResourceListPane();
|
||||
public final SearchBoxPane searchBoxPane = new SearchBoxPane();
|
||||
public JSplitPane splitPane1;
|
||||
|
@ -108,9 +101,9 @@ public class MainViewerGUI extends JFrame {
|
|||
|
||||
//all of the view main menu components
|
||||
public final JMenu viewMainMenu = new JMenu("View");
|
||||
public final ViewPane viewPane1 = new ViewPane(1);
|
||||
public final ViewPane viewPane2 = new ViewPane(2);
|
||||
public final ViewPane viewPane3 = new ViewPane(3);
|
||||
public final DecompilerSelectionPane viewPane1 = new DecompilerSelectionPane(1);
|
||||
public final DecompilerSelectionPane viewPane2 = new DecompilerSelectionPane(2);
|
||||
public final DecompilerSelectionPane viewPane3 = new DecompilerSelectionPane(3);
|
||||
|
||||
//all of the plugins main menu components
|
||||
public final JMenu pluginsMainMenu = new JMenu("Plugins");
|
||||
|
@ -132,6 +125,8 @@ public class MainViewerGUI extends JFrame {
|
|||
public final JRadioButtonMenuItem apkConversionEnjarify = new JRadioButtonMenuItem("Enjarify");
|
||||
public final JMenu fontSize = new JMenu("Font Size");
|
||||
public final JSpinner fontSpinner = new JSpinner();
|
||||
public final JMenu rstaTheme = new JMenu("Text Area Theme");
|
||||
public final JMenu lafTheme = new JMenu("Window Theme");
|
||||
//BCV settings
|
||||
public final JCheckBoxMenuItem refreshOnChange = new JCheckBoxMenuItem("Refresh On View Change");
|
||||
private final JCheckBoxMenuItem deleteForeignOutdatedLibs = new JCheckBoxMenuItem("Delete Foreign/Outdated Libs");
|
||||
|
@ -147,11 +142,14 @@ public class MainViewerGUI extends JFrame {
|
|||
public final JMenuItem setOptionalLibrary = new JMenuItem("Set Optional Library Folder");
|
||||
public final JCheckBoxMenuItem compileOnSave = new JCheckBoxMenuItem("Compile On Save");
|
||||
public final JCheckBoxMenuItem showFileInTabTitle = new JCheckBoxMenuItem("Show File In Tab Title");
|
||||
public final JCheckBoxMenuItem simplifyNameInTabTitle = new JCheckBoxMenuItem("Simplify Name In Tab Title");
|
||||
public final JCheckBoxMenuItem forcePureAsciiAsText = new JCheckBoxMenuItem("Force Pure Ascii As Text");
|
||||
public final JCheckBoxMenuItem autoCompileOnRefresh = new JCheckBoxMenuItem("Compile On Refresh");
|
||||
public final JCheckBoxMenuItem decodeAPKResources = new JCheckBoxMenuItem("Decode APK Resources");
|
||||
public final JCheckBoxMenuItem synchronizedViewing = new JCheckBoxMenuItem("Synchronized Viewing");
|
||||
public final JCheckBoxMenuItem showClassMethods = new JCheckBoxMenuItem("Show Class Methods");
|
||||
public final Map<RSTATheme, JRadioButtonMenuItem> rstaThemes = new HashMap<>();
|
||||
public final Map<LAFTheme, JRadioButtonMenuItem> lafThemes = new HashMap<>();
|
||||
//CFIDE settings
|
||||
public final JCheckBoxMenuItem appendBracketsToLabels = new JCheckBoxMenuItem("Append Brackets To Labels");
|
||||
public JCheckBoxMenuItem debugHelpers = new JCheckBoxMenuItem("Debug Helpers");
|
||||
|
@ -384,6 +382,7 @@ public class MainViewerGUI extends JFrame {
|
|||
public void buildViewMenu()
|
||||
{
|
||||
rootMenu.add(viewMainMenu);
|
||||
viewMainMenu.add(visualSettings);
|
||||
viewMainMenu.add(viewPane1.menu);
|
||||
viewMainMenu.add(viewPane2.menu);
|
||||
viewMainMenu.add(viewPane3.menu);
|
||||
|
@ -393,8 +392,8 @@ public class MainViewerGUI extends JFrame {
|
|||
{
|
||||
rootMenu.add(settingsMainMenu);
|
||||
|
||||
settingsMainMenu.add(visualSettings);
|
||||
settingsMainMenu.add(new JSeparator());
|
||||
//settingsMainMenu.add(visualSettings);
|
||||
//settingsMainMenu.add(new JSeparator());
|
||||
settingsMainMenu.add(compileOnSave);
|
||||
settingsMainMenu.add(autoCompileOnRefresh);
|
||||
settingsMainMenu.add(refreshOnChange);
|
||||
|
@ -420,8 +419,54 @@ public class MainViewerGUI extends JFrame {
|
|||
fontSpinner.setSize(new Dimension(42, 20));
|
||||
fontSpinner.setModel(new SpinnerNumberModel(12, 1, null, 1));
|
||||
fontSize.add(fontSpinner);
|
||||
|
||||
ButtonGroup rstaGroup = new ButtonGroup();
|
||||
for (RSTATheme t : RSTATheme.values())
|
||||
{
|
||||
JRadioButtonMenuItem item = new JRadioButtonMenuItem(t.getReadableName());
|
||||
if (Configuration.rstaTheme.equals(t))
|
||||
item.setSelected(true);
|
||||
|
||||
rstaGroup.add(item);
|
||||
|
||||
item.addActionListener(e ->
|
||||
{
|
||||
Configuration.rstaTheme = t;
|
||||
item.setSelected(true);
|
||||
Settings.saveSettings();
|
||||
});
|
||||
|
||||
rstaThemes.put(t, item);
|
||||
rstaTheme.add(item);
|
||||
}
|
||||
|
||||
ButtonGroup lafGroup = new ButtonGroup();
|
||||
for (LAFTheme theme : LAFTheme.values())
|
||||
{
|
||||
JRadioButtonMenuItem item = new JRadioButtonMenuItem(theme.getReadableName());
|
||||
if (Configuration.lafTheme.equals(theme))
|
||||
item.setSelected(true);
|
||||
|
||||
lafGroup.add(item);
|
||||
|
||||
item.addActionListener(e ->
|
||||
{
|
||||
Configuration.lafTheme = theme;
|
||||
Configuration.rstaTheme = theme.getRSTATheme();
|
||||
rstaThemes.get(Configuration.rstaTheme).setSelected(true);
|
||||
item.setSelected(true);
|
||||
Settings.saveSettings();
|
||||
});
|
||||
|
||||
lafThemes.put(theme, item);
|
||||
lafTheme.add(item);
|
||||
}
|
||||
|
||||
visualSettings.add(lafTheme);
|
||||
visualSettings.add(rstaTheme);
|
||||
visualSettings.add(fontSize);
|
||||
visualSettings.add(showFileInTabTitle);
|
||||
visualSettings.add(simplifyNameInTabTitle);
|
||||
visualSettings.add(synchronizedViewing);
|
||||
visualSettings.add(showClassMethods);
|
||||
|
||||
|
@ -527,6 +572,10 @@ public class MainViewerGUI extends JFrame {
|
|||
Configuration.displayParentInTab = BytecodeViewer.viewer.showFileInTabTitle.isSelected();
|
||||
Settings.saveSettings();
|
||||
});
|
||||
simplifyNameInTabTitle.addActionListener(arg0 -> {
|
||||
Configuration.simplifiedTabNames = BytecodeViewer.viewer.simplifyNameInTabTitle.isSelected();
|
||||
Settings.saveSettings();
|
||||
});
|
||||
}
|
||||
|
||||
public void buildPluginMenu()
|
||||
|
|
|
@ -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.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;
|
||||
|
||||
|
@ -33,6 +33,7 @@ public class DecompilerViewComponent
|
|||
menu.add(java);
|
||||
if(hasBytecodeOption)
|
||||
menu.add(bytecode);
|
||||
|
||||
menu.add(new JSeparator());
|
||||
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 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 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 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 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 org.objectweb.asm.tree.ClassNode;
|
||||
import the.bytecode.club.bytecodeviewer.BytecodeViewer;
|
||||
import the.bytecode.club.bytecodeviewer.gui.VisibleComponent;
|
||||
import the.bytecode.club.bytecodeviewer.gui.components.VisibleComponent;
|
||||
import the.bytecode.club.bytecodeviewer.util.FileContainer;
|
||||
import the.bytecode.club.bytecodeviewer.util.FileDrop;
|
||||
import the.bytecode.club.bytecodeviewer.util.LazyNameUtil;
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
package the.bytecode.club.bytecodeviewer.gui.resourcelist;
|
||||
|
||||
import the.bytecode.club.bytecodeviewer.gui.extras.StringMetricsUtil;
|
||||
import the.bytecode.club.bytecodeviewer.gui.util.StringMetricsUtil;
|
||||
|
||||
import javax.swing.*;
|
||||
import javax.swing.tree.DefaultMutableTreeNode;
|
||||
|
|
|
@ -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.GridLayout;
|
||||
import java.awt.event.ItemListener;
|
||||
import java.util.Objects;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.regex.PatternSyntaxException;
|
||||
import javax.swing.DefaultComboBoxModel;
|
||||
import javax.swing.JButton;
|
||||
import javax.swing.JCheckBox;
|
||||
|
@ -15,18 +13,15 @@ import javax.swing.JPanel;
|
|||
import javax.swing.JScrollPane;
|
||||
import javax.swing.JTree;
|
||||
import javax.swing.tree.DefaultMutableTreeNode;
|
||||
import javax.swing.tree.TreePath;
|
||||
|
||||
import org.objectweb.asm.tree.ClassNode;
|
||||
import the.bytecode.club.bytecodeviewer.BytecodeViewer;
|
||||
import the.bytecode.club.bytecodeviewer.gui.resourcelist.ResourceListPane;
|
||||
import the.bytecode.club.bytecodeviewer.gui.MainViewerGUI;
|
||||
import the.bytecode.club.bytecodeviewer.gui.resourceviewer.WorkPaneMainComponent;
|
||||
import the.bytecode.club.bytecodeviewer.gui.components.VisibleComponent;
|
||||
import the.bytecode.club.bytecodeviewer.gui.resourceviewer.viewer.ResourceViewer;
|
||||
import the.bytecode.club.bytecodeviewer.searching.BackgroundSearchThread;
|
||||
import the.bytecode.club.bytecodeviewer.searching.FieldCallSearch;
|
||||
import the.bytecode.club.bytecodeviewer.searching.LDCSearch;
|
||||
import the.bytecode.club.bytecodeviewer.searching.MethodCallSearch;
|
||||
import the.bytecode.club.bytecodeviewer.searching.RegexInsnFinder;
|
||||
import the.bytecode.club.bytecodeviewer.searching.RegexSearch;
|
||||
import the.bytecode.club.bytecodeviewer.searching.SearchResultNotifier;
|
||||
import the.bytecode.club.bytecodeviewer.searching.SearchTypeDetails;
|
||||
import the.bytecode.club.bytecodeviewer.util.FileContainer;
|
||||
|
||||
/***************************************************************************
|
||||
|
@ -55,8 +50,8 @@ import the.bytecode.club.bytecodeviewer.util.FileContainer;
|
|||
*/
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
public class SearchBoxPane extends VisibleComponent {
|
||||
|
||||
public class SearchBoxPane extends VisibleComponent
|
||||
{
|
||||
private static final long serialVersionUID = -1098524689236993932L;
|
||||
public static final SearchRadius[] SEARCH_RADII = SearchRadius.values();
|
||||
public static final SearchType[] SEARCH_TYPES = SearchType.values();
|
||||
|
@ -170,30 +165,7 @@ public class SearchBoxPane extends VisibleComponent {
|
|||
final SearchResultNotifier srn = debug -> treeRoot.add(new DefaultMutableTreeNode(debug));
|
||||
if (radius == SearchRadius.All_Classes) {
|
||||
if (t.finished) {
|
||||
t = new BackgroundSearchThread() {
|
||||
@Override
|
||||
public void doSearch() {
|
||||
|
||||
try {
|
||||
Pattern.compile(RegexInsnFinder.processRegex(RegexSearch.searchText.getText()), Pattern.MULTILINE);
|
||||
} catch (PatternSyntaxException ex) {
|
||||
BytecodeViewer.showMessage("You have an error in your regex syntax.");
|
||||
}
|
||||
|
||||
for (FileContainer container : BytecodeViewer.files)
|
||||
for (ClassNode c : container.classes)
|
||||
searchType.details.search(container, c, srn, exact.isSelected());
|
||||
|
||||
Objects.requireNonNull(MainViewerGUI.getComponent(SearchBoxPane.class))
|
||||
.search.setEnabled(true);
|
||||
Objects.requireNonNull(MainViewerGUI.getComponent(SearchBoxPane.class))
|
||||
.search.setText("Search");
|
||||
|
||||
tree.expandPath(new TreePath(tree.getModel().getRoot()));
|
||||
tree.updateUI();
|
||||
}
|
||||
|
||||
};
|
||||
t = new PerformSearch(this, srn);
|
||||
Objects.requireNonNull(MainViewerGUI.getComponent(SearchBoxPane.class))
|
||||
.search.setEnabled(false);
|
||||
Objects.requireNonNull(MainViewerGUI.getComponent(SearchBoxPane.class))
|
||||
|
@ -203,32 +175,16 @@ public class SearchBoxPane extends VisibleComponent {
|
|||
BytecodeViewer.showMessage("You currently have a search performing in the background, please wait for that to finish.");
|
||||
}
|
||||
} else if (radius == SearchRadius.Current_Class) {
|
||||
final Viewer cv = Objects.requireNonNull(MainViewerGUI.getComponent(WorkPane.class)).getCurrentViewer();
|
||||
final ResourceViewer cv = Objects.requireNonNull(MainViewerGUI.getComponent(WorkPaneMainComponent.class)).getCurrentViewer();
|
||||
if (cv != null) {
|
||||
searchType.details.search(cv.container, cv.cn, srn, exact.isSelected());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public enum SearchType {
|
||||
Strings(new LDCSearch()),
|
||||
Regex(new RegexSearch()),
|
||||
MethodCall(new MethodCallSearch()),
|
||||
FieldCall(new FieldCallSearch());
|
||||
|
||||
public final SearchTypeDetails details;
|
||||
|
||||
SearchType(final SearchTypeDetails details) {
|
||||
this.details = details;
|
||||
}
|
||||
}
|
||||
|
||||
public enum SearchRadius {
|
||||
All_Classes, Current_Class
|
||||
}
|
||||
|
||||
public void resetWorkspace() {
|
||||
treeRoot.removeAllChildren();
|
||||
tree.updateUI();
|
||||
}
|
||||
|
||||
}
|
|
@ -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.*;
|
||||
|
||||
|
@ -6,7 +9,7 @@ import javax.swing.*;
|
|||
* @author Konloch
|
||||
* @since 6/21/2021
|
||||
*/
|
||||
public class ViewPane
|
||||
public class DecompilerSelectionPane
|
||||
{
|
||||
public final int paneID;
|
||||
public final JMenu menu;
|
||||
|
@ -23,7 +26,7 @@ public class ViewPane
|
|||
public final JRadioButtonMenuItem bytecode = new JRadioButtonMenuItem("Bytecode");
|
||||
public final JRadioButtonMenuItem asmTextify = new JRadioButtonMenuItem("ASM Textify");
|
||||
|
||||
public ViewPane(int paneID) {
|
||||
public DecompilerSelectionPane(int paneID) {
|
||||
this.paneID = paneID;
|
||||
this.menu = new JMenu("Pane " + paneID);
|
||||
buildMenu();
|
|
@ -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 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/>. *
|
||||
***************************************************************************/
|
||||
|
||||
public abstract class Viewer extends JPanel {
|
||||
|
||||
public abstract class ResourceViewer extends JPanel
|
||||
{
|
||||
public ClassNode cn;
|
||||
public String name;
|
||||
FileContainer container;
|
||||
public FileContainer container;
|
||||
|
||||
private static final long serialVersionUID = -2965538493489119191L;
|
||||
}
|
|
@ -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 javax.swing.SwingUtilities;
|
||||
|
@ -6,7 +8,8 @@ import javax.swing.SwingUtilities;
|
|||
/**
|
||||
* @author Konloch
|
||||
*/
|
||||
public class DelayTabbedPaneThread extends Thread {
|
||||
public class DelayTabbedPaneThread extends Thread
|
||||
{
|
||||
public boolean stopped = false;
|
||||
private final TabbedPane pane;
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package the.bytecode.club.bytecodeviewer.gui;
|
||||
package the.bytecode.club.bytecodeviewer.gui.util;
|
||||
|
||||
/***************************************************************************
|
||||
* Bytecode Viewer (BCV) - Java & Android Reverse Engineering Suite *
|
||||
|
@ -19,17 +19,13 @@ package the.bytecode.club.bytecodeviewer.gui;
|
|||
***************************************************************************/
|
||||
|
||||
import java.awt.BorderLayout;
|
||||
import java.awt.Component;
|
||||
import java.awt.Font;
|
||||
import java.awt.event.InputEvent;
|
||||
import java.util.Objects;
|
||||
import java.util.regex.Matcher;
|
||||
import javax.swing.JComboBox;
|
||||
import javax.swing.JLabel;
|
||||
import javax.swing.JList;
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.JViewport;
|
||||
import javax.swing.ListCellRenderer;
|
||||
import javax.swing.event.CaretEvent;
|
||||
import javax.swing.event.CaretListener;
|
||||
import javax.swing.event.ChangeEvent;
|
||||
|
@ -37,9 +33,12 @@ import javax.swing.event.ChangeListener;
|
|||
import org.fife.ui.rsyntaxtextarea.RSyntaxTextArea;
|
||||
import org.fife.ui.rtextarea.RTextScrollPane;
|
||||
import the.bytecode.club.bytecodeviewer.BytecodeViewer;
|
||||
import the.bytecode.club.bytecodeviewer.gui.components.MethodsRenderer;
|
||||
import the.bytecode.club.bytecodeviewer.gui.components.SearchableRSyntaxTextArea;
|
||||
import the.bytecode.club.bytecodeviewer.gui.resourceviewer.viewer.ClassViewer;
|
||||
import the.bytecode.club.bytecodeviewer.util.MethodParser;
|
||||
|
||||
import static the.bytecode.club.bytecodeviewer.gui.TabbedPane.BLANK;
|
||||
import static the.bytecode.club.bytecodeviewer.gui.resourceviewer.TabbedPane.BLANK_COLOR;
|
||||
|
||||
/**
|
||||
* Allows us to run a background thread
|
||||
|
@ -47,21 +46,40 @@ import static the.bytecode.club.bytecodeviewer.gui.TabbedPane.BLANK;
|
|||
* @author Konloch
|
||||
* @author DreamSworK
|
||||
*/
|
||||
public abstract class PaneUpdaterThread extends Thread {
|
||||
public abstract class PaneUpdaterThread implements Runnable
|
||||
{
|
||||
public ClassViewer viewer;
|
||||
public RSyntaxTextArea panelArea;
|
||||
public RTextScrollPane scrollPane;
|
||||
public SearchableRSyntaxTextArea updateUpdaterTextArea;
|
||||
public JComboBox<Integer> methodsList;
|
||||
public int decompiler;
|
||||
public int paneId;
|
||||
private Thread thread;
|
||||
public int paneIndex;
|
||||
public int decompilerViewIndex;
|
||||
|
||||
public PaneUpdaterThread(int paneIndex, int decompilerViewIndex)
|
||||
{
|
||||
this.paneIndex = paneIndex;
|
||||
this.decompilerViewIndex = decompilerViewIndex;
|
||||
}
|
||||
|
||||
public abstract void doShit();
|
||||
|
||||
public void startNewThread()
|
||||
{
|
||||
thread = new Thread(this);
|
||||
thread.start();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
public void run()
|
||||
{
|
||||
if(decompilerViewIndex == 0)
|
||||
return;
|
||||
|
||||
doShit();
|
||||
|
||||
synchronizePane();
|
||||
attachCtrlMouseWheelZoom(scrollPane, panelArea); //freezes the UI for some reason
|
||||
|
||||
attachCtrlMouseWheelZoom(updateUpdaterTextArea.getScrollPane(), updateUpdaterTextArea); //freezes the UI for some reason
|
||||
//probably cause BCV is doing dumb shit with the swing thread
|
||||
}
|
||||
|
||||
|
@ -89,9 +107,9 @@ public abstract class PaneUpdaterThread extends Thread {
|
|||
public final CaretListener caretListener = new CaretListener() {
|
||||
@Override
|
||||
public void caretUpdate(CaretEvent e) {
|
||||
MethodParser methods = viewer.methods.get(paneId);
|
||||
MethodParser methods = viewer.methods.get(paneIndex);
|
||||
if (methods != null) {
|
||||
int methodLine = methods.findActiveMethod(panelArea.getCaretLineNumber());
|
||||
int methodLine = methods.findActiveMethod(updateUpdaterTextArea.getCaretLineNumber());
|
||||
if (methodLine != -1) {
|
||||
if (BytecodeViewer.viewer.showClassMethods.isSelected()) {
|
||||
if (methodsList != null) {
|
||||
|
@ -102,11 +120,11 @@ public abstract class PaneUpdaterThread extends Thread {
|
|||
}
|
||||
if (BytecodeViewer.viewer.synchronizedViewing.isSelected()) {
|
||||
int panes = 2;
|
||||
if (viewer.panel3 != null)
|
||||
if (viewer.resourceViewPanel3.panel != null)
|
||||
panes = 3;
|
||||
|
||||
for (int i = 0; i < panes; i++) {
|
||||
if (i != paneId) {
|
||||
if (i != paneIndex) {
|
||||
ClassViewer.selectMethod(viewer, i, methods.getMethod(methodLine));
|
||||
}
|
||||
}
|
||||
|
@ -120,41 +138,41 @@ public abstract class PaneUpdaterThread extends Thread {
|
|||
@Override
|
||||
public void stateChanged(ChangeEvent e) {
|
||||
int panes = 2;
|
||||
if (viewer.panel3 != null)
|
||||
if (viewer.resourceViewPanel3.panel != null)
|
||||
panes = 3;
|
||||
|
||||
if (BytecodeViewer.viewer.synchronizedViewing.isSelected()) {
|
||||
if (panelArea.isShowing() && (panelArea.hasFocus() || panelArea.getMousePosition() != null)) {
|
||||
int caretLine = panelArea.getCaretLineNumber();
|
||||
int maxViewLine = ClassViewer.getMaxViewLine(panelArea);
|
||||
int activeViewLine = ClassViewer.getViewLine(panelArea);
|
||||
if (updateUpdaterTextArea.isShowing() && (updateUpdaterTextArea.hasFocus() || updateUpdaterTextArea.getMousePosition() != null)) {
|
||||
int caretLine = updateUpdaterTextArea.getCaretLineNumber();
|
||||
int maxViewLine = ClassViewer.getMaxViewLine(updateUpdaterTextArea);
|
||||
int activeViewLine = ClassViewer.getViewLine(updateUpdaterTextArea);
|
||||
int activeLine = (activeViewLine == maxViewLine && caretLine > maxViewLine) ? caretLine :
|
||||
activeViewLine;
|
||||
int activeLineDelta = -1;
|
||||
MethodParser.Method activeMethod = null;
|
||||
MethodParser activeMethods = viewer.methods.get(paneId);
|
||||
MethodParser activeMethods = viewer.methods.get(paneIndex);
|
||||
if (activeMethods != null) {
|
||||
int activeMethodLine = activeMethods.findActiveMethod(activeLine);
|
||||
if (activeMethodLine != -1) {
|
||||
activeLineDelta = activeLine - activeMethodLine;
|
||||
activeMethod = activeMethods.getMethod(activeMethodLine);
|
||||
ClassViewer.selectMethod(panelArea, activeMethodLine);
|
||||
ClassViewer.selectMethod(updateUpdaterTextArea, activeMethodLine);
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < panes; i++) {
|
||||
if (i != paneId) {
|
||||
if (i != paneIndex) {
|
||||
int setLine = -1;
|
||||
|
||||
RSyntaxTextArea area = null;
|
||||
switch (i) {
|
||||
case 0:
|
||||
area = viewer.t1.panelArea;
|
||||
area = viewer.resourceViewPanel1.updateThread.updateUpdaterTextArea;
|
||||
break;
|
||||
case 1:
|
||||
area = viewer.t2.panelArea;
|
||||
area = viewer.resourceViewPanel2.updateThread.updateUpdaterTextArea;
|
||||
break;
|
||||
case 2:
|
||||
area = viewer.t3.panelArea;
|
||||
area = viewer.resourceViewPanel3.updateThread.updateUpdaterTextArea;
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -184,29 +202,18 @@ public abstract class PaneUpdaterThread extends Thread {
|
|||
}
|
||||
};
|
||||
|
||||
class MethodsRenderer extends JLabel implements ListCellRenderer<Object> {
|
||||
public MethodsRenderer() {
|
||||
setOpaque(true);
|
||||
}
|
||||
public void synchronizePane()
|
||||
{
|
||||
if(decompilerViewIndex == 5 || decompilerViewIndex < 0)
|
||||
return;
|
||||
|
||||
@Override
|
||||
public Component getListCellRendererComponent(JList<?> list, Object value, int index, boolean isSelected,
|
||||
boolean cellHasFocus) {
|
||||
MethodParser methods = viewer.methods.get(paneId);
|
||||
MethodParser.Method method = methods.getMethod((Integer) value);
|
||||
setText(method.toString());
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
public void synchronizePane() {
|
||||
JViewport viewport = scrollPane.getViewport();
|
||||
JViewport viewport = updateUpdaterTextArea.getScrollPane().getViewport();
|
||||
viewport.addChangeListener(viewportListener);
|
||||
panelArea.addCaretListener(caretListener);
|
||||
updateUpdaterTextArea.addCaretListener(caretListener);
|
||||
|
||||
final MethodParser methods = viewer.methods.get(paneId);
|
||||
for (int i = 0; i < panelArea.getLineCount(); i++) {
|
||||
String lineText = ClassViewer.getLineText(panelArea, i);
|
||||
final MethodParser methods = viewer.methods.get(paneIndex);
|
||||
for (int i = 0; i < updateUpdaterTextArea.getLineCount(); i++) {
|
||||
String lineText = ClassViewer.getLineText(updateUpdaterTextArea, i);
|
||||
Matcher regexMatcher = MethodParser.regex.matcher(lineText);
|
||||
if (regexMatcher.find()) {
|
||||
String methodName = regexMatcher.group("name");
|
||||
|
@ -221,20 +228,22 @@ public abstract class PaneUpdaterThread extends Thread {
|
|||
for (Integer line : methods.getMethodsLines()) {
|
||||
methodsList.addItem(line);
|
||||
}
|
||||
methodsList.setRenderer(new PaneUpdaterThread.MethodsRenderer());
|
||||
methodsList.addActionListener(e -> {
|
||||
methodsList.setRenderer(new MethodsRenderer(this));
|
||||
methodsList.addActionListener(e ->
|
||||
{
|
||||
int line = (int) Objects.requireNonNull(methodsList.getSelectedItem());
|
||||
|
||||
RSyntaxTextArea area = null;
|
||||
switch (paneId) {
|
||||
switch (paneIndex)
|
||||
{
|
||||
case 0:
|
||||
area = viewer.t1.panelArea;
|
||||
area = viewer.resourceViewPanel1.updateThread.updateUpdaterTextArea;
|
||||
break;
|
||||
case 1:
|
||||
area = viewer.t2.panelArea;
|
||||
area = viewer.resourceViewPanel2.updateThread.updateUpdaterTextArea;
|
||||
break;
|
||||
case 2:
|
||||
area = viewer.t3.panelArea;
|
||||
area = viewer.resourceViewPanel3.updateThread.updateUpdaterTextArea;
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -243,11 +252,11 @@ public abstract class PaneUpdaterThread extends Thread {
|
|||
});
|
||||
|
||||
JPanel panel = new JPanel(new BorderLayout());
|
||||
panel.add(scrollPane.getColumnHeader().getComponent(0), BorderLayout.NORTH);
|
||||
panel.add(updateUpdaterTextArea.getScrollPane().getColumnHeader().getComponent(0), BorderLayout.NORTH);
|
||||
panel.add(methodsList, BorderLayout.SOUTH);
|
||||
methodsList.setBackground(BLANK);
|
||||
scrollPane.getColumnHeader().removeAll();
|
||||
scrollPane.getColumnHeader().add(panel);
|
||||
methodsList.setBackground(BLANK_COLOR);
|
||||
updateUpdaterTextArea.getScrollPane().getColumnHeader().removeAll();
|
||||
updateUpdaterTextArea.getScrollPane().getColumnHeader().add(panel);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
package the.bytecode.club.bytecodeviewer.gui.extras;
|
||||
package the.bytecode.club.bytecodeviewer.gui.util;
|
||||
|
||||
import java.awt.*;
|
||||
import java.awt.font.FontRenderContext;
|
|
@ -15,7 +15,7 @@ import org.objectweb.asm.tree.MethodNode;
|
|||
import the.bytecode.club.bytecodeviewer.BytecodeViewer;
|
||||
import the.bytecode.club.bytecodeviewer.Resources;
|
||||
import the.bytecode.club.bytecodeviewer.api.Plugin;
|
||||
import the.bytecode.club.bytecodeviewer.gui.ClassViewer;
|
||||
import the.bytecode.club.bytecodeviewer.gui.resourceviewer.viewer.ClassViewer;
|
||||
import the.bytecode.club.bytecodeviewer.plugin.PluginManager;
|
||||
|
||||
/***************************************************************************
|
||||
|
|
|
@ -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;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.objectweb.asm.tree.ClassNode;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.File;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import javax.imageio.ImageIO;
|
||||
import java.awt.*;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.*;
|
||||
import java.lang.reflect.Field;
|
||||
import java.nio.charset.CharsetEncoder;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.*;
|
||||
import java.util.List;
|
||||
|
||||
import static the.bytecode.club.bytecodeviewer.Constants.gson;
|
||||
|
||||
|
@ -35,7 +39,9 @@ import static the.bytecode.club.bytecodeviewer.Constants.gson;
|
|||
* @author Konloch
|
||||
*/
|
||||
|
||||
public class MiscUtils {
|
||||
public class MiscUtils
|
||||
{
|
||||
private static CharsetEncoder asciiEncoder = StandardCharsets.US_ASCII.newEncoder(); // or "ISO-8859-1" for ISO Latin 1
|
||||
private static final String AB = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
|
||||
private static final String AN = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
|
||||
private static final Random rnd = new Random();
|
||||
|
@ -192,4 +198,30 @@ public class MiscUtils {
|
|||
field.setAccessible(true);
|
||||
((Map<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 the.bytecode.club.bytecodeviewer.BytecodeViewer;
|
||||
import the.bytecode.club.bytecodeviewer.api.ExceptionUI;
|
||||
import the.bytecode.club.bytecodeviewer.decompilers.Decompilers;
|
||||
import the.bytecode.club.bytecodeviewer.decompilers.Decompiler;
|
||||
|
||||
import javax.swing.*;
|
||||
import javax.swing.filechooser.FileFilter;
|
||||
|
@ -101,7 +101,7 @@ public class ResourceDecompiling
|
|||
if (result == 0) {
|
||||
Thread t12 = new Thread(() -> {
|
||||
try {
|
||||
Decompilers.procyon.decompileToZip(tempZip.getAbsolutePath(),
|
||||
Decompiler.PROCYON.getDecompiler().decompileToZip(tempZip.getAbsolutePath(),
|
||||
MiscUtils.append(javaSucks, "-proycon.zip"));
|
||||
BytecodeViewer.viewer.updateBusyStatus(false);
|
||||
} catch (Exception e) {
|
||||
|
@ -112,7 +112,7 @@ public class ResourceDecompiling
|
|||
Thread t2 = new Thread(() -> {
|
||||
try {
|
||||
BytecodeViewer.viewer.updateBusyStatus(true);
|
||||
Decompilers.cfr.decompileToZip(tempZip.getAbsolutePath(),
|
||||
Decompiler.CFR.getDecompiler().decompileToZip(tempZip.getAbsolutePath(),
|
||||
MiscUtils.append(javaSucks, "-CFR.zip"));
|
||||
BytecodeViewer.viewer.updateBusyStatus(false);
|
||||
} catch (Exception e) {
|
||||
|
@ -123,7 +123,7 @@ public class ResourceDecompiling
|
|||
Thread t3 = new Thread(() -> {
|
||||
try {
|
||||
BytecodeViewer.viewer.updateBusyStatus(true);
|
||||
Decompilers.fernflower.decompileToZip(tempZip.getAbsolutePath(),
|
||||
Decompiler.FERNFLOWER.getDecompiler().decompileToZip(tempZip.getAbsolutePath(),
|
||||
MiscUtils.append(javaSucks, "-fernflower.zip"));
|
||||
BytecodeViewer.viewer.updateBusyStatus(false);
|
||||
} catch (Exception e) {
|
||||
|
@ -134,7 +134,7 @@ public class ResourceDecompiling
|
|||
Thread t4 = new Thread(() -> {
|
||||
try {
|
||||
BytecodeViewer.viewer.updateBusyStatus(true);
|
||||
Decompilers.krakatau.decompileToZip(tempZip.getAbsolutePath(),
|
||||
Decompiler.KRAKATAU.getDecompiler().decompileToZip(tempZip.getAbsolutePath(),
|
||||
MiscUtils.append(javaSucks, "-kraktau.zip"));
|
||||
BytecodeViewer.viewer.updateBusyStatus(false);
|
||||
} catch (Exception e) {
|
||||
|
@ -146,7 +146,7 @@ public class ResourceDecompiling
|
|||
if (result == 1) {
|
||||
Thread t12 = new Thread(() -> {
|
||||
try {
|
||||
Decompilers.procyon.decompileToZip(tempZip.getAbsolutePath(), path);
|
||||
Decompiler.PROCYON.getDecompiler().decompileToZip(tempZip.getAbsolutePath(), path);
|
||||
BytecodeViewer.viewer.updateBusyStatus(false);
|
||||
} catch (Exception e) {
|
||||
new ExceptionUI(e);
|
||||
|
@ -157,7 +157,7 @@ public class ResourceDecompiling
|
|||
if (result == 2) {
|
||||
Thread t12 = new Thread(() -> {
|
||||
try {
|
||||
Decompilers.cfr.decompileToZip(tempZip.getAbsolutePath(), path);
|
||||
Decompiler.CFR.getDecompiler().decompileToZip(tempZip.getAbsolutePath(), path);
|
||||
BytecodeViewer.viewer.updateBusyStatus(false);
|
||||
} catch (Exception e) {
|
||||
new ExceptionUI(e);
|
||||
|
@ -168,7 +168,7 @@ public class ResourceDecompiling
|
|||
if (result == 3) {
|
||||
Thread t12 = new Thread(() -> {
|
||||
try {
|
||||
Decompilers.fernflower.decompileToZip(tempZip.getAbsolutePath(), path);
|
||||
Decompiler.FERNFLOWER.getDecompiler().decompileToZip(tempZip.getAbsolutePath(), path);
|
||||
BytecodeViewer.viewer.updateBusyStatus(false);
|
||||
} catch (Exception e) {
|
||||
new ExceptionUI(e);
|
||||
|
@ -180,7 +180,7 @@ public class ResourceDecompiling
|
|||
if (result == 4) {
|
||||
Thread t12 = new Thread(() -> {
|
||||
try {
|
||||
Decompilers.krakatau.decompileToZip(tempZip.getAbsolutePath(), path);
|
||||
Decompiler.KRAKATAU.getDecompiler().decompileToZip(tempZip.getAbsolutePath(), path);
|
||||
BytecodeViewer.viewer.updateBusyStatus(false);
|
||||
} catch (Exception e) {
|
||||
new ExceptionUI(e);
|
||||
|
@ -288,28 +288,28 @@ public class ResourceDecompiling
|
|||
|
||||
try {
|
||||
DiskWriter.replaceFile(MiscUtils.append(file, "-proycon.java"),
|
||||
Decompilers.procyon.decompileClassNode(cn, cw.toByteArray()), false);
|
||||
Decompiler.PROCYON.getDecompiler().decompileClassNode(cn, cw.toByteArray()), false);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
try {
|
||||
DiskWriter.replaceFile(MiscUtils.append(file, "-CFR.java"),
|
||||
Decompilers.cfr.decompileClassNode(cn, cw.toByteArray()), false);
|
||||
Decompiler.CFR.getDecompiler().decompileClassNode(cn, cw.toByteArray()), false);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
try {
|
||||
DiskWriter.replaceFile(MiscUtils.append(file, "-fernflower.java"),
|
||||
Decompilers.fernflower.decompileClassNode(cn, cw.toByteArray()), false);
|
||||
Decompiler.FERNFLOWER.getDecompiler().decompileClassNode(cn, cw.toByteArray()), false);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
try {
|
||||
DiskWriter.replaceFile(MiscUtils.append(file, "-kraktau.java"),
|
||||
Decompilers.krakatau.decompileClassNode(cn, cw.toByteArray()), false);
|
||||
Decompiler.KRAKATAU.getDecompiler().decompileClassNode(cn, cw.toByteArray()), false);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
@ -337,8 +337,7 @@ public class ResourceDecompiling
|
|||
} catch (InterruptedException ignored) {
|
||||
}
|
||||
}
|
||||
String contents = Decompilers.procyon.decompileClassNode(cn,
|
||||
cw.toByteArray());
|
||||
String contents = Decompiler.PROCYON.getDecompiler().decompileClassNode(cn, cw.toByteArray());
|
||||
DiskWriter.replaceFile(path, contents, false);
|
||||
BytecodeViewer.viewer.updateBusyStatus(false);
|
||||
} catch (Exception e) {
|
||||
|
@ -364,7 +363,7 @@ public class ResourceDecompiling
|
|||
} catch (InterruptedException ignored) {
|
||||
}
|
||||
}
|
||||
String contents = Decompilers.cfr.decompileClassNode(cn, cw.toByteArray());
|
||||
String contents = Decompiler.CFR.getDecompiler().decompileClassNode(cn, cw.toByteArray());
|
||||
DiskWriter.replaceFile(path, contents, false);
|
||||
BytecodeViewer.viewer.updateBusyStatus(false);
|
||||
} catch (Exception e) {
|
||||
|
@ -391,7 +390,7 @@ public class ResourceDecompiling
|
|||
} catch (InterruptedException ignored) {
|
||||
}
|
||||
}
|
||||
String contents = Decompilers.fernflower.decompileClassNode(cn,
|
||||
String contents = Decompiler.FERNFLOWER.getDecompiler().decompileClassNode(cn,
|
||||
cw.toByteArray());
|
||||
DiskWriter.replaceFile(path, contents, false);
|
||||
BytecodeViewer.viewer.updateBusyStatus(false);
|
||||
|
@ -419,7 +418,7 @@ public class ResourceDecompiling
|
|||
}
|
||||
}
|
||||
|
||||
String contents = Decompilers.krakatau.decompileClassNode(cn,
|
||||
String contents = Decompiler.KRAKATAU.getDecompiler().decompileClassNode(cn,
|
||||
cw.toByteArray());
|
||||
DiskWriter.replaceFile(path, contents, false);
|
||||
BytecodeViewer.viewer.updateBusyStatus(false);
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
package the.bytecode.club.bytecodeviewer.util;
|
||||
|
||||
import the.bytecode.club.bytecodeviewer.BytecodeViewer;
|
||||
import the.bytecode.club.bytecodeviewer.gui.extras.ExportJar;
|
||||
import the.bytecode.club.bytecodeviewer.gui.components.ExportJar;
|
||||
|
||||
import javax.swing.*;
|
||||
import javax.swing.filechooser.FileFilter;
|
||||
|
|
|
@ -3,8 +3,8 @@ package the.bytecode.club.bytecodeviewer.util;
|
|||
import java.util.function.BiFunction;
|
||||
import org.fife.ui.rsyntaxtextarea.SyntaxConstants;
|
||||
|
||||
public enum Language {
|
||||
|
||||
public enum SyntaxLanguage
|
||||
{
|
||||
XML(SyntaxConstants.SYNTAX_STYLE_XML, (n, c) -> n.endsWith(".xml")
|
||||
|| c.startsWith("<?xml") || c.startsWith("<xml")),
|
||||
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")),
|
||||
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 String syntaxConstant;
|
||||
|
||||
Language(String syntaxConstant, BiFunction<String, String, Boolean> criteria) {
|
||||
SyntaxLanguage(String syntaxConstant, BiFunction<String, String, Boolean> criteria) {
|
||||
this.criteria = criteria;
|
||||
this.syntaxConstant = syntaxConstant;
|
||||
}
|
||||
|
@ -61,13 +61,12 @@ public enum Language {
|
|||
return syntaxConstant;
|
||||
}
|
||||
|
||||
public static Language detectLanguage(String fileName, String content) {
|
||||
for (Language lang : VALUES) {
|
||||
public static SyntaxLanguage detectLanguage(String fileName, String content) {
|
||||
for (SyntaxLanguage lang : VALUES) {
|
||||
if (lang.isLanguage(fileName, content)) {
|
||||
return lang;
|
||||
}
|
||||
}
|
||||
return NONE;
|
||||
}
|
||||
|
||||
}
|
|
@ -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