Code Style Update
This commit is contained in:
parent
c85a8a21f3
commit
fda1ecab66
|
@ -1,14 +1,11 @@
|
|||
package me.konloch.kontainer.io;
|
||||
|
||||
import the.bytecode.club.bytecodeviewer.util.EncodeUtils;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.File;
|
||||
import java.io.FileReader;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Random;
|
||||
import the.bytecode.club.bytecodeviewer.util.EncodeUtils;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* Used to load from the disk, optional caching
|
||||
|
@ -16,7 +13,8 @@ import the.bytecode.club.bytecodeviewer.util.EncodeUtils;
|
|||
* @author Konloch
|
||||
*/
|
||||
|
||||
public class DiskReader {
|
||||
public class DiskReader
|
||||
{
|
||||
|
||||
public static Random random = new Random();
|
||||
public static Map<String, List<String>> map = new HashMap<>();
|
||||
|
@ -24,17 +22,19 @@ public class DiskReader {
|
|||
/**
|
||||
* Used to load from file, allows caching
|
||||
*/
|
||||
public synchronized static List<String> loadArrayList(String fileName,
|
||||
boolean cache) {
|
||||
public synchronized static List<String> loadArrayList(String fileName, boolean cache)
|
||||
{
|
||||
List<String> array = new ArrayList<>();
|
||||
if (!map.containsKey(fileName)) {
|
||||
try {
|
||||
if (!map.containsKey(fileName))
|
||||
{
|
||||
try
|
||||
{
|
||||
File file = new File(fileName);
|
||||
if (!file.exists()) // doesn't exist, return empty
|
||||
return array;
|
||||
|
||||
try (FileReader fr = new FileReader(file);
|
||||
BufferedReader reader = new BufferedReader(fr)) {
|
||||
try (FileReader fr = new FileReader(file); BufferedReader reader = new BufferedReader(fr))
|
||||
{
|
||||
String add;
|
||||
|
||||
while ((add = reader.readLine()) != null)
|
||||
|
@ -44,10 +44,14 @@ public class DiskReader {
|
|||
|
||||
if (cache)
|
||||
map.put(fileName, array);
|
||||
} catch (Exception e) {
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
}
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
array = map.get(fileName);
|
||||
}
|
||||
|
||||
|
@ -58,12 +62,14 @@ public class DiskReader {
|
|||
/**
|
||||
* Used to load from file
|
||||
*/
|
||||
public synchronized static String loadAsString(String fileName) throws Exception {
|
||||
public synchronized static String loadAsString(String fileName) throws Exception
|
||||
{
|
||||
StringBuilder s = new StringBuilder();
|
||||
|
||||
try (FileReader fr = new FileReader(fileName);
|
||||
BufferedReader reader = new BufferedReader(fr)) {
|
||||
for (String add = reader.readLine(); add != null; add = reader.readLine()) {
|
||||
try (FileReader fr = new FileReader(fileName); BufferedReader reader = new BufferedReader(fr))
|
||||
{
|
||||
for (String add = reader.readLine(); add != null; add = reader.readLine())
|
||||
{
|
||||
s.append(EncodeUtils.unicodeToString(add)).append(System.lineSeparator());
|
||||
}
|
||||
}
|
||||
|
@ -74,16 +80,17 @@ public class DiskReader {
|
|||
/**
|
||||
* Used to load a string via line number lineNumber = -1 means random.
|
||||
*/
|
||||
public static String loadString(String fileName, int lineNumber,
|
||||
boolean cache) throws Exception {
|
||||
public static String loadString(String fileName, int lineNumber, boolean cache) throws Exception
|
||||
{
|
||||
|
||||
List<String> array;
|
||||
if (!map.containsKey(fileName)) {
|
||||
if (!map.containsKey(fileName))
|
||||
{
|
||||
array = new ArrayList<>();
|
||||
File file = new File(fileName);
|
||||
|
||||
try (FileReader fr = new FileReader(file);
|
||||
BufferedReader reader = new BufferedReader(fr)) {
|
||||
try (FileReader fr = new FileReader(file); BufferedReader reader = new BufferedReader(fr))
|
||||
{
|
||||
String add;
|
||||
|
||||
while ((add = reader.readLine()) != null)
|
||||
|
@ -92,14 +99,18 @@ public class DiskReader {
|
|||
|
||||
if (cache)
|
||||
map.put(fileName, array);
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
array = map.get(fileName);
|
||||
}
|
||||
|
||||
if (lineNumber == -1) {
|
||||
if (lineNumber == -1)
|
||||
{
|
||||
int size = array.size();
|
||||
return array.get(random.nextInt(size));
|
||||
} else
|
||||
}
|
||||
else
|
||||
return array.get(lineNumber);
|
||||
}
|
||||
|
||||
|
|
|
@ -1,10 +1,6 @@
|
|||
package me.konloch.kontainer.io;
|
||||
|
||||
import java.io.BufferedWriter;
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.FileWriter;
|
||||
import java.io.PrintWriter;
|
||||
import java.io.*;
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
|
@ -13,7 +9,8 @@ import java.util.Arrays;
|
|||
* @author Konloch
|
||||
*/
|
||||
|
||||
public class DiskWriter {
|
||||
public class DiskWriter
|
||||
{
|
||||
|
||||
/**
|
||||
* Used to insert a difference string with preserving the file extension
|
||||
|
@ -21,15 +18,17 @@ public class DiskWriter {
|
|||
* @param fileName The file name
|
||||
* @param difference Normally an integer
|
||||
* @return The filename with the difference inserted and the file extension
|
||||
* preserved
|
||||
* preserved
|
||||
*/
|
||||
public static String insertFileName(String fileName, String difference) {
|
||||
public static String insertFileName(String fileName, String difference)
|
||||
{
|
||||
String[] babe = fileName.split("\\.");
|
||||
int count = 0;
|
||||
int math = babe.length;
|
||||
StringBuilder m = new StringBuilder();
|
||||
|
||||
for (String s2 : babe) {
|
||||
for (String s2 : babe)
|
||||
{
|
||||
m.append(s2);
|
||||
if (math - 2 == count)
|
||||
m.append(difference).append(".");
|
||||
|
@ -49,8 +48,8 @@ public class DiskWriter {
|
|||
* @param fileContents
|
||||
* @param debug
|
||||
*/
|
||||
public static synchronized void writeNewLine(String filename,
|
||||
byte[] fileContents, boolean debug) {
|
||||
public static synchronized void writeNewLine(String filename, byte[] fileContents, boolean debug)
|
||||
{
|
||||
new File(filename).getParentFile().mkdirs();
|
||||
String original = filename;
|
||||
int counter = 0;
|
||||
|
@ -59,26 +58,28 @@ public class DiskWriter {
|
|||
int failSafe = 0;
|
||||
while (!saved && failSafe++ <= 42069)
|
||||
{
|
||||
try (FileWriter fr = new FileWriter(filename, true);
|
||||
BufferedWriter bw = new BufferedWriter(fr);
|
||||
PrintWriter writer = new PrintWriter(bw)) {
|
||||
try (FileWriter fr = new FileWriter(filename, true); BufferedWriter bw = new BufferedWriter(fr); PrintWriter writer = new PrintWriter(bw))
|
||||
{
|
||||
writer.println(Arrays.toString(fileContents));
|
||||
if (debug)
|
||||
System.out.println("Saved " + filename + " to disk");
|
||||
saved = true;
|
||||
} catch (Exception e) {
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
if (debug)
|
||||
System.out.println("Failed saving, trying to save as "
|
||||
+ filename);
|
||||
if (original.contains(".")) {
|
||||
System.out.println("Failed saving, trying to save as " + filename);
|
||||
if (original.contains("."))
|
||||
{
|
||||
filename = insertFileName(original, "" + counter);
|
||||
} else
|
||||
}
|
||||
else
|
||||
filename = original + counter;
|
||||
counter++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Writes a string to the file
|
||||
*/
|
||||
|
@ -90,8 +91,8 @@ public class DiskWriter {
|
|||
/**
|
||||
* Writes a string to the file
|
||||
*/
|
||||
public static synchronized void writeNewLine(String filename,
|
||||
String lineToWrite, boolean debug) {
|
||||
public static synchronized void writeNewLine(String filename, String lineToWrite, boolean debug)
|
||||
{
|
||||
new File(filename).getParentFile().mkdirs();
|
||||
String original = filename;
|
||||
int counter = 0;
|
||||
|
@ -100,21 +101,22 @@ public class DiskWriter {
|
|||
int failSafe = 0;
|
||||
while (!saved && failSafe++ <= 42069)
|
||||
{
|
||||
try (FileWriter fr = new FileWriter(filename, true);
|
||||
BufferedWriter bw = new BufferedWriter(fr);
|
||||
PrintWriter writer = new PrintWriter(bw)) {
|
||||
try (FileWriter fr = new FileWriter(filename, true); BufferedWriter bw = new BufferedWriter(fr); PrintWriter writer = new PrintWriter(bw))
|
||||
{
|
||||
writer.println(lineToWrite);
|
||||
if (debug)
|
||||
System.out.println("Saved " + filename + ">" + lineToWrite
|
||||
+ " to disk");
|
||||
System.out.println("Saved " + filename + ">" + lineToWrite + " to disk");
|
||||
saved = true;
|
||||
} catch (Exception e) {
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
if (debug)
|
||||
System.out.println("Failed saving, trying to save as "
|
||||
+ filename);
|
||||
if (original.contains(".")) {
|
||||
System.out.println("Failed saving, trying to save as " + filename);
|
||||
if (original.contains("."))
|
||||
{
|
||||
filename = insertFileName(original, "" + counter);
|
||||
} else
|
||||
}
|
||||
else
|
||||
filename = original + counter;
|
||||
counter++;
|
||||
}
|
||||
|
@ -129,13 +131,13 @@ public class DiskWriter {
|
|||
* @param fileContents
|
||||
* @param debug
|
||||
*/
|
||||
public static synchronized void replaceFileBytes(String filename,
|
||||
byte[] fileContents, boolean debug) {
|
||||
public static synchronized void replaceFileBytes(String filename, byte[] fileContents, boolean debug)
|
||||
{
|
||||
new File(filename).getParentFile().mkdirs();
|
||||
File f = new File(filename);
|
||||
if (f.exists())
|
||||
f.delete();
|
||||
|
||||
|
||||
String original = filename;
|
||||
int counter = 0;
|
||||
|
||||
|
@ -150,13 +152,16 @@ public class DiskWriter {
|
|||
if (debug)
|
||||
System.out.println("Saved " + filename + " to disk");
|
||||
saved = true;
|
||||
} catch (Exception e) {
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
if (debug)
|
||||
System.out.println("Failed saving, trying to save as "
|
||||
+ filename);
|
||||
if (original.contains(".")) {
|
||||
System.out.println("Failed saving, trying to save as " + filename);
|
||||
if (original.contains("."))
|
||||
{
|
||||
filename = insertFileName(original, "" + counter);
|
||||
} else
|
||||
}
|
||||
else
|
||||
filename = original + counter;
|
||||
counter++;
|
||||
}
|
||||
|
@ -171,8 +176,8 @@ public class DiskWriter {
|
|||
* @param lineToWrite
|
||||
* @param debug
|
||||
*/
|
||||
public static synchronized void replaceFile(String filename,
|
||||
String lineToWrite, boolean debug) {
|
||||
public static synchronized void replaceFile(String filename, String lineToWrite, boolean debug)
|
||||
{
|
||||
new File(filename).getParentFile().mkdirs();
|
||||
File f = new File(filename);
|
||||
if (f.exists())
|
||||
|
@ -184,21 +189,22 @@ public class DiskWriter {
|
|||
int failSafe = 0;
|
||||
while (!saved && failSafe++ <= 42069)
|
||||
{
|
||||
try (FileWriter fr = new FileWriter(filename, true);
|
||||
BufferedWriter bw = new BufferedWriter(fr);
|
||||
PrintWriter writer = new PrintWriter(bw)) {
|
||||
try (FileWriter fr = new FileWriter(filename, true); BufferedWriter bw = new BufferedWriter(fr); PrintWriter writer = new PrintWriter(bw))
|
||||
{
|
||||
writer.println(lineToWrite);
|
||||
if (debug)
|
||||
System.out.println("Saved " + filename + ">" + lineToWrite
|
||||
+ " to disk");
|
||||
System.out.println("Saved " + filename + ">" + lineToWrite + " to disk");
|
||||
saved = true;
|
||||
} catch (Exception e) {
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
if (debug)
|
||||
System.out.println("Failed saving, trying to save as "
|
||||
+ filename + "_");
|
||||
if (original.contains(".")) {
|
||||
System.out.println("Failed saving, trying to save as " + filename + "_");
|
||||
if (original.contains("."))
|
||||
{
|
||||
filename = insertFileName(original, "" + counter);
|
||||
} else
|
||||
}
|
||||
else
|
||||
filename = original + counter;
|
||||
counter++;
|
||||
}
|
||||
|
|
|
@ -20,14 +20,6 @@ package the.bytecode.club.bytecodeviewer;
|
|||
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.GsonBuilder;
|
||||
|
||||
import java.awt.*;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.*;
|
||||
import java.util.List;
|
||||
import javax.swing.*;
|
||||
|
||||
import me.konloch.kontainer.io.DiskReader;
|
||||
import org.apache.commons.io.FileUtils;
|
||||
import org.objectweb.asm.tree.ClassNode;
|
||||
|
@ -50,56 +42,55 @@ import the.bytecode.club.bytecodeviewer.plugin.PluginWriter;
|
|||
import the.bytecode.club.bytecodeviewer.resources.ResourceContainer;
|
||||
import the.bytecode.club.bytecodeviewer.resources.importing.ImportResource;
|
||||
import the.bytecode.club.bytecodeviewer.translation.TranslatedStrings;
|
||||
import the.bytecode.club.bytecodeviewer.util.BootCheck;
|
||||
import the.bytecode.club.bytecodeviewer.util.ClassFileUtils;
|
||||
import the.bytecode.club.bytecodeviewer.util.LazyNameUtil;
|
||||
import the.bytecode.club.bytecodeviewer.util.MiscUtils;
|
||||
import the.bytecode.club.bytecodeviewer.util.PingBack;
|
||||
import the.bytecode.club.bytecodeviewer.util.SecurityMan;
|
||||
import the.bytecode.club.bytecodeviewer.util.*;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.awt.*;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
import java.util.*;
|
||||
|
||||
import static javax.swing.JOptionPane.QUESTION_MESSAGE;
|
||||
import static the.bytecode.club.bytecodeviewer.Constants.DEV_MODE;
|
||||
import static the.bytecode.club.bytecodeviewer.Constants.FAT_JAR;
|
||||
import static the.bytecode.club.bytecodeviewer.Constants.VERSION;
|
||||
import static the.bytecode.club.bytecodeviewer.Constants.tempDirectory;
|
||||
import static the.bytecode.club.bytecodeviewer.Constants.*;
|
||||
|
||||
/**
|
||||
* A lightweight Java Reverse Engineering suite, developed by Konloch - http://konloch.me
|
||||
*
|
||||
* <p>
|
||||
* All you have to do is add a jar or class file into the workspace,
|
||||
* select the file you want then it will start decompiling the class in the background.
|
||||
* When it's done it will show the Source code, Bytecode and Hexcode of the class file you chose.
|
||||
*
|
||||
* <p>
|
||||
* There is also a plugin system that will allow you to interact with the loaded classfiles.
|
||||
* For example you can write a String deobfuscator, a malicious code searcher,
|
||||
* or anything else you can think of.
|
||||
*
|
||||
* <p>
|
||||
* You can either use one of the pre-written plugins, or write your own. It supports java scripting.
|
||||
* Once a plugin is activated, it will send a ClassNode ArrayList of every single class loaded in the
|
||||
* file system to the execute function, this allows the user to handle it completely using ASM.
|
||||
*
|
||||
* <p>
|
||||
* Are you a Java Reverse Engineer? Or maybe you want to learn Java Reverse Engineering?
|
||||
* Join The Bytecode Club, we're noob friendly, and censorship free.
|
||||
* http://the.bytecode.club
|
||||
*
|
||||
* <p>
|
||||
* TODO BUGS:
|
||||
* + View>Visual Settings>Show Class Methods
|
||||
* + Spam-clicking the refresh button will cause the swing thread to deadlock (Quickly opening resources used to also do this)
|
||||
* This is caused by the ctrlMouseWheelZoom code, a temporary patch is just removing it worst case
|
||||
*
|
||||
* <p>
|
||||
* TODO API BUGS:
|
||||
* + All of the plugins that modify code need to include BytecodeViewer.updateAllClassNodeByteArrays();
|
||||
* + All of the plugins that do any code changes should also include BytecodeViewer.refreshAllTabs();
|
||||
* + Anything using getLoadedClasses() needs to be replaced with the new API
|
||||
* + Anything using blindlySearchForClassNode() should instead search through the resource container search function
|
||||
* + BCV's classLoader should be destroyed each time a resource is added or removed
|
||||
*
|
||||
* <p>
|
||||
* TODO IN-PROGRESS:
|
||||
* + Resource Exporter/Save/Decompile As Zip needs to be rewritten
|
||||
* + Finish dragging code
|
||||
* + Finish right-click tab menu detection
|
||||
* + Fix hook inject for EZ-Injection
|
||||
*
|
||||
* <p>
|
||||
* TODO FEATURES:
|
||||
* + On refresh save scroll position
|
||||
* + Option to only compile currently viewed class (true by default)
|
||||
|
@ -111,7 +102,7 @@ import static the.bytecode.club.bytecodeviewer.Constants.tempDirectory;
|
|||
* + Add decompile all as zip for CLI
|
||||
* + Console on the Main Viewer UI
|
||||
* + Font settings
|
||||
*
|
||||
* <p>
|
||||
* TODO IDEAS:
|
||||
* + App Bundle Support
|
||||
* + Add JEB decompiler optionally, requires them to add jeb library jar
|
||||
|
@ -130,34 +121,34 @@ import static the.bytecode.club.bytecodeviewer.Constants.tempDirectory;
|
|||
|
||||
public class BytecodeViewer
|
||||
{
|
||||
|
||||
|
||||
//the launch args called on BCV
|
||||
public static String[] launchArgs;
|
||||
|
||||
|
||||
//the GUI reference
|
||||
public static MainViewerGUI viewer;
|
||||
|
||||
|
||||
//All of the opened resources (Files/Classes/Etc)
|
||||
public static Map<String,ResourceContainer> resourceContainers = new LinkedHashMap<>();
|
||||
|
||||
public static Map<String, ResourceContainer> resourceContainers = new LinkedHashMap<>();
|
||||
|
||||
//All of the created processes (Decompilers/etc)
|
||||
public static List<Process> createdProcesses = new ArrayList<>();
|
||||
|
||||
|
||||
//Security Manager for dynamic analysis debugging
|
||||
public static SecurityMan sm = new SecurityMan();
|
||||
|
||||
|
||||
//Refactorer
|
||||
public static Refactorer refactorer = new Refactorer();
|
||||
|
||||
|
||||
//GSON Reference
|
||||
public static final Gson gson = new GsonBuilder().setPrettyPrinting().create();
|
||||
|
||||
|
||||
//Threads
|
||||
private static final Thread versionChecker = new Thread(new UpdateCheck(), "Version Checker");
|
||||
private static final Thread pingBack = new Thread(new PingBack(), "Pingback");
|
||||
private static final Thread installFatJar = new Thread(new InstallFatJar(), "Install Fat-Jar");
|
||||
private static final Thread bootCheck = new Thread(new BootCheck(), "Boot Check");
|
||||
|
||||
|
||||
/**
|
||||
* Main startup
|
||||
*
|
||||
|
@ -166,19 +157,22 @@ public class BytecodeViewer
|
|||
public static void main(String[] args)
|
||||
{
|
||||
launchArgs = args;
|
||||
|
||||
|
||||
//CLI startup banner
|
||||
System.out.print("Bytecode Viewer " + VERSION);
|
||||
|
||||
|
||||
if (FAT_JAR)
|
||||
System.out.print(" [Fat Jar]");
|
||||
|
||||
|
||||
System.out.println(" - https://bytecodeviewer.com\r\nCreated by @Konloch - https://konloch.com\r\nPresented by https://the.bytecode.club");
|
||||
|
||||
// Set the security manager
|
||||
try {
|
||||
try
|
||||
{
|
||||
System.setSecurityManager(sm);
|
||||
} catch (Throwable t) {
|
||||
}
|
||||
catch (Throwable t)
|
||||
{
|
||||
System.err.println("Cannot set security manager! Are you on Java 18+ and have not enabled support for it?");
|
||||
System.err.println("Because of this, you may be susceptible to some exploits!");
|
||||
System.err.println("Either deal with it or allow it using the -Djava.security.manager=allow parameter.");
|
||||
|
@ -188,30 +182,30 @@ public class BytecodeViewer
|
|||
{
|
||||
//precache settings file
|
||||
SettingsSerializer.preloadSettingsFile();
|
||||
|
||||
|
||||
//setup look and feel
|
||||
Configuration.lafTheme.setLAF();
|
||||
|
||||
|
||||
//set swing specific system properties
|
||||
System.setProperty("swing.aatext", "true");
|
||||
|
||||
|
||||
//setup swing components
|
||||
viewer = new MainViewerGUI();
|
||||
//SwingUtilities.updateComponentTreeUI(viewer);
|
||||
|
||||
|
||||
//load settings and set swing components state
|
||||
SettingsSerializer.loadSettings();
|
||||
Configuration.bootState = BootState.SETTINGS_LOADED;
|
||||
|
||||
|
||||
//set translation language
|
||||
if (!Settings.hasSetLanguageAsSystemLanguage)
|
||||
MiscUtils.setLanguage(MiscUtils.guessLanguage());
|
||||
|
||||
|
||||
//handle CLI
|
||||
int CLI = CommandLineInput.parseCommandLine(args);
|
||||
if (CLI == CommandLineInput.STOP)
|
||||
return;
|
||||
|
||||
|
||||
//load with shaded libraries
|
||||
if (FAT_JAR)
|
||||
{
|
||||
|
@ -222,7 +216,7 @@ public class BytecodeViewer
|
|||
bootCheck.start();
|
||||
Boot.boot(args, CLI != CommandLineInput.GUI);
|
||||
}
|
||||
|
||||
|
||||
//CLI arguments say spawn the GUI
|
||||
if (CLI == CommandLineInput.GUI)
|
||||
{
|
||||
|
@ -240,7 +234,7 @@ public class BytecodeViewer
|
|||
BytecodeViewer.handleException(e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Boot after all of the libraries have been loaded
|
||||
*
|
||||
|
@ -250,51 +244,51 @@ public class BytecodeViewer
|
|||
{
|
||||
//delete files in the temp folder
|
||||
cleanupAsync();
|
||||
|
||||
|
||||
//shutdown hooks
|
||||
Runtime.getRuntime().addShutdownHook(new Thread(() ->
|
||||
{
|
||||
for (Process proc : createdProcesses)
|
||||
proc.destroy();
|
||||
|
||||
|
||||
SettingsSerializer.saveSettings();
|
||||
cleanup();
|
||||
}, "Shutdown Hook"));
|
||||
|
||||
|
||||
//setup the viewer
|
||||
viewer.calledAfterLoad();
|
||||
|
||||
|
||||
//setup the recent files
|
||||
Settings.resetRecentFilesMenu();
|
||||
|
||||
|
||||
//ping back once on first boot to add to global user count
|
||||
if (!Configuration.pingback)
|
||||
{
|
||||
pingBack.start();
|
||||
Configuration.pingback = true;
|
||||
}
|
||||
|
||||
|
||||
//version checking
|
||||
if (viewer.updateCheck.isSelected() && !DEV_MODE)
|
||||
versionChecker.start();
|
||||
|
||||
|
||||
//show the main UI
|
||||
if (!cli)
|
||||
viewer.setVisible(true);
|
||||
|
||||
|
||||
//print startup time
|
||||
System.out.println("Start up took " + ((System.currentTimeMillis() - Configuration.start) / 1000) + " seconds");
|
||||
|
||||
|
||||
//request focus on GUI for hotkeys on start
|
||||
if (!cli)
|
||||
viewer.requestFocus();
|
||||
|
||||
|
||||
//open files from launch args
|
||||
if (!cli && launchArgs.length >= 1)
|
||||
for (String s : launchArgs)
|
||||
openFiles(new File[]{new File(s)}, true);
|
||||
for (String s : launchArgs)
|
||||
openFiles(new File[]{new File(s)}, true);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Adds a resource container to BCVs resource container list
|
||||
*/
|
||||
|
@ -303,14 +297,17 @@ public class BytecodeViewer
|
|||
resourceContainers.put(container.name, container);
|
||||
SwingUtilities.invokeLater(() ->
|
||||
{
|
||||
try {
|
||||
try
|
||||
{
|
||||
viewer.resourcePane.addResourceContainer(container);
|
||||
} catch (Exception e) {
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns true if there is at least one file resource loaded
|
||||
*/
|
||||
|
@ -318,7 +315,7 @@ public class BytecodeViewer
|
|||
{
|
||||
return !resourceContainers.isEmpty();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns true if there is currently a tab open with a resource inside of it
|
||||
*/
|
||||
|
@ -326,7 +323,7 @@ public class BytecodeViewer
|
|||
{
|
||||
return getActiveResource() != null;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns true if there is currently a tab open with a resource inside of it
|
||||
*/
|
||||
|
@ -335,7 +332,7 @@ public class BytecodeViewer
|
|||
ResourceViewer resource = getActiveResource();
|
||||
return resource instanceof ClassViewer;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the currently opened & viewed resource
|
||||
*/
|
||||
|
@ -343,7 +340,7 @@ public class BytecodeViewer
|
|||
{
|
||||
return BytecodeViewer.viewer.workPane.getActiveResource();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the currently opened ClassNode
|
||||
*
|
||||
|
@ -353,7 +350,7 @@ public class BytecodeViewer
|
|||
{
|
||||
return getActiveResource().resource.getResourceClassNode();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the ClassNode by the specified name
|
||||
* <p>
|
||||
|
@ -368,14 +365,14 @@ public class BytecodeViewer
|
|||
for (ResourceContainer container : resourceContainers.values())
|
||||
{
|
||||
ClassNode node = container.getClassNode(name);
|
||||
|
||||
|
||||
if (node != null)
|
||||
return node;
|
||||
}
|
||||
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the resource container by the specific name
|
||||
*/
|
||||
|
@ -384,10 +381,10 @@ public class BytecodeViewer
|
|||
for (ResourceContainer container : resourceContainers.values())
|
||||
if (container.name.equals(name))
|
||||
return container;
|
||||
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns all of the loaded resource containers
|
||||
*/
|
||||
|
@ -395,7 +392,7 @@ public class BytecodeViewer
|
|||
{
|
||||
return resourceContainers.values();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Grabs the file contents of the loaded resources.
|
||||
* <p>
|
||||
|
@ -410,10 +407,10 @@ public class BytecodeViewer
|
|||
for (ResourceContainer container : resourceContainers.values())
|
||||
if (container.resourceFiles.containsKey(name))
|
||||
return container.resourceFiles.get(name);
|
||||
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Grab the byte array from the loaded Class object by getting the resource from the classloader
|
||||
*/
|
||||
|
@ -421,10 +418,10 @@ public class BytecodeViewer
|
|||
{
|
||||
return ClassFileUtils.getClassFileBytes(clazz);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Gets all of the loaded classes as an array list
|
||||
*
|
||||
* <p>
|
||||
* TODO: remove this and replace it with:
|
||||
* BytecodeViewer.getResourceContainers().forEach(container -> {
|
||||
* execute(new ArrayList<>(container.resourceClasses.values()));
|
||||
|
@ -436,15 +433,15 @@ public class BytecodeViewer
|
|||
public static List<ClassNode> getLoadedClasses()
|
||||
{
|
||||
List<ClassNode> a = new ArrayList<>();
|
||||
|
||||
|
||||
for (ResourceContainer container : resourceContainers.values())
|
||||
for (ClassNode c : container.resourceClasses.values())
|
||||
if (!a.contains(c))
|
||||
a.add(c);
|
||||
|
||||
|
||||
return a;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Called any time refresh is called to automatically compile all of the compilable panes that're opened.
|
||||
*/
|
||||
|
@ -452,7 +449,7 @@ public class BytecodeViewer
|
|||
{
|
||||
if (!BytecodeViewer.viewer.autoCompileOnRefresh.isSelected())
|
||||
return true;
|
||||
|
||||
|
||||
try
|
||||
{
|
||||
return compile(false, false);
|
||||
|
@ -462,7 +459,7 @@ public class BytecodeViewer
|
|||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Compile all of the compilable panes that're opened.
|
||||
*
|
||||
|
@ -474,20 +471,20 @@ public class BytecodeViewer
|
|||
BytecodeViewer.updateBusyStatus(true);
|
||||
boolean noErrors = true;
|
||||
boolean actuallyTried = false;
|
||||
|
||||
|
||||
for (java.awt.Component c : BytecodeViewer.viewer.workPane.getLoadedViewers())
|
||||
{
|
||||
if (c instanceof ClassViewer)
|
||||
{
|
||||
ClassViewer cv = (ClassViewer) c;
|
||||
|
||||
|
||||
if (noErrors && !cv.bytecodeViewPanel1.compile())
|
||||
noErrors = false;
|
||||
if (noErrors && !cv.bytecodeViewPanel2.compile())
|
||||
noErrors = false;
|
||||
if (noErrors && !cv.bytecodeViewPanel3.compile())
|
||||
noErrors = false;
|
||||
|
||||
|
||||
if (cv.bytecodeViewPanel1.textArea != null && cv.bytecodeViewPanel1.textArea.isEditable())
|
||||
actuallyTried = true;
|
||||
if (cv.bytecodeViewPanel2.textArea != null && cv.bytecodeViewPanel2.textArea.isEditable())
|
||||
|
@ -496,7 +493,7 @@ public class BytecodeViewer
|
|||
actuallyTried = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (message)
|
||||
{
|
||||
if (actuallyTried)
|
||||
|
@ -509,11 +506,11 @@ public class BytecodeViewer
|
|||
BytecodeViewer.showMessage("You have no editable panes opened, make one editable and try again.");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
BytecodeViewer.updateBusyStatus(false);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Opens a file, optional if it should append to the recent files menu
|
||||
*
|
||||
|
@ -527,16 +524,16 @@ public class BytecodeViewer
|
|||
for (File f : files)
|
||||
if (f.exists())
|
||||
Settings.addRecentFile(f);
|
||||
|
||||
|
||||
SettingsSerializer.saveSettingsAsync();
|
||||
}
|
||||
|
||||
|
||||
BytecodeViewer.updateBusyStatus(true);
|
||||
Configuration.needsReDump = true;
|
||||
Thread t = new Thread(new ImportResource(files), "Import Resource");
|
||||
t.start();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Starts the specified plugin
|
||||
*
|
||||
|
@ -550,7 +547,7 @@ public class BytecodeViewer
|
|||
Settings.removeRecentPlugin(file);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
try
|
||||
{
|
||||
PluginWriter writer = new PluginWriter(DiskReader.loadAsString(file.getAbsolutePath()), file.getName());
|
||||
|
@ -561,10 +558,10 @@ public class BytecodeViewer
|
|||
{
|
||||
BytecodeViewer.handleException(e);
|
||||
}
|
||||
|
||||
|
||||
Settings.addRecentPlugin(file);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Send a message to alert the user
|
||||
*
|
||||
|
@ -574,7 +571,7 @@ public class BytecodeViewer
|
|||
{
|
||||
ExtendedJOptionPane.showMessageDialog(viewer, message);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Send a message to alert the user
|
||||
*/
|
||||
|
@ -582,16 +579,15 @@ public class BytecodeViewer
|
|||
{
|
||||
return ExtendedJOptionPane.showInputDialog(viewer, message);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Send a message to alert the user
|
||||
*/
|
||||
public static String showInput(String message, String title, String initialMessage)
|
||||
{
|
||||
return (String) ExtendedJOptionPane.showInputDialog(viewer, message, title,
|
||||
QUESTION_MESSAGE, null, null, initialMessage);
|
||||
return (String) ExtendedJOptionPane.showInputDialog(viewer, message, title, QUESTION_MESSAGE, null, null, initialMessage);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Alerts the user the program is running something in the background
|
||||
*/
|
||||
|
@ -599,7 +595,7 @@ public class BytecodeViewer
|
|||
{
|
||||
viewer.updateBusyStatus(busyStatus);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Clears all active busy status icons
|
||||
*/
|
||||
|
@ -607,7 +603,7 @@ public class BytecodeViewer
|
|||
{
|
||||
viewer.clearBusyStatus();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns true if there are no loaded resource classes
|
||||
*/
|
||||
|
@ -618,10 +614,10 @@ public class BytecodeViewer
|
|||
BytecodeViewer.showMessage(TranslatedStrings.FIRST_OPEN_A_CLASS.toString());
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns true if there are no loaded resource classes
|
||||
*/
|
||||
|
@ -632,10 +628,10 @@ public class BytecodeViewer
|
|||
BytecodeViewer.showMessage(TranslatedStrings.FIRST_OPEN_A_RESOURCE.toString());
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Handle the exception by creating a new window for bug reporting
|
||||
*/
|
||||
|
@ -643,7 +639,7 @@ public class BytecodeViewer
|
|||
{
|
||||
handleException(t, ExceptionUI.KONLOCH);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Handle the exception by creating a new window for bug reporting
|
||||
*/
|
||||
|
@ -651,7 +647,7 @@ public class BytecodeViewer
|
|||
{
|
||||
new ExceptionUI(t, author);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Refreshes the title on all of the opened tabs
|
||||
*/
|
||||
|
@ -659,26 +655,26 @@ public class BytecodeViewer
|
|||
{
|
||||
resourceContainers.values().forEach(ResourceContainer::updateClassNodeBytes);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Refreshes the title on all of the opened tabs
|
||||
*/
|
||||
public static void refreshAllTabTitles()
|
||||
{
|
||||
for(int i = 0; i < BytecodeViewer.viewer.workPane.tabs.getTabCount(); i++)
|
||||
for (int i = 0; i < BytecodeViewer.viewer.workPane.tabs.getTabCount(); i++)
|
||||
{
|
||||
//ResourceViewer viewer = ((TabbedPane) BytecodeViewer.viewer.workPane.tabs.getTabComponentAt(i)).resource;
|
||||
//viewer.refreshTitle();
|
||||
//TODO
|
||||
//TODO
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Refreshes all the opened tabs
|
||||
*/
|
||||
public static void refreshAllTabs()
|
||||
{
|
||||
new Thread(()->
|
||||
new Thread(() ->
|
||||
{
|
||||
updateBusyStatus(true);
|
||||
for (int i = 0; i < BytecodeViewer.viewer.workPane.tabs.getTabCount(); i++)
|
||||
|
@ -699,17 +695,15 @@ public class BytecodeViewer
|
|||
{
|
||||
if (ask)
|
||||
{
|
||||
MultipleChoiceDialog dialog = new MultipleChoiceDialog(TranslatedStrings.RESET_TITLE.toString(),
|
||||
TranslatedStrings.RESET_CONFIRM.toString(),
|
||||
new String[]{TranslatedStrings.YES.toString(), TranslatedStrings.NO.toString()});
|
||||
|
||||
MultipleChoiceDialog dialog = new MultipleChoiceDialog(TranslatedStrings.RESET_TITLE.toString(), TranslatedStrings.RESET_CONFIRM.toString(), new String[]{TranslatedStrings.YES.toString(), TranslatedStrings.NO.toString()});
|
||||
|
||||
if (dialog.promptChoice() != 0)
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
resetWorkspace();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Resets the workspace
|
||||
*/
|
||||
|
@ -723,7 +717,7 @@ public class BytecodeViewer
|
|||
BCV.getClassNodeLoader().clear();
|
||||
ResourceListIconRenderer.iconCache.clear();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Clears the temp directory
|
||||
*/
|
||||
|
@ -740,42 +734,51 @@ public class BytecodeViewer
|
|||
{
|
||||
File tempF = new File(tempDirectory);
|
||||
|
||||
try {
|
||||
try
|
||||
{
|
||||
FileUtils.deleteDirectory(tempF);
|
||||
} catch (Exception ignored) { }
|
||||
}
|
||||
catch (Exception ignored)
|
||||
{
|
||||
}
|
||||
|
||||
while (!tempF.exists()) // keep making dirs
|
||||
tempF.mkdir();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* because Smali and Baksmali System.exit if it failed
|
||||
*/
|
||||
public static void exit(int i) { }
|
||||
public static void exit(int i)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates all UI components fonts.
|
||||
*
|
||||
* @param font The font to change everything to.
|
||||
* @implNote {@link SearchableRSyntaxTextArea} and {@link SearchableJTextArea}
|
||||
* do not update until "Refresh" button is clicked.
|
||||
*
|
||||
* @param font The font to change everything to.
|
||||
*/
|
||||
public static void updateAllFonts(Font font) {
|
||||
public static void updateAllFonts(Font font)
|
||||
{
|
||||
Enumeration<Object> enumeration = UIManager.getDefaults().keys();
|
||||
while (enumeration.hasMoreElements()) {
|
||||
while (enumeration.hasMoreElements())
|
||||
{
|
||||
Object key = enumeration.nextElement();
|
||||
Object value = UIManager.get (key);
|
||||
Object value = UIManager.get(key);
|
||||
if (value instanceof Font)
|
||||
UIManager.put (key, font);
|
||||
UIManager.put(key, font);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates all swing components.
|
||||
*/
|
||||
public static void updateUI() {
|
||||
for (Window w : Window.getWindows()) {
|
||||
public static void updateUI()
|
||||
{
|
||||
for (Window w : Window.getWindows())
|
||||
{
|
||||
SwingUtilities.updateComponentTreeUI(w);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,7 +18,6 @@
|
|||
|
||||
package the.bytecode.club.bytecodeviewer;
|
||||
|
||||
import java.io.File;
|
||||
import me.konloch.kontainer.io.DiskWriter;
|
||||
import org.apache.commons.cli.CommandLine;
|
||||
import org.apache.commons.cli.CommandLineParser;
|
||||
|
@ -31,9 +30,9 @@ import the.bytecode.club.bytecodeviewer.translation.Language;
|
|||
import the.bytecode.club.bytecodeviewer.util.JarUtils;
|
||||
import the.bytecode.club.bytecodeviewer.util.MiscUtils;
|
||||
|
||||
import static the.bytecode.club.bytecodeviewer.Constants.VERSION;
|
||||
import static the.bytecode.club.bytecodeviewer.Constants.fs;
|
||||
import static the.bytecode.club.bytecodeviewer.Constants.tempDirectory;
|
||||
import java.io.File;
|
||||
|
||||
import static the.bytecode.club.bytecodeviewer.Constants.*;
|
||||
|
||||
/**
|
||||
* Used to allow BCV to be integrated as CLI instead of GUI.
|
||||
|
@ -41,7 +40,8 @@ import static the.bytecode.club.bytecodeviewer.Constants.tempDirectory;
|
|||
* @author Konloch
|
||||
*/
|
||||
|
||||
public class CommandLineInput {
|
||||
public class CommandLineInput
|
||||
{
|
||||
|
||||
private static final Options options = new Options();
|
||||
private static final CommandLineParser parser = new DefaultParser();
|
||||
|
@ -51,7 +51,8 @@ public class CommandLineInput {
|
|||
public static int GUI = 0;
|
||||
public static int CLI = 1;
|
||||
|
||||
static {
|
||||
static
|
||||
{
|
||||
options.addOption("help", false, "prints the help menu.");
|
||||
options.addOption("list", false, "lists all the available decompilers for BCV " + VERSION + ".");
|
||||
options.addOption("decompiler", true, "sets the decompiler, procyon by default.");
|
||||
|
@ -61,38 +62,36 @@ public class CommandLineInput {
|
|||
options.addOption("nowait", true, "won't wait the 5 seconds to allow the user to read the CLI.");
|
||||
}
|
||||
|
||||
public static boolean containsCommand(String[] args) {
|
||||
public static boolean containsCommand(String[] args)
|
||||
{
|
||||
if (args == null || args.length == 0)
|
||||
return false;
|
||||
|
||||
try {
|
||||
try
|
||||
{
|
||||
CommandLine cmd = parser.parse(options, args);
|
||||
if (
|
||||
cmd.hasOption("help") ||
|
||||
cmd.hasOption("clean") ||
|
||||
cmd.hasOption("english") ||
|
||||
cmd.hasOption("list") ||
|
||||
cmd.hasOption("decompiler") ||
|
||||
cmd.hasOption("i") ||
|
||||
cmd.hasOption("o") ||
|
||||
cmd.hasOption("t") ||
|
||||
cmd.hasOption("nowait")
|
||||
) {
|
||||
if (cmd.hasOption("help") || cmd.hasOption("clean") || cmd.hasOption("english") || cmd.hasOption("list") || cmd.hasOption("decompiler") || cmd.hasOption("i") || cmd.hasOption("o") || cmd.hasOption("t") || cmd.hasOption("nowait"))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static int parseCommandLine(String[] args) {
|
||||
public static int parseCommandLine(String[] args)
|
||||
{
|
||||
if (!containsCommand(args))
|
||||
return GUI;
|
||||
try {
|
||||
try
|
||||
{
|
||||
CommandLine cmd = parser.parse(options, args);
|
||||
if (cmd.hasOption("list")) {
|
||||
if (cmd.hasOption("list"))
|
||||
{
|
||||
System.out.println("Procyon");
|
||||
System.out.println("CFR");
|
||||
System.out.println("FernFlower");
|
||||
|
@ -102,38 +101,38 @@ public class CommandLineInput {
|
|||
System.out.println("Smali");
|
||||
System.out.println("ASMifier");
|
||||
return STOP;
|
||||
} else if (cmd.hasOption("clean")) {
|
||||
}
|
||||
else if (cmd.hasOption("clean"))
|
||||
{
|
||||
new File(Constants.getBCVDirectory()).delete();
|
||||
if(cmd.getOptionValue("i") == null && cmd.getOptionValue("o") == null
|
||||
&& cmd.getOptionValue("t") == null)
|
||||
if (cmd.getOptionValue("i") == null && cmd.getOptionValue("o") == null && cmd.getOptionValue("t") == null)
|
||||
return GUI;
|
||||
} else if (cmd.hasOption("english")) {
|
||||
}
|
||||
else if (cmd.hasOption("english"))
|
||||
{
|
||||
Configuration.language = Language.ENGLISH;
|
||||
return GUI;
|
||||
} else if (cmd.hasOption("help")) {
|
||||
for (String s : new String[]{
|
||||
"-help Displays the help menu",
|
||||
"-clean Deletes the BCV directory",
|
||||
"-english Forces English language translations",
|
||||
"-list Displays the available decompilers",
|
||||
"-decompiler <decompiler> Selects the decompiler, procyon by default",
|
||||
"-i <input file> Selects the input file",
|
||||
"-o <output file> Selects the output file",
|
||||
"-t <target classname> Must either be the fully qualified classname or \"all\" to decompile all as zip",
|
||||
"-nowait Doesn't wait for the user to read the CLI messages"
|
||||
})
|
||||
}
|
||||
else if (cmd.hasOption("help"))
|
||||
{
|
||||
for (String s : new String[]{"-help Displays the help menu", "-clean Deletes the BCV directory", "-english Forces English language translations", "-list Displays the available decompilers", "-decompiler <decompiler> Selects the decompiler, procyon by default", "-i <input file> Selects the input file", "-o <output file> Selects the output file", "-t <target classname> Must either be the fully qualified classname or \"all\" to decompile all as zip", "-nowait Doesn't wait for the user to read the CLI messages"})
|
||||
System.out.println(s);
|
||||
return STOP;
|
||||
} else {
|
||||
if (cmd.getOptionValue("i") == null) {
|
||||
}
|
||||
else
|
||||
{
|
||||
if (cmd.getOptionValue("i") == null)
|
||||
{
|
||||
System.err.println("Set the input with -i");
|
||||
return STOP;
|
||||
}
|
||||
if (cmd.getOptionValue("o") == null) {
|
||||
if (cmd.getOptionValue("o") == null)
|
||||
{
|
||||
System.err.println("Set the output with -o");
|
||||
return STOP;
|
||||
}
|
||||
if (cmd.getOptionValue("t") == null) {
|
||||
if (cmd.getOptionValue("t") == null)
|
||||
{
|
||||
System.err.println("Set the target with -t");
|
||||
return STOP;
|
||||
}
|
||||
|
@ -142,12 +141,14 @@ public class CommandLineInput {
|
|||
File output = new File(cmd.getOptionValue("o"));
|
||||
String decompiler = cmd.getOptionValue("decompiler");
|
||||
|
||||
if (!input.exists()) {
|
||||
if (!input.exists())
|
||||
{
|
||||
System.err.println(input.getAbsolutePath() + " does not exist.");
|
||||
return STOP;
|
||||
}
|
||||
|
||||
if (output.exists()) {
|
||||
if (output.exists())
|
||||
{
|
||||
System.err.println("WARNING: Deleted old " + output.getAbsolutePath() + ".");
|
||||
output.delete();
|
||||
}
|
||||
|
@ -156,19 +157,9 @@ public class CommandLineInput {
|
|||
//if its zip/jar/apk/dex attempt unzip as whole zip
|
||||
//if its just class allow any
|
||||
|
||||
if (
|
||||
decompiler != null &&
|
||||
!decompiler.equalsIgnoreCase("procyon") &&
|
||||
!decompiler.equalsIgnoreCase("cfr") &&
|
||||
!decompiler.equalsIgnoreCase("fernflower") &&
|
||||
!decompiler.equalsIgnoreCase("krakatau") &&
|
||||
!decompiler.equalsIgnoreCase("krakatau-bytecode") &&
|
||||
!decompiler.equalsIgnoreCase("jd-gui") &&
|
||||
!decompiler.equalsIgnoreCase("smali") &&
|
||||
!decompiler.equalsIgnoreCase("asmifier")
|
||||
) {
|
||||
System.out.println("Error, no decompiler called '" + decompiler + "' found. Type -list"
|
||||
+ " for the list");
|
||||
if (decompiler != null && !decompiler.equalsIgnoreCase("procyon") && !decompiler.equalsIgnoreCase("cfr") && !decompiler.equalsIgnoreCase("fernflower") && !decompiler.equalsIgnoreCase("krakatau") && !decompiler.equalsIgnoreCase("krakatau-bytecode") && !decompiler.equalsIgnoreCase("jd-gui") && !decompiler.equalsIgnoreCase("smali") && !decompiler.equalsIgnoreCase("asmifier"))
|
||||
{
|
||||
System.out.println("Error, no decompiler called '" + decompiler + "' found. Type -list" + " for the list");
|
||||
}
|
||||
|
||||
|
||||
|
@ -177,24 +168,28 @@ public class CommandLineInput {
|
|||
|
||||
return CLI;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
BytecodeViewer.handleException(e);
|
||||
}
|
||||
|
||||
return GUI;
|
||||
}
|
||||
|
||||
public static void executeCommandLine(String[] args) {
|
||||
try {
|
||||
public static void executeCommandLine(String[] args)
|
||||
{
|
||||
try
|
||||
{
|
||||
CommandLine cmd = parser.parse(options, args);
|
||||
String decompiler = cmd.getOptionValue("decompiler");
|
||||
File input = new File(cmd.getOptionValue("i"));
|
||||
File output = new File(cmd.getOptionValue("o"));
|
||||
String target = cmd.getOptionValue("t");
|
||||
|
||||
if (cmd.getOptionValue("decompiler") == null) {
|
||||
System.out.println("You can define another decompiler by appending -decompiler \"name\", by default "
|
||||
+ "procyon has been set.");
|
||||
if (cmd.getOptionValue("decompiler") == null)
|
||||
{
|
||||
System.out.println("You can define another decompiler by appending -decompiler \"name\", by default " + "procyon has been set.");
|
||||
decompiler = "procyon";
|
||||
}
|
||||
|
||||
|
@ -202,178 +197,247 @@ public class CommandLineInput {
|
|||
//if its zip/jar/apk/dex attempt unzip as whole zip
|
||||
//if its just class allow any
|
||||
|
||||
File tempZip =
|
||||
new File(tempDirectory + fs + "temp_" + MiscUtils.getRandomizedName() + ".jar");
|
||||
File tempZip = new File(tempDirectory + fs + "temp_" + MiscUtils.getRandomizedName() + ".jar");
|
||||
if (tempZip.exists())
|
||||
tempZip.delete();
|
||||
|
||||
JarUtils.saveAsJarClassesOnly(BytecodeViewer.getLoadedClasses(), tempZip.getAbsolutePath());
|
||||
|
||||
if (decompiler.equalsIgnoreCase("procyon")) {
|
||||
if (decompiler.equalsIgnoreCase("procyon"))
|
||||
{
|
||||
System.out.println("Decompiling " + input.getAbsolutePath() + " with Procyon");
|
||||
BytecodeViewer.openFiles(new File[]{input}, false);
|
||||
|
||||
Thread.sleep(5 * 1000);
|
||||
|
||||
if (target.equalsIgnoreCase("all")) {
|
||||
if (target.equalsIgnoreCase("all"))
|
||||
{
|
||||
Decompiler.PROCYON_DECOMPILER.getDecompiler().decompileToZip(tempZip.getAbsolutePath(), output.getAbsolutePath());
|
||||
} else {
|
||||
try {
|
||||
}
|
||||
else
|
||||
{
|
||||
try
|
||||
{
|
||||
ClassNode cn = BytecodeViewer.blindlySearchForClassNode(target);
|
||||
final ClassWriter cw = accept(cn);
|
||||
String contents = Decompiler.PROCYON_DECOMPILER.getDecompiler().decompileClassNode(cn, cw.toByteArray());
|
||||
DiskWriter.replaceFile(output.getAbsolutePath(), contents, false);
|
||||
} catch (Exception e) {
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
BytecodeViewer.handleException(e);
|
||||
}
|
||||
}
|
||||
} else if (decompiler.equalsIgnoreCase("cfr")) {
|
||||
}
|
||||
else if (decompiler.equalsIgnoreCase("cfr"))
|
||||
{
|
||||
System.out.println("Decompiling " + input.getAbsolutePath() + " with CFR");
|
||||
BytecodeViewer.openFiles(new File[]{input}, false);
|
||||
|
||||
Thread.sleep(5 * 1000);
|
||||
|
||||
if (target.equalsIgnoreCase("all")) {
|
||||
if (target.equalsIgnoreCase("all"))
|
||||
{
|
||||
Decompiler.CFR_DECOMPILER.getDecompiler().decompileToZip(tempZip.getAbsolutePath(), output.getAbsolutePath());
|
||||
} else {
|
||||
try {
|
||||
}
|
||||
else
|
||||
{
|
||||
try
|
||||
{
|
||||
ClassNode cn = BytecodeViewer.blindlySearchForClassNode(target);
|
||||
final ClassWriter cw = accept(cn);
|
||||
String contents = Decompiler.CFR_DECOMPILER.getDecompiler().decompileClassNode(cn, cw.toByteArray());
|
||||
DiskWriter.replaceFile(output.getAbsolutePath(), contents, false);
|
||||
} catch (Exception e) {
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
BytecodeViewer.handleException(e);
|
||||
}
|
||||
}
|
||||
} else if (decompiler.equalsIgnoreCase("fernflower")) {
|
||||
}
|
||||
else if (decompiler.equalsIgnoreCase("fernflower"))
|
||||
{
|
||||
System.out.println("Decompiling " + input.getAbsolutePath() + " with FernFlower");
|
||||
BytecodeViewer.openFiles(new File[]{input}, false);
|
||||
|
||||
Thread.sleep(5 * 1000);
|
||||
|
||||
if (target.equalsIgnoreCase("all")) {
|
||||
if (target.equalsIgnoreCase("all"))
|
||||
{
|
||||
Decompiler.FERNFLOWER_DECOMPILER.getDecompiler().decompileToZip(tempZip.getAbsolutePath(), output.getAbsolutePath());
|
||||
} else {
|
||||
try {
|
||||
}
|
||||
else
|
||||
{
|
||||
try
|
||||
{
|
||||
ClassNode cn = BytecodeViewer.blindlySearchForClassNode(target);
|
||||
final ClassWriter cw = accept(cn);
|
||||
String contents = Decompiler.FERNFLOWER_DECOMPILER.getDecompiler().decompileClassNode(cn, cw.toByteArray());
|
||||
DiskWriter.replaceFile(output.getAbsolutePath(), contents, false);
|
||||
} catch (Exception e) {
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
BytecodeViewer.handleException(e);
|
||||
}
|
||||
}
|
||||
} else if (decompiler.equalsIgnoreCase("krakatau")) {
|
||||
}
|
||||
else if (decompiler.equalsIgnoreCase("krakatau"))
|
||||
{
|
||||
System.out.println("Decompiling " + input.getAbsolutePath() + " with Krakatau");
|
||||
BytecodeViewer.openFiles(new File[]{input}, false);
|
||||
|
||||
Thread.sleep(5 * 1000);
|
||||
|
||||
if (target.equalsIgnoreCase("all")) {
|
||||
if (target.equalsIgnoreCase("all"))
|
||||
{
|
||||
Decompiler.KRAKATAU_DECOMPILER.getDecompiler().decompileToZip(tempZip.getAbsolutePath(), output.getAbsolutePath());
|
||||
} else {
|
||||
try {
|
||||
}
|
||||
else
|
||||
{
|
||||
try
|
||||
{
|
||||
ClassNode cn = BytecodeViewer.blindlySearchForClassNode(target);
|
||||
final ClassWriter cw = accept(cn);
|
||||
String contents = Decompiler.KRAKATAU_DECOMPILER.getDecompiler().decompileClassNode(cn, cw.toByteArray());
|
||||
DiskWriter.replaceFile(output.getAbsolutePath(), contents, false);
|
||||
} catch (Exception e) {
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
BytecodeViewer.handleException(e);
|
||||
}
|
||||
}
|
||||
} else if (decompiler.equalsIgnoreCase("krakatau-bytecode")) {
|
||||
}
|
||||
else if (decompiler.equalsIgnoreCase("krakatau-bytecode"))
|
||||
{
|
||||
System.out.println("Decompiling " + input.getAbsolutePath() + " with Krakatau-Bytecode");
|
||||
BytecodeViewer.openFiles(new File[]{input}, false);
|
||||
|
||||
Thread.sleep(5 * 1000);
|
||||
|
||||
if (target.equalsIgnoreCase("all")) {
|
||||
if (target.equalsIgnoreCase("all"))
|
||||
{
|
||||
System.out.println("Coming soon.");
|
||||
//Decompiler.krakatauDA.decompileToZip(output.getAbsolutePath());
|
||||
} else {
|
||||
try {
|
||||
}
|
||||
else
|
||||
{
|
||||
try
|
||||
{
|
||||
ClassNode cn = BytecodeViewer.blindlySearchForClassNode(target);
|
||||
final ClassWriter cw = accept(cn);
|
||||
String contents = Decompiler.KRAKATAU_DISASSEMBLER.getDecompiler().decompileClassNode(cn, cw.toByteArray());
|
||||
DiskWriter.replaceFile(output.getAbsolutePath(), contents, false);
|
||||
} catch (Exception e) {
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
BytecodeViewer.handleException(e);
|
||||
}
|
||||
}
|
||||
} else if (decompiler.equalsIgnoreCase("jd-gui")) {
|
||||
}
|
||||
else if (decompiler.equalsIgnoreCase("jd-gui"))
|
||||
{
|
||||
System.out.println("Decompiling " + input.getAbsolutePath() + " with JD-GUI");
|
||||
BytecodeViewer.openFiles(new File[]{input}, false);
|
||||
|
||||
Thread.sleep(5 * 1000);
|
||||
|
||||
if (target.equalsIgnoreCase("all")) {
|
||||
if (target.equalsIgnoreCase("all"))
|
||||
{
|
||||
System.out.println("Coming soon.");
|
||||
//Decompiler.jdgui.decompileToZip(output.getAbsolutePath());
|
||||
} else {
|
||||
try {
|
||||
}
|
||||
else
|
||||
{
|
||||
try
|
||||
{
|
||||
ClassNode cn = BytecodeViewer.blindlySearchForClassNode(target);
|
||||
final ClassWriter cw = accept(cn);
|
||||
String contents = Decompiler.JD_DECOMPILER.getDecompiler().decompileClassNode(cn, cw.toByteArray());
|
||||
DiskWriter.replaceFile(output.getAbsolutePath(), contents, false);
|
||||
} catch (Exception e) {
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
BytecodeViewer.handleException(e);
|
||||
}
|
||||
}
|
||||
} else if (decompiler.equalsIgnoreCase("smali")) {
|
||||
}
|
||||
else if (decompiler.equalsIgnoreCase("smali"))
|
||||
{
|
||||
System.out.println("Decompiling " + input.getAbsolutePath() + " with Smali");
|
||||
BytecodeViewer.openFiles(new File[]{input}, false);
|
||||
|
||||
Thread.sleep(5 * 1000);
|
||||
|
||||
if (target.equalsIgnoreCase("all")) {
|
||||
if (target.equalsIgnoreCase("all"))
|
||||
{
|
||||
System.out.println("Coming soon.");
|
||||
//Decompiler.smali.decompileToZip(output.getAbsolutePath());
|
||||
} else {
|
||||
try {
|
||||
}
|
||||
else
|
||||
{
|
||||
try
|
||||
{
|
||||
ClassNode cn = BytecodeViewer.blindlySearchForClassNode(target);
|
||||
final ClassWriter cw = accept(cn);
|
||||
String contents = Decompiler.SMALI_DISASSEMBLER.getDecompiler().decompileClassNode(cn, cw.toByteArray());
|
||||
DiskWriter.replaceFile(output.getAbsolutePath(), contents, false);
|
||||
} catch (Exception e) {
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
BytecodeViewer.handleException(e);
|
||||
}
|
||||
}
|
||||
} else if (decompiler.equalsIgnoreCase("jadx")) {
|
||||
}
|
||||
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")) {
|
||||
if (target.equalsIgnoreCase("all"))
|
||||
{
|
||||
System.out.println("Coming soon.");
|
||||
//Decompiler.smali.decompileToZip(output.getAbsolutePath());
|
||||
} else {
|
||||
try {
|
||||
}
|
||||
else
|
||||
{
|
||||
try
|
||||
{
|
||||
ClassNode cn = BytecodeViewer.blindlySearchForClassNode(target);
|
||||
final ClassWriter cw = accept(cn);
|
||||
String contents = Decompiler.JADX_DECOMPILER.getDecompiler().decompileClassNode(cn, cw.toByteArray());
|
||||
DiskWriter.replaceFile(output.getAbsolutePath(), contents, false);
|
||||
} catch (Exception e) {
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
BytecodeViewer.handleException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (decompiler.equalsIgnoreCase("asmifier")) {
|
||||
else if (decompiler.equalsIgnoreCase("asmifier"))
|
||||
{
|
||||
System.out.println("Generating ASM code for " + input.getAbsolutePath() + " with ASMifier");
|
||||
BytecodeViewer.openFiles(new File[]{input}, false);
|
||||
|
||||
Thread.sleep(5 * 1000);
|
||||
|
||||
if (target.equalsIgnoreCase("all")) {
|
||||
if (target.equalsIgnoreCase("all"))
|
||||
{
|
||||
System.out.println("Coming soon.");
|
||||
//Decompiler.smali.decompileToZip(output.getAbsolutePath());
|
||||
} else {
|
||||
try {
|
||||
}
|
||||
else
|
||||
{
|
||||
try
|
||||
{
|
||||
ClassNode cn = BytecodeViewer.blindlySearchForClassNode(target);
|
||||
final ClassWriter cw = accept(cn);
|
||||
String contents = Decompiler.ASMIFIER_DECOMPILER.getDecompiler().decompileClassNode(cn, cw.toByteArray());
|
||||
DiskWriter.replaceFile(output.getAbsolutePath(), contents, false);
|
||||
} catch (Exception e) {
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
BytecodeViewer.handleException(e);
|
||||
}
|
||||
}
|
||||
|
@ -383,21 +447,30 @@ public class CommandLineInput {
|
|||
System.out.println("Bytecode Viewer " + VERSION + " [CLI] - Created by @Konloch - https://bytecodeviewer.com");
|
||||
Configuration.canExit = true;
|
||||
System.exit(0);
|
||||
} catch (Exception e) {
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
BytecodeViewer.handleException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public static ClassWriter accept(ClassNode cn) {
|
||||
public static ClassWriter accept(ClassNode cn)
|
||||
{
|
||||
ClassWriter cw = new ClassWriter(0);
|
||||
try {
|
||||
try
|
||||
{
|
||||
cn.accept(cw);
|
||||
} catch (Exception e) {
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
try {
|
||||
try
|
||||
{
|
||||
Thread.sleep(200);
|
||||
cn.accept(cw);
|
||||
} catch (InterruptedException ignored) {
|
||||
}
|
||||
catch (InterruptedException ignored)
|
||||
{
|
||||
}
|
||||
}
|
||||
return cw;
|
||||
|
|
|
@ -18,15 +18,15 @@
|
|||
|
||||
package the.bytecode.club.bytecodeviewer;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.Locale;
|
||||
|
||||
import the.bytecode.club.bytecodeviewer.bootloader.BootState;
|
||||
import the.bytecode.club.bytecodeviewer.gui.theme.LAFTheme;
|
||||
import the.bytecode.club.bytecodeviewer.gui.theme.RSTATheme;
|
||||
import the.bytecode.club.bytecodeviewer.translation.Language;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.Locale;
|
||||
|
||||
/**
|
||||
* A collection of variables that can be configured through the settings menu or some form of UI/plugin
|
||||
*
|
||||
|
@ -36,118 +36,117 @@ import the.bytecode.club.bytecodeviewer.translation.Language;
|
|||
|
||||
public class Configuration
|
||||
{
|
||||
public static String python2 = "";
|
||||
public static boolean python2Extra = false;
|
||||
public static String python3 = "";
|
||||
public static boolean python3Extra = false;
|
||||
public static String rt = "";
|
||||
public static String library = "";
|
||||
public static String java = Constants.JAVA_BINARY.exists() ? Constants.JAVA_BINARY.getAbsolutePath() :
|
||||
Constants.JAVA_BINARY_NIX.exists() ? Constants.JAVA_BINARY_NIX.getAbsolutePath() : "";
|
||||
public static String javac = "";
|
||||
public static String javaTools = "";
|
||||
public static File krakatauTempDir;
|
||||
public static File krakatauTempJar;
|
||||
|
||||
public static boolean displayParentInTab = false; //also change in the main GUI
|
||||
public static boolean simplifiedTabNames = false;
|
||||
|
||||
//if true it will show a settings dialog on click instead of more menu items
|
||||
public static boolean useNewSettingsDialog = true; //TODO add to GUI
|
||||
|
||||
//if true it will put force error UIs and console UIs to be added as a tab
|
||||
public static boolean pluginConsoleAsNewTab = true; //TODO add to GUI
|
||||
//if true it will put force error UIs and console UIs to be added as a tab
|
||||
public static boolean errorLogsAsNewTab = true; //TODO add to GUI
|
||||
//if true the plugin writer will open inside of a tab
|
||||
public static boolean pluginWriterAsNewTab = true; //TODO add to GUI
|
||||
|
||||
//if true jadx will be above smali in an android grouping
|
||||
public static boolean jadxGroupedWithSmali = true; //TODO add to GUI
|
||||
|
||||
public static boolean forceResourceUpdateFromClassNode = false; //TODO add to GUI
|
||||
public static boolean showDarkLAFComponentIcons = false;
|
||||
public static boolean currentlyDumping = false;
|
||||
public static boolean needsReDump = true;
|
||||
public static boolean warnForEditing = false;
|
||||
public static boolean runningObfuscation = false;
|
||||
public static final long start = System.currentTimeMillis();
|
||||
public static String lastOpenDirectory = ".";
|
||||
public static String lastSaveDirectory = ".";
|
||||
public static String lastPluginDirectory = ".";
|
||||
public static boolean pingback = false;
|
||||
public static boolean deleteForeignLibraries = true;
|
||||
public static boolean canExit = false;
|
||||
public static int silenceExceptionGUI = 0;
|
||||
public static int pauseExceptionGUI = 0;
|
||||
|
||||
public static final int maxRecentFiles = 25; //eventually may be a setting
|
||||
public static boolean verifyCorruptedStateOnBoot = false; //eventually may be a setting
|
||||
|
||||
public static BootState bootState = BootState.START_UP;
|
||||
public static Language language = guessBestLanguage();
|
||||
public static LAFTheme lafTheme = LAFTheme.DARK;
|
||||
public static RSTATheme rstaTheme = lafTheme.getRSTATheme();
|
||||
public static long lastHotKeyExecuted = 0;
|
||||
|
||||
public static void setLastOpenDirectory(File file)
|
||||
{
|
||||
lastOpenDirectory = file.getAbsolutePath();
|
||||
}
|
||||
|
||||
public static void setLastSaveDirectory(File file)
|
||||
{
|
||||
lastSaveDirectory = file.getAbsolutePath();
|
||||
}
|
||||
|
||||
public static void setLastPluginDirectory(File file)
|
||||
{
|
||||
lastPluginDirectory = file.getAbsolutePath();
|
||||
}
|
||||
|
||||
public static File getLastOpenDirectory()
|
||||
{
|
||||
File lastDir = new File(lastOpenDirectory);
|
||||
if(lastDir.getParentFile() != null && lastDir.getParentFile().exists())
|
||||
return lastDir;
|
||||
|
||||
return new File(".");
|
||||
}
|
||||
|
||||
public static File getLastSaveDirectory()
|
||||
{
|
||||
File lastDir = new File(lastSaveDirectory);
|
||||
if(lastDir.getParentFile() != null && lastDir.getParentFile().exists())
|
||||
return lastDir;
|
||||
|
||||
try
|
||||
{
|
||||
return new File(".").getCanonicalFile();
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
return new File(".");
|
||||
}
|
||||
}
|
||||
|
||||
public static File getLastPluginDirectory()
|
||||
{
|
||||
File lastDir = new File(lastPluginDirectory);
|
||||
|
||||
if(lastDir.getParentFile() != null && lastDir.getParentFile().exists())
|
||||
return lastDir;
|
||||
|
||||
return new File(".");
|
||||
}
|
||||
|
||||
public static Language guessBestLanguage()
|
||||
{
|
||||
Language language = Language.getLanguageCodeLookup().get(Locale.getDefault().getLanguage());
|
||||
|
||||
if(language != null)
|
||||
return language;
|
||||
|
||||
//fallback to english
|
||||
return Language.ENGLISH;
|
||||
}
|
||||
public static String python2 = "";
|
||||
public static boolean python2Extra = false;
|
||||
public static String python3 = "";
|
||||
public static boolean python3Extra = false;
|
||||
public static String rt = "";
|
||||
public static String library = "";
|
||||
public static String java = Constants.JAVA_BINARY.exists() ? Constants.JAVA_BINARY.getAbsolutePath() : Constants.JAVA_BINARY_NIX.exists() ? Constants.JAVA_BINARY_NIX.getAbsolutePath() : "";
|
||||
public static String javac = "";
|
||||
public static String javaTools = "";
|
||||
public static File krakatauTempDir;
|
||||
public static File krakatauTempJar;
|
||||
|
||||
public static boolean displayParentInTab = false; //also change in the main GUI
|
||||
public static boolean simplifiedTabNames = false;
|
||||
|
||||
//if true it will show a settings dialog on click instead of more menu items
|
||||
public static boolean useNewSettingsDialog = true; //TODO add to GUI
|
||||
|
||||
//if true it will put force error UIs and console UIs to be added as a tab
|
||||
public static boolean pluginConsoleAsNewTab = true; //TODO add to GUI
|
||||
//if true it will put force error UIs and console UIs to be added as a tab
|
||||
public static boolean errorLogsAsNewTab = true; //TODO add to GUI
|
||||
//if true the plugin writer will open inside of a tab
|
||||
public static boolean pluginWriterAsNewTab = true; //TODO add to GUI
|
||||
|
||||
//if true jadx will be above smali in an android grouping
|
||||
public static boolean jadxGroupedWithSmali = true; //TODO add to GUI
|
||||
|
||||
public static boolean forceResourceUpdateFromClassNode = false; //TODO add to GUI
|
||||
public static boolean showDarkLAFComponentIcons = false;
|
||||
public static boolean currentlyDumping = false;
|
||||
public static boolean needsReDump = true;
|
||||
public static boolean warnForEditing = false;
|
||||
public static boolean runningObfuscation = false;
|
||||
public static final long start = System.currentTimeMillis();
|
||||
public static String lastOpenDirectory = ".";
|
||||
public static String lastSaveDirectory = ".";
|
||||
public static String lastPluginDirectory = ".";
|
||||
public static boolean pingback = false;
|
||||
public static boolean deleteForeignLibraries = true;
|
||||
public static boolean canExit = false;
|
||||
public static int silenceExceptionGUI = 0;
|
||||
public static int pauseExceptionGUI = 0;
|
||||
|
||||
public static final int maxRecentFiles = 25; //eventually may be a setting
|
||||
public static boolean verifyCorruptedStateOnBoot = false; //eventually may be a setting
|
||||
|
||||
public static BootState bootState = BootState.START_UP;
|
||||
public static Language language = guessBestLanguage();
|
||||
public static LAFTheme lafTheme = LAFTheme.DARK;
|
||||
public static RSTATheme rstaTheme = lafTheme.getRSTATheme();
|
||||
public static long lastHotKeyExecuted = 0;
|
||||
|
||||
public static void setLastOpenDirectory(File file)
|
||||
{
|
||||
lastOpenDirectory = file.getAbsolutePath();
|
||||
}
|
||||
|
||||
public static void setLastSaveDirectory(File file)
|
||||
{
|
||||
lastSaveDirectory = file.getAbsolutePath();
|
||||
}
|
||||
|
||||
public static void setLastPluginDirectory(File file)
|
||||
{
|
||||
lastPluginDirectory = file.getAbsolutePath();
|
||||
}
|
||||
|
||||
public static File getLastOpenDirectory()
|
||||
{
|
||||
File lastDir = new File(lastOpenDirectory);
|
||||
if (lastDir.getParentFile() != null && lastDir.getParentFile().exists())
|
||||
return lastDir;
|
||||
|
||||
return new File(".");
|
||||
}
|
||||
|
||||
public static File getLastSaveDirectory()
|
||||
{
|
||||
File lastDir = new File(lastSaveDirectory);
|
||||
if (lastDir.getParentFile() != null && lastDir.getParentFile().exists())
|
||||
return lastDir;
|
||||
|
||||
try
|
||||
{
|
||||
return new File(".").getCanonicalFile();
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
return new File(".");
|
||||
}
|
||||
}
|
||||
|
||||
public static File getLastPluginDirectory()
|
||||
{
|
||||
File lastDir = new File(lastPluginDirectory);
|
||||
|
||||
if (lastDir.getParentFile() != null && lastDir.getParentFile().exists())
|
||||
return lastDir;
|
||||
|
||||
return new File(".");
|
||||
}
|
||||
|
||||
public static Language guessBestLanguage()
|
||||
{
|
||||
Language language = Language.getLanguageCodeLookup().get(Locale.getDefault().getLanguage());
|
||||
|
||||
if (language != null)
|
||||
return language;
|
||||
|
||||
//fallback to english
|
||||
return Language.ENGLISH;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,163 +18,165 @@
|
|||
|
||||
package the.bytecode.club.bytecodeviewer;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.PrintStream;
|
||||
|
||||
import org.objectweb.asm.Opcodes;
|
||||
import the.bytecode.club.bytecodeviewer.resources.ResourceType;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.PrintStream;
|
||||
|
||||
/**
|
||||
* General program constants, to use this class include everything as a wildcard static import:
|
||||
* import static the.bytecode.club.bytecodeviewer.Constants.*;
|
||||
* import static the.bytecode.club.bytecodeviewer.Constants.*;
|
||||
*
|
||||
* @author Konloch
|
||||
* @since 6/21/2021
|
||||
*/
|
||||
public class Constants
|
||||
{
|
||||
/*per version*/
|
||||
public static String krakatauVersion = "12";
|
||||
public static String enjarifyVersion = "4";
|
||||
|
||||
//if true this disables testing code for tabs
|
||||
//until dragging and full right-click menu support is added this is
|
||||
//a starting point
|
||||
public static final boolean BLOCK_TAB_MENU = true;
|
||||
|
||||
//if true this will attempt to launch the decompilers in a new JVM process
|
||||
//the pro's to this are:
|
||||
// + You can control the java arguments (more memory & stack)
|
||||
//the cons to this are:
|
||||
// + If you could keep it in memory, now you need to write to disk (windows limitations)
|
||||
public static final boolean LAUNCH_DECOMPILERS_IN_NEW_PROCESS = false; //TODO
|
||||
|
||||
//could be automatic by checking if it's loaded a class named whatever for a library
|
||||
//maybe it could be automatic with some maven plugin?
|
||||
public static final boolean FAT_JAR = true;
|
||||
|
||||
//the automatic updater
|
||||
//SHADED_LIBRARIES must be false for the boot loader to startup
|
||||
//TODO this needs to be changed to support maven
|
||||
public static final boolean AUTOMATIC_LIBRARY_UPDATING = false;
|
||||
|
||||
//version is set via maven
|
||||
public static final String VERSION = getVersion(BytecodeViewer.class.getPackage().getImplementationVersion());
|
||||
//dev mode is just a check for running via IDE
|
||||
public static boolean DEV_MODE;
|
||||
|
||||
//if true the version checker will prompt and ask how you would like to proceed
|
||||
public static final boolean FORCE_VERSION_CHECKER_PROMPT = false;
|
||||
|
||||
public static final String fs = System.getProperty("file.separator");
|
||||
public static final String nl = System.getProperty("line.separator");
|
||||
|
||||
public static final File BCVDir = resolveBCVRoot();
|
||||
public static final File RT_JAR = new File(System.getProperty("java.home") + fs + "lib" + fs + "rt.jar");
|
||||
public static final File JAVA_BINARY = new File(System.getProperty("java.home") + fs + "bin" + fs + "java.exe");
|
||||
public static final File JAVA_BINARY_NIX = new File(System.getProperty("java.home") + fs + "bin" + fs + "java");
|
||||
public static final File RT_JAR_DUMPED = new File(getBCVDirectory() + fs + "rt.jar");
|
||||
public static final String filesName = getBCVDirectory() + fs + "recentfiles.json";
|
||||
public static final String pluginsName = getBCVDirectory() + fs + "recentplugins.json";
|
||||
public static final String settingsName = getBCVDirectory() + fs + "settings.bcv";
|
||||
public static final String tempDirectory = getBCVDirectory() + fs + "bcv_temp" + fs;
|
||||
public static final String systemTempDirectory = System.getProperty("java.io.tmpdir");
|
||||
public static final String libsDirectory = getBCVDirectory() + fs + "libs" + fs;
|
||||
public static String krakatauWorkingDirectory = getBCVDirectory() + fs + "krakatau_" + krakatauVersion;
|
||||
public static String enjarifyWorkingDirectory = getBCVDirectory() + fs + "enjarify_" + enjarifyVersion;
|
||||
public static final String[] SUPPORTED_FILE_EXTENSIONS = ResourceType.supportedBCVExtensionMap.keySet().toArray(new String[0]);
|
||||
public static final int ASM_VERSION = Opcodes.ASM9;
|
||||
|
||||
public static final PrintStream ERR = System.err;
|
||||
public static final PrintStream OUT = System.out;
|
||||
|
||||
public static File resolveBCVRoot()
|
||||
{
|
||||
File defaultLocation = new File(System.getProperty("user.home") + fs + ".Bytecode-Viewer");
|
||||
|
||||
//if BCV was previously installed using the default directory, continue to use that
|
||||
if(defaultLocation.exists())
|
||||
return defaultLocation;
|
||||
|
||||
//handle XDG Base Directory - https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html
|
||||
if(isNix())
|
||||
{
|
||||
File homeLocal = new File(System.getProperty("user.home") + fs + ".local");
|
||||
if(homeLocal.exists())
|
||||
return new File(homeLocal, "share" + fs + ".Bytecode-Viewer");
|
||||
|
||||
File homeConfig = new File(System.getProperty("user.home") + fs + ".config");
|
||||
if(homeConfig.exists())
|
||||
return new File(homeConfig, ".Bytecode-Viewer");
|
||||
}
|
||||
|
||||
//return BCV default location
|
||||
return defaultLocation;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the BCV directory
|
||||
*
|
||||
* @return the static BCV directory
|
||||
*/
|
||||
public static String getBCVDirectory()
|
||||
{
|
||||
while (!BCVDir.exists())
|
||||
BCVDir.mkdirs();
|
||||
|
||||
//hides the BCV directory
|
||||
if (isWindows() && !BCVDir.isHidden())
|
||||
{
|
||||
new Thread(()->{
|
||||
try {
|
||||
// Hide file by running attrib system command (on Windows)
|
||||
Process p = new ProcessBuilder("attrib",
|
||||
"+H",
|
||||
BCVDir.getAbsolutePath()).start();
|
||||
} catch (Exception e) {
|
||||
//ignore
|
||||
}
|
||||
}, "Hide BCV Dir").start();
|
||||
}
|
||||
|
||||
return BCVDir.getAbsolutePath();
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the OS contains 'win'
|
||||
*
|
||||
* @return true if the os.name property contains 'win'
|
||||
*/
|
||||
private static boolean isWindows()
|
||||
{
|
||||
return System.getProperty("os.name").toLowerCase().contains("win");
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the OS contains 'nix', 'nux', or 'bsd'
|
||||
*
|
||||
* @return true if the os.name property contains 'nix', 'nux', or 'bsd'
|
||||
*/
|
||||
private static boolean isNix()
|
||||
{
|
||||
String os = System.getProperty("os.name").toLowerCase();
|
||||
return os.contains("nix") || os.contains("nux") || os.contains("bsd");
|
||||
}
|
||||
|
||||
/**
|
||||
* Detects developer mode or returns the current version
|
||||
*/
|
||||
public static String getVersion(String mavenVersion)
|
||||
{
|
||||
if(FORCE_VERSION_CHECKER_PROMPT)
|
||||
return "1.0.0";
|
||||
|
||||
if(mavenVersion == null)
|
||||
{
|
||||
DEV_MODE = true;
|
||||
return "Developer Mode";
|
||||
}
|
||||
|
||||
return mavenVersion;
|
||||
}
|
||||
/*per version*/
|
||||
public static String krakatauVersion = "12";
|
||||
public static String enjarifyVersion = "4";
|
||||
|
||||
//if true this disables testing code for tabs
|
||||
//until dragging and full right-click menu support is added this is
|
||||
//a starting point
|
||||
public static final boolean BLOCK_TAB_MENU = true;
|
||||
|
||||
//if true this will attempt to launch the decompilers in a new JVM process
|
||||
//the pro's to this are:
|
||||
// + You can control the java arguments (more memory & stack)
|
||||
//the cons to this are:
|
||||
// + If you could keep it in memory, now you need to write to disk (windows limitations)
|
||||
public static final boolean LAUNCH_DECOMPILERS_IN_NEW_PROCESS = false; //TODO
|
||||
|
||||
//could be automatic by checking if it's loaded a class named whatever for a library
|
||||
//maybe it could be automatic with some maven plugin?
|
||||
public static final boolean FAT_JAR = true;
|
||||
|
||||
//the automatic updater
|
||||
//SHADED_LIBRARIES must be false for the boot loader to startup
|
||||
//TODO this needs to be changed to support maven
|
||||
public static final boolean AUTOMATIC_LIBRARY_UPDATING = false;
|
||||
|
||||
//version is set via maven
|
||||
public static final String VERSION = getVersion(BytecodeViewer.class.getPackage().getImplementationVersion());
|
||||
//dev mode is just a check for running via IDE
|
||||
public static boolean DEV_MODE;
|
||||
|
||||
//if true the version checker will prompt and ask how you would like to proceed
|
||||
public static final boolean FORCE_VERSION_CHECKER_PROMPT = false;
|
||||
|
||||
public static final String fs = System.getProperty("file.separator");
|
||||
public static final String nl = System.getProperty("line.separator");
|
||||
|
||||
public static final File BCVDir = resolveBCVRoot();
|
||||
public static final File RT_JAR = new File(System.getProperty("java.home") + fs + "lib" + fs + "rt.jar");
|
||||
public static final File JAVA_BINARY = new File(System.getProperty("java.home") + fs + "bin" + fs + "java.exe");
|
||||
public static final File JAVA_BINARY_NIX = new File(System.getProperty("java.home") + fs + "bin" + fs + "java");
|
||||
public static final File RT_JAR_DUMPED = new File(getBCVDirectory() + fs + "rt.jar");
|
||||
public static final String filesName = getBCVDirectory() + fs + "recentfiles.json";
|
||||
public static final String pluginsName = getBCVDirectory() + fs + "recentplugins.json";
|
||||
public static final String settingsName = getBCVDirectory() + fs + "settings.bcv";
|
||||
public static final String tempDirectory = getBCVDirectory() + fs + "bcv_temp" + fs;
|
||||
public static final String systemTempDirectory = System.getProperty("java.io.tmpdir");
|
||||
public static final String libsDirectory = getBCVDirectory() + fs + "libs" + fs;
|
||||
public static String krakatauWorkingDirectory = getBCVDirectory() + fs + "krakatau_" + krakatauVersion;
|
||||
public static String enjarifyWorkingDirectory = getBCVDirectory() + fs + "enjarify_" + enjarifyVersion;
|
||||
public static final String[] SUPPORTED_FILE_EXTENSIONS = ResourceType.supportedBCVExtensionMap.keySet().toArray(new String[0]);
|
||||
public static final int ASM_VERSION = Opcodes.ASM9;
|
||||
|
||||
public static final PrintStream ERR = System.err;
|
||||
public static final PrintStream OUT = System.out;
|
||||
|
||||
public static File resolveBCVRoot()
|
||||
{
|
||||
File defaultLocation = new File(System.getProperty("user.home") + fs + ".Bytecode-Viewer");
|
||||
|
||||
//if BCV was previously installed using the default directory, continue to use that
|
||||
if (defaultLocation.exists())
|
||||
return defaultLocation;
|
||||
|
||||
//handle XDG Base Directory - https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html
|
||||
if (isNix())
|
||||
{
|
||||
File homeLocal = new File(System.getProperty("user.home") + fs + ".local");
|
||||
if (homeLocal.exists())
|
||||
return new File(homeLocal, "share" + fs + ".Bytecode-Viewer");
|
||||
|
||||
File homeConfig = new File(System.getProperty("user.home") + fs + ".config");
|
||||
if (homeConfig.exists())
|
||||
return new File(homeConfig, ".Bytecode-Viewer");
|
||||
}
|
||||
|
||||
//return BCV default location
|
||||
return defaultLocation;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the BCV directory
|
||||
*
|
||||
* @return the static BCV directory
|
||||
*/
|
||||
public static String getBCVDirectory()
|
||||
{
|
||||
while (!BCVDir.exists())
|
||||
BCVDir.mkdirs();
|
||||
|
||||
//hides the BCV directory
|
||||
if (isWindows() && !BCVDir.isHidden())
|
||||
{
|
||||
new Thread(() ->
|
||||
{
|
||||
try
|
||||
{
|
||||
// Hide file by running attrib system command (on Windows)
|
||||
Process p = new ProcessBuilder("attrib", "+H", BCVDir.getAbsolutePath()).start();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
//ignore
|
||||
}
|
||||
}, "Hide BCV Dir").start();
|
||||
}
|
||||
|
||||
return BCVDir.getAbsolutePath();
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the OS contains 'win'
|
||||
*
|
||||
* @return true if the os.name property contains 'win'
|
||||
*/
|
||||
private static boolean isWindows()
|
||||
{
|
||||
return System.getProperty("os.name").toLowerCase().contains("win");
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the OS contains 'nix', 'nux', or 'bsd'
|
||||
*
|
||||
* @return true if the os.name property contains 'nix', 'nux', or 'bsd'
|
||||
*/
|
||||
private static boolean isNix()
|
||||
{
|
||||
String os = System.getProperty("os.name").toLowerCase();
|
||||
return os.contains("nix") || os.contains("nux") || os.contains("bsd");
|
||||
}
|
||||
|
||||
/**
|
||||
* Detects developer mode or returns the current version
|
||||
*/
|
||||
public static String getVersion(String mavenVersion)
|
||||
{
|
||||
if (FORCE_VERSION_CHECKER_PROMPT)
|
||||
return "1.0.0";
|
||||
|
||||
if (mavenVersion == null)
|
||||
{
|
||||
DEV_MODE = true;
|
||||
return "Developer Mode";
|
||||
}
|
||||
|
||||
return mavenVersion;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,15 +18,16 @@
|
|||
|
||||
package the.bytecode.club.bytecodeviewer;
|
||||
|
||||
import java.awt.event.KeyEvent;
|
||||
import java.io.File;
|
||||
import javax.swing.JFileChooser;
|
||||
import the.bytecode.club.bytecodeviewer.gui.components.FileChooser;
|
||||
import the.bytecode.club.bytecodeviewer.gui.components.RunOptions;
|
||||
import the.bytecode.club.bytecodeviewer.util.DialogUtils;
|
||||
import the.bytecode.club.bytecodeviewer.util.JarUtils;
|
||||
import the.bytecode.club.bytecodeviewer.util.MiscUtils;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.awt.event.KeyEvent;
|
||||
import java.io.File;
|
||||
|
||||
/**
|
||||
* Whenever a key is pressed on the swing UI it should get logged here
|
||||
*
|
||||
|
@ -35,133 +36,128 @@ import the.bytecode.club.bytecodeviewer.util.MiscUtils;
|
|||
*/
|
||||
public class GlobalHotKeys
|
||||
{
|
||||
/**
|
||||
* Checks the hotkeys
|
||||
*/
|
||||
public static void keyPressed(KeyEvent e)
|
||||
{
|
||||
if (System.currentTimeMillis() - Configuration.lastHotKeyExecuted <= (600))
|
||||
return;
|
||||
|
||||
//CTRL + O
|
||||
//open resource
|
||||
if ((e.getKeyCode() == KeyEvent.VK_O) && ((e.getModifiersEx() & KeyEvent.CTRL_DOWN_MASK) != 0))
|
||||
{
|
||||
Configuration.lastHotKeyExecuted = System.currentTimeMillis();
|
||||
|
||||
final File file = DialogUtils.fileChooser("Select File or Folder to open in BCV",
|
||||
"APKs, DEX, Class Files or Zip/Jar/War Archives",
|
||||
Constants.SUPPORTED_FILE_EXTENSIONS);
|
||||
|
||||
if(file == null)
|
||||
return;
|
||||
|
||||
BytecodeViewer.updateBusyStatus(true);
|
||||
BytecodeViewer.openFiles(new File[]{file}, true);
|
||||
BytecodeViewer.updateBusyStatus(false);
|
||||
}
|
||||
|
||||
//CTRL + N
|
||||
//new workspace
|
||||
else if ((e.getKeyCode() == KeyEvent.VK_N) && ((e.getModifiersEx() & KeyEvent.CTRL_DOWN_MASK) != 0))
|
||||
{
|
||||
Configuration.lastHotKeyExecuted = System.currentTimeMillis();
|
||||
BytecodeViewer.resetWorkspace(true);
|
||||
}
|
||||
|
||||
//CTRL + T
|
||||
//compile
|
||||
else if ((e.getKeyCode() == KeyEvent.VK_T) && ((e.getModifiersEx() & KeyEvent.CTRL_DOWN_MASK) != 0))
|
||||
{
|
||||
Configuration.lastHotKeyExecuted = System.currentTimeMillis();
|
||||
Thread t = new Thread(() -> BytecodeViewer.compile(true, false), "Compile");
|
||||
t.start();
|
||||
}
|
||||
|
||||
//CTRL + R
|
||||
//Run remote code
|
||||
else if ((e.getKeyCode() == KeyEvent.VK_R) && ((e.getModifiersEx() & KeyEvent.CTRL_DOWN_MASK) != 0))
|
||||
{
|
||||
Configuration.lastHotKeyExecuted = System.currentTimeMillis();
|
||||
|
||||
if (BytecodeViewer.promptIfNoLoadedClasses())
|
||||
return;
|
||||
|
||||
new RunOptions().setVisible(true);
|
||||
}
|
||||
|
||||
//CTRL + S
|
||||
//Export resources
|
||||
else if ((e.getKeyCode() == KeyEvent.VK_S) && ((e.getModifiersEx() & KeyEvent.CTRL_DOWN_MASK) != 0))
|
||||
{
|
||||
Configuration.lastHotKeyExecuted = System.currentTimeMillis();
|
||||
|
||||
if (BytecodeViewer.promptIfNoLoadedResources())
|
||||
return;
|
||||
|
||||
Thread resourceExport = new Thread(() ->
|
||||
{
|
||||
if (!BytecodeViewer.autoCompileSuccessful())
|
||||
return;
|
||||
|
||||
JFileChooser fc = new FileChooser(Configuration.getLastSaveDirectory(),
|
||||
"Select Zip Export",
|
||||
"Zip Archives",
|
||||
"zip");
|
||||
|
||||
int returnVal = fc.showSaveDialog(BytecodeViewer.viewer);
|
||||
if (returnVal == JFileChooser.APPROVE_OPTION)
|
||||
{
|
||||
Configuration.setLastSaveDirectory(fc.getSelectedFile());
|
||||
|
||||
File file = MiscUtils.autoAppendFileExtension(".zip", fc.getSelectedFile());
|
||||
|
||||
if (!DialogUtils.canOverwriteFile(file))
|
||||
return;
|
||||
|
||||
BytecodeViewer.updateBusyStatus(true);
|
||||
Thread jarExport = new Thread(() -> {
|
||||
JarUtils.saveAsJar(BytecodeViewer.getLoadedClasses(),
|
||||
file.getAbsolutePath());
|
||||
BytecodeViewer.updateBusyStatus(false);
|
||||
}, "Jar Export");
|
||||
jarExport.start();
|
||||
}
|
||||
}, "Resource Export");
|
||||
resourceExport.start();
|
||||
}
|
||||
|
||||
//CTRL + W
|
||||
//close active resource (currently opened tab)
|
||||
else if ((e.getKeyCode() == KeyEvent.VK_W) && ((e.getModifiersEx() & KeyEvent.CTRL_DOWN_MASK) != 0))
|
||||
{
|
||||
Configuration.lastHotKeyExecuted = System.currentTimeMillis();
|
||||
|
||||
if (BytecodeViewer.hasActiveResource())
|
||||
BytecodeViewer.viewer.workPane.tabs.remove(BytecodeViewer.viewer.workPane.getActiveResource());
|
||||
}
|
||||
|
||||
//CTRL + L
|
||||
//open last opened resource
|
||||
else if ((e.getKeyCode() == KeyEvent.VK_L) && ((e.getModifiersEx() & KeyEvent.CTRL_DOWN_MASK) != 0))
|
||||
{
|
||||
Configuration.lastHotKeyExecuted = System.currentTimeMillis();
|
||||
|
||||
String recentFile = Settings.getRecentFile();
|
||||
|
||||
if(!BytecodeViewer.hasResources() && recentFile != null)
|
||||
{
|
||||
File file = new File(recentFile);
|
||||
if(file.exists())
|
||||
{
|
||||
BytecodeViewer.openFiles(new File[]{file}, false);
|
||||
}
|
||||
else
|
||||
{
|
||||
BytecodeViewer.showMessage("The file " + file.getAbsolutePath() + " could not be found.");
|
||||
Settings.removeRecentFile(file);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Checks the hotkeys
|
||||
*/
|
||||
public static void keyPressed(KeyEvent e)
|
||||
{
|
||||
if (System.currentTimeMillis() - Configuration.lastHotKeyExecuted <= (600))
|
||||
return;
|
||||
|
||||
//CTRL + O
|
||||
//open resource
|
||||
if ((e.getKeyCode() == KeyEvent.VK_O) && ((e.getModifiersEx() & KeyEvent.CTRL_DOWN_MASK) != 0))
|
||||
{
|
||||
Configuration.lastHotKeyExecuted = System.currentTimeMillis();
|
||||
|
||||
final File file = DialogUtils.fileChooser("Select File or Folder to open in BCV", "APKs, DEX, Class Files or Zip/Jar/War Archives", Constants.SUPPORTED_FILE_EXTENSIONS);
|
||||
|
||||
if (file == null)
|
||||
return;
|
||||
|
||||
BytecodeViewer.updateBusyStatus(true);
|
||||
BytecodeViewer.openFiles(new File[]{file}, true);
|
||||
BytecodeViewer.updateBusyStatus(false);
|
||||
}
|
||||
|
||||
//CTRL + N
|
||||
//new workspace
|
||||
else if ((e.getKeyCode() == KeyEvent.VK_N) && ((e.getModifiersEx() & KeyEvent.CTRL_DOWN_MASK) != 0))
|
||||
{
|
||||
Configuration.lastHotKeyExecuted = System.currentTimeMillis();
|
||||
BytecodeViewer.resetWorkspace(true);
|
||||
}
|
||||
|
||||
//CTRL + T
|
||||
//compile
|
||||
else if ((e.getKeyCode() == KeyEvent.VK_T) && ((e.getModifiersEx() & KeyEvent.CTRL_DOWN_MASK) != 0))
|
||||
{
|
||||
Configuration.lastHotKeyExecuted = System.currentTimeMillis();
|
||||
Thread t = new Thread(() -> BytecodeViewer.compile(true, false), "Compile");
|
||||
t.start();
|
||||
}
|
||||
|
||||
//CTRL + R
|
||||
//Run remote code
|
||||
else if ((e.getKeyCode() == KeyEvent.VK_R) && ((e.getModifiersEx() & KeyEvent.CTRL_DOWN_MASK) != 0))
|
||||
{
|
||||
Configuration.lastHotKeyExecuted = System.currentTimeMillis();
|
||||
|
||||
if (BytecodeViewer.promptIfNoLoadedClasses())
|
||||
return;
|
||||
|
||||
new RunOptions().setVisible(true);
|
||||
}
|
||||
|
||||
//CTRL + S
|
||||
//Export resources
|
||||
else if ((e.getKeyCode() == KeyEvent.VK_S) && ((e.getModifiersEx() & KeyEvent.CTRL_DOWN_MASK) != 0))
|
||||
{
|
||||
Configuration.lastHotKeyExecuted = System.currentTimeMillis();
|
||||
|
||||
if (BytecodeViewer.promptIfNoLoadedResources())
|
||||
return;
|
||||
|
||||
Thread resourceExport = new Thread(() ->
|
||||
{
|
||||
if (!BytecodeViewer.autoCompileSuccessful())
|
||||
return;
|
||||
|
||||
JFileChooser fc = new FileChooser(Configuration.getLastSaveDirectory(), "Select Zip Export", "Zip Archives", "zip");
|
||||
|
||||
int returnVal = fc.showSaveDialog(BytecodeViewer.viewer);
|
||||
if (returnVal == JFileChooser.APPROVE_OPTION)
|
||||
{
|
||||
Configuration.setLastSaveDirectory(fc.getSelectedFile());
|
||||
|
||||
File file = MiscUtils.autoAppendFileExtension(".zip", fc.getSelectedFile());
|
||||
|
||||
if (!DialogUtils.canOverwriteFile(file))
|
||||
return;
|
||||
|
||||
BytecodeViewer.updateBusyStatus(true);
|
||||
Thread jarExport = new Thread(() ->
|
||||
{
|
||||
JarUtils.saveAsJar(BytecodeViewer.getLoadedClasses(), file.getAbsolutePath());
|
||||
BytecodeViewer.updateBusyStatus(false);
|
||||
}, "Jar Export");
|
||||
jarExport.start();
|
||||
}
|
||||
}, "Resource Export");
|
||||
resourceExport.start();
|
||||
}
|
||||
|
||||
//CTRL + W
|
||||
//close active resource (currently opened tab)
|
||||
else if ((e.getKeyCode() == KeyEvent.VK_W) && ((e.getModifiersEx() & KeyEvent.CTRL_DOWN_MASK) != 0))
|
||||
{
|
||||
Configuration.lastHotKeyExecuted = System.currentTimeMillis();
|
||||
|
||||
if (BytecodeViewer.hasActiveResource())
|
||||
BytecodeViewer.viewer.workPane.tabs.remove(BytecodeViewer.viewer.workPane.getActiveResource());
|
||||
}
|
||||
|
||||
//CTRL + L
|
||||
//open last opened resource
|
||||
else if ((e.getKeyCode() == KeyEvent.VK_L) && ((e.getModifiersEx() & KeyEvent.CTRL_DOWN_MASK) != 0))
|
||||
{
|
||||
Configuration.lastHotKeyExecuted = System.currentTimeMillis();
|
||||
|
||||
String recentFile = Settings.getRecentFile();
|
||||
|
||||
if (!BytecodeViewer.hasResources() && recentFile != null)
|
||||
{
|
||||
File file = new File(recentFile);
|
||||
if (file.exists())
|
||||
{
|
||||
BytecodeViewer.openFiles(new File[]{file}, false);
|
||||
}
|
||||
else
|
||||
{
|
||||
BytecodeViewer.showMessage("The file " + file.getAbsolutePath() + " could not be found.");
|
||||
Settings.removeRecentFile(file);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,20 +19,18 @@
|
|||
package the.bytecode.club.bytecodeviewer;
|
||||
|
||||
import com.google.gson.reflect.TypeToken;
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import javax.swing.JMenuItem;
|
||||
import me.konloch.kontainer.io.DiskReader;
|
||||
import me.konloch.kontainer.io.DiskWriter;
|
||||
import the.bytecode.club.bytecodeviewer.util.MiscUtils;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import static the.bytecode.club.bytecodeviewer.BytecodeViewer.gson;
|
||||
import static the.bytecode.club.bytecodeviewer.Configuration.maxRecentFiles;
|
||||
import static the.bytecode.club.bytecodeviewer.Constants.filesName;
|
||||
import static the.bytecode.club.bytecodeviewer.Constants.fs;
|
||||
import static the.bytecode.club.bytecodeviewer.Constants.getBCVDirectory;
|
||||
import static the.bytecode.club.bytecodeviewer.Constants.pluginsName;
|
||||
import static the.bytecode.club.bytecodeviewer.Constants.*;
|
||||
|
||||
/**
|
||||
* @author Konloch
|
||||
|
@ -40,123 +38,123 @@ import static the.bytecode.club.bytecodeviewer.Constants.pluginsName;
|
|||
*/
|
||||
public class Settings
|
||||
{
|
||||
public static boolean firstBoot = true; //stays true after settings load on first boot
|
||||
public static boolean hasSetLanguageAsSystemLanguage = false;
|
||||
private static List<String> recentPlugins;
|
||||
private static List<String> recentFiles;
|
||||
|
||||
static
|
||||
{
|
||||
try
|
||||
{
|
||||
if (new File(filesName).exists())
|
||||
recentFiles = gson.fromJson(DiskReader.loadAsString(filesName), new TypeToken<ArrayList<String>>() {}.getType());
|
||||
else
|
||||
recentFiles = DiskReader.loadArrayList(getBCVDirectory() + fs + "recentfiles.bcv", false);
|
||||
|
||||
if (new File(pluginsName).exists())
|
||||
recentPlugins = gson.fromJson(DiskReader.loadAsString(pluginsName), new TypeToken<ArrayList<String>>() {}.getType());
|
||||
else
|
||||
recentPlugins = DiskReader.loadArrayList(getBCVDirectory() + fs + "recentplugins.bcv", false);
|
||||
|
||||
MiscUtils.deduplicateAndTrim(recentFiles, maxRecentFiles);
|
||||
MiscUtils.deduplicateAndTrim(recentPlugins, maxRecentFiles);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the recent file
|
||||
*
|
||||
* @param f the recent file
|
||||
*/
|
||||
public static synchronized void addRecentFile(File f)
|
||||
{
|
||||
recentFiles.remove(f.getAbsolutePath()); // already added on the list
|
||||
recentFiles.add(0, f.getAbsolutePath());
|
||||
MiscUtils.deduplicateAndTrim(recentFiles, maxRecentFiles);
|
||||
DiskWriter.replaceFile(filesName, MiscUtils.listToString(recentFiles), false);
|
||||
resetRecentFilesMenu();
|
||||
}
|
||||
|
||||
public static synchronized void removeRecentFile(File f)
|
||||
{
|
||||
if(recentFiles.remove(f.getAbsolutePath()))
|
||||
{
|
||||
DiskWriter.replaceFile(filesName, MiscUtils.listToString(recentFiles), false);
|
||||
resetRecentFilesMenu();
|
||||
}
|
||||
}
|
||||
|
||||
public static String getRecentFile()
|
||||
{
|
||||
if(recentFiles.isEmpty())
|
||||
return null;
|
||||
|
||||
return recentFiles.get(0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add to the recent plugin list
|
||||
*
|
||||
* @param f the plugin file
|
||||
*/
|
||||
public static synchronized void addRecentPlugin(File f)
|
||||
{
|
||||
recentPlugins.remove(f.getAbsolutePath()); // already added on the list
|
||||
recentPlugins.add(0, f.getAbsolutePath());
|
||||
MiscUtils.deduplicateAndTrim(recentPlugins, maxRecentFiles);
|
||||
DiskWriter.replaceFile(pluginsName, MiscUtils.listToString(recentPlugins), false);
|
||||
resetRecentFilesMenu();
|
||||
}
|
||||
|
||||
public static synchronized void removeRecentPlugin(File f)
|
||||
{
|
||||
if(recentPlugins.remove(f.getAbsolutePath()))
|
||||
{
|
||||
DiskWriter.replaceFile(pluginsName, MiscUtils.listToString(recentPlugins), false);
|
||||
resetRecentFilesMenu();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* resets the recent files menu
|
||||
*/
|
||||
protected static void resetRecentFilesMenu()
|
||||
{
|
||||
//build recent files
|
||||
BytecodeViewer.viewer.recentFilesSecondaryMenu.removeAll();
|
||||
for (String s : recentFiles)
|
||||
{
|
||||
if (!s.isEmpty())
|
||||
{
|
||||
JMenuItem m = new JMenuItem(s);
|
||||
m.addActionListener(e ->
|
||||
{
|
||||
JMenuItem m12 = (JMenuItem) e.getSource();
|
||||
BytecodeViewer.openFiles(new File[]{new File(m12.getText())}, true);
|
||||
});
|
||||
BytecodeViewer.viewer.recentFilesSecondaryMenu.add(m);
|
||||
}
|
||||
}
|
||||
|
||||
//build recent plugins
|
||||
BytecodeViewer.viewer.recentPluginsSecondaryMenu.removeAll();
|
||||
for (String s : recentPlugins)
|
||||
{
|
||||
if (!s.isEmpty())
|
||||
{
|
||||
JMenuItem m = new JMenuItem(s);
|
||||
m.addActionListener(e ->
|
||||
{
|
||||
JMenuItem m1 = (JMenuItem) e.getSource();
|
||||
BytecodeViewer.startPlugin(new File(m1.getText()));
|
||||
});
|
||||
BytecodeViewer.viewer.recentPluginsSecondaryMenu.add(m);
|
||||
}
|
||||
}
|
||||
}
|
||||
public static boolean firstBoot = true; //stays true after settings load on first boot
|
||||
public static boolean hasSetLanguageAsSystemLanguage = false;
|
||||
private static List<String> recentPlugins;
|
||||
private static List<String> recentFiles;
|
||||
|
||||
static
|
||||
{
|
||||
try
|
||||
{
|
||||
if (new File(filesName).exists())
|
||||
recentFiles = gson.fromJson(DiskReader.loadAsString(filesName), new TypeToken<ArrayList<String>>() {}.getType());
|
||||
else
|
||||
recentFiles = DiskReader.loadArrayList(getBCVDirectory() + fs + "recentfiles.bcv", false);
|
||||
|
||||
if (new File(pluginsName).exists())
|
||||
recentPlugins = gson.fromJson(DiskReader.loadAsString(pluginsName), new TypeToken<ArrayList<String>>() {}.getType());
|
||||
else
|
||||
recentPlugins = DiskReader.loadArrayList(getBCVDirectory() + fs + "recentplugins.bcv", false);
|
||||
|
||||
MiscUtils.deduplicateAndTrim(recentFiles, maxRecentFiles);
|
||||
MiscUtils.deduplicateAndTrim(recentPlugins, maxRecentFiles);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the recent file
|
||||
*
|
||||
* @param f the recent file
|
||||
*/
|
||||
public static synchronized void addRecentFile(File f)
|
||||
{
|
||||
recentFiles.remove(f.getAbsolutePath()); // already added on the list
|
||||
recentFiles.add(0, f.getAbsolutePath());
|
||||
MiscUtils.deduplicateAndTrim(recentFiles, maxRecentFiles);
|
||||
DiskWriter.replaceFile(filesName, MiscUtils.listToString(recentFiles), false);
|
||||
resetRecentFilesMenu();
|
||||
}
|
||||
|
||||
public static synchronized void removeRecentFile(File f)
|
||||
{
|
||||
if (recentFiles.remove(f.getAbsolutePath()))
|
||||
{
|
||||
DiskWriter.replaceFile(filesName, MiscUtils.listToString(recentFiles), false);
|
||||
resetRecentFilesMenu();
|
||||
}
|
||||
}
|
||||
|
||||
public static String getRecentFile()
|
||||
{
|
||||
if (recentFiles.isEmpty())
|
||||
return null;
|
||||
|
||||
return recentFiles.get(0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add to the recent plugin list
|
||||
*
|
||||
* @param f the plugin file
|
||||
*/
|
||||
public static synchronized void addRecentPlugin(File f)
|
||||
{
|
||||
recentPlugins.remove(f.getAbsolutePath()); // already added on the list
|
||||
recentPlugins.add(0, f.getAbsolutePath());
|
||||
MiscUtils.deduplicateAndTrim(recentPlugins, maxRecentFiles);
|
||||
DiskWriter.replaceFile(pluginsName, MiscUtils.listToString(recentPlugins), false);
|
||||
resetRecentFilesMenu();
|
||||
}
|
||||
|
||||
public static synchronized void removeRecentPlugin(File f)
|
||||
{
|
||||
if (recentPlugins.remove(f.getAbsolutePath()))
|
||||
{
|
||||
DiskWriter.replaceFile(pluginsName, MiscUtils.listToString(recentPlugins), false);
|
||||
resetRecentFilesMenu();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* resets the recent files menu
|
||||
*/
|
||||
protected static void resetRecentFilesMenu()
|
||||
{
|
||||
//build recent files
|
||||
BytecodeViewer.viewer.recentFilesSecondaryMenu.removeAll();
|
||||
for (String s : recentFiles)
|
||||
{
|
||||
if (!s.isEmpty())
|
||||
{
|
||||
JMenuItem m = new JMenuItem(s);
|
||||
m.addActionListener(e ->
|
||||
{
|
||||
JMenuItem m12 = (JMenuItem) e.getSource();
|
||||
BytecodeViewer.openFiles(new File[]{new File(m12.getText())}, true);
|
||||
});
|
||||
BytecodeViewer.viewer.recentFilesSecondaryMenu.add(m);
|
||||
}
|
||||
}
|
||||
|
||||
//build recent plugins
|
||||
BytecodeViewer.viewer.recentPluginsSecondaryMenu.removeAll();
|
||||
for (String s : recentPlugins)
|
||||
{
|
||||
if (!s.isEmpty())
|
||||
{
|
||||
JMenuItem m = new JMenuItem(s);
|
||||
m.addActionListener(e ->
|
||||
{
|
||||
JMenuItem m1 = (JMenuItem) e.getSource();
|
||||
BytecodeViewer.startPlugin(new File(m1.getText()));
|
||||
});
|
||||
BytecodeViewer.viewer.recentPluginsSecondaryMenu.add(m);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,8 +18,6 @@
|
|||
|
||||
package the.bytecode.club.bytecodeviewer;
|
||||
|
||||
import java.io.File;
|
||||
import javax.swing.JFrame;
|
||||
import me.konloch.kontainer.io.DiskReader;
|
||||
import me.konloch.kontainer.io.DiskWriter;
|
||||
import the.bytecode.club.bytecodeviewer.decompilers.Decompiler;
|
||||
|
@ -27,6 +25,9 @@ import the.bytecode.club.bytecodeviewer.gui.theme.LAFTheme;
|
|||
import the.bytecode.club.bytecodeviewer.gui.theme.RSTATheme;
|
||||
import the.bytecode.club.bytecodeviewer.translation.Language;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.io.File;
|
||||
|
||||
import static the.bytecode.club.bytecodeviewer.Constants.VERSION;
|
||||
import static the.bytecode.club.bytecodeviewer.Constants.settingsName;
|
||||
|
||||
|
@ -39,13 +40,13 @@ import static the.bytecode.club.bytecodeviewer.Constants.settingsName;
|
|||
public class SettingsSerializer
|
||||
{
|
||||
private static boolean settingsFileExists;
|
||||
|
||||
|
||||
public static void saveSettingsAsync()
|
||||
{
|
||||
Thread saveThread = new Thread(SettingsSerializer::saveSettings, "Save Settings");
|
||||
saveThread.start();
|
||||
}
|
||||
|
||||
|
||||
public static synchronized void saveSettings()
|
||||
{
|
||||
try
|
||||
|
@ -164,12 +165,12 @@ public class SettingsSerializer
|
|||
save("deprecated");
|
||||
save(BytecodeViewer.viewer.getFontSize());
|
||||
save(Configuration.deleteForeignLibraries);
|
||||
|
||||
|
||||
if (BytecodeViewer.viewer.apkConversionGroup.isSelected(BytecodeViewer.viewer.apkConversionDex.getModel()))
|
||||
DiskWriter.writeNewLine(settingsName, "0");
|
||||
else if (BytecodeViewer.viewer.apkConversionGroup.isSelected(BytecodeViewer.viewer.apkConversionEnjarify.getModel()))
|
||||
DiskWriter.writeNewLine(settingsName, "1");
|
||||
|
||||
|
||||
save(Configuration.python3);
|
||||
save(Configuration.javac);
|
||||
save(Configuration.java);
|
||||
|
@ -182,16 +183,16 @@ public class SettingsSerializer
|
|||
save(BytecodeViewer.viewer.showClassMethods.isSelected());
|
||||
save(BytecodeViewer.viewer.ren.isSelected());
|
||||
save("deprecated");
|
||||
|
||||
|
||||
save(Configuration.lafTheme.name());
|
||||
save(Configuration.rstaTheme.name());
|
||||
save(BytecodeViewer.viewer.simplifyNameInTabTitle.isSelected());
|
||||
save(Configuration.language.name());
|
||||
|
||||
|
||||
save(BytecodeViewer.viewer.viewPane1.isPaneEditable());
|
||||
save(BytecodeViewer.viewer.viewPane2.isPaneEditable());
|
||||
save(BytecodeViewer.viewer.viewPane3.isPaneEditable());
|
||||
|
||||
|
||||
save(Configuration.javaTools);
|
||||
save("deprecated");
|
||||
save("deprecated");
|
||||
|
@ -201,11 +202,13 @@ public class SettingsSerializer
|
|||
save(Configuration.python3Extra);
|
||||
save(BytecodeViewer.viewer.getMinSdkVersion());
|
||||
save(BytecodeViewer.viewer.printLineNumbers.isSelected());
|
||||
} catch (Exception e) {
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
BytecodeViewer.handleException(e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Preload data used to configure the looks and components of the application
|
||||
*/
|
||||
|
@ -214,13 +217,13 @@ public class SettingsSerializer
|
|||
try
|
||||
{
|
||||
settingsFileExists = new File(settingsName).exists();
|
||||
|
||||
if(!settingsFileExists)
|
||||
|
||||
if (!settingsFileExists)
|
||||
return;
|
||||
|
||||
|
||||
//precache the file
|
||||
DiskReader.loadString(settingsName, 0, true);
|
||||
|
||||
|
||||
//process the cached file
|
||||
Configuration.lafTheme = LAFTheme.valueOf(asString(127));
|
||||
Configuration.rstaTheme = RSTATheme.valueOf(asString(128));
|
||||
|
@ -236,15 +239,15 @@ public class SettingsSerializer
|
|||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//utilizes the Disk Reader's caching system.
|
||||
public static void loadSettings()
|
||||
{
|
||||
if(!settingsFileExists)
|
||||
if (!settingsFileExists)
|
||||
return;
|
||||
|
||||
|
||||
Settings.firstBoot = false;
|
||||
|
||||
|
||||
try
|
||||
{
|
||||
//parse the cached file from memory (from preload)
|
||||
|
@ -335,7 +338,8 @@ public class SettingsSerializer
|
|||
BytecodeViewer.viewer.refreshOnChange.setSelected(asBoolean(84));
|
||||
|
||||
boolean bool = Boolean.parseBoolean(asString(85));
|
||||
if (bool) {
|
||||
if (bool)
|
||||
{
|
||||
BytecodeViewer.viewer.setExtendedState(JFrame.MAXIMIZED_BOTH);
|
||||
BytecodeViewer.viewer.isMaximized = true;
|
||||
}
|
||||
|
@ -344,16 +348,16 @@ public class SettingsSerializer
|
|||
Configuration.lastOpenDirectory = asString(88);
|
||||
Configuration.python2 = asString(89);
|
||||
Configuration.rt = asString(90);
|
||||
|
||||
|
||||
BytecodeViewer.viewer.decodeAPKResources.setSelected(asBoolean(106));
|
||||
Configuration.library = asString(107);
|
||||
Configuration.pingback = asBoolean(108);
|
||||
|
||||
|
||||
BytecodeViewer.viewer.fontSpinner.setValue(asInt(112));
|
||||
Configuration.deleteForeignLibraries = asBoolean(113);
|
||||
|
||||
|
||||
//APK Decompiler
|
||||
switch(asInt(114))
|
||||
switch (asInt(114))
|
||||
{
|
||||
case 0:
|
||||
BytecodeViewer.viewer.apkConversionGroup.setSelected(BytecodeViewer.viewer.apkConversionDex.getModel(), true);
|
||||
|
@ -362,7 +366,7 @@ public class SettingsSerializer
|
|||
BytecodeViewer.viewer.apkConversionGroup.setSelected(BytecodeViewer.viewer.apkConversionEnjarify.getModel(), true);
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
Configuration.python3 = asString(115);
|
||||
Configuration.javac = asString(116);
|
||||
Configuration.java = asString(117);
|
||||
|
@ -380,16 +384,16 @@ public class SettingsSerializer
|
|||
//line 128 is used for theme on preload
|
||||
BytecodeViewer.viewer.simplifyNameInTabTitle.setSelected(asBoolean(129));
|
||||
Configuration.simplifiedTabNames = BytecodeViewer.viewer.simplifyNameInTabTitle.isSelected();
|
||||
|
||||
|
||||
//line 130 is used for preload
|
||||
if(Configuration.language != Language.ENGLISH)
|
||||
if (Configuration.language != Language.ENGLISH)
|
||||
Configuration.language.setLanguageTranslations(); //load language translations
|
||||
Settings.hasSetLanguageAsSystemLanguage = true;
|
||||
|
||||
|
||||
BytecodeViewer.viewer.viewPane1.setPaneEditable(asBoolean(131));
|
||||
BytecodeViewer.viewer.viewPane2.setPaneEditable(asBoolean(132));
|
||||
BytecodeViewer.viewer.viewPane3.setPaneEditable(asBoolean(133));
|
||||
|
||||
|
||||
Configuration.javaTools = asString(134);
|
||||
//ignore 135
|
||||
//ignore 136
|
||||
|
@ -409,22 +413,22 @@ public class SettingsSerializer
|
|||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static void save(Object o)
|
||||
{
|
||||
DiskWriter.writeNewLine(settingsName, String.valueOf(o), false);
|
||||
}
|
||||
|
||||
|
||||
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 asInt(int lineNumber) throws Exception
|
||||
{
|
||||
return Integer.parseInt(DiskReader.loadString(settingsName, lineNumber, false));
|
||||
|
|
|
@ -18,15 +18,7 @@
|
|||
|
||||
package the.bytecode.club.bytecodeviewer.api;
|
||||
|
||||
import org.objectweb.asm.tree.AbstractInsnNode;
|
||||
import org.objectweb.asm.tree.ClassNode;
|
||||
import org.objectweb.asm.tree.FieldInsnNode;
|
||||
import org.objectweb.asm.tree.FieldNode;
|
||||
import org.objectweb.asm.tree.InnerClassNode;
|
||||
import org.objectweb.asm.tree.LocalVariableNode;
|
||||
import org.objectweb.asm.tree.MethodInsnNode;
|
||||
import org.objectweb.asm.tree.MethodNode;
|
||||
import org.objectweb.asm.tree.TypeInsnNode;
|
||||
import org.objectweb.asm.tree.*;
|
||||
import the.bytecode.club.bytecodeviewer.BytecodeViewer;
|
||||
|
||||
/**
|
||||
|
@ -47,20 +39,18 @@ public final class ASMResourceUtil
|
|||
for (Object o : cn.methods.toArray())
|
||||
{
|
||||
MethodNode m = (MethodNode) o;
|
||||
|
||||
|
||||
if (m.name.equals("main") && m.desc.equals("([Ljava/lang/String;)V"))
|
||||
{
|
||||
return cn.name + "." + m.name;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return defaultFQN;
|
||||
}
|
||||
|
||||
public static void renameFieldNode(String originalParentName,
|
||||
String originalFieldName, String originalFieldDesc,
|
||||
String newFieldParent, String newFieldName, String newFieldDesc)
|
||||
public static void renameFieldNode(String originalParentName, String originalFieldName, String originalFieldDesc, String newFieldParent, String newFieldName, String newFieldDesc)
|
||||
{
|
||||
for (ClassNode c : BytecodeViewer.getLoadedClasses())
|
||||
{
|
||||
|
@ -73,9 +63,7 @@ public final class ASMResourceUtil
|
|||
{
|
||||
FieldInsnNode field = (FieldInsnNode) i;
|
||||
|
||||
if (field.owner.equals(originalParentName)
|
||||
&& field.name.equals(originalFieldName)
|
||||
&& field.desc.equals(originalFieldDesc))
|
||||
if (field.owner.equals(originalParentName) && field.name.equals(originalFieldName) && field.desc.equals(originalFieldDesc))
|
||||
{
|
||||
if (newFieldParent != null)
|
||||
field.owner = newFieldParent;
|
||||
|
@ -90,9 +78,7 @@ public final class ASMResourceUtil
|
|||
}
|
||||
}
|
||||
|
||||
public static void renameMethodNode(String originalParentName,
|
||||
String originalMethodName, String originalMethodDesc,
|
||||
String newParent, String newName, String newDesc)
|
||||
public static void renameMethodNode(String originalParentName, String originalMethodName, String originalMethodDesc, String newParent, String newName, String newDesc)
|
||||
{
|
||||
for (ClassNode c : BytecodeViewer.getLoadedClasses())
|
||||
{
|
||||
|
@ -104,9 +90,7 @@ public final class ASMResourceUtil
|
|||
if (i instanceof MethodInsnNode)
|
||||
{
|
||||
MethodInsnNode mi = (MethodInsnNode) i;
|
||||
if (mi.owner.equals(originalParentName)
|
||||
&& mi.name.equals(originalMethodName)
|
||||
&& mi.desc.equals(originalMethodDesc))
|
||||
if (mi.owner.equals(originalParentName) && mi.name.equals(originalMethodName) && mi.desc.equals(originalMethodDesc))
|
||||
{
|
||||
if (newParent != null)
|
||||
mi.owner = newParent;
|
||||
|
@ -123,16 +107,12 @@ public final class ASMResourceUtil
|
|||
if (m.signature != null)
|
||||
{
|
||||
if (newName != null)
|
||||
m.signature = m.signature.replace(originalMethodName,
|
||||
newName);
|
||||
m.signature = m.signature.replace(originalMethodName, newName);
|
||||
if (newParent != null)
|
||||
m.signature = m.signature.replace(originalParentName,
|
||||
newParent);
|
||||
m.signature = m.signature.replace(originalParentName, newParent);
|
||||
}
|
||||
|
||||
if (m.name.equals(originalMethodName)
|
||||
&& m.desc.equals(originalMethodDesc)
|
||||
&& c.name.equals(originalParentName))
|
||||
if (m.name.equals(originalMethodName) && m.desc.equals(originalMethodDesc) && c.name.equals(originalParentName))
|
||||
{
|
||||
if (newName != null)
|
||||
m.name = newName;
|
||||
|
@ -151,10 +131,10 @@ public final class ASMResourceUtil
|
|||
{
|
||||
if (oo.innerName != null && oo.innerName.equals(oldName))
|
||||
oo.innerName = newName;
|
||||
|
||||
|
||||
if (oo.name.equals(oldName))
|
||||
oo.name = newName;
|
||||
|
||||
|
||||
if (oo.outerName != null && oo.outerName.equals(oldName))
|
||||
oo.outerName = newName;
|
||||
}
|
||||
|
@ -164,13 +144,13 @@ public final class ASMResourceUtil
|
|||
|
||||
if (c.superName.equals(oldName))
|
||||
c.superName = newName;
|
||||
|
||||
|
||||
for (Object o : c.fields.toArray())
|
||||
{
|
||||
FieldNode f = (FieldNode) o;
|
||||
f.desc = f.desc.replace(oldName, newName);
|
||||
}
|
||||
|
||||
|
||||
for (Object o : c.methods.toArray())
|
||||
{
|
||||
MethodNode m = (MethodNode) o;
|
||||
|
@ -194,7 +174,7 @@ public final class ASMResourceUtil
|
|||
if (t.desc.equals(oldName))
|
||||
t.desc = newName;
|
||||
}
|
||||
|
||||
|
||||
if (i instanceof MethodInsnNode)
|
||||
{
|
||||
MethodInsnNode mi = (MethodInsnNode) i;
|
||||
|
@ -213,4 +193,4 @@ public final class ASMResourceUtil
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -29,49 +29,59 @@ import org.objectweb.asm.tree.MethodNode;
|
|||
*/
|
||||
public class ASMUtil
|
||||
{
|
||||
/**
|
||||
* Creates a new ClassNode instances from the provided byte[]
|
||||
*/
|
||||
public static ClassNode bytesToNode(byte[] b)
|
||||
{
|
||||
ClassReader cr = new ClassReader(b);
|
||||
ClassNode cn = new ClassNode();
|
||||
try {
|
||||
cr.accept(cn, ClassReader.EXPAND_FRAMES);
|
||||
} catch (Exception e) {
|
||||
cr.accept(cn, ClassReader.SKIP_FRAMES);
|
||||
}
|
||||
return cn;
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes a valid byte[] from the provided classnode
|
||||
*/
|
||||
public static byte[] nodeToBytes(ClassNode cn)
|
||||
{
|
||||
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) { }
|
||||
}
|
||||
|
||||
return cw.toByteArray();
|
||||
}
|
||||
|
||||
public static MethodNode getMethodByName(ClassNode cn, String name)
|
||||
{
|
||||
for(MethodNode m : cn.methods)
|
||||
{
|
||||
if(m.name.equals(name))
|
||||
return m;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
/**
|
||||
* Creates a new ClassNode instances from the provided byte[]
|
||||
*/
|
||||
public static ClassNode bytesToNode(byte[] b)
|
||||
{
|
||||
ClassReader cr = new ClassReader(b);
|
||||
ClassNode cn = new ClassNode();
|
||||
try
|
||||
{
|
||||
cr.accept(cn, ClassReader.EXPAND_FRAMES);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
cr.accept(cn, ClassReader.SKIP_FRAMES);
|
||||
}
|
||||
return cn;
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes a valid byte[] from the provided classnode
|
||||
*/
|
||||
public static byte[] nodeToBytes(ClassNode cn)
|
||||
{
|
||||
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)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
return cw.toByteArray();
|
||||
}
|
||||
|
||||
public static MethodNode getMethodByName(ClassNode cn, String name)
|
||||
{
|
||||
for (MethodNode m : cn.methods)
|
||||
{
|
||||
if (m.name.equals(name))
|
||||
return m;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,17 +18,6 @@
|
|||
|
||||
package the.bytecode.club.bytecodeviewer.api;
|
||||
|
||||
import java.io.File;
|
||||
import java.net.URL;
|
||||
import java.net.URLClassLoader;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Enumeration;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.jar.JarEntry;
|
||||
import java.util.jar.JarFile;
|
||||
import javax.swing.JFrame;
|
||||
|
||||
import org.objectweb.asm.ClassWriter;
|
||||
import org.objectweb.asm.tree.ClassNode;
|
||||
import the.bytecode.club.bytecodeviewer.BytecodeViewer;
|
||||
|
@ -42,9 +31,18 @@ import the.bytecode.club.bytecodeviewer.util.JarUtils;
|
|||
import the.bytecode.club.bytecodeviewer.util.MiscUtils;
|
||||
import the.bytecode.club.bytecodeviewer.util.SleepUtil;
|
||||
|
||||
import static the.bytecode.club.bytecodeviewer.Constants.DEV_MODE;
|
||||
import static the.bytecode.club.bytecodeviewer.Constants.fs;
|
||||
import static the.bytecode.club.bytecodeviewer.Constants.tempDirectory;
|
||||
import javax.swing.*;
|
||||
import java.io.File;
|
||||
import java.net.URL;
|
||||
import java.net.URLClassLoader;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Enumeration;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.jar.JarEntry;
|
||||
import java.util.jar.JarFile;
|
||||
|
||||
import static the.bytecode.club.bytecodeviewer.Constants.*;
|
||||
|
||||
/**
|
||||
* An easier to use version of the BCV API, this is designed for anyone who wants to extend BCV, in any shape
|
||||
|
@ -62,7 +60,8 @@ public class BCV
|
|||
*
|
||||
* @return the static ClassNodeLoader instance
|
||||
*/
|
||||
public static ClassNodeLoader getClassNodeLoader() {
|
||||
public static ClassNodeLoader getClassNodeLoader()
|
||||
{
|
||||
return loader;
|
||||
}
|
||||
|
||||
|
@ -71,7 +70,8 @@ public class BCV
|
|||
*
|
||||
* @return the URLClassLoader instance
|
||||
*/
|
||||
public static URLClassLoader getClassLoaderInstance() {
|
||||
public static URLClassLoader getClassLoaderInstance()
|
||||
{
|
||||
return cl;
|
||||
}
|
||||
|
||||
|
@ -83,25 +83,27 @@ public class BCV
|
|||
*/
|
||||
public static Class<?> loadClassIntoClassLoader(ClassNode cn)
|
||||
{
|
||||
if(cn == null)
|
||||
if (cn == null)
|
||||
return null;
|
||||
|
||||
|
||||
getClassNodeLoader().addClass(cn);
|
||||
|
||||
|
||||
try
|
||||
{
|
||||
//TODO this should be rebuilding the class loader each time a new resource has been added or removed
|
||||
if(cl == null)
|
||||
if (cl == null)
|
||||
loadClassesIntoClassLoader();
|
||||
|
||||
|
||||
return cl.loadClass(cn.name);
|
||||
} catch (Exception classLoadException) {
|
||||
}
|
||||
catch (Exception classLoadException)
|
||||
{
|
||||
BytecodeViewer.handleException(classLoadException);
|
||||
}
|
||||
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This shotgun approach will class-load all the classes that have been imported into BCV.
|
||||
*
|
||||
|
@ -113,16 +115,18 @@ public class BCV
|
|||
{
|
||||
File f = new File(tempDirectory + fs + MiscUtils.randomString(12) + "loaded_temp.jar");
|
||||
List<Class<?>> ret = new ArrayList<>();
|
||||
|
||||
|
||||
JarUtils.saveAsJar(BCV.getLoadedClasses(), f.getAbsolutePath());
|
||||
try (JarFile jarFile = new JarFile("" + f.getAbsolutePath())) {
|
||||
try (JarFile jarFile = new JarFile("" + f.getAbsolutePath()))
|
||||
{
|
||||
|
||||
Enumeration<JarEntry> e = jarFile.entries();
|
||||
URL[] urls = {new URL("jar:file:" + "" + f.getAbsolutePath() + "!/")};
|
||||
|
||||
cl = URLClassLoader.newInstance(urls);
|
||||
|
||||
while (e.hasMoreElements()) {
|
||||
while (e.hasMoreElements())
|
||||
{
|
||||
JarEntry je = e.nextElement();
|
||||
|
||||
if (je.isDirectory() || !je.getName().endsWith(".class"))
|
||||
|
@ -131,16 +135,21 @@ public class BCV
|
|||
String className = je.getName().replace("/", ".").replace(".class", "");
|
||||
className = className.replace('/', '.');
|
||||
|
||||
try {
|
||||
try
|
||||
{
|
||||
ret.add(cl.loadClass(className));
|
||||
} catch (Exception classLoadException) {
|
||||
}
|
||||
catch (Exception classLoadException)
|
||||
{
|
||||
BytecodeViewer.handleException(classLoadException);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
} catch (Exception e) {
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
BytecodeViewer.handleException(e);
|
||||
}
|
||||
return null;
|
||||
|
@ -149,7 +158,8 @@ public class BCV
|
|||
/**
|
||||
* Creates a new instance of the ClassNode loader.
|
||||
*/
|
||||
public static void createNewClassNodeLoaderInstance() {
|
||||
public static void createNewClassNodeLoaderInstance()
|
||||
{
|
||||
loader.clear();
|
||||
loader = new ClassNodeLoader();
|
||||
}
|
||||
|
@ -159,7 +169,8 @@ public class BCV
|
|||
*
|
||||
* @param plugin the file of the plugin
|
||||
*/
|
||||
public static void startPlugin(File plugin) {
|
||||
public static void startPlugin(File plugin)
|
||||
{
|
||||
BytecodeViewer.startPlugin(plugin);
|
||||
}
|
||||
|
||||
|
@ -169,7 +180,8 @@ public class BCV
|
|||
* @param files an array of the files you want loaded.
|
||||
* @param recentFiles if it should save to the recent files menu.
|
||||
*/
|
||||
public static void openFiles(File[] files, boolean recentFiles) {
|
||||
public static void openFiles(File[] files, boolean recentFiles)
|
||||
{
|
||||
BytecodeViewer.openFiles(files, recentFiles);
|
||||
}
|
||||
|
||||
|
@ -178,10 +190,11 @@ public class BCV
|
|||
*
|
||||
* @return The opened class node or a null if nothing is opened
|
||||
*/
|
||||
public static ClassNode getCurrentlyOpenedClassNode() {
|
||||
public static ClassNode getCurrentlyOpenedClassNode()
|
||||
{
|
||||
return BytecodeViewer.getCurrentlyOpenedClassNode();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the currently opened class nodes ClassFile bytes
|
||||
*
|
||||
|
@ -191,21 +204,27 @@ public class BCV
|
|||
{
|
||||
final ClassNode cn = BytecodeViewer.getCurrentlyOpenedClassNode();
|
||||
final ClassWriter cw = new ClassWriter(0);
|
||||
|
||||
try {
|
||||
|
||||
try
|
||||
{
|
||||
Objects.requireNonNull(cn).accept(cw);
|
||||
} catch (Exception e) {
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
try {
|
||||
try
|
||||
{
|
||||
Thread.sleep(200);
|
||||
Objects.requireNonNull(cn).accept(cw);
|
||||
} catch (InterruptedException ignored) {
|
||||
}
|
||||
catch (InterruptedException ignored)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return cw.toByteArray();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This decompiles the actively opened ClassFile inside of BCV.
|
||||
*
|
||||
|
@ -223,7 +242,8 @@ public class BCV
|
|||
* @param name the full name of the ClassNode
|
||||
* @return the ClassNode
|
||||
*/
|
||||
public static ClassNode getClassNode(String name) {
|
||||
public static ClassNode getClassNode(String name)
|
||||
{
|
||||
return BytecodeViewer.blindlySearchForClassNode(name);
|
||||
}
|
||||
|
||||
|
@ -232,7 +252,8 @@ public class BCV
|
|||
*
|
||||
* @return the loaded classes
|
||||
*/
|
||||
public static List<ClassNode> getLoadedClasses() {
|
||||
public static List<ClassNode> getLoadedClasses()
|
||||
{
|
||||
return BytecodeViewer.getLoadedClasses();
|
||||
}
|
||||
|
||||
|
@ -241,7 +262,8 @@ public class BCV
|
|||
*
|
||||
* @param hook
|
||||
*/
|
||||
public static void insertHook(BytecodeHook hook) {
|
||||
public static void insertHook(BytecodeHook hook)
|
||||
{
|
||||
EZInjection.hookArray.add(hook);
|
||||
}
|
||||
|
||||
|
@ -251,7 +273,8 @@ public class BCV
|
|||
*
|
||||
* @param ask if it should ask the user about resetting the workspace
|
||||
*/
|
||||
public static void resetWorkSpace(boolean ask) {
|
||||
public static void resetWorkSpace(boolean ask)
|
||||
{
|
||||
BytecodeViewer.resetWorkspace(ask);
|
||||
}
|
||||
|
||||
|
@ -261,7 +284,8 @@ public class BCV
|
|||
*
|
||||
* @param busy if it should display the busy icon or not
|
||||
*/
|
||||
public static void setBusy(boolean busy) {
|
||||
public static void setBusy(boolean busy)
|
||||
{
|
||||
BytecodeViewer.updateBusyStatus(busy);
|
||||
}
|
||||
|
||||
|
@ -270,33 +294,35 @@ public class BCV
|
|||
*
|
||||
* @param message the message you want to display
|
||||
*/
|
||||
public static void showMessage(String message) {
|
||||
public static void showMessage(String message)
|
||||
{
|
||||
BytecodeViewer.showMessage(message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Asks if the user would like to overwrite the file
|
||||
*/
|
||||
public static boolean canOverwriteFile(File file) {
|
||||
public static boolean canOverwriteFile(File file)
|
||||
{
|
||||
return DialogUtils.canOverwriteFile(file);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This function will hide a JFrame after a given amount of time.
|
||||
*
|
||||
* @param frame Any JFrame object
|
||||
* @param frame Any JFrame object
|
||||
* @param milliseconds The amount of time until it will be hidden represented in milliseconds
|
||||
*/
|
||||
public static void hideFrame(JFrame frame, long milliseconds)
|
||||
{
|
||||
new Thread(()->
|
||||
new Thread(() ->
|
||||
{
|
||||
SleepUtil.sleep(milliseconds);
|
||||
|
||||
SleepUtil.sleep(milliseconds);
|
||||
|
||||
frame.setVisible(false);
|
||||
}, "Timed Swing Hide").start();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Log to System.out
|
||||
*/
|
||||
|
@ -304,16 +330,16 @@ public class BCV
|
|||
{
|
||||
log(false, s);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Log to System.out
|
||||
*/
|
||||
public static void log(boolean devModeOnly, String s)
|
||||
{
|
||||
if(!devModeOnly || DEV_MODE)
|
||||
if (!devModeOnly || DEV_MODE)
|
||||
System.out.println(s);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Log to System.err
|
||||
*/
|
||||
|
@ -321,13 +347,13 @@ public class BCV
|
|||
{
|
||||
logE(false, s);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Log to System.err
|
||||
*/
|
||||
public static void logE(boolean devModeOnly, String s)
|
||||
{
|
||||
if(!devModeOnly || DEV_MODE)
|
||||
if (!devModeOnly || DEV_MODE)
|
||||
System.err.println(s);
|
||||
}
|
||||
|
||||
|
@ -336,7 +362,8 @@ public class BCV
|
|||
*
|
||||
* @return The wrapped Krakatau Decompiler instance
|
||||
*/
|
||||
public static InternalDecompiler getKrakatauDecompiler() {
|
||||
public static InternalDecompiler getKrakatauDecompiler()
|
||||
{
|
||||
return Decompiler.KRAKATAU_DECOMPILER.getDecompiler();
|
||||
}
|
||||
|
||||
|
@ -345,7 +372,8 @@ public class BCV
|
|||
*
|
||||
* @return The wrapped Procyon Decompiler instance
|
||||
*/
|
||||
public static InternalDecompiler getProcyonDecompiler() {
|
||||
public static InternalDecompiler getProcyonDecompiler()
|
||||
{
|
||||
return Decompiler.PROCYON_DECOMPILER.getDecompiler();
|
||||
}
|
||||
|
||||
|
@ -354,7 +382,8 @@ public class BCV
|
|||
*
|
||||
* @return The wrapped CFR Decompiler instance
|
||||
*/
|
||||
public static InternalDecompiler getCFRDecompiler() {
|
||||
public static InternalDecompiler getCFRDecompiler()
|
||||
{
|
||||
return Decompiler.CFR_DECOMPILER.getDecompiler();
|
||||
}
|
||||
|
||||
|
@ -363,7 +392,8 @@ public class BCV
|
|||
*
|
||||
* @return The wrapped FernFlower Decompiler instance
|
||||
*/
|
||||
public static InternalDecompiler getFernFlowerDecompiler() {
|
||||
public static InternalDecompiler getFernFlowerDecompiler()
|
||||
{
|
||||
return Decompiler.FERNFLOWER_DECOMPILER.getDecompiler();
|
||||
}
|
||||
|
||||
|
@ -372,25 +402,28 @@ public class BCV
|
|||
*
|
||||
* @return The wrapped Krakatau Disassembler instance
|
||||
*/
|
||||
public static InternalDecompiler getKrakatauDisassembler() {
|
||||
public static InternalDecompiler getKrakatauDisassembler()
|
||||
{
|
||||
return Decompiler.KRAKATAU_DISASSEMBLER.getDecompiler();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the wrapped JD-GUI Decompiler instance.
|
||||
*
|
||||
* @return The wrapped JD-GUI Decompiler instance
|
||||
*/
|
||||
public static InternalDecompiler getDJGUIDecompiler() {
|
||||
public static InternalDecompiler getDJGUIDecompiler()
|
||||
{
|
||||
return Decompiler.JD_DECOMPILER.getDecompiler();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the wrapped JADX Decompiler instance.
|
||||
*
|
||||
* @return The wrapped JADX Decompiler instance
|
||||
*/
|
||||
public static InternalDecompiler getJADXDecompiler() {
|
||||
public static InternalDecompiler getJADXDecompiler()
|
||||
{
|
||||
return Decompiler.JADX_DECOMPILER.getDecompiler();
|
||||
}
|
||||
|
||||
|
@ -399,7 +432,8 @@ public class BCV
|
|||
*
|
||||
* @return The wrapped Java Compiler instance
|
||||
*/
|
||||
public static InternalCompiler getJavaCompiler() {
|
||||
public static InternalCompiler getJavaCompiler()
|
||||
{
|
||||
return Compiler.JAVA_COMPILER.getCompiler();
|
||||
}
|
||||
|
||||
|
@ -408,7 +442,8 @@ public class BCV
|
|||
*
|
||||
* @return The wrapped Krakatau Assembler instance
|
||||
*/
|
||||
public static InternalCompiler getKrakatauCompiler() {
|
||||
public static InternalCompiler getKrakatauCompiler()
|
||||
{
|
||||
return Compiler.KRAKATAU_ASSEMBLER.getCompiler();
|
||||
}
|
||||
|
||||
|
@ -417,7 +452,8 @@ public class BCV
|
|||
*
|
||||
* @return The wrapped Smali Assembler instance
|
||||
*/
|
||||
public static InternalCompiler getSmaliCompiler() {
|
||||
public static InternalCompiler getSmaliCompiler()
|
||||
{
|
||||
return Compiler.SMALI_ASSEMBLER.getCompiler();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,18 +18,15 @@
|
|||
|
||||
package the.bytecode.club.bytecodeviewer.api;
|
||||
|
||||
import org.objectweb.asm.ClassWriter;
|
||||
import org.objectweb.asm.tree.ClassNode;
|
||||
|
||||
import java.security.AllPermission;
|
||||
import java.security.CodeSource;
|
||||
import java.security.Permissions;
|
||||
import java.security.ProtectionDomain;
|
||||
import java.security.cert.Certificate;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import org.objectweb.asm.ClassWriter;
|
||||
import org.objectweb.asm.tree.ClassNode;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* @author Demmonic
|
||||
|
@ -44,7 +41,8 @@ public final class ClassNodeLoader extends ClassLoader
|
|||
*
|
||||
* @param cn The class
|
||||
*/
|
||||
public void addClass(ClassNode cn) {
|
||||
public void addClass(ClassNode cn)
|
||||
{
|
||||
classes.put(cn.name.replace("/", "."), cn);
|
||||
}
|
||||
|
||||
|
@ -52,33 +50,41 @@ public final class ClassNodeLoader extends ClassLoader
|
|||
* @param name The name of the class
|
||||
* @return If this class loader contains the provided class node
|
||||
*/
|
||||
public boolean contains(String name) {
|
||||
public boolean contains(String name)
|
||||
{
|
||||
return (classes.get(name) != null);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return All class nodes in this loader
|
||||
*/
|
||||
public Collection<ClassNode> getAll() {
|
||||
public Collection<ClassNode> getAll()
|
||||
{
|
||||
return classes.values();
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears out all class nodes
|
||||
*/
|
||||
public void clear() {
|
||||
public void clear()
|
||||
{
|
||||
classes.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return All classes in this loader
|
||||
*/
|
||||
public Collection<Class<?>> getAllClasses() {
|
||||
public Collection<Class<?>> getAllClasses()
|
||||
{
|
||||
List<Class<?>> classes = new ArrayList<>();
|
||||
for (String s : this.classes.keySet()) {
|
||||
try {
|
||||
for (String s : this.classes.keySet())
|
||||
{
|
||||
try
|
||||
{
|
||||
classes.add(loadClass(s));
|
||||
} catch (ClassNotFoundException e) {
|
||||
}
|
||||
catch (ClassNotFoundException e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
@ -90,20 +96,26 @@ public final class ClassNodeLoader extends ClassLoader
|
|||
* @param name The name of the class
|
||||
* @return The class node with the provided name
|
||||
*/
|
||||
public ClassNode get(String name) {
|
||||
public ClassNode get(String name)
|
||||
{
|
||||
return classes.get(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<?> loadClass(String className) throws ClassNotFoundException {
|
||||
public Class<?> loadClass(String className) throws ClassNotFoundException
|
||||
{
|
||||
return findClass(className);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<?> findClass(String name) throws ClassNotFoundException {
|
||||
if (classes.containsKey(name)) {
|
||||
public Class<?> findClass(String name) throws ClassNotFoundException
|
||||
{
|
||||
if (classes.containsKey(name))
|
||||
{
|
||||
return nodeToClass(classes.get(name));
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
return super.loadClass(name);
|
||||
}
|
||||
}
|
||||
|
@ -118,23 +130,26 @@ public final class ClassNodeLoader extends ClassLoader
|
|||
{
|
||||
if (super.findLoadedClass(node.name.replace("/", ".")) != null)
|
||||
return findLoadedClass(node.name.replace("/", "."));
|
||||
|
||||
|
||||
ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS);
|
||||
try {
|
||||
try
|
||||
{
|
||||
node.accept(cw);
|
||||
} catch (Exception e) {
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
|
||||
byte[] b = cw.toByteArray();
|
||||
return defineClass(node.name.replaceAll("/", "."), b, 0, b.length,
|
||||
getDomain());
|
||||
return defineClass(node.name.replaceAll("/", "."), b, 0, b.length, getDomain());
|
||||
}
|
||||
|
||||
/**
|
||||
* @return This class loader's protection domain
|
||||
*/
|
||||
private ProtectionDomain getDomain() {
|
||||
private ProtectionDomain getDomain()
|
||||
{
|
||||
CodeSource code = new CodeSource(null, (Certificate[]) null);
|
||||
return new ProtectionDomain(code, getPermissions());
|
||||
}
|
||||
|
@ -142,7 +157,8 @@ public final class ClassNodeLoader extends ClassLoader
|
|||
/**
|
||||
* @return This class loader's permissions
|
||||
*/
|
||||
private Permissions getPermissions() {
|
||||
private Permissions getPermissions()
|
||||
{
|
||||
Permissions permissions = new Permissions();
|
||||
permissions.add(new AllPermission());
|
||||
return permissions;
|
||||
|
|
|
@ -18,11 +18,6 @@
|
|||
|
||||
package the.bytecode.club.bytecodeviewer.api;
|
||||
|
||||
import java.awt.CardLayout;
|
||||
import java.awt.Dimension;
|
||||
import java.io.IOException;
|
||||
import java.io.PrintWriter;
|
||||
import java.io.StringWriter;
|
||||
import the.bytecode.club.bytecodeviewer.BytecodeViewer;
|
||||
import the.bytecode.club.bytecodeviewer.Configuration;
|
||||
import the.bytecode.club.bytecodeviewer.gui.components.JFrameConsole;
|
||||
|
@ -30,9 +25,12 @@ import the.bytecode.club.bytecodeviewer.plugin.PluginManager;
|
|||
import the.bytecode.club.bytecodeviewer.resources.IconResources;
|
||||
import the.bytecode.club.bytecodeviewer.translation.TranslatedStrings;
|
||||
|
||||
import static the.bytecode.club.bytecodeviewer.Constants.FAT_JAR;
|
||||
import static the.bytecode.club.bytecodeviewer.Constants.VERSION;
|
||||
import static the.bytecode.club.bytecodeviewer.Constants.nl;
|
||||
import java.awt.*;
|
||||
import java.io.IOException;
|
||||
import java.io.PrintWriter;
|
||||
import java.io.StringWriter;
|
||||
|
||||
import static the.bytecode.club.bytecodeviewer.Constants.*;
|
||||
|
||||
/**
|
||||
* A simple class designed to show exceptions in the UI.
|
||||
|
@ -45,18 +43,20 @@ public class ExceptionUI extends JFrameConsole
|
|||
public static final String KONLOCH = "https://github.com/Konloch/bytecode-viewer/issues or Konloch at https://the.bytecode.club or konloch@gmail.com";
|
||||
public static final String SEND_STACKTRACE_TO = buildErrorLogHeader(KONLOCH);
|
||||
public static final String SEND_STACKTRACE_TO_NL = SEND_STACKTRACE_TO + nl + nl;
|
||||
|
||||
|
||||
/**
|
||||
* @param e The exception to be shown
|
||||
*/
|
||||
public ExceptionUI(Throwable e) {
|
||||
public ExceptionUI(Throwable e)
|
||||
{
|
||||
setupException(e, KONLOCH);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param e The exception to be shown
|
||||
*/
|
||||
public ExceptionUI(String e) {
|
||||
public ExceptionUI(String e)
|
||||
{
|
||||
setupFrame(e, KONLOCH);
|
||||
}
|
||||
|
||||
|
@ -64,7 +64,8 @@ public class ExceptionUI extends JFrameConsole
|
|||
* @param e The exception to be shown
|
||||
* @param author the author of the plugin throwing this exception.
|
||||
*/
|
||||
public ExceptionUI(Throwable e, String author) {
|
||||
public ExceptionUI(Throwable e, String author)
|
||||
{
|
||||
setupException(e, author);
|
||||
}
|
||||
|
||||
|
@ -72,36 +73,39 @@ public class ExceptionUI extends JFrameConsole
|
|||
* @param e The exception to be shown
|
||||
* @param author the author of the plugin throwing this exception.
|
||||
*/
|
||||
public ExceptionUI(String e, String author) {
|
||||
public ExceptionUI(String e, String author)
|
||||
{
|
||||
setupFrame(e, author);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Handles error suppression and prints stacktraces to strings
|
||||
*/
|
||||
private void setupException(Throwable error, String author)
|
||||
{
|
||||
//exceptions are completely hidden
|
||||
if(Configuration.silenceExceptionGUI > 0)
|
||||
if (Configuration.silenceExceptionGUI > 0)
|
||||
return;
|
||||
|
||||
|
||||
//exception GUI is disabled but printstack is still enabled
|
||||
if(Configuration.pauseExceptionGUI > 0)
|
||||
if (Configuration.pauseExceptionGUI > 0)
|
||||
{
|
||||
error.printStackTrace();
|
||||
return;
|
||||
}
|
||||
|
||||
try (StringWriter sw = new StringWriter();
|
||||
PrintWriter pw = new PrintWriter(sw)) {
|
||||
|
||||
try (StringWriter sw = new StringWriter(); PrintWriter pw = new PrintWriter(sw))
|
||||
{
|
||||
error.printStackTrace(pw);
|
||||
error.printStackTrace();
|
||||
|
||||
setupFrame(sw.toString(), author);
|
||||
} catch (IOException ignored) {
|
||||
}
|
||||
catch (IOException ignored)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Creates a new frame and fills it with the error log
|
||||
*/
|
||||
|
@ -111,35 +115,31 @@ public class ExceptionUI extends JFrameConsole
|
|||
setSize(new Dimension(600, 400));
|
||||
setTitle("Bytecode Viewer " + VERSION + " - Error Log - Send this to " + author);
|
||||
getContentPane().setLayout(new CardLayout(0, 0));
|
||||
|
||||
|
||||
getTextArea().setText(buildErrorLogHeader(author) + nl + nl + error);
|
||||
getTextArea().setCaretPosition(0);
|
||||
|
||||
|
||||
//embed error log as a new tab
|
||||
if(Configuration.errorLogsAsNewTab)
|
||||
if (Configuration.errorLogsAsNewTab)
|
||||
PluginManager.addExceptionUI(this);
|
||||
|
||||
//pop open a new window frame
|
||||
|
||||
//pop open a new window frame
|
||||
else
|
||||
{
|
||||
setLocationRelativeTo(BytecodeViewer.viewer);
|
||||
setVisible(true);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the error log header
|
||||
*/
|
||||
public static String buildErrorLogHeader(String author)
|
||||
{
|
||||
String fatJar = FAT_JAR ? " [Fat Jar]" : "";
|
||||
|
||||
return TranslatedStrings.PLEASE_SEND_THIS_ERROR_LOG_TO + " " + author +
|
||||
"\n" + TranslatedStrings.PLEASE_SEND_RESOURCES +
|
||||
"\nBytecode Viewer Version: " + VERSION + fatJar +
|
||||
", OS: " + System.getProperty("os.name") +
|
||||
", Java: " + System.getProperty("java.version");
|
||||
|
||||
return TranslatedStrings.PLEASE_SEND_THIS_ERROR_LOG_TO + " " + author + "\n" + TranslatedStrings.PLEASE_SEND_RESOURCES + "\nBytecode Viewer Version: " + VERSION + fatJar + ", OS: " + System.getProperty("os.name") + ", Java: " + System.getProperty("java.version");
|
||||
}
|
||||
|
||||
|
||||
private static final long serialVersionUID = -5230501978224926296L;
|
||||
}
|
||||
|
|
|
@ -18,12 +18,13 @@
|
|||
|
||||
package the.bytecode.club.bytecodeviewer.api;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import org.objectweb.asm.tree.ClassNode;
|
||||
import the.bytecode.club.bytecodeviewer.BytecodeViewer;
|
||||
import the.bytecode.club.bytecodeviewer.resources.ResourceContainer;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* A simple plugin class, it will run the plugin in a background thread.
|
||||
*
|
||||
|
@ -35,21 +36,25 @@ public abstract class Plugin extends Thread
|
|||
//as long as your code is being called from the execute function
|
||||
// this will be the current container
|
||||
public ResourceContainer activeContainer = null;
|
||||
|
||||
|
||||
@Override
|
||||
public void run()
|
||||
{
|
||||
BytecodeViewer.updateBusyStatus(true);
|
||||
|
||||
|
||||
try
|
||||
{
|
||||
if (BytecodeViewer.promptIfNoLoadedResources())
|
||||
return;
|
||||
|
||||
|
||||
executeContainer();
|
||||
} catch (Exception e) {
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
BytecodeViewer.handleException(e);
|
||||
} finally {
|
||||
}
|
||||
finally
|
||||
{
|
||||
finished = true;
|
||||
BytecodeViewer.updateBusyStatus(false);
|
||||
}
|
||||
|
@ -62,7 +67,8 @@ public abstract class Plugin extends Thread
|
|||
*
|
||||
* @return true if the plugin is finished executing
|
||||
*/
|
||||
public boolean isFinished() {
|
||||
public boolean isFinished()
|
||||
{
|
||||
return finished;
|
||||
}
|
||||
|
||||
|
@ -71,24 +77,26 @@ public abstract class Plugin extends Thread
|
|||
* still be considered finished (EZ-Injection), you can call this function
|
||||
* and it will set the finished boolean to true.
|
||||
*/
|
||||
public void setFinished() {
|
||||
public void setFinished()
|
||||
{
|
||||
finished = true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* On plugin start each resource container is iterated through
|
||||
*/
|
||||
public void executeContainer()
|
||||
{
|
||||
BytecodeViewer.getResourceContainers().forEach(container -> {
|
||||
BytecodeViewer.getResourceContainers().forEach(container ->
|
||||
{
|
||||
//set the active container
|
||||
activeContainer = container;
|
||||
|
||||
|
||||
//call on the plugin code
|
||||
execute(new ArrayList<>(container.resourceClasses.values()));
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* On plugin start each resource container is iterated through,
|
||||
* then this is called with the resource container classes
|
||||
|
|
|
@ -34,28 +34,27 @@ public class PluginConsole extends SystemConsole
|
|||
//window showing is disabled to allow this frame to be added as a tab
|
||||
private boolean showWindow;
|
||||
private boolean added;
|
||||
|
||||
|
||||
public PluginConsole(String pluginName)
|
||||
{
|
||||
super(Configuration.pluginConsoleAsNewTab ? (pluginName + " Output")
|
||||
: (TranslatedStrings.PLUGIN_CONSOLE_TITLE + " - " + pluginName));
|
||||
super(Configuration.pluginConsoleAsNewTab ? (pluginName + " Output") : (TranslatedStrings.PLUGIN_CONSOLE_TITLE + " - " + pluginName));
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void setVisible(boolean visible)
|
||||
{
|
||||
if(!added && visible)
|
||||
if (!added && visible)
|
||||
{
|
||||
added = true;
|
||||
PluginManager.addConsole(this);
|
||||
}
|
||||
|
||||
|
||||
//do nothing
|
||||
if(!showWindow)
|
||||
if (!showWindow)
|
||||
return;
|
||||
|
||||
|
||||
super.setVisible(visible);
|
||||
}
|
||||
|
||||
|
||||
private static final long serialVersionUID = -6556940545421437508L;
|
||||
}
|
||||
|
|
|
@ -18,15 +18,6 @@
|
|||
|
||||
package the.bytecode.club.bytecodeviewer.bootloader;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.InputStream;
|
||||
import java.net.URL;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import javax.swing.JOptionPane;
|
||||
import javax.swing.SwingUtilities;
|
||||
import com.konloch.httprequest.HTTPRequest;
|
||||
import org.apache.commons.io.FileUtils;
|
||||
import the.bytecode.club.bytecodeviewer.BytecodeViewer;
|
||||
|
@ -40,18 +31,24 @@ import the.bytecode.club.bytecodeviewer.bootloader.resource.external.ExternalRes
|
|||
import the.bytecode.club.bytecodeviewer.util.MiscUtils;
|
||||
import the.bytecode.club.bytecodeviewer.util.ZipUtils;
|
||||
|
||||
import static the.bytecode.club.bytecodeviewer.Constants.fs;
|
||||
import static the.bytecode.club.bytecodeviewer.Constants.getBCVDirectory;
|
||||
import static the.bytecode.club.bytecodeviewer.Constants.krakatauVersion;
|
||||
import static the.bytecode.club.bytecodeviewer.Constants.krakatauWorkingDirectory;
|
||||
import static the.bytecode.club.bytecodeviewer.Constants.nl;
|
||||
import javax.swing.*;
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.InputStream;
|
||||
import java.net.URL;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
import static the.bytecode.club.bytecodeviewer.Constants.*;
|
||||
|
||||
/**
|
||||
* @author Konloch
|
||||
* @author Bibl (don't ban me pls)
|
||||
* @since 19 Jul 2015 03:22:37
|
||||
*/
|
||||
public class Boot {
|
||||
public class Boot
|
||||
{
|
||||
|
||||
/*flags*/
|
||||
public static boolean globalstop = false;
|
||||
|
@ -63,12 +60,13 @@ public class Boot {
|
|||
private static final List<String> libsFileList = new ArrayList<>();
|
||||
private static final List<String> urlList = new ArrayList<>();
|
||||
|
||||
public static void boot(String[] args, boolean CLI) throws Exception {
|
||||
public static void boot(String[] args, boolean CLI) throws Exception
|
||||
{
|
||||
bootstrap();
|
||||
ILoader<?> loader = findLoader();
|
||||
|
||||
screen = new InitialBootScreen();
|
||||
|
||||
|
||||
if (!CLI)
|
||||
SwingUtilities.invokeLater(() -> screen.setVisible(true));
|
||||
|
||||
|
@ -77,27 +75,30 @@ public class Boot {
|
|||
SwingUtilities.invokeLater(() -> screen.setVisible(false));
|
||||
}
|
||||
|
||||
public static void hide() {
|
||||
public static void hide()
|
||||
{
|
||||
SwingUtilities.invokeLater(() -> screen.setVisible(false));
|
||||
}
|
||||
|
||||
@SuppressWarnings({"rawtypes", "unchecked"})
|
||||
private static void create(ILoader<?> loader, boolean clean) throws Exception {
|
||||
private static void create(ILoader<?> loader, boolean clean) throws Exception
|
||||
{
|
||||
setState("Bytecode Viewer Boot Screen - Checking Libraries...");
|
||||
final File libsDirectory = libsDir();
|
||||
|
||||
populateUrlList();
|
||||
|
||||
if (globalstop) {
|
||||
while (true) {
|
||||
if (globalstop)
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
Thread.sleep(100);//just keep this thread halted.
|
||||
}
|
||||
}
|
||||
|
||||
if (urlList.isEmpty()) {
|
||||
JOptionPane.showMessageDialog(null, "Bytecode Viewer ran into an issue, for some reason github is not "
|
||||
+ "returning what we're expecting. Please try rebooting, if this issue persists please contact "
|
||||
+ "@Konloch.", "Error", JOptionPane.ERROR_MESSAGE);
|
||||
if (urlList.isEmpty())
|
||||
{
|
||||
JOptionPane.showMessageDialog(null, "Bytecode Viewer ran into an issue, for some reason github is not " + "returning what we're expecting. Please try rebooting, if this issue persists please contact " + "@Konloch.", "Error", JOptionPane.ERROR_MESSAGE);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -113,46 +114,52 @@ public class Boot {
|
|||
|
||||
int completedCheck = 0;
|
||||
|
||||
for (String s : urlList) {
|
||||
String fileName = s.substring("https://github.com/Konloch/bytecode-viewer/blob/master/libs/".length()
|
||||
);
|
||||
for (String s : urlList)
|
||||
{
|
||||
String fileName = s.substring("https://github.com/Konloch/bytecode-viewer/blob/master/libs/".length());
|
||||
File file = new File(libsDirectory, fileName);
|
||||
|
||||
boolean passed = false;
|
||||
while (!passed) {
|
||||
if (!libsList.contains(fileName)) {
|
||||
while (!passed)
|
||||
{
|
||||
if (!libsList.contains(fileName))
|
||||
{
|
||||
downloading = true;
|
||||
setState("Bytecode Viewer Boot Screen - Downloading " + fileName + "...");
|
||||
System.out.println("Downloading " + fileName);
|
||||
|
||||
try (InputStream is = new URL("https://github.com/Konloch/bytecode-viewer/raw/master/libs/" + fileName)
|
||||
.openConnection().getInputStream();
|
||||
FileOutputStream fos = new FileOutputStream(file)) {
|
||||
try (InputStream is = new URL("https://github.com/Konloch/bytecode-viewer/raw/master/libs/" + fileName).openConnection().getInputStream(); FileOutputStream fos = new FileOutputStream(file))
|
||||
{
|
||||
System.out.println("Downloading from " + s);
|
||||
byte[] buffer = new byte[8192];
|
||||
int len;
|
||||
int downloaded = 0;
|
||||
boolean flag = false;
|
||||
while ((len = is.read(buffer)) > 0) {
|
||||
while ((len = is.read(buffer)) > 0)
|
||||
{
|
||||
fos.write(buffer, 0, len);
|
||||
fos.flush();
|
||||
downloaded += 8192;
|
||||
int mbs = downloaded / 1048576;
|
||||
if (mbs % 5 == 0 && mbs != 0) {
|
||||
if (mbs % 5 == 0 && mbs != 0)
|
||||
{
|
||||
if (!flag)
|
||||
System.out.println("Downloaded " + mbs + "MBs so far");
|
||||
flag = true;
|
||||
} else
|
||||
}
|
||||
else
|
||||
flag = false;
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
try
|
||||
{
|
||||
setState("Bytecode Viewer Boot Screen - Verifying " + fileName + "...");
|
||||
System.out.println("Verifying " + fileName + "...");
|
||||
|
||||
File f = new File(Constants.tempDirectory, "temp");
|
||||
if (!f.exists()) {
|
||||
if (!f.exists())
|
||||
{
|
||||
f.getParentFile().mkdirs();
|
||||
}
|
||||
ZipUtils.zipFile(file, f);
|
||||
|
@ -161,13 +168,18 @@ public class Boot {
|
|||
libsFileList.add(file.getAbsolutePath());
|
||||
System.out.println("Download finished!");
|
||||
passed = true;
|
||||
} catch (Exception e) {
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
System.out.println("Jar or Zip" + file.getAbsolutePath() + " is corrupt, redownloading.");
|
||||
file.delete();
|
||||
}
|
||||
} else if (Configuration.verifyCorruptedStateOnBoot) { //verify its not corrupt each boot (adds 3 seconds boot time)
|
||||
try {
|
||||
}
|
||||
else if (Configuration.verifyCorruptedStateOnBoot)
|
||||
{ //verify its not corrupt each boot (adds 3 seconds boot time)
|
||||
try
|
||||
{
|
||||
setState("Bytecode Viewer Boot Screen - Verifying " + fileName + "...");
|
||||
System.out.println("Verifying " + fileName + "...");
|
||||
|
||||
|
@ -176,13 +188,17 @@ public class Boot {
|
|||
f.delete();
|
||||
|
||||
passed = true;
|
||||
} catch (Exception e) {
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
System.out.println("Jar or Zip" + file.getAbsolutePath() + " is corrupt, redownloading.");
|
||||
libsFileList.remove(file.getAbsolutePath());
|
||||
file.delete();
|
||||
}
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
passed = true;
|
||||
}
|
||||
}
|
||||
|
@ -193,17 +209,18 @@ public class Boot {
|
|||
|
||||
setState("Bytecode Viewer Boot Screen - Checking & Deleting Foreign/Outdated Libraries...");
|
||||
System.out.println("Checking & Deleting foreign/outdated libraries");
|
||||
for (String s : libsFileList) {
|
||||
for (String s : libsFileList)
|
||||
{
|
||||
File f = new File(s);
|
||||
boolean delete = true;
|
||||
for (String urlS : urlList) {
|
||||
String fileName =
|
||||
urlS.substring("https://github.com/Konloch/bytecode-viewer/blob/master/libs/".length()
|
||||
);
|
||||
for (String urlS : urlList)
|
||||
{
|
||||
String fileName = urlS.substring("https://github.com/Konloch/bytecode-viewer/blob/master/libs/".length());
|
||||
if (fileName.equals(f.getName()))
|
||||
delete = false;
|
||||
}
|
||||
if (delete) {
|
||||
if (delete)
|
||||
{
|
||||
f.delete();
|
||||
System.out.println("Detected & Deleted Foreign/Outdated Jar/File: " + f.getName());
|
||||
}
|
||||
|
@ -212,23 +229,27 @@ public class Boot {
|
|||
setState("Bytecode Viewer Boot Screen - Loading Libraries...");
|
||||
System.out.println("Loading libraries...");
|
||||
|
||||
for (String s : libsFileList) {
|
||||
if (s.endsWith(".jar")) {
|
||||
for (String s : libsFileList)
|
||||
{
|
||||
if (s.endsWith(".jar"))
|
||||
{
|
||||
File f = new File(s);
|
||||
if (f.exists()) {
|
||||
if (f.exists())
|
||||
{
|
||||
setState("Bytecode Viewer Boot Screen - Loading Library " + f.getName());
|
||||
System.out.println("Loading library " + f.getName());
|
||||
|
||||
try {
|
||||
try
|
||||
{
|
||||
ExternalResource res = new EmptyExternalResource<>(f.toURI().toURL());
|
||||
loader.bind(res);
|
||||
System.out.println("Successfully loaded " + f.getName());
|
||||
} catch (Exception e) {
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
f.delete();
|
||||
JOptionPane.showMessageDialog(null, "Error, Library " + f.getName() + " is corrupt, please "
|
||||
+ "restart to redownload it.",
|
||||
"Error", JOptionPane.ERROR_MESSAGE);
|
||||
JOptionPane.showMessageDialog(null, "Error, Library " + f.getName() + " is corrupt, please " + "restart to redownload it.", "Error", JOptionPane.ERROR_MESSAGE);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -249,7 +270,8 @@ public class Boot {
|
|||
completedboot = true;
|
||||
}
|
||||
|
||||
public static File libsDir() {
|
||||
public static File libsDir()
|
||||
{
|
||||
File dir = new File(System.getProperty("user.home"), ".Bytecode-Viewer/libs");
|
||||
while (!dir.exists())
|
||||
dir.mkdirs();
|
||||
|
@ -263,7 +285,8 @@ public class Boot {
|
|||
screen.setTitle(s);
|
||||
}
|
||||
|
||||
public static ILoader<?> findLoader() {
|
||||
public static ILoader<?> findLoader()
|
||||
{
|
||||
// TODO: Find from providers
|
||||
// return new LibraryClassLoader();
|
||||
|
||||
|
@ -271,32 +294,39 @@ public class Boot {
|
|||
return AbstractLoaderFactory.find().spawnLoader();
|
||||
}
|
||||
|
||||
private static void bootstrap() {
|
||||
private static void bootstrap()
|
||||
{
|
||||
AbstractLoaderFactory.register(ClassPathLoader::new);
|
||||
}
|
||||
|
||||
public static void populateUrlList() throws Exception {
|
||||
public static void populateUrlList() throws Exception
|
||||
{
|
||||
HTTPRequest req = new HTTPRequest(new URL("https://github.com/Konloch/bytecode-viewer/tree/master/libs"));
|
||||
for (String s : req.read())
|
||||
if (s.contains("href=\"/Konloch/bytecode-viewer/blob/master/libs/")) {
|
||||
if (s.contains("href=\"/Konloch/bytecode-viewer/blob/master/libs/"))
|
||||
{
|
||||
urlList.add("https://github.com" + s.split("href=")[1].split("\"")[1]);
|
||||
}
|
||||
}
|
||||
|
||||
public static void populateLibsDirectory() {
|
||||
public static void populateLibsDirectory()
|
||||
{
|
||||
File libsDir = libsDir();
|
||||
if (libsDir.exists())
|
||||
for (File f : MiscUtils.listFiles(libsDir)) {
|
||||
for (File f : MiscUtils.listFiles(libsDir))
|
||||
{
|
||||
libsList.add(f.getName());
|
||||
libsFileList.add(f.getAbsolutePath());
|
||||
}
|
||||
}
|
||||
|
||||
public static void dropKrakatau() {
|
||||
public static void dropKrakatau()
|
||||
{
|
||||
File temp = new File(getBCVDirectory() + fs + "krakatau_" + krakatauVersion + ".zip");
|
||||
File krakatauDirectory = new File(krakatauWorkingDirectory);
|
||||
krakatauWorkingDirectory += fs + "Krakatau-master";
|
||||
if (!krakatauDirectory.exists() || temp.exists()) {
|
||||
if (!krakatauDirectory.exists() || temp.exists())
|
||||
{
|
||||
if (temp.exists())
|
||||
temp.delete();
|
||||
|
||||
|
@ -306,96 +336,110 @@ public class Boot {
|
|||
while (temp.exists())
|
||||
temp.delete();
|
||||
|
||||
try (InputStream is = BytecodeViewer.class.getClassLoader().getResourceAsStream("Krakatau-"
|
||||
+ krakatauVersion + ".zip");
|
||||
FileOutputStream baos = new FileOutputStream(temp)) {
|
||||
try (InputStream is = BytecodeViewer.class.getClassLoader().getResourceAsStream("Krakatau-" + krakatauVersion + ".zip"); FileOutputStream baos = new FileOutputStream(temp))
|
||||
{
|
||||
int r;
|
||||
byte[] buffer = new byte[8192];
|
||||
while ((r = Objects.requireNonNull(is).read(buffer)) >= 0) {
|
||||
while ((r = Objects.requireNonNull(is).read(buffer)) >= 0)
|
||||
{
|
||||
baos.write(buffer, 0, r);
|
||||
}
|
||||
|
||||
ZipUtils.unzipFilesToPath(temp.getAbsolutePath(), krakatauDirectory.getAbsolutePath());
|
||||
temp.delete();
|
||||
System.out.println("Successfully extracted Krakatau");
|
||||
} catch (Exception e) {
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
setState("Bytecode Viewer Boot Screen - ERROR, please contact @Konloch with your stacktrace.");
|
||||
BytecodeViewer.handleException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void dropEnjarify() {
|
||||
public static void dropEnjarify()
|
||||
{
|
||||
File temp = new File(getBCVDirectory() + fs + "enjarify" + Constants.enjarifyVersion + ".zip");
|
||||
File enjarifyDirectory = new File(Constants.enjarifyWorkingDirectory);
|
||||
Constants.enjarifyWorkingDirectory += fs + "enjarify-master";
|
||||
if (!enjarifyDirectory.exists() || temp.exists()) {
|
||||
if (!enjarifyDirectory.exists() || temp.exists())
|
||||
{
|
||||
if (temp.exists())
|
||||
temp.delete();
|
||||
|
||||
|
||||
setState("Bytecode Viewer Boot Screen - Extracting Enjarify");
|
||||
System.out.println("Extracting Enjarify");
|
||||
|
||||
while (temp.exists())
|
||||
temp.delete();
|
||||
|
||||
try (InputStream is = BytecodeViewer.class.getClassLoader().getResourceAsStream("enjarify-" +
|
||||
Constants.enjarifyVersion + ".zip");
|
||||
FileOutputStream baos = new FileOutputStream(temp)) {
|
||||
try (InputStream is = BytecodeViewer.class.getClassLoader().getResourceAsStream("enjarify-" + Constants.enjarifyVersion + ".zip"); FileOutputStream baos = new FileOutputStream(temp))
|
||||
{
|
||||
int r;
|
||||
byte[] buffer = new byte[8192];
|
||||
while ((r = Objects.requireNonNull(is).read(buffer)) >= 0) {
|
||||
while ((r = Objects.requireNonNull(is).read(buffer)) >= 0)
|
||||
{
|
||||
baos.write(buffer, 0, r);
|
||||
}
|
||||
|
||||
ZipUtils.unzipFilesToPath(temp.getAbsolutePath(), enjarifyDirectory.getAbsolutePath());
|
||||
temp.delete();
|
||||
System.out.println("Successfully extracted Enjarify");
|
||||
} catch (Exception e) {
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
setState("Bytecode Viewer Boot Screen - ERROR, please contact @Konloch with your stacktrace.");
|
||||
BytecodeViewer.handleException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void downloadZipsOnly() {
|
||||
for (String s : urlList) {
|
||||
String fileName = s.substring("https://github.com/Konloch/bytecode-viewer/blob/master/libs/".length()
|
||||
);
|
||||
public static void downloadZipsOnly()
|
||||
{
|
||||
for (String s : urlList)
|
||||
{
|
||||
String fileName = s.substring("https://github.com/Konloch/bytecode-viewer/blob/master/libs/".length());
|
||||
File file = new File(libsDir(), fileName);
|
||||
|
||||
boolean passed = false;
|
||||
while (!passed) {
|
||||
if (!libsList.contains(fileName) && fileName.endsWith(".zip")) {
|
||||
while (!passed)
|
||||
{
|
||||
if (!libsList.contains(fileName) && fileName.endsWith(".zip"))
|
||||
{
|
||||
downloading = true;
|
||||
setState("Bytecode Viewer Boot Screen - Downloading " + fileName + "...");
|
||||
System.out.println("Downloading " + fileName);
|
||||
|
||||
try (InputStream is = new URL("https://github.com/Konloch/bytecode-viewer/raw/master/libs/" + fileName)
|
||||
.openConnection().getInputStream();
|
||||
FileOutputStream fos = new FileOutputStream(file)) {
|
||||
try (InputStream is = new URL("https://github.com/Konloch/bytecode-viewer/raw/master/libs/" + fileName).openConnection().getInputStream(); FileOutputStream fos = new FileOutputStream(file))
|
||||
{
|
||||
System.out.println("Downloading from " + s);
|
||||
byte[] buffer = new byte[8192];
|
||||
int len;
|
||||
int downloaded = 0;
|
||||
boolean flag = false;
|
||||
while ((len = is.read(buffer)) > 0) {
|
||||
while ((len = is.read(buffer)) > 0)
|
||||
{
|
||||
fos.write(buffer, 0, len);
|
||||
fos.flush();
|
||||
downloaded += 8192;
|
||||
int mbs = downloaded / 1048576;
|
||||
if (mbs % 5 == 0 && mbs != 0) {
|
||||
if (mbs % 5 == 0 && mbs != 0)
|
||||
{
|
||||
if (!flag)
|
||||
System.out.println("Downloaded " + mbs + "MBs so far");
|
||||
flag = true;
|
||||
} else
|
||||
}
|
||||
else
|
||||
flag = false;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
try {
|
||||
try
|
||||
{
|
||||
setState("Bytecode Viewer Boot Screen - Verifying " + fileName + "...");
|
||||
System.out.println("Verifying " + fileName + "...");
|
||||
|
||||
|
@ -406,52 +450,64 @@ public class Boot {
|
|||
libsFileList.add(file.getAbsolutePath());
|
||||
System.out.println("Download finished!");
|
||||
passed = true;
|
||||
} catch (Exception e) {
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
System.out.println("Jar or Zip" + file.getAbsolutePath() + " is corrupt, redownloading.");
|
||||
file.delete();
|
||||
}
|
||||
} else
|
||||
}
|
||||
else
|
||||
passed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void checkEnjarify() {
|
||||
public static void checkEnjarify()
|
||||
{
|
||||
setState("Bytecode Viewer Boot Screen - Checking Enjarify...");
|
||||
System.out.println("Checking enjarify");
|
||||
File enjarifyZip = null;
|
||||
for (File f : MiscUtils.listFiles(new File(Constants.libsDirectory))) {
|
||||
if (f.getName().toLowerCase().startsWith("enjarify-")) {
|
||||
for (File f : MiscUtils.listFiles(new File(Constants.libsDirectory)))
|
||||
{
|
||||
if (f.getName().toLowerCase().startsWith("enjarify-"))
|
||||
{
|
||||
Constants.enjarifyVersion = f.getName().split("-")[1].split("\\.")[0];
|
||||
enjarifyZip = f;
|
||||
}
|
||||
}
|
||||
|
||||
for (File f : MiscUtils.listFiles(new File(getBCVDirectory()))) {
|
||||
if (f.getName().toLowerCase().startsWith("enjarify_") && !f.getName().split("_")[1].split("\\.")[0].equals(Constants.enjarifyVersion)) {
|
||||
for (File f : MiscUtils.listFiles(new File(getBCVDirectory())))
|
||||
{
|
||||
if (f.getName().toLowerCase().startsWith("enjarify_") && !f.getName().split("_")[1].split("\\.")[0].equals(Constants.enjarifyVersion))
|
||||
{
|
||||
setState("Bytecode Viewer Boot Screen - Removing Outdated " + f.getName() + "...");
|
||||
System.out.println("Removing oudated " + f.getName());
|
||||
try {
|
||||
try
|
||||
{
|
||||
FileUtils.deleteDirectory(f);
|
||||
} catch (Exception e) {
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Constants.enjarifyWorkingDirectory = getBCVDirectory() + fs + "enjarify_" + Constants.enjarifyVersion + fs + "enjarify-master";
|
||||
File enjarifyDirectory = new File(getBCVDirectory() + fs + "enjarify_" + Constants.enjarifyVersion);
|
||||
if (!enjarifyDirectory.exists()) {
|
||||
try {
|
||||
if (!enjarifyDirectory.exists())
|
||||
{
|
||||
try
|
||||
{
|
||||
setState("Bytecode Viewer Boot Screen - Updating to " + enjarifyDirectory.getName() + "...");
|
||||
ZipUtils.unzipFilesToPath(Objects.requireNonNull(enjarifyZip).getAbsolutePath(),
|
||||
enjarifyDirectory.getAbsolutePath());
|
||||
ZipUtils.unzipFilesToPath(Objects.requireNonNull(enjarifyZip).getAbsolutePath(), enjarifyDirectory.getAbsolutePath());
|
||||
System.out.println("Updated to enjarify v" + Constants.enjarifyVersion);
|
||||
} catch (Exception e) {
|
||||
BytecodeViewer.showMessage("ERROR: There was an issue unzipping enjarify (possibly corrupt). Restart "
|
||||
+ "BCV." + nl +
|
||||
"If the error persists contact @Konloch.");
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
BytecodeViewer.showMessage("ERROR: There was an issue unzipping enjarify (possibly corrupt). Restart " + "BCV." + nl + "If the error persists contact @Konloch.");
|
||||
BytecodeViewer.handleException(e);
|
||||
Objects.requireNonNull(enjarifyZip).delete();
|
||||
}
|
||||
|
@ -459,26 +515,34 @@ public class Boot {
|
|||
|
||||
}
|
||||
|
||||
public static void checkKrakatau() {
|
||||
public static void checkKrakatau()
|
||||
{
|
||||
setState("Bytecode Viewer Boot Screen - Checking Krakatau...");
|
||||
System.out.println("Checking krakatau");
|
||||
|
||||
File krakatauZip = null;
|
||||
for (File f : MiscUtils.listFiles(new File(Constants.libsDirectory))) {
|
||||
if (f.getName().toLowerCase().startsWith("krakatau-")) {
|
||||
for (File f : MiscUtils.listFiles(new File(Constants.libsDirectory)))
|
||||
{
|
||||
if (f.getName().toLowerCase().startsWith("krakatau-"))
|
||||
{
|
||||
//System.out.println(f.getName());
|
||||
Constants.krakatauVersion = f.getName().split("-")[1].split("\\.")[0];
|
||||
krakatauZip = f;
|
||||
}
|
||||
}
|
||||
|
||||
for (File f : MiscUtils.listFiles(new File(getBCVDirectory()))) {
|
||||
if (f.getName().toLowerCase().startsWith("krakatau_") && !f.getName().split("_")[1].split("\\.")[0].equals(Constants.krakatauVersion)) {
|
||||
for (File f : MiscUtils.listFiles(new File(getBCVDirectory())))
|
||||
{
|
||||
if (f.getName().toLowerCase().startsWith("krakatau_") && !f.getName().split("_")[1].split("\\.")[0].equals(Constants.krakatauVersion))
|
||||
{
|
||||
setState("Bytecode Viewer Boot Screen - Removing Outdated " + f.getName() + "...");
|
||||
System.out.println("Removing oudated " + f.getName());
|
||||
try {
|
||||
try
|
||||
{
|
||||
FileUtils.deleteDirectory(f);
|
||||
} catch (Exception e) {
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
@ -487,16 +551,17 @@ public class Boot {
|
|||
Constants.krakatauWorkingDirectory = getBCVDirectory() + fs + "krakatau_" + Constants.krakatauVersion + fs + "Krakatau-master";
|
||||
|
||||
File krakatauDirectory = new File(getBCVDirectory() + fs + "krakatau_" + Constants.krakatauVersion);
|
||||
if (!krakatauDirectory.exists()) {
|
||||
try {
|
||||
if (!krakatauDirectory.exists())
|
||||
{
|
||||
try
|
||||
{
|
||||
setState("Bytecode Viewer Boot Screen - Updating to " + krakatauDirectory.getName() + "...");
|
||||
ZipUtils.unzipFilesToPath(Objects.requireNonNull(krakatauZip).getAbsolutePath(),
|
||||
krakatauDirectory.getAbsolutePath());
|
||||
ZipUtils.unzipFilesToPath(Objects.requireNonNull(krakatauZip).getAbsolutePath(), krakatauDirectory.getAbsolutePath());
|
||||
System.out.println("Updated to krakatau v" + Constants.krakatauVersion);
|
||||
} catch (Exception e) {
|
||||
BytecodeViewer.showMessage("ERROR: There was an issue unzipping Krakatau decompiler (possibly "
|
||||
+ "corrupt). Restart BCV." + nl +
|
||||
"If the error persists contact @Konloch.");
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
BytecodeViewer.showMessage("ERROR: There was an issue unzipping Krakatau decompiler (possibly " + "corrupt). Restart BCV." + nl + "If the error persists contact @Konloch.");
|
||||
BytecodeViewer.handleException(e);
|
||||
Objects.requireNonNull(krakatauZip).delete();
|
||||
}
|
||||
|
|
|
@ -25,7 +25,5 @@ package the.bytecode.club.bytecodeviewer.bootloader;
|
|||
|
||||
public enum BootState
|
||||
{
|
||||
START_UP,
|
||||
SETTINGS_LOADED,
|
||||
GUI_SHOWING,
|
||||
START_UP, SETTINGS_LOADED, GUI_SHOWING,
|
||||
}
|
||||
|
|
|
@ -18,21 +18,16 @@
|
|||
|
||||
package the.bytecode.club.bytecodeviewer.bootloader;
|
||||
|
||||
import java.awt.Dimension;
|
||||
import java.awt.GridBagConstraints;
|
||||
import java.awt.GridBagLayout;
|
||||
import java.awt.Insets;
|
||||
import java.awt.Toolkit;
|
||||
import java.awt.event.WindowAdapter;
|
||||
import java.awt.event.WindowEvent;
|
||||
import java.io.IOException;
|
||||
import javax.swing.JFrame;
|
||||
import javax.swing.JProgressBar;
|
||||
import javax.swing.JScrollPane;
|
||||
import the.bytecode.club.bytecodeviewer.Configuration;
|
||||
import the.bytecode.club.bytecodeviewer.gui.components.HTMLPane;
|
||||
import the.bytecode.club.bytecodeviewer.resources.IconResources;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.awt.*;
|
||||
import java.awt.event.WindowAdapter;
|
||||
import java.awt.event.WindowEvent;
|
||||
import java.io.IOException;
|
||||
|
||||
import static the.bytecode.club.bytecodeviewer.Configuration.language;
|
||||
|
||||
/**
|
||||
|
@ -47,9 +42,11 @@ public class InitialBootScreen extends JFrame
|
|||
public InitialBootScreen() throws IOException
|
||||
{
|
||||
setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
|
||||
addWindowListener(new WindowAdapter() {
|
||||
addWindowListener(new WindowAdapter()
|
||||
{
|
||||
@Override
|
||||
public void windowClosing(WindowEvent e) {
|
||||
public void windowClosing(WindowEvent e)
|
||||
{
|
||||
Configuration.canExit = true;
|
||||
System.exit(0);
|
||||
}
|
||||
|
@ -74,7 +71,7 @@ public class InitialBootScreen extends JFrame
|
|||
gbc_scrollPane.gridx = 0;
|
||||
gbc_scrollPane.gridy = 0;
|
||||
getContentPane().add(scrollPane, gbc_scrollPane);
|
||||
|
||||
|
||||
scrollPane.setViewportView(HTMLPane.fromResource(language.getHTMLPath("intro")));
|
||||
|
||||
GridBagConstraints gbc_progressBar = new GridBagConstraints();
|
||||
|
@ -84,12 +81,12 @@ public class InitialBootScreen extends JFrame
|
|||
getContentPane().add(progressBar, gbc_progressBar);
|
||||
this.setLocationRelativeTo(null);
|
||||
}
|
||||
|
||||
|
||||
public static Dimension getSafeSize()
|
||||
{
|
||||
int i = (int) Toolkit.getDefaultToolkit().getScreenSize().getHeight();
|
||||
if (i >= 840)
|
||||
return new Dimension(600, 800);
|
||||
return new Dimension(600, 800);
|
||||
else if (i >= 640)
|
||||
return new Dimension(500, 600);
|
||||
else if (i >= 440)
|
||||
|
@ -98,9 +95,10 @@ public class InitialBootScreen extends JFrame
|
|||
return Toolkit.getDefaultToolkit().getScreenSize();
|
||||
}
|
||||
|
||||
public JProgressBar getProgressBar() {
|
||||
public JProgressBar getProgressBar()
|
||||
{
|
||||
return progressBar;
|
||||
}
|
||||
|
||||
|
||||
private static final long serialVersionUID = -1098467609722393444L;
|
||||
}
|
||||
|
|
|
@ -22,7 +22,7 @@ import static the.bytecode.club.bytecodeviewer.Constants.AUTOMATIC_LIBRARY_UPDAT
|
|||
|
||||
/**
|
||||
* Downloads & installs the krakatau & enjarify zips
|
||||
*
|
||||
* <p>
|
||||
* Alternatively if OFFLINE_MODE is enabled it will drop the Krakatau and Enjarify versions supplied with BCV
|
||||
*
|
||||
* @author Konloch
|
||||
|
@ -30,28 +30,28 @@ import static the.bytecode.club.bytecodeviewer.Constants.AUTOMATIC_LIBRARY_UPDAT
|
|||
*/
|
||||
public class InstallFatJar implements Runnable
|
||||
{
|
||||
@Override
|
||||
public void run()
|
||||
{
|
||||
try
|
||||
{
|
||||
if (AUTOMATIC_LIBRARY_UPDATING)
|
||||
{
|
||||
Boot.populateUrlList();
|
||||
Boot.populateLibsDirectory();
|
||||
Boot.downloadZipsOnly();
|
||||
Boot.checkKrakatau();
|
||||
Boot.checkEnjarify();
|
||||
}
|
||||
else
|
||||
{
|
||||
Boot.dropKrakatau();
|
||||
Boot.dropEnjarify();
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
@Override
|
||||
public void run()
|
||||
{
|
||||
try
|
||||
{
|
||||
if (AUTOMATIC_LIBRARY_UPDATING)
|
||||
{
|
||||
Boot.populateUrlList();
|
||||
Boot.populateLibsDirectory();
|
||||
Boot.downloadZipsOnly();
|
||||
Boot.checkKrakatau();
|
||||
Boot.checkEnjarify();
|
||||
}
|
||||
else
|
||||
{
|
||||
Boot.dropKrakatau();
|
||||
Boot.dropEnjarify();
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,17 +18,8 @@
|
|||
|
||||
package the.bytecode.club.bytecodeviewer.bootloader;
|
||||
|
||||
import de.skuzzle.semantic.Version;
|
||||
import java.awt.Desktop;
|
||||
import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.net.URI;
|
||||
import java.net.URL;
|
||||
import javax.swing.JFileChooser;
|
||||
import com.konloch.httprequest.HTTPRequest;
|
||||
import de.skuzzle.semantic.Version;
|
||||
import the.bytecode.club.bytecodeviewer.BytecodeViewer;
|
||||
import the.bytecode.club.bytecodeviewer.Configuration;
|
||||
import the.bytecode.club.bytecodeviewer.api.BCV;
|
||||
|
@ -36,6 +27,12 @@ import the.bytecode.club.bytecodeviewer.gui.components.FileChooser;
|
|||
import the.bytecode.club.bytecodeviewer.gui.components.MultipleChoiceDialog;
|
||||
import the.bytecode.club.bytecodeviewer.translation.TranslatedStrings;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.awt.*;
|
||||
import java.io.*;
|
||||
import java.net.URI;
|
||||
import java.net.URL;
|
||||
|
||||
import static the.bytecode.club.bytecodeviewer.Constants.VERSION;
|
||||
import static the.bytecode.club.bytecodeviewer.Constants.nl;
|
||||
|
||||
|
@ -44,170 +41,130 @@ import static the.bytecode.club.bytecodeviewer.Constants.nl;
|
|||
*/
|
||||
public class UpdateCheck implements Runnable
|
||||
{
|
||||
//just brute force download the url path
|
||||
//one of these works for every single version of BCV
|
||||
public static final String[] remoteGithubReleases = new String[]
|
||||
{
|
||||
//current url scheme since v2.9.12
|
||||
"https://github.com/Konloch/bytecode-viewer/releases/download/v{VERSION}/Bytecode-Viewer-{VERSION}.jar",
|
||||
//for v2.9.10 and v2.9.11
|
||||
"https://github.com/Konloch/bytecode-viewer/releases/download/{VERSION}/Bytecode-Viewer-{VERSION}.jar",
|
||||
//for v2.7.0 to v2.9.8
|
||||
"https://github.com/Konloch/bytecode-viewer/releases/download/v{VERSION}/BytecodeViewer.{VERSION}.zip",
|
||||
//for v2.0 to v2.6.0
|
||||
"https://github.com/Konloch/bytecode-viewer/releases/download/v{VERSION}/BytecodeViewer.{VERSION}.jar",
|
||||
//for v1.1 to v1.5.3
|
||||
"https://github.com/Konloch/bytecode-viewer/releases/download/b{VERSION}/BytecodeViewer.Beta.{VERSION}.jar",
|
||||
//for v1.4
|
||||
"https://github.com/Konloch/bytecode-viewer/releases/download/b.{VERSION}/BytecodeViewer.Beta.{VERSION}.jar",
|
||||
//for v1.0
|
||||
"https://github.com/Konloch/bytecode-viewer/releases/download/B{VERSION}/BytecodeViewer.jar",
|
||||
//zip variant of current url scheme since v2.9.12 (not currently used but incase it ever does)
|
||||
"https://github.com/Konloch/bytecode-viewer/releases/download/v{VERSION}/Bytecode-Viewer-{VERSION}.zip",
|
||||
};
|
||||
|
||||
//a list of all of the released versions of BCV
|
||||
public static final String[] versions = new String[]
|
||||
{
|
||||
//"2.11.0",
|
||||
//"2.10.15",
|
||||
"2.10.14",
|
||||
"2.10.13",
|
||||
"2.10.12",
|
||||
"2.10.11",
|
||||
"2.9.22",
|
||||
"2.9.21",
|
||||
"2.9.20",
|
||||
"2.9.19",
|
||||
"2.9.18",
|
||||
"2.9.17",
|
||||
"2.9.16",
|
||||
"2.9.15",
|
||||
"2.9.14",
|
||||
"2.9.13",
|
||||
"2.9.12",
|
||||
"2.9.11",
|
||||
"2.9.10", //broken due to repo change
|
||||
"2.9.8", //broken due to repo change & zip
|
||||
"2.9.7", //broken due to repo change & zip
|
||||
"2.9.6", //zip
|
||||
"2.9.5", //zip
|
||||
"2.9.4", //zip
|
||||
"2.9.3", //zip
|
||||
"2.9.2", //zip
|
||||
"2.9.1", //zip
|
||||
"2.9.0", //zip
|
||||
"2.8.1", //zip
|
||||
"2.8.0", //zip
|
||||
"2.7.1", //zip
|
||||
"2.7.0", //zip
|
||||
"2.6.0",
|
||||
"2.5.2",
|
||||
"2.5.1",
|
||||
"2.5.0",
|
||||
"2.4.0",
|
||||
"2.3.0",
|
||||
"2.2.1",
|
||||
"2.2.0",
|
||||
"2.1.1",
|
||||
"2.1.0",
|
||||
"2.0.1",
|
||||
"2.0",
|
||||
"1.5.3",
|
||||
"1.5.2",
|
||||
"1.5.1",
|
||||
"1.5",
|
||||
"1.4",
|
||||
"1.3.1",
|
||||
"1.3",
|
||||
"1.2",
|
||||
"1.1",
|
||||
"1.0",
|
||||
};
|
||||
|
||||
@Override
|
||||
public void run()
|
||||
{
|
||||
try {
|
||||
HTTPRequest r = new HTTPRequest(new URL("https://raw.githubusercontent.com/Konloch/bytecode-viewer/master/VERSION"));
|
||||
final Version version = Version.parseVersion(r.readSingle());
|
||||
final Version localVersion = Version.parseVersion(VERSION);
|
||||
|
||||
try {
|
||||
//developer version
|
||||
if (Version.compare(localVersion, version) > 0)
|
||||
return;
|
||||
} catch (Exception ignored) { }
|
||||
|
||||
MultipleChoiceDialog outdatedDialog = new MultipleChoiceDialog("Bytecode Viewer - Outdated Version",
|
||||
"Your version: " + localVersion + ", latest version: " + version + nl +
|
||||
"What would you like to do?",
|
||||
new String[]{"Open The Download Page", "Download The Updated Jar", "Do Nothing (And Don't Ask Again)"});
|
||||
|
||||
int result = outdatedDialog.promptChoice();
|
||||
|
||||
if (result == 0)
|
||||
{
|
||||
if (Desktop.isDesktopSupported())
|
||||
Desktop.getDesktop().browse(new URI("https://github.com/Konloch/bytecode-viewer/releases"));
|
||||
else
|
||||
BytecodeViewer.showMessage("Cannot open the page, please manually type it."
|
||||
+ nl + "https://github.com/Konloch/bytecode-viewer/releases");
|
||||
}
|
||||
else if (result == 1)
|
||||
{
|
||||
//TODO move this to after the file extension has been found
|
||||
final File file = promptFileSave("Jar Archives", "jar");
|
||||
|
||||
if(file != null)
|
||||
{
|
||||
Thread downloadThread = new Thread(() ->
|
||||
downloadBCV(version.toString(), file, ()->{}, ()->{}), "Downloader");
|
||||
downloadThread.start();
|
||||
}
|
||||
}
|
||||
else if(result == 2)
|
||||
{
|
||||
//TODO save version into a hashset called doNotPrompt
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public static File promptFileSave(String description, String extension) throws IOException
|
||||
{
|
||||
JFileChooser fc = new FileChooser(new File("./").getCanonicalFile(),
|
||||
"Select Save File", description, extension);
|
||||
|
||||
int returnVal = fc.showSaveDialog(BytecodeViewer.viewer);
|
||||
File file = null;
|
||||
if (returnVal == JFileChooser.APPROVE_OPTION)
|
||||
{
|
||||
Configuration.setLastOpenDirectory(fc.getSelectedFile());
|
||||
|
||||
file = fc.getSelectedFile();
|
||||
String nameLowercase = file.getAbsolutePath().toLowerCase();
|
||||
if (!nameLowercase.endsWith(".jar"))
|
||||
file = new File(file.getAbsolutePath() + ".jar");
|
||||
|
||||
if (file.exists())
|
||||
{
|
||||
MultipleChoiceDialog overwriteDialog = new MultipleChoiceDialog("Bytecode Viewer - Overwrite File",
|
||||
"The file " + file + " exists, would you like to overwrite it?",
|
||||
new String[]{TranslatedStrings.YES.toString(), TranslatedStrings.NO.toString()});
|
||||
|
||||
if (overwriteDialog.promptChoice() != 0)
|
||||
return null;
|
||||
|
||||
file.delete();
|
||||
}
|
||||
}
|
||||
|
||||
return file;
|
||||
}
|
||||
|
||||
//used to download all released versions of BCV
|
||||
//just brute force download the url path
|
||||
//one of these works for every single version of BCV
|
||||
public static final String[] remoteGithubReleases = new String[]{
|
||||
//current url scheme since v2.9.12
|
||||
"https://github.com/Konloch/bytecode-viewer/releases/download/v{VERSION}/Bytecode-Viewer-{VERSION}.jar",
|
||||
//for v2.9.10 and v2.9.11
|
||||
"https://github.com/Konloch/bytecode-viewer/releases/download/{VERSION}/Bytecode-Viewer-{VERSION}.jar",
|
||||
//for v2.7.0 to v2.9.8
|
||||
"https://github.com/Konloch/bytecode-viewer/releases/download/v{VERSION}/BytecodeViewer.{VERSION}.zip",
|
||||
//for v2.0 to v2.6.0
|
||||
"https://github.com/Konloch/bytecode-viewer/releases/download/v{VERSION}/BytecodeViewer.{VERSION}.jar",
|
||||
//for v1.1 to v1.5.3
|
||||
"https://github.com/Konloch/bytecode-viewer/releases/download/b{VERSION}/BytecodeViewer.Beta.{VERSION}.jar",
|
||||
//for v1.4
|
||||
"https://github.com/Konloch/bytecode-viewer/releases/download/b.{VERSION}/BytecodeViewer.Beta.{VERSION}.jar",
|
||||
//for v1.0
|
||||
"https://github.com/Konloch/bytecode-viewer/releases/download/B{VERSION}/BytecodeViewer.jar",
|
||||
//zip variant of current url scheme since v2.9.12 (not currently used but incase it ever does)
|
||||
"https://github.com/Konloch/bytecode-viewer/releases/download/v{VERSION}/Bytecode-Viewer-{VERSION}.zip",};
|
||||
|
||||
//a list of all of the released versions of BCV
|
||||
public static final String[] versions = new String[]{
|
||||
//"2.11.0",
|
||||
//"2.10.15",
|
||||
"2.10.14", "2.10.13", "2.10.12", "2.10.11", "2.9.22", "2.9.21", "2.9.20", "2.9.19", "2.9.18", "2.9.17", "2.9.16", "2.9.15", "2.9.14", "2.9.13", "2.9.12", "2.9.11", "2.9.10", //broken due to repo change
|
||||
"2.9.8", //broken due to repo change & zip
|
||||
"2.9.7", //broken due to repo change & zip
|
||||
"2.9.6", //zip
|
||||
"2.9.5", //zip
|
||||
"2.9.4", //zip
|
||||
"2.9.3", //zip
|
||||
"2.9.2", //zip
|
||||
"2.9.1", //zip
|
||||
"2.9.0", //zip
|
||||
"2.8.1", //zip
|
||||
"2.8.0", //zip
|
||||
"2.7.1", //zip
|
||||
"2.7.0", //zip
|
||||
"2.6.0", "2.5.2", "2.5.1", "2.5.0", "2.4.0", "2.3.0", "2.2.1", "2.2.0", "2.1.1", "2.1.0", "2.0.1", "2.0", "1.5.3", "1.5.2", "1.5.1", "1.5", "1.4", "1.3.1", "1.3", "1.2", "1.1", "1.0",};
|
||||
|
||||
@Override
|
||||
public void run()
|
||||
{
|
||||
try
|
||||
{
|
||||
HTTPRequest r = new HTTPRequest(new URL("https://raw.githubusercontent.com/Konloch/bytecode-viewer/master/VERSION"));
|
||||
final Version version = Version.parseVersion(r.readSingle());
|
||||
final Version localVersion = Version.parseVersion(VERSION);
|
||||
|
||||
try
|
||||
{
|
||||
//developer version
|
||||
if (Version.compare(localVersion, version) > 0)
|
||||
return;
|
||||
}
|
||||
catch (Exception ignored)
|
||||
{
|
||||
}
|
||||
|
||||
MultipleChoiceDialog outdatedDialog = new MultipleChoiceDialog("Bytecode Viewer - Outdated Version", "Your version: " + localVersion + ", latest version: " + version + nl + "What would you like to do?", new String[]{"Open The Download Page", "Download The Updated Jar", "Do Nothing (And Don't Ask Again)"});
|
||||
|
||||
int result = outdatedDialog.promptChoice();
|
||||
|
||||
if (result == 0)
|
||||
{
|
||||
if (Desktop.isDesktopSupported())
|
||||
Desktop.getDesktop().browse(new URI("https://github.com/Konloch/bytecode-viewer/releases"));
|
||||
else
|
||||
BytecodeViewer.showMessage("Cannot open the page, please manually type it." + nl + "https://github.com/Konloch/bytecode-viewer/releases");
|
||||
}
|
||||
else if (result == 1)
|
||||
{
|
||||
//TODO move this to after the file extension has been found
|
||||
final File file = promptFileSave("Jar Archives", "jar");
|
||||
|
||||
if (file != null)
|
||||
{
|
||||
Thread downloadThread = new Thread(() -> downloadBCV(version.toString(), file, () ->
|
||||
{}, () ->
|
||||
{}), "Downloader");
|
||||
downloadThread.start();
|
||||
}
|
||||
}
|
||||
else if (result == 2)
|
||||
{
|
||||
//TODO save version into a hashset called doNotPrompt
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public static File promptFileSave(String description, String extension) throws IOException
|
||||
{
|
||||
JFileChooser fc = new FileChooser(new File("./").getCanonicalFile(), "Select Save File", description, extension);
|
||||
|
||||
int returnVal = fc.showSaveDialog(BytecodeViewer.viewer);
|
||||
File file = null;
|
||||
if (returnVal == JFileChooser.APPROVE_OPTION)
|
||||
{
|
||||
Configuration.setLastOpenDirectory(fc.getSelectedFile());
|
||||
|
||||
file = fc.getSelectedFile();
|
||||
String nameLowercase = file.getAbsolutePath().toLowerCase();
|
||||
if (!nameLowercase.endsWith(".jar"))
|
||||
file = new File(file.getAbsolutePath() + ".jar");
|
||||
|
||||
if (file.exists())
|
||||
{
|
||||
MultipleChoiceDialog overwriteDialog = new MultipleChoiceDialog("Bytecode Viewer - Overwrite File", "The file " + file + " exists, would you like to overwrite it?", new String[]{TranslatedStrings.YES.toString(), TranslatedStrings.NO.toString()});
|
||||
|
||||
if (overwriteDialog.promptChoice() != 0)
|
||||
return null;
|
||||
|
||||
file.delete();
|
||||
}
|
||||
}
|
||||
|
||||
return file;
|
||||
}
|
||||
|
||||
//used to download all released versions of BCV
|
||||
/*public static void main(String[] args)
|
||||
{
|
||||
BytecodeViewer.viewer = new MainViewerGUI();
|
||||
|
@ -219,79 +176,83 @@ public class UpdateCheck implements Runnable
|
|||
downloadBCV(version, file, () -> {}, () -> {});
|
||||
}
|
||||
}*/
|
||||
|
||||
private static void downloadBCV(String version, File saveTo, Runnable onFinish, Runnable onFail)
|
||||
{
|
||||
boolean found = false;
|
||||
for(String urlAttempt : remoteGithubReleases)
|
||||
{
|
||||
try
|
||||
{
|
||||
String url = urlAttempt.replace("{VERSION}", version);
|
||||
|
||||
if(validURl(url))
|
||||
{
|
||||
download(url, saveTo, onFinish);
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
|
||||
} catch (FileNotFoundException ex) {
|
||||
//ignore 404s
|
||||
} catch (Exception e) {
|
||||
//print network errors but don't alert user
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
if(!found)
|
||||
{
|
||||
BCV.logE("Failed to download BCV v" + version);
|
||||
BytecodeViewer.showMessage("Unable to download BCV v" + version + ", please let Konloch know.");
|
||||
onFail.run();
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean validURl(String url) throws Exception
|
||||
{
|
||||
HTTPRequest request = new HTTPRequest(new URL(url));
|
||||
request.readSingle();
|
||||
return request.getLastStatusCode() == 200;
|
||||
}
|
||||
|
||||
private static void download(String url, File saveTo, Runnable onFinish) throws Exception
|
||||
{
|
||||
BCV.log("Downloading from: " + url);
|
||||
BytecodeViewer.showMessage("Downloading the jar in the background, when it's finished you will be alerted with another message box."
|
||||
+ nl + nl + "Expect this to take several minutes.");
|
||||
|
||||
try (InputStream is = new URL(url).openConnection().getInputStream();
|
||||
FileOutputStream fos = new FileOutputStream(saveTo)) {
|
||||
byte[] buffer = new byte[8192];
|
||||
int len;
|
||||
int downloaded = 0;
|
||||
boolean flag = false;
|
||||
|
||||
while ((len = is.read(buffer)) > 0)
|
||||
{
|
||||
fos.write(buffer, 0, len);
|
||||
fos.flush();
|
||||
|
||||
downloaded += 8192;
|
||||
int mbs = downloaded / 1048576;
|
||||
if (mbs % 5 == 0 && mbs != 0)
|
||||
{
|
||||
if (!flag)
|
||||
System.out.println("Downloaded " + mbs + "MBs so far");
|
||||
flag = true;
|
||||
} else
|
||||
flag = false;
|
||||
}
|
||||
}
|
||||
|
||||
BCV.log("Download finished!");
|
||||
BytecodeViewer.showMessage("Download successful! You can find the updated program at " + saveTo.getAbsolutePath());
|
||||
|
||||
onFinish.run();
|
||||
}
|
||||
private static void downloadBCV(String version, File saveTo, Runnable onFinish, Runnable onFail)
|
||||
{
|
||||
boolean found = false;
|
||||
for (String urlAttempt : remoteGithubReleases)
|
||||
{
|
||||
try
|
||||
{
|
||||
String url = urlAttempt.replace("{VERSION}", version);
|
||||
|
||||
if (validURl(url))
|
||||
{
|
||||
download(url, saveTo, onFinish);
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
catch (FileNotFoundException ex)
|
||||
{
|
||||
//ignore 404s
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
//print network errors but don't alert user
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
if (!found)
|
||||
{
|
||||
BCV.logE("Failed to download BCV v" + version);
|
||||
BytecodeViewer.showMessage("Unable to download BCV v" + version + ", please let Konloch know.");
|
||||
onFail.run();
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean validURl(String url) throws Exception
|
||||
{
|
||||
HTTPRequest request = new HTTPRequest(new URL(url));
|
||||
request.readSingle();
|
||||
return request.getLastStatusCode() == 200;
|
||||
}
|
||||
|
||||
private static void download(String url, File saveTo, Runnable onFinish) throws Exception
|
||||
{
|
||||
BCV.log("Downloading from: " + url);
|
||||
BytecodeViewer.showMessage("Downloading the jar in the background, when it's finished you will be alerted with another message box." + nl + nl + "Expect this to take several minutes.");
|
||||
|
||||
try (InputStream is = new URL(url).openConnection().getInputStream(); FileOutputStream fos = new FileOutputStream(saveTo))
|
||||
{
|
||||
byte[] buffer = new byte[8192];
|
||||
int len;
|
||||
int downloaded = 0;
|
||||
boolean flag = false;
|
||||
|
||||
while ((len = is.read(buffer)) > 0)
|
||||
{
|
||||
fos.write(buffer, 0, len);
|
||||
fos.flush();
|
||||
|
||||
downloaded += 8192;
|
||||
int mbs = downloaded / 1048576;
|
||||
if (mbs % 5 == 0 && mbs != 0)
|
||||
{
|
||||
if (!flag)
|
||||
System.out.println("Downloaded " + mbs + "MBs so far");
|
||||
flag = true;
|
||||
}
|
||||
else
|
||||
flag = false;
|
||||
}
|
||||
}
|
||||
|
||||
BCV.log("Download finished!");
|
||||
BytecodeViewer.showMessage("Download successful! You can find the updated program at " + saveTo.getAbsolutePath());
|
||||
|
||||
onFinish.run();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,32 +18,38 @@
|
|||
|
||||
package the.bytecode.club.bytecodeviewer.bootloader.classtree;
|
||||
|
||||
import org.objectweb.asm.tree.ClassNode;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import org.objectweb.asm.tree.ClassNode;
|
||||
|
||||
/**
|
||||
* @author Bibl (don't ban me pls)
|
||||
* @since 25 May 2015 (actually before this)
|
||||
*/
|
||||
public class ClassHelper {
|
||||
public class ClassHelper
|
||||
{
|
||||
|
||||
public static Map<String, ClassNode> convertToMap(Collection<ClassNode> classes) {
|
||||
public static Map<String, ClassNode> convertToMap(Collection<ClassNode> classes)
|
||||
{
|
||||
Map<String, ClassNode> map = new HashMap<>();
|
||||
for (ClassNode cn : classes) {
|
||||
for (ClassNode cn : classes)
|
||||
{
|
||||
map.put(cn.name, cn);
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
public static <T, K> Map<T, K> copyOf(Map<T, K> src) {
|
||||
public static <T, K> Map<T, K> copyOf(Map<T, K> src)
|
||||
{
|
||||
Map<T, K> dst = new HashMap<>();
|
||||
copy(src, dst);
|
||||
return dst;
|
||||
}
|
||||
|
||||
public static <T, K> void copy(Map<T, K> src, Map<T, K> dst) {
|
||||
public static <T, K> void copy(Map<T, K> src, Map<T, K> dst)
|
||||
{
|
||||
dst.putAll(src);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,17 +18,13 @@
|
|||
|
||||
package the.bytecode.club.bytecodeviewer.bootloader.classtree;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import org.objectweb.asm.tree.ClassNode;
|
||||
import org.objectweb.asm.tree.MethodNode;
|
||||
import the.bytecode.club.bytecodeviewer.bootloader.classtree.nullpermablehashmap.NullPermeableHashMap;
|
||||
import the.bytecode.club.bytecodeviewer.bootloader.classtree.nullpermablehashmap.SetCreator;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
import static the.bytecode.club.bytecodeviewer.bootloader.classtree.ClassHelper.convertToMap;
|
||||
import static the.bytecode.club.bytecodeviewer.bootloader.classtree.ClassHelper.copyOf;
|
||||
|
||||
|
@ -36,24 +32,28 @@ import static the.bytecode.club.bytecodeviewer.bootloader.classtree.ClassHelper.
|
|||
* @author Bibl (don't ban me pls)
|
||||
* @since 25 May 2015 (actually before this)
|
||||
*/
|
||||
public class ClassTree {
|
||||
public class ClassTree
|
||||
{
|
||||
private static final SetCreator<ClassNode> SET_CREATOR = new SetCreator<>();
|
||||
|
||||
private final Map<String, ClassNode> classes;
|
||||
private final NullPermeableHashMap<ClassNode, Set<ClassNode>> supers;
|
||||
private final NullPermeableHashMap<ClassNode, Set<ClassNode>> delgates;
|
||||
|
||||
public ClassTree() {
|
||||
public ClassTree()
|
||||
{
|
||||
classes = new HashMap<>();
|
||||
supers = new NullPermeableHashMap<>(SET_CREATOR);
|
||||
delgates = new NullPermeableHashMap<>(SET_CREATOR);
|
||||
}
|
||||
|
||||
public ClassTree(Collection<ClassNode> classes) {
|
||||
public ClassTree(Collection<ClassNode> classes)
|
||||
{
|
||||
this(convertToMap(classes));
|
||||
}
|
||||
|
||||
public ClassTree(Map<String, ClassNode> classes_) {
|
||||
public ClassTree(Map<String, ClassNode> classes_)
|
||||
{
|
||||
classes = copyOf(classes_);
|
||||
supers = new NullPermeableHashMap<>(SET_CREATOR);
|
||||
delgates = new NullPermeableHashMap<>(SET_CREATOR);
|
||||
|
@ -62,9 +62,12 @@ public class ClassTree {
|
|||
}
|
||||
|
||||
// TODO: optimise
|
||||
public void build(Map<String, ClassNode> classes) {
|
||||
for (ClassNode node : classes.values()) {
|
||||
for (String iface : node.interfaces) {
|
||||
public void build(Map<String, ClassNode> classes)
|
||||
{
|
||||
for (ClassNode node : classes.values())
|
||||
{
|
||||
for (String iface : node.interfaces)
|
||||
{
|
||||
ClassNode ifacecs = classes.get(iface);
|
||||
if (ifacecs == null)
|
||||
continue;
|
||||
|
@ -77,10 +80,12 @@ public class ClassTree {
|
|||
getSupers0(node).addAll(superinterfaces);
|
||||
}
|
||||
ClassNode currentSuper = classes.get(node.superName);
|
||||
while (currentSuper != null) {
|
||||
while (currentSuper != null)
|
||||
{
|
||||
getDelegates0(currentSuper).add(node);
|
||||
getSupers0(node).add(currentSuper);
|
||||
for (String iface : currentSuper.interfaces) {
|
||||
for (String iface : currentSuper.interfaces)
|
||||
{
|
||||
ClassNode ifacecs = classes.get(iface);
|
||||
if (ifacecs == null)
|
||||
continue;
|
||||
|
@ -98,8 +103,10 @@ public class ClassTree {
|
|||
}
|
||||
}
|
||||
|
||||
public void build(ClassNode node) {
|
||||
for (String iface : node.interfaces) {
|
||||
public void build(ClassNode node)
|
||||
{
|
||||
for (String iface : node.interfaces)
|
||||
{
|
||||
ClassNode ifacecs = classes.get(iface);
|
||||
if (ifacecs == null)
|
||||
continue;
|
||||
|
@ -112,10 +119,12 @@ public class ClassTree {
|
|||
getSupers0(node).addAll(superinterfaces);
|
||||
}
|
||||
ClassNode currentSuper = classes.get(node.superName);
|
||||
while (currentSuper != null) {
|
||||
while (currentSuper != null)
|
||||
{
|
||||
getDelegates0(currentSuper).add(node);
|
||||
getSupers0(node).add(currentSuper);
|
||||
for (String iface : currentSuper.interfaces) {
|
||||
for (String iface : currentSuper.interfaces)
|
||||
{
|
||||
ClassNode ifacecs = classes.get(iface);
|
||||
if (ifacecs == null)
|
||||
continue;
|
||||
|
@ -134,12 +143,14 @@ public class ClassTree {
|
|||
classes.put(node.name, node);
|
||||
}
|
||||
|
||||
private void buildSubTree(Map<String, ClassNode> classes, Collection<ClassNode> superinterfaces,
|
||||
ClassNode current) {
|
||||
private void buildSubTree(Map<String, ClassNode> classes, Collection<ClassNode> superinterfaces, ClassNode current)
|
||||
{
|
||||
superinterfaces.add(current);
|
||||
for (String iface : current.interfaces) {
|
||||
for (String iface : current.interfaces)
|
||||
{
|
||||
ClassNode cs = classes.get(iface);
|
||||
if (cs != null) {
|
||||
if (cs != null)
|
||||
{
|
||||
getDelegates0(cs).add(current);
|
||||
buildSubTree(classes, superinterfaces, cs);
|
||||
} /*else {
|
||||
|
@ -148,11 +159,15 @@ public class ClassTree {
|
|||
}
|
||||
}
|
||||
|
||||
public Set<MethodNode> getMethodsFromSuper(ClassNode node, String name, String desc) {
|
||||
public Set<MethodNode> getMethodsFromSuper(ClassNode node, String name, String desc)
|
||||
{
|
||||
Set<MethodNode> methods = new HashSet<>();
|
||||
for (ClassNode super_ : getSupers(node)) {
|
||||
for (MethodNode mn : super_.methods) {
|
||||
if (mn.name.equals(name) && mn.desc.equals(desc)) {
|
||||
for (ClassNode super_ : getSupers(node))
|
||||
{
|
||||
for (MethodNode mn : super_.methods)
|
||||
{
|
||||
if (mn.name.equals(name) && mn.desc.equals(desc))
|
||||
{
|
||||
methods.add(mn);
|
||||
}
|
||||
}
|
||||
|
@ -160,11 +175,15 @@ public class ClassTree {
|
|||
return methods;
|
||||
}
|
||||
|
||||
public Set<MethodNode> getMethodsFromDelegates(ClassNode node, String name, String desc) {
|
||||
public Set<MethodNode> getMethodsFromDelegates(ClassNode node, String name, String desc)
|
||||
{
|
||||
Set<MethodNode> methods = new HashSet<>();
|
||||
for (ClassNode delegate : getDelegates(node)) {
|
||||
for (MethodNode mn : delegate.methods) {
|
||||
if (mn.name.equals(name) && mn.desc.equals(desc)) {
|
||||
for (ClassNode delegate : getDelegates(node))
|
||||
{
|
||||
for (MethodNode mn : delegate.methods)
|
||||
{
|
||||
if (mn.name.equals(name) && mn.desc.equals(desc))
|
||||
{
|
||||
methods.add(mn);
|
||||
}
|
||||
}
|
||||
|
@ -172,10 +191,14 @@ public class ClassTree {
|
|||
return methods;
|
||||
}
|
||||
|
||||
public MethodNode getFirstMethodFromSuper(ClassNode node, String name, String desc) {
|
||||
for (ClassNode super_ : getSupers(node)) {
|
||||
for (MethodNode mn : super_.methods) {
|
||||
if (mn.name.equals(name) && mn.desc.equals(desc)) {
|
||||
public MethodNode getFirstMethodFromSuper(ClassNode node, String name, String desc)
|
||||
{
|
||||
for (ClassNode super_ : getSupers(node))
|
||||
{
|
||||
for (MethodNode mn : super_.methods)
|
||||
{
|
||||
if (mn.name.equals(name) && mn.desc.equals(desc))
|
||||
{
|
||||
return mn;
|
||||
}
|
||||
}
|
||||
|
@ -183,33 +206,40 @@ public class ClassTree {
|
|||
return null;
|
||||
}
|
||||
|
||||
public ClassNode getClass(String name) {
|
||||
public ClassNode getClass(String name)
|
||||
{
|
||||
return classes.get(name);
|
||||
}
|
||||
|
||||
public boolean isInherited(ClassNode cn, String name, String desc) {
|
||||
public boolean isInherited(ClassNode cn, String name, String desc)
|
||||
{
|
||||
return getFirstMethodFromSuper(cn, name, desc) != null;
|
||||
}
|
||||
|
||||
private Set<ClassNode> getSupers0(ClassNode cn) {
|
||||
private Set<ClassNode> getSupers0(ClassNode cn)
|
||||
{
|
||||
return supers.getNonNull(cn);
|
||||
}
|
||||
|
||||
private Set<ClassNode> getDelegates0(ClassNode cn) {
|
||||
private Set<ClassNode> getDelegates0(ClassNode cn)
|
||||
{
|
||||
return delgates.getNonNull(cn);
|
||||
}
|
||||
|
||||
public Map<String, ClassNode> getClasses() {
|
||||
public Map<String, ClassNode> getClasses()
|
||||
{
|
||||
return classes;
|
||||
}
|
||||
|
||||
public Set<ClassNode> getSupers(ClassNode cn) {
|
||||
public Set<ClassNode> getSupers(ClassNode cn)
|
||||
{
|
||||
return Collections.unmodifiableSet(supers.get(cn));
|
||||
// return supers.get(cn);
|
||||
}
|
||||
|
||||
public Set<ClassNode> getDelegates(ClassNode cn) {
|
||||
public Set<ClassNode> getDelegates(ClassNode cn)
|
||||
{
|
||||
return Collections.unmodifiableSet(delgates.get(cn));
|
||||
// return delgates.get(cn);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,10 +22,12 @@ package the.bytecode.club.bytecodeviewer.bootloader.classtree.nullpermablehashma
|
|||
* @author Bibl (don't ban me pls)
|
||||
* @since ages ago
|
||||
*/
|
||||
public class NullCreator<V> implements ValueCreator<V> {
|
||||
public class NullCreator<V> implements ValueCreator<V>
|
||||
{
|
||||
|
||||
@Override
|
||||
public V create() {
|
||||
public V create()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -24,26 +24,31 @@ import java.util.HashMap;
|
|||
* @author Bibl (don't ban me pls)
|
||||
* @since ages ago
|
||||
*/
|
||||
public class NullPermeableHashMap<K, V> extends HashMap<K, V> {
|
||||
public class NullPermeableHashMap<K, V> extends HashMap<K, V>
|
||||
{
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private final ValueCreator<V> creator;
|
||||
|
||||
public NullPermeableHashMap(ValueCreator<V> creator) {
|
||||
public NullPermeableHashMap(ValueCreator<V> creator)
|
||||
{
|
||||
this.creator = creator;
|
||||
}
|
||||
|
||||
public NullPermeableHashMap() {
|
||||
public NullPermeableHashMap()
|
||||
{
|
||||
this(new NullCreator<>());
|
||||
}
|
||||
|
||||
public V getNonNull(K k) {
|
||||
public V getNonNull(K k)
|
||||
{
|
||||
V val = get(k);
|
||||
if (val == null) {
|
||||
if (val == null)
|
||||
{
|
||||
val = creator.create();
|
||||
put(k, val);
|
||||
}
|
||||
return val;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -25,10 +25,12 @@ import java.util.Set;
|
|||
* @author Bibl (don't ban me pls)
|
||||
* @since 25 May 2015 (actually before this)
|
||||
*/
|
||||
public class SetCreator<T> implements ValueCreator<Set<T>> {
|
||||
public class SetCreator<T> implements ValueCreator<Set<T>>
|
||||
{
|
||||
|
||||
@Override
|
||||
public Set<T> create() {
|
||||
public Set<T> create()
|
||||
{
|
||||
return new HashSet<>();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,7 +22,8 @@ package the.bytecode.club.bytecodeviewer.bootloader.classtree.nullpermablehashma
|
|||
* @author Bibl (don't ban me pls)
|
||||
* @since ages ago
|
||||
*/
|
||||
public interface ValueCreator<V> {
|
||||
public interface ValueCreator<V>
|
||||
{
|
||||
|
||||
V create();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,61 +18,74 @@
|
|||
|
||||
package the.bytecode.club.bytecodeviewer.bootloader.loader;
|
||||
|
||||
import the.bytecode.club.bytecodeviewer.bootloader.resource.external.ExternalResource;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import the.bytecode.club.bytecodeviewer.bootloader.resource.external.ExternalResource;
|
||||
|
||||
/**
|
||||
* @author Bibl (don't ban me pls)
|
||||
* @since 21 Jul 2015 00:18:07
|
||||
*/
|
||||
public final class AbstractLoaderFactory {
|
||||
public final class AbstractLoaderFactory
|
||||
{
|
||||
|
||||
private static final String DEFAULT_KEY = "default-factory";
|
||||
private static final Map<String, LoaderFactory<?>> FACTORY_CACHE = new HashMap<>();
|
||||
|
||||
public static void register(LoaderFactory<?> factory) {
|
||||
public static void register(LoaderFactory<?> factory)
|
||||
{
|
||||
register(DEFAULT_KEY, factory);
|
||||
}
|
||||
|
||||
public static void register(String key, LoaderFactory<?> factory) {
|
||||
if (key == null || factory == null) {
|
||||
public static void register(String key, LoaderFactory<?> factory)
|
||||
{
|
||||
if (key == null || factory == null)
|
||||
{
|
||||
throw new IllegalArgumentException("null key or factory");
|
||||
}
|
||||
|
||||
if (FACTORY_CACHE.containsKey(key)) {
|
||||
if (FACTORY_CACHE.containsKey(key))
|
||||
{
|
||||
throw new IllegalArgumentException("factory already registered with key: " + key);
|
||||
}
|
||||
|
||||
FACTORY_CACHE.put(key, factory);
|
||||
}
|
||||
|
||||
public static void unregister(String key) {
|
||||
if (key == null) {
|
||||
public static void unregister(String key)
|
||||
{
|
||||
if (key == null)
|
||||
{
|
||||
throw new IllegalArgumentException("null key");
|
||||
}
|
||||
|
||||
if (!FACTORY_CACHE.containsKey(key)) {
|
||||
if (!FACTORY_CACHE.containsKey(key))
|
||||
{
|
||||
throw new IllegalArgumentException("factory doesn't key for key: " + key);
|
||||
}
|
||||
|
||||
FACTORY_CACHE.remove(key);
|
||||
}
|
||||
|
||||
public static <T extends ExternalResource<?>> LoaderFactory<T> find() {
|
||||
public static <T extends ExternalResource<?>> LoaderFactory<T> find()
|
||||
{
|
||||
return find(DEFAULT_KEY);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public static <T extends ExternalResource<?>> LoaderFactory<T> find(String key) {
|
||||
if (key == null) {
|
||||
public static <T extends ExternalResource<?>> LoaderFactory<T> find(String key)
|
||||
{
|
||||
if (key == null)
|
||||
{
|
||||
throw new IllegalArgumentException("null key");
|
||||
}
|
||||
|
||||
if (!FACTORY_CACHE.containsKey(key)) {
|
||||
if (!FACTORY_CACHE.containsKey(key))
|
||||
{
|
||||
throw new IllegalArgumentException("factory doesn't key for key: " + key);
|
||||
}
|
||||
|
||||
return (LoaderFactory<T>) FACTORY_CACHE.get(key);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,21 +18,22 @@
|
|||
|
||||
package the.bytecode.club.bytecodeviewer.bootloader.loader;
|
||||
|
||||
import the.bytecode.club.bytecodeviewer.bootloader.resource.external.ExternalResource;
|
||||
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.net.URL;
|
||||
import java.net.URLClassLoader;
|
||||
import the.bytecode.club.bytecodeviewer.bootloader.resource.external.ExternalResource;
|
||||
|
||||
/**
|
||||
* @author Bibl (don't ban me pls)
|
||||
* @since 21 Jul 2015 00:09:53
|
||||
*/
|
||||
public class ClassPathLoader implements ILoader<Object> {
|
||||
public class ClassPathLoader implements ILoader<Object>
|
||||
{
|
||||
|
||||
void extendClassPath(URL url) throws NoSuchMethodException, SecurityException, IllegalAccessException,
|
||||
IllegalArgumentException,
|
||||
InvocationTargetException {
|
||||
void extendClassPath(URL url) throws NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException, InvocationTargetException
|
||||
{
|
||||
URLClassLoader urlClassLoader = (URLClassLoader) ClassLoader.getSystemClassLoader();
|
||||
Class<URLClassLoader> urlClass = URLClassLoader.class;
|
||||
Method method = urlClass.getDeclaredMethod("addURL", URL.class);
|
||||
|
@ -46,18 +47,24 @@ public class ClassPathLoader implements ILoader<Object> {
|
|||
* @see the.bytecode.club.bootloader.ILoader#bind(the.bytecode.club.bootloader .resource.ExternalResource)
|
||||
*/
|
||||
@Override
|
||||
public void bind(ExternalResource<Object> resource) {
|
||||
try {
|
||||
if (resource != null) {
|
||||
public void bind(ExternalResource<Object> resource)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (resource != null)
|
||||
{
|
||||
URL url = resource.getLocation();
|
||||
if (url != null) {
|
||||
if (url != null)
|
||||
{
|
||||
extendClassPath(url);
|
||||
}
|
||||
}
|
||||
}/* catch (IOException e) {
|
||||
System.err.println("Error loading resource.");
|
||||
e.printStackTrace();
|
||||
}*/ catch (NoSuchMethodException | SecurityException | IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
|
||||
}*/
|
||||
catch (NoSuchMethodException | SecurityException | IllegalAccessException | IllegalArgumentException | InvocationTargetException e)
|
||||
{
|
||||
System.err.println("Error reflecting URLClassLoader.addURL(URL) ?");
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
@ -69,7 +76,8 @@ public class ClassPathLoader implements ILoader<Object> {
|
|||
* @see the.bytecode.club.bootloader.ILoader#findClass(java.lang.String)
|
||||
*/
|
||||
@Override
|
||||
public Class<?> findClass(String name) throws ClassNotFoundException, NoClassDefFoundError {
|
||||
public Class<?> findClass(String name) throws ClassNotFoundException, NoClassDefFoundError
|
||||
{
|
||||
return Class.forName(name);
|
||||
}
|
||||
|
||||
|
@ -79,7 +87,8 @@ public class ClassPathLoader implements ILoader<Object> {
|
|||
* @see the.bytecode.club.bootloader.ILoader#loadClass(java.lang.String)
|
||||
*/
|
||||
@Override
|
||||
public Class<?> loadClass(String name) throws ClassNotFoundException, NoClassDefFoundError {
|
||||
public Class<?> loadClass(String name) throws ClassNotFoundException, NoClassDefFoundError
|
||||
{
|
||||
return findClass(name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -24,11 +24,12 @@ import the.bytecode.club.bytecodeviewer.bootloader.resource.external.ExternalRes
|
|||
* @author Bibl (don't ban me pls)
|
||||
* @since 19 Jul 2015 02:29:43
|
||||
*/
|
||||
public interface ILoader<T> {
|
||||
public interface ILoader<T>
|
||||
{
|
||||
|
||||
void bind(ExternalResource<T> resource);
|
||||
|
||||
Class<?> findClass(String name) throws ClassNotFoundException, NoClassDefFoundError;
|
||||
|
||||
Class<?> loadClass(String name) throws ClassNotFoundException, NoClassDefFoundError;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,12 +18,6 @@
|
|||
|
||||
package the.bytecode.club.bytecodeviewer.bootloader.loader;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import org.objectweb.asm.ClassReader;
|
||||
import org.objectweb.asm.ClassWriter;
|
||||
import org.objectweb.asm.tree.ClassNode;
|
||||
|
@ -31,20 +25,29 @@ import the.bytecode.club.bytecodeviewer.bootloader.classtree.ClassTree;
|
|||
import the.bytecode.club.bytecodeviewer.bootloader.resource.external.ExternalResource;
|
||||
import the.bytecode.club.bytecodeviewer.bootloader.resource.jar.contents.JarContents;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* @author Bibl (don't ban me pls)
|
||||
* @since 19 Jul 2015 02:48:41
|
||||
*
|
||||
* <p>
|
||||
* TODO: Resource loading
|
||||
*/
|
||||
@Deprecated
|
||||
public class LibraryClassLoader extends ClassLoader implements ILoader<JarContents<ClassNode>> {
|
||||
public class LibraryClassLoader extends ClassLoader implements ILoader<JarContents<ClassNode>>
|
||||
{
|
||||
|
||||
private final Set<JarContents<ClassNode>> binded;
|
||||
private final Map<String, Class<?>> classCache;
|
||||
private final ClassTree tree;
|
||||
|
||||
public LibraryClassLoader() {
|
||||
public LibraryClassLoader()
|
||||
{
|
||||
binded = new HashSet<>();
|
||||
classCache = new HashMap<>();
|
||||
tree = new ClassTree();
|
||||
|
@ -55,16 +58,23 @@ public class LibraryClassLoader extends ClassLoader implements ILoader<JarConten
|
|||
* .ExternalResource)
|
||||
*/
|
||||
@Override
|
||||
public void bind(ExternalResource<JarContents<ClassNode>> resource) {
|
||||
try {
|
||||
public void bind(ExternalResource<JarContents<ClassNode>> resource)
|
||||
{
|
||||
try
|
||||
{
|
||||
JarContents<ClassNode> contents = resource.load();
|
||||
if (contents != null) {
|
||||
if (contents != null)
|
||||
{
|
||||
binded.add(contents);
|
||||
tree.build(contents.getClassContents().namedMap());
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
System.err.println("Null contents?");
|
||||
}
|
||||
} catch (IOException e) {
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
@ -73,21 +83,25 @@ public class LibraryClassLoader extends ClassLoader implements ILoader<JarConten
|
|||
* @see the.bytecode.club.bytecodeviewer.loadermodel.ILoader#loadClass(java.lang.String)
|
||||
*/
|
||||
@Override
|
||||
public Class<?> findClass(String name) throws ClassNotFoundException, NoClassDefFoundError {
|
||||
public Class<?> findClass(String name) throws ClassNotFoundException, NoClassDefFoundError
|
||||
{
|
||||
String byte_name = name.replace(".", "/");
|
||||
if (classCache.containsKey(byte_name))
|
||||
return classCache.get(byte_name);
|
||||
|
||||
ClassNode cn = null;
|
||||
for (JarContents<ClassNode> contents : binded) {
|
||||
for (JarContents<ClassNode> contents : binded)
|
||||
{
|
||||
cn = contents.getClassContents().namedMap().get(byte_name);
|
||||
if (cn != null)
|
||||
break;
|
||||
}
|
||||
|
||||
if (cn != null) {
|
||||
if (cn != null)
|
||||
{
|
||||
Class<?> klass = define(cn);
|
||||
if (klass != null) {
|
||||
if (klass != null)
|
||||
{
|
||||
classCache.put(byte_name, klass);
|
||||
return klass;
|
||||
}
|
||||
|
@ -96,39 +110,46 @@ public class LibraryClassLoader extends ClassLoader implements ILoader<JarConten
|
|||
return super.loadClass(name);
|
||||
}
|
||||
|
||||
protected Class<?> define(ClassNode cn) {
|
||||
protected Class<?> define(ClassNode cn)
|
||||
{
|
||||
ClassWriter writer = new ResolvingClassWriter(tree);
|
||||
cn.accept(cn);
|
||||
byte[] bytes = writer.toByteArray();
|
||||
return defineClass(bytes, 0, bytes.length);
|
||||
}
|
||||
|
||||
public static class ResolvingClassWriter extends ClassWriter {
|
||||
public static class ResolvingClassWriter extends ClassWriter
|
||||
{
|
||||
|
||||
private final ClassTree classTree;
|
||||
|
||||
public ResolvingClassWriter(ClassTree classTree) {
|
||||
public ResolvingClassWriter(ClassTree classTree)
|
||||
{
|
||||
super(ClassWriter.COMPUTE_FRAMES);
|
||||
this.classTree = classTree;
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
void update(Map<String, ClassNode> classes) {
|
||||
void update(Map<String, ClassNode> classes)
|
||||
{
|
||||
classTree.build(classes);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getCommonSuperClass(String type1, String type2) {
|
||||
protected String getCommonSuperClass(String type1, String type2)
|
||||
{
|
||||
ClassNode ccn = classTree.getClass(type1);
|
||||
ClassNode dcn = classTree.getClass(type2);
|
||||
|
||||
//System.out.println(type1 + " " + type2);
|
||||
if (ccn == null) {
|
||||
if (ccn == null)
|
||||
{
|
||||
classTree.build(createQuick(type1));
|
||||
return getCommonSuperClass(type1, type2);
|
||||
}
|
||||
|
||||
if (dcn == null) {
|
||||
if (dcn == null)
|
||||
{
|
||||
classTree.build(createQuick(type2));
|
||||
return getCommonSuperClass(type1, type2);
|
||||
}
|
||||
|
@ -142,10 +163,14 @@ public class LibraryClassLoader extends ClassLoader implements ILoader<JarConten
|
|||
if (d.contains(ccn))
|
||||
return type2;
|
||||
|
||||
if (Modifier.isInterface(ccn.access) || Modifier.isInterface(dcn.access)) {
|
||||
if (Modifier.isInterface(ccn.access) || Modifier.isInterface(dcn.access))
|
||||
{
|
||||
return "java/lang/Object";
|
||||
} else {
|
||||
do {
|
||||
}
|
||||
else
|
||||
{
|
||||
do
|
||||
{
|
||||
ClassNode nccn = classTree.getClass(ccn.superName);
|
||||
if (nccn == null)
|
||||
break;
|
||||
|
@ -156,13 +181,17 @@ public class LibraryClassLoader extends ClassLoader implements ILoader<JarConten
|
|||
}
|
||||
}
|
||||
|
||||
public ClassNode createQuick(String name) {
|
||||
try {
|
||||
public ClassNode createQuick(String name)
|
||||
{
|
||||
try
|
||||
{
|
||||
ClassReader cr = new ClassReader(name);
|
||||
ClassNode cn = new ClassNode();
|
||||
cr.accept(cn, ClassReader.SKIP_CODE | ClassReader.SKIP_FRAMES | ClassReader.SKIP_DEBUG);
|
||||
return cn;
|
||||
} catch (IOException e) {
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
return null;
|
||||
}
|
||||
|
|
|
@ -22,7 +22,8 @@ package the.bytecode.club.bytecodeviewer.bootloader.loader;
|
|||
* @author Bibl (don't ban me pls)
|
||||
* @since 21 Jul 2015 00:14:53
|
||||
*/
|
||||
public interface LoaderFactory<T> {
|
||||
public interface LoaderFactory<T>
|
||||
{
|
||||
|
||||
ILoader<T> spawnLoader();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -26,21 +26,25 @@ import java.util.Map;
|
|||
* @author Bibl (don't ban me pls)
|
||||
* @since 21 Jul 2013
|
||||
*/
|
||||
public abstract class DataContainer<T> extends ArrayList<T> {
|
||||
public abstract class DataContainer<T> extends ArrayList<T>
|
||||
{
|
||||
|
||||
private static final long serialVersionUID = -9022506488647444546L;
|
||||
|
||||
public DataContainer() {
|
||||
public DataContainer()
|
||||
{
|
||||
this(16);
|
||||
}
|
||||
|
||||
public DataContainer(int cap) {
|
||||
public DataContainer(int cap)
|
||||
{
|
||||
super(cap);
|
||||
}
|
||||
|
||||
public DataContainer(Collection<T> data) {
|
||||
public DataContainer(Collection<T> data)
|
||||
{
|
||||
addAll(data);
|
||||
}
|
||||
|
||||
public abstract Map<String, T> namedMap();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -24,12 +24,14 @@ import java.net.URL;
|
|||
* @author Bibl (don't ban me pls)
|
||||
* @since 21 Jul 2015 00:29:11
|
||||
*/
|
||||
public class EmptyExternalResource<T> extends ExternalResource<T> {
|
||||
public class EmptyExternalResource<T> extends ExternalResource<T>
|
||||
{
|
||||
|
||||
/**
|
||||
* @param location
|
||||
*/
|
||||
public EmptyExternalResource(URL location) {
|
||||
public EmptyExternalResource(URL location)
|
||||
{
|
||||
super(location);
|
||||
}
|
||||
|
||||
|
@ -37,7 +39,8 @@ public class EmptyExternalResource<T> extends ExternalResource<T> {
|
|||
* @see the.bytecode.club.bootloader.resource.ExternalResource#load()
|
||||
*/
|
||||
@Override
|
||||
public T load() {
|
||||
public T load()
|
||||
{
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,6 +18,12 @@
|
|||
|
||||
package the.bytecode.club.bytecodeviewer.bootloader.resource.external;
|
||||
|
||||
import org.objectweb.asm.ClassReader;
|
||||
import org.objectweb.asm.tree.ClassNode;
|
||||
import the.bytecode.club.bytecodeviewer.bootloader.resource.jar.JarInfo;
|
||||
import the.bytecode.club.bytecodeviewer.bootloader.resource.jar.JarResource;
|
||||
import the.bytecode.club.bytecodeviewer.bootloader.resource.jar.contents.JarContents;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
@ -27,43 +33,47 @@ import java.net.URL;
|
|||
import java.util.Enumeration;
|
||||
import java.util.jar.JarEntry;
|
||||
import java.util.jar.JarFile;
|
||||
import org.objectweb.asm.ClassReader;
|
||||
import org.objectweb.asm.tree.ClassNode;
|
||||
import the.bytecode.club.bytecodeviewer.bootloader.resource.jar.JarInfo;
|
||||
import the.bytecode.club.bytecodeviewer.bootloader.resource.jar.JarResource;
|
||||
import the.bytecode.club.bytecodeviewer.bootloader.resource.jar.contents.JarContents;
|
||||
|
||||
/**
|
||||
* @author Bibl (don't ban me pls)
|
||||
* @since 19 Jul 2015 02:33:23
|
||||
*/
|
||||
public class ExternalLibrary extends ExternalResource<JarContents<ClassNode>> {
|
||||
public class ExternalLibrary extends ExternalResource<JarContents<ClassNode>>
|
||||
{
|
||||
|
||||
/**
|
||||
* @param location
|
||||
*/
|
||||
public ExternalLibrary(URL location) {
|
||||
public ExternalLibrary(URL location)
|
||||
{
|
||||
super(location);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param jar
|
||||
*/
|
||||
public ExternalLibrary(JarInfo jar) {
|
||||
public ExternalLibrary(JarInfo jar)
|
||||
{
|
||||
super(createJarURL(jar));
|
||||
}
|
||||
|
||||
public static URL createJarURL(JarInfo jar) {
|
||||
try {
|
||||
public static URL createJarURL(JarInfo jar)
|
||||
{
|
||||
try
|
||||
{
|
||||
return jar.formattedURL();
|
||||
} catch (MalformedURLException e) {
|
||||
}
|
||||
catch (MalformedURLException e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static byte[] read(InputStream in) throws IOException {
|
||||
try (ByteArrayOutputStream byteArrayOut = new ByteArrayOutputStream()) {
|
||||
public static byte[] read(InputStream in) throws IOException
|
||||
{
|
||||
try (ByteArrayOutputStream byteArrayOut = new ByteArrayOutputStream())
|
||||
{
|
||||
byte[] buffer = new byte[1024];
|
||||
int bytesRead;
|
||||
while ((bytesRead = in.read(buffer)) != -1)
|
||||
|
@ -72,7 +82,8 @@ public class ExternalLibrary extends ExternalResource<JarContents<ClassNode>> {
|
|||
}
|
||||
}
|
||||
|
||||
protected ClassNode create(byte[] b) {
|
||||
protected ClassNode create(byte[] b)
|
||||
{
|
||||
ClassReader cr = new ClassReader(b);
|
||||
ClassNode cn = new ClassNode();
|
||||
cr.accept(cn, 0);
|
||||
|
@ -83,21 +94,27 @@ public class ExternalLibrary extends ExternalResource<JarContents<ClassNode>> {
|
|||
* @see the.bytecode.club.bytecodeviewer.loadermodel.ExternalResource#load()
|
||||
*/
|
||||
@Override
|
||||
public JarContents<ClassNode> load() throws IOException {
|
||||
public JarContents<ClassNode> load() throws IOException
|
||||
{
|
||||
JarContents<ClassNode> contents = new JarContents<>();
|
||||
|
||||
JarURLConnection con = (JarURLConnection) getLocation().openConnection();
|
||||
JarFile jar = con.getJarFile();
|
||||
|
||||
Enumeration<JarEntry> entries = jar.entries();
|
||||
while (entries.hasMoreElements()) {
|
||||
while (entries.hasMoreElements())
|
||||
{
|
||||
JarEntry entry = entries.nextElement();
|
||||
try (InputStream is = jar.getInputStream(entry)) {
|
||||
try (InputStream is = jar.getInputStream(entry))
|
||||
{
|
||||
byte[] bytes = read(is);
|
||||
if (entry.getName().endsWith(".class")) {
|
||||
if (entry.getName().endsWith(".class"))
|
||||
{
|
||||
ClassNode cn = create(bytes);
|
||||
contents.getClassContents().add(cn);
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
JarResource resource = new JarResource(entry.getName(), bytes);
|
||||
contents.getResourceContents().add(resource);
|
||||
}
|
||||
|
|
|
@ -25,24 +25,28 @@ import java.net.URL;
|
|||
* @author Bibl (don't ban me pls)
|
||||
* @since 19 Jul 2015 02:30:30
|
||||
*/
|
||||
public abstract class ExternalResource<T> {
|
||||
public abstract class ExternalResource<T>
|
||||
{
|
||||
|
||||
private final URL location;
|
||||
|
||||
public ExternalResource(URL location) {
|
||||
public ExternalResource(URL location)
|
||||
{
|
||||
if (location == null)
|
||||
throw new IllegalArgumentException();
|
||||
this.location = location;
|
||||
}
|
||||
|
||||
public URL getLocation() {
|
||||
public URL getLocation()
|
||||
{
|
||||
return location;
|
||||
}
|
||||
|
||||
public abstract T load() throws IOException;
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
public int hashCode()
|
||||
{
|
||||
final int prime = 31;
|
||||
int result = 1;
|
||||
result = prime * result + location.hashCode();
|
||||
|
@ -50,7 +54,8 @@ public abstract class ExternalResource<T> {
|
|||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
public boolean equals(Object obj)
|
||||
{
|
||||
if (this == obj)
|
||||
return true;
|
||||
if (obj == null)
|
||||
|
@ -62,7 +67,8 @@ public abstract class ExternalResource<T> {
|
|||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
public String toString()
|
||||
{
|
||||
return "Library @" + location.toExternalForm();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -29,7 +29,8 @@ import java.net.URL;
|
|||
* @author Bibl
|
||||
* @since 19 Jul 2013
|
||||
*/
|
||||
public class JarInfo {
|
||||
public class JarInfo
|
||||
{
|
||||
|
||||
private final String path;
|
||||
private final JarType type;
|
||||
|
@ -39,7 +40,8 @@ public class JarInfo {
|
|||
*
|
||||
* @param path Path to jar.
|
||||
*/
|
||||
public JarInfo(File path) {
|
||||
public JarInfo(File path)
|
||||
{
|
||||
this(path.getAbsolutePath(), JarType.FILE);
|
||||
}
|
||||
|
||||
|
@ -49,7 +51,8 @@ public class JarInfo {
|
|||
* @param path Path to jar.
|
||||
* @param type Type of jar.
|
||||
*/
|
||||
public JarInfo(String path, JarType type) {
|
||||
public JarInfo(String path, JarType type)
|
||||
{
|
||||
this.path = path;
|
||||
this.type = type;
|
||||
}
|
||||
|
@ -59,18 +62,21 @@ public class JarInfo {
|
|||
*
|
||||
* @param url URL to jar.
|
||||
*/
|
||||
public JarInfo(URL url) {
|
||||
public JarInfo(URL url)
|
||||
{
|
||||
this(url.toExternalForm(), JarType.WEB);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Real path to JarFile.
|
||||
*/
|
||||
public final String getPath() {
|
||||
public final String getPath()
|
||||
{
|
||||
return path;
|
||||
}
|
||||
|
||||
public final JarType getType() {
|
||||
public final JarType getType()
|
||||
{
|
||||
return type;
|
||||
}
|
||||
|
||||
|
@ -80,9 +86,11 @@ public class JarInfo {
|
|||
* @return The formatted url.
|
||||
* @throws MalformedURLException
|
||||
*/
|
||||
public URL formattedURL() throws MalformedURLException {
|
||||
public URL formattedURL() throws MalformedURLException
|
||||
{
|
||||
StringBuilder sb = new StringBuilder().append("jar:").append(type.prefix()).append(path);
|
||||
if (type.equals(JarType.FILE) && !path.endsWith(".jar")) {
|
||||
if (type.equals(JarType.FILE) && !path.endsWith(".jar"))
|
||||
{
|
||||
File file = new File(path);
|
||||
if (!file.exists())
|
||||
sb.append(".jar");
|
||||
|
@ -92,7 +100,8 @@ public class JarInfo {
|
|||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
public int hashCode()
|
||||
{
|
||||
final int prime = 31;
|
||||
int result = 1;
|
||||
result = (prime * result) + ((path == null) ? 0 : path.hashCode());
|
||||
|
@ -101,7 +110,8 @@ public class JarInfo {
|
|||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
public boolean equals(Object obj)
|
||||
{
|
||||
if (this == obj)
|
||||
return true;
|
||||
if (obj == null)
|
||||
|
@ -109,11 +119,13 @@ public class JarInfo {
|
|||
if (getClass() != obj.getClass())
|
||||
return false;
|
||||
JarInfo other = (JarInfo) obj;
|
||||
if (path == null) {
|
||||
if (path == null)
|
||||
{
|
||||
if (other.path != null)
|
||||
return false;
|
||||
} else if (!path.equals(other.path))
|
||||
}
|
||||
else if (!path.equals(other.path))
|
||||
return false;
|
||||
return type == other.type;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -24,26 +24,31 @@ import java.util.Arrays;
|
|||
* @author Bibl (don't ban me pls)
|
||||
* @since 19 Jul 2013
|
||||
*/
|
||||
public class JarResource {
|
||||
public class JarResource
|
||||
{
|
||||
|
||||
private final String name;
|
||||
private final byte[] data;
|
||||
|
||||
public JarResource(String name, byte[] data) {
|
||||
public JarResource(String name, byte[] data)
|
||||
{
|
||||
this.name = name;
|
||||
this.data = data;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
public String getName()
|
||||
{
|
||||
return name;
|
||||
}
|
||||
|
||||
public byte[] getData() {
|
||||
public byte[] getData()
|
||||
{
|
||||
return data;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
public int hashCode()
|
||||
{
|
||||
final int prime = 31;
|
||||
int result = 1;
|
||||
result = (prime * result) + Arrays.hashCode(data);
|
||||
|
@ -52,7 +57,8 @@ public class JarResource {
|
|||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
public boolean equals(Object obj)
|
||||
{
|
||||
if (this == obj)
|
||||
return true;
|
||||
if (obj == null)
|
||||
|
@ -62,8 +68,11 @@ public class JarResource {
|
|||
JarResource other = (JarResource) obj;
|
||||
if (!Arrays.equals(data, other.data))
|
||||
return false;
|
||||
if (name == null) {
|
||||
if (name == null)
|
||||
{
|
||||
return other.name == null;
|
||||
} else return name.equals(other.name);
|
||||
}
|
||||
else
|
||||
return name.equals(other.name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -24,7 +24,8 @@ package the.bytecode.club.bytecodeviewer.bootloader.resource.jar;
|
|||
* @author Bibl
|
||||
* @since 19 Jul 2013
|
||||
*/
|
||||
public enum JarType {
|
||||
public enum JarType
|
||||
{
|
||||
|
||||
/**
|
||||
* Local file
|
||||
|
@ -37,14 +38,16 @@ public enum JarType {
|
|||
|
||||
private final String prefix;
|
||||
|
||||
JarType(String prefix) {
|
||||
JarType(String prefix)
|
||||
{
|
||||
this.prefix = prefix;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the prefix for the JarURLConnection.
|
||||
**/
|
||||
public String prefix() {
|
||||
public String prefix()
|
||||
{
|
||||
return prefix;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,49 +18,52 @@
|
|||
|
||||
package the.bytecode.club.bytecodeviewer.bootloader.resource.jar.contents;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import org.objectweb.asm.tree.ClassNode;
|
||||
import the.bytecode.club.bytecodeviewer.bootloader.resource.DataContainer;
|
||||
import the.bytecode.club.bytecodeviewer.bootloader.resource.jar.JarResource;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* @author Bibl (don't ban me pls)
|
||||
* @since 19 Jul 2013
|
||||
*/
|
||||
public class JarContents<C extends ClassNode> {
|
||||
public class JarContents<C extends ClassNode>
|
||||
{
|
||||
|
||||
private final DataContainer<C> classContents;
|
||||
private final DataContainer<JarResource> resourceContents;
|
||||
|
||||
public JarContents() {
|
||||
public JarContents()
|
||||
{
|
||||
classContents = new ClassNodeContainer<>();
|
||||
resourceContents = new ResourceContainer();
|
||||
}
|
||||
|
||||
public JarContents(DataContainer<C> classContents, DataContainer<JarResource> resourceContents) {
|
||||
public JarContents(DataContainer<C> classContents, DataContainer<JarResource> resourceContents)
|
||||
{
|
||||
this.classContents = classContents == null ? new ClassNodeContainer<>() : classContents;
|
||||
this.resourceContents = resourceContents == null ? new ResourceContainer() : resourceContents;
|
||||
}
|
||||
|
||||
public final DataContainer<C> getClassContents() {
|
||||
public final DataContainer<C> getClassContents()
|
||||
{
|
||||
return classContents;
|
||||
}
|
||||
|
||||
public final DataContainer<JarResource> getResourceContents() {
|
||||
public final DataContainer<JarResource> getResourceContents()
|
||||
{
|
||||
return resourceContents;
|
||||
}
|
||||
|
||||
public void merge(JarContents<C> contents) {
|
||||
public void merge(JarContents<C> contents)
|
||||
{
|
||||
classContents.addAll(contents.classContents);
|
||||
resourceContents.addAll(contents.resourceContents);
|
||||
}
|
||||
|
||||
public JarContents<C> add(JarContents<C> contents) {
|
||||
public JarContents<C> add(JarContents<C> contents)
|
||||
{
|
||||
List<C> c1 = classContents;
|
||||
List<C> c2 = contents.classContents;
|
||||
|
||||
|
@ -78,53 +81,66 @@ public class JarContents<C extends ClassNode> {
|
|||
return new JarContents<>(new ClassNodeContainer<>(c3), new ResourceContainer(r3));
|
||||
}
|
||||
|
||||
public static class ClassNodeContainer<C extends ClassNode> extends DataContainer<C> {
|
||||
public static class ClassNodeContainer<C extends ClassNode> extends DataContainer<C>
|
||||
{
|
||||
private static final long serialVersionUID = -6169578803641192235L;
|
||||
|
||||
private Map<String, C> lastMap = new HashMap<>();
|
||||
private boolean invalidated;
|
||||
|
||||
public ClassNodeContainer() {
|
||||
public ClassNodeContainer()
|
||||
{
|
||||
this(16);
|
||||
}
|
||||
|
||||
public ClassNodeContainer(int cap) {
|
||||
public ClassNodeContainer(int cap)
|
||||
{
|
||||
super(cap);
|
||||
}
|
||||
|
||||
public ClassNodeContainer(Collection<C> data) {
|
||||
public ClassNodeContainer(Collection<C> data)
|
||||
{
|
||||
super(data);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean add(C c) {
|
||||
public boolean add(C c)
|
||||
{
|
||||
invalidated = true;
|
||||
return super.add(c);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean addAll(Collection<? extends C> c) {
|
||||
public boolean addAll(Collection<? extends C> c)
|
||||
{
|
||||
invalidated = true;
|
||||
return super.addAll(c);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean remove(Object c) {
|
||||
public boolean remove(Object c)
|
||||
{
|
||||
invalidated = true;
|
||||
return super.remove(c);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, C> namedMap() {
|
||||
if (invalidated) {
|
||||
public Map<String, C> namedMap()
|
||||
{
|
||||
if (invalidated)
|
||||
{
|
||||
invalidated = false;
|
||||
Map<String, C> nodeMap = new HashMap<>();
|
||||
Iterator<C> it = iterator();
|
||||
while (it.hasNext()) {
|
||||
while (it.hasNext())
|
||||
{
|
||||
C cn = it.next();
|
||||
if (nodeMap.containsKey(cn.name)) {
|
||||
if (nodeMap.containsKey(cn.name))
|
||||
{
|
||||
it.remove();
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
nodeMap.put(cn.name, cn);
|
||||
}
|
||||
}
|
||||
|
@ -134,28 +150,34 @@ public class JarContents<C extends ClassNode> {
|
|||
}
|
||||
}
|
||||
|
||||
public static class ResourceContainer extends DataContainer<JarResource> {
|
||||
public static class ResourceContainer extends DataContainer<JarResource>
|
||||
{
|
||||
private static final long serialVersionUID = -6169578803641192235L;
|
||||
|
||||
public ResourceContainer() {
|
||||
public ResourceContainer()
|
||||
{
|
||||
this(16);
|
||||
}
|
||||
|
||||
public ResourceContainer(int cap) {
|
||||
public ResourceContainer(int cap)
|
||||
{
|
||||
super(cap);
|
||||
}
|
||||
|
||||
public ResourceContainer(List<JarResource> data) {
|
||||
public ResourceContainer(List<JarResource> data)
|
||||
{
|
||||
addAll(data);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, JarResource> namedMap() {
|
||||
public Map<String, JarResource> namedMap()
|
||||
{
|
||||
Map<String, JarResource> map = new HashMap<>();
|
||||
for (JarResource resource : this) {
|
||||
for (JarResource resource : this)
|
||||
{
|
||||
map.put(resource.getName(), resource);
|
||||
}
|
||||
return map;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,31 +18,35 @@
|
|||
|
||||
package the.bytecode.club.bytecodeviewer.bootloader.resource.jar.contents;
|
||||
|
||||
import java.net.URL;
|
||||
import org.objectweb.asm.tree.ClassNode;
|
||||
import the.bytecode.club.bytecodeviewer.bootloader.resource.DataContainer;
|
||||
import the.bytecode.club.bytecodeviewer.bootloader.resource.jar.JarResource;
|
||||
|
||||
import java.net.URL;
|
||||
|
||||
/**
|
||||
* @author Bibl (don't ban me pls)
|
||||
* @since 19 Jul 2013
|
||||
*/
|
||||
public class LocateableJarContents<C extends ClassNode> extends JarContents<C> {
|
||||
public class LocateableJarContents<C extends ClassNode> extends JarContents<C>
|
||||
{
|
||||
|
||||
private final URL[] jarUrls;
|
||||
|
||||
public LocateableJarContents(URL... jarUrls) {
|
||||
public LocateableJarContents(URL... jarUrls)
|
||||
{
|
||||
super();
|
||||
this.jarUrls = jarUrls;
|
||||
}
|
||||
|
||||
public LocateableJarContents(DataContainer<C> classContents, DataContainer<JarResource> resourceContents,
|
||||
URL... jarUrls) {
|
||||
public LocateableJarContents(DataContainer<C> classContents, DataContainer<JarResource> resourceContents, URL... jarUrls)
|
||||
{
|
||||
super(classContents, resourceContents);
|
||||
this.jarUrls = jarUrls;
|
||||
}
|
||||
|
||||
public URL[] getJarUrls() {
|
||||
public URL[] getJarUrls()
|
||||
{
|
||||
return jarUrls;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -29,15 +29,16 @@ import the.bytecode.club.bytecodeviewer.compilers.impl.SmaliAssembler;
|
|||
*/
|
||||
public enum Compiler
|
||||
{
|
||||
KRAKATAU_ASSEMBLER(new KrakatauAssembler()),
|
||||
SMALI_ASSEMBLER(new SmaliAssembler()),
|
||||
JAVA_COMPILER(new JavaCompiler()),
|
||||
KRAKATAU_ASSEMBLER(new KrakatauAssembler()), SMALI_ASSEMBLER(new SmaliAssembler()), JAVA_COMPILER(new JavaCompiler()),
|
||||
;
|
||||
|
||||
|
||||
private final InternalCompiler compiler;
|
||||
|
||||
Compiler(InternalCompiler compiler) {this.compiler = compiler;}
|
||||
|
||||
|
||||
Compiler(InternalCompiler compiler)
|
||||
{
|
||||
this.compiler = compiler;
|
||||
}
|
||||
|
||||
public InternalCompiler getCompiler()
|
||||
{
|
||||
return compiler;
|
||||
|
|
|
@ -18,11 +18,6 @@
|
|||
|
||||
package the.bytecode.club.bytecodeviewer.compilers.impl;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import me.konloch.kontainer.io.DiskWriter;
|
||||
import the.bytecode.club.bytecodeviewer.BytecodeViewer;
|
||||
import the.bytecode.club.bytecodeviewer.Configuration;
|
||||
|
@ -33,9 +28,9 @@ import the.bytecode.club.bytecodeviewer.util.JarUtils;
|
|||
import the.bytecode.club.bytecodeviewer.util.MiscUtils;
|
||||
import the.bytecode.club.bytecodeviewer.util.SleepUtil;
|
||||
|
||||
import static the.bytecode.club.bytecodeviewer.Constants.fs;
|
||||
import static the.bytecode.club.bytecodeviewer.Constants.nl;
|
||||
import static the.bytecode.club.bytecodeviewer.Constants.tempDirectory;
|
||||
import java.io.*;
|
||||
|
||||
import static the.bytecode.club.bytecodeviewer.Constants.*;
|
||||
|
||||
/**
|
||||
* Java Compiler
|
||||
|
@ -54,16 +49,18 @@ public class JavaCompiler extends InternalCompiler
|
|||
File clazz = new File(fileStart2 + fs + fullyQualifiedName + ".class");
|
||||
File cp = new File(tempDirectory + fs + "cpath_" + MiscUtils.randomString(12) + ".jar");
|
||||
File tempD = new File(fileStart + fs + fullyQualifiedName.substring(0, fullyQualifiedName.length() - fullyQualifiedName.split("/")[fullyQualifiedName.split("/").length - 1].length()));
|
||||
|
||||
|
||||
tempD.mkdirs();
|
||||
new File(fileStart2).mkdirs();
|
||||
|
||||
if (Configuration.javac.isEmpty() || !new File(Configuration.javac).exists()) {
|
||||
if (Configuration.javac.isEmpty() || !new File(Configuration.javac).exists())
|
||||
{
|
||||
BytecodeViewer.showMessage("You need to set your Javac path, this requires the JDK to be downloaded." + nl + "(C:/Program Files/Java/JDK_xx/bin/javac.exe)");
|
||||
ExternalResources.getSingleton().selectJavac();
|
||||
}
|
||||
|
||||
if (Configuration.javac.isEmpty() || !new File(Configuration.javac).exists()) {
|
||||
if (Configuration.javac.isEmpty() || !new File(Configuration.javac).exists())
|
||||
{
|
||||
BytecodeViewer.showMessage("You need to set Javac!");
|
||||
return null;
|
||||
}
|
||||
|
@ -72,25 +69,18 @@ public class JavaCompiler extends InternalCompiler
|
|||
JarUtils.saveAsJar(BytecodeViewer.getLoadedClasses(), cp.getAbsolutePath());
|
||||
|
||||
boolean cont = true;
|
||||
try {
|
||||
try
|
||||
{
|
||||
StringBuilder log = new StringBuilder();
|
||||
ProcessBuilder pb;
|
||||
|
||||
if (Configuration.library.isEmpty()) {
|
||||
pb = new ProcessBuilder(
|
||||
Configuration.javac,
|
||||
"-d", fileStart2,
|
||||
"-classpath", cp.getAbsolutePath(),
|
||||
java.getAbsolutePath()
|
||||
);
|
||||
} else {
|
||||
pb = new ProcessBuilder(
|
||||
Configuration.javac,
|
||||
"-d", fileStart2,
|
||||
"-classpath",
|
||||
cp.getAbsolutePath() + System.getProperty("path.separator") + Configuration.library,
|
||||
java.getAbsolutePath()
|
||||
);
|
||||
if (Configuration.library.isEmpty())
|
||||
{
|
||||
pb = new ProcessBuilder(Configuration.javac, "-d", fileStart2, "-classpath", cp.getAbsolutePath(), java.getAbsolutePath());
|
||||
}
|
||||
else
|
||||
{
|
||||
pb = new ProcessBuilder(Configuration.javac, "-d", fileStart2, "-classpath", cp.getAbsolutePath() + System.getProperty("path.separator") + Configuration.library, java.getAbsolutePath());
|
||||
}
|
||||
|
||||
Process process = pb.start();
|
||||
|
@ -98,8 +88,8 @@ public class JavaCompiler extends InternalCompiler
|
|||
|
||||
Thread failSafe = new Thread(() ->
|
||||
{
|
||||
//wait 10 seconds
|
||||
SleepUtil.sleep(10_000);
|
||||
//wait 10 seconds
|
||||
SleepUtil.sleep(10_000);
|
||||
|
||||
if (process.isAlive())
|
||||
{
|
||||
|
@ -112,18 +102,16 @@ public class JavaCompiler extends InternalCompiler
|
|||
int exitValue = process.waitFor();
|
||||
|
||||
//Read out dir output
|
||||
try (InputStream is = process.getInputStream();
|
||||
InputStreamReader isr = new InputStreamReader(is);
|
||||
BufferedReader br = new BufferedReader(isr)) {
|
||||
try (InputStream is = process.getInputStream(); InputStreamReader isr = new InputStreamReader(is); BufferedReader br = new BufferedReader(isr))
|
||||
{
|
||||
String line;
|
||||
while ((line = br.readLine()) != null)
|
||||
log.append(nl).append(line);
|
||||
}
|
||||
|
||||
log.append(nl).append(nl).append(TranslatedStrings.ERROR2).append(nl).append(nl);
|
||||
try (InputStream is = process.getErrorStream();
|
||||
InputStreamReader isr = new InputStreamReader(is);
|
||||
BufferedReader br = new BufferedReader(isr)) {
|
||||
try (InputStream is = process.getErrorStream(); InputStreamReader isr = new InputStreamReader(is); BufferedReader br = new BufferedReader(isr))
|
||||
{
|
||||
String line;
|
||||
while ((line = br.readLine()) != null)
|
||||
log.append(nl).append(line);
|
||||
|
@ -134,7 +122,9 @@ public class JavaCompiler extends InternalCompiler
|
|||
|
||||
if (!clazz.exists())
|
||||
throw new Exception(log.toString());
|
||||
} catch (Exception e) {
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
cont = false;
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
@ -142,9 +132,12 @@ public class JavaCompiler extends InternalCompiler
|
|||
cp.delete();
|
||||
|
||||
if (cont)
|
||||
try {
|
||||
try
|
||||
{
|
||||
return org.apache.commons.io.FileUtils.readFileToByteArray(clazz);
|
||||
} catch (IOException e) {
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
//BytecodeViewer.handleException(e);
|
||||
}
|
||||
|
|
|
@ -18,11 +18,6 @@
|
|||
|
||||
package the.bytecode.club.bytecodeviewer.compilers.impl;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.File;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.util.Objects;
|
||||
import me.konloch.kontainer.io.DiskWriter;
|
||||
import org.apache.commons.io.FileUtils;
|
||||
import org.apache.commons.lang3.ArrayUtils;
|
||||
|
@ -35,9 +30,13 @@ import the.bytecode.club.bytecodeviewer.translation.TranslatedStrings;
|
|||
import the.bytecode.club.bytecodeviewer.util.JarUtils;
|
||||
import the.bytecode.club.bytecodeviewer.util.MiscUtils;
|
||||
|
||||
import static the.bytecode.club.bytecodeviewer.Constants.fs;
|
||||
import static the.bytecode.club.bytecodeviewer.Constants.krakatauWorkingDirectory;
|
||||
import static the.bytecode.club.bytecodeviewer.Constants.nl;
|
||||
import java.io.BufferedReader;
|
||||
import java.io.File;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.util.Objects;
|
||||
|
||||
import static the.bytecode.club.bytecodeviewer.Constants.*;
|
||||
|
||||
/**
|
||||
* Krakatau Java assembler, requires Python 2.7
|
||||
|
@ -49,7 +48,7 @@ public class KrakatauAssembler extends InternalCompiler
|
|||
@Override
|
||||
public byte[] compile(String contents, String fullyQualifiedName)
|
||||
{
|
||||
if(!ExternalResources.getSingleton().hasSetPython2Command())
|
||||
if (!ExternalResources.getSingleton().hasSetPython2Command())
|
||||
return null;
|
||||
|
||||
File tempD = new File(Constants.tempDirectory + fs + MiscUtils.randomString(32) + fs);
|
||||
|
@ -60,43 +59,35 @@ public class KrakatauAssembler extends InternalCompiler
|
|||
|
||||
final File tempDirectory = new File(Constants.tempDirectory + fs + MiscUtils.randomString(32) + fs);
|
||||
tempDirectory.mkdir();
|
||||
|
||||
|
||||
final File tempJar = new File(Constants.tempDirectory + fs + "temp" + MiscUtils.randomString(32) + ".jar");
|
||||
JarUtils.saveAsJar(BytecodeViewer.getLoadedClasses(), tempJar.getAbsolutePath());
|
||||
|
||||
|
||||
StringBuilder log = new StringBuilder();
|
||||
|
||||
|
||||
try
|
||||
{
|
||||
String[] pythonCommands = new String[]{Configuration.python2};
|
||||
if(Configuration.python2Extra)
|
||||
if (Configuration.python2Extra)
|
||||
pythonCommands = ArrayUtils.addAll(pythonCommands, "-2");
|
||||
|
||||
ProcessBuilder pb = new ProcessBuilder(ArrayUtils.addAll(
|
||||
pythonCommands,
|
||||
"-O", //love you storyyeller <3
|
||||
krakatauWorkingDirectory + fs + "assemble.py",
|
||||
"-out",
|
||||
tempDirectory.getAbsolutePath(),
|
||||
tempJ.getAbsolutePath()
|
||||
));
|
||||
|
||||
ProcessBuilder pb = new ProcessBuilder(ArrayUtils.addAll(pythonCommands, "-O", //love you storyyeller <3
|
||||
krakatauWorkingDirectory + fs + "assemble.py", "-out", tempDirectory.getAbsolutePath(), tempJ.getAbsolutePath()));
|
||||
|
||||
Process process = pb.start();
|
||||
BytecodeViewer.createdProcesses.add(process);
|
||||
|
||||
//Read out dir output
|
||||
try (InputStream is = process.getInputStream();
|
||||
InputStreamReader isr = new InputStreamReader(is);
|
||||
BufferedReader br = new BufferedReader(isr)) {
|
||||
try (InputStream is = process.getInputStream(); InputStreamReader isr = new InputStreamReader(is); BufferedReader br = new BufferedReader(isr))
|
||||
{
|
||||
String line;
|
||||
while ((line = br.readLine()) != null)
|
||||
log.append(nl).append(line);
|
||||
}
|
||||
|
||||
log.append(nl).append(nl).append(TranslatedStrings.ERROR2).append(nl).append(nl);
|
||||
try (InputStream is = process.getErrorStream();
|
||||
InputStreamReader isr = new InputStreamReader(is);
|
||||
BufferedReader br = new BufferedReader(isr)) {
|
||||
try (InputStream is = process.getErrorStream(); InputStreamReader isr = new InputStreamReader(is); BufferedReader br = new BufferedReader(isr))
|
||||
{
|
||||
String line;
|
||||
while ((line = br.readLine()) != null)
|
||||
log.append(nl).append(line);
|
||||
|
@ -106,12 +97,13 @@ public class KrakatauAssembler extends InternalCompiler
|
|||
log.append(nl).append(nl).append(TranslatedStrings.EXIT_VALUE_IS).append(" ").append(exitValue);
|
||||
System.err.println(log);
|
||||
|
||||
byte[] b = FileUtils.readFileToByteArray(Objects.requireNonNull(
|
||||
ExternalResources.getSingleton().findFile(tempDirectory, ".class")));
|
||||
byte[] b = FileUtils.readFileToByteArray(Objects.requireNonNull(ExternalResources.getSingleton().findFile(tempDirectory, ".class")));
|
||||
tempDirectory.delete();
|
||||
tempJar.delete();
|
||||
return b;
|
||||
} catch (Exception e) {
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
//BytecodeViewer.handleException(log.toString());
|
||||
}
|
||||
|
|
|
@ -18,8 +18,6 @@
|
|||
|
||||
package the.bytecode.club.bytecodeviewer.compilers.impl;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.Objects;
|
||||
import me.konloch.kontainer.io.DiskWriter;
|
||||
import org.apache.commons.io.FileUtils;
|
||||
import the.bytecode.club.bytecodeviewer.BytecodeViewer;
|
||||
|
@ -29,6 +27,9 @@ import the.bytecode.club.bytecodeviewer.util.Enjarify;
|
|||
import the.bytecode.club.bytecodeviewer.util.MiscUtils;
|
||||
import the.bytecode.club.bytecodeviewer.util.ZipUtils;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.Objects;
|
||||
|
||||
import static the.bytecode.club.bytecodeviewer.Constants.fs;
|
||||
import static the.bytecode.club.bytecodeviewer.Constants.tempDirectory;
|
||||
|
||||
|
@ -54,17 +55,22 @@ public class SmaliAssembler extends InternalCompiler
|
|||
File tempJar = new File(fileStart + fileNumber + ".jar");
|
||||
File tempJarFolder = new File(fileStart + fileNumber + "-jar" + fs);
|
||||
|
||||
try {
|
||||
try
|
||||
{
|
||||
DiskWriter.replaceFile(tempSmali.getAbsolutePath(), contents, false);
|
||||
} catch (Exception e) {
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
//BytecodeViewer.handleException(e);
|
||||
}
|
||||
|
||||
try {
|
||||
com.googlecode.d2j.smali.SmaliCmd.main(tempSmaliFolder.getAbsolutePath(),
|
||||
"-o", tempDex.getAbsolutePath());
|
||||
} catch (Exception e) {
|
||||
try
|
||||
{
|
||||
com.googlecode.d2j.smali.SmaliCmd.main(tempSmaliFolder.getAbsolutePath(), "-o", tempDex.getAbsolutePath());
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
//BytecodeViewer.handleException(e);
|
||||
}
|
||||
|
@ -77,14 +83,16 @@ public class SmaliAssembler extends InternalCompiler
|
|||
|
||||
System.out.println("Temporary dex: " + tempDex.getAbsolutePath());
|
||||
|
||||
try {
|
||||
try
|
||||
{
|
||||
System.out.println("Unzipping to " + tempJarFolder.getAbsolutePath());
|
||||
ZipUtils.unzipFilesToPath(tempJar.getAbsolutePath(), tempJarFolder.getAbsolutePath());
|
||||
|
||||
File outputClass = null;
|
||||
boolean found = false;
|
||||
File current = tempJarFolder;
|
||||
try {
|
||||
try
|
||||
{
|
||||
while (!found)
|
||||
{
|
||||
File f = Objects.requireNonNull(current.listFiles())[0];
|
||||
|
@ -100,8 +108,13 @@ public class SmaliAssembler extends InternalCompiler
|
|||
System.out.println("Saved as: " + outputClass.getAbsolutePath());
|
||||
|
||||
return FileUtils.readFileToByteArray(outputClass);
|
||||
} catch (java.lang.NullPointerException ignored) { }
|
||||
} catch (Exception e) {
|
||||
}
|
||||
catch (java.lang.NullPointerException ignored)
|
||||
{
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
//BytecodeViewer.handleException(e);
|
||||
}
|
||||
|
|
|
@ -29,43 +29,30 @@ public enum Decompiler
|
|||
{
|
||||
//TODO WARNING: do not change the decompiler order, when adding a new decompiler just add it to the end
|
||||
// enum ordinal is used for settings serialization instead of the enum name
|
||||
NONE("None", "", null),
|
||||
PROCYON_DECOMPILER("Procyon Decompiler", "proycon", new ProcyonDecompiler()),
|
||||
CFR_DECOMPILER("CFR Decompiler", "cfr", new CFRDecompiler()),
|
||||
FERNFLOWER_DECOMPILER("FernFlower Decompiler", "fernflower", new FernFlowerDecompiler()),
|
||||
BYTECODE_DISASSEMBLER("Bytecode Disassembler", "bcvbd", new BytecodeDisassembler()),
|
||||
HEXCODE_VIEWER("Hexcode Viewer", "bcvhex", null),
|
||||
SMALI_DISASSEMBLER("Smali Disassembler", "smali", new SmaliDisassembler()),
|
||||
KRAKATAU_DECOMPILER("Krakatau Decompiler", "krakatau", new KrakatauDecompiler()),
|
||||
KRAKATAU_DISASSEMBLER("Krakatau Disassembler", "krakataud", new KrakatauDisassembler()),
|
||||
JD_DECOMPILER("JD-GUI Decompiler", "jdgui", new JDGUIDecompiler()),
|
||||
JADX_DECOMPILER("JADX Decompiler", "jadx", new JADXDecompiler()),
|
||||
ASM_TEXTIFY_DISASSEMBLER("ASM Disassembler", "asm", new ASMTextifierDisassembler()),
|
||||
ASMIFIER_DECOMPILER("ASMifier Generator", "asmifier", new ASMifierGenerator()),
|
||||
JAVAP_DISASSEMBLER("Javap Disassembler", "javap", new JavapDisassembler()),
|
||||
NONE("None", "", null), PROCYON_DECOMPILER("Procyon Decompiler", "proycon", new ProcyonDecompiler()), CFR_DECOMPILER("CFR Decompiler", "cfr", new CFRDecompiler()), FERNFLOWER_DECOMPILER("FernFlower Decompiler", "fernflower", new FernFlowerDecompiler()), BYTECODE_DISASSEMBLER("Bytecode Disassembler", "bcvbd", new BytecodeDisassembler()), HEXCODE_VIEWER("Hexcode Viewer", "bcvhex", null), SMALI_DISASSEMBLER("Smali Disassembler", "smali", new SmaliDisassembler()), KRAKATAU_DECOMPILER("Krakatau Decompiler", "krakatau", new KrakatauDecompiler()), KRAKATAU_DISASSEMBLER("Krakatau Disassembler", "krakataud", new KrakatauDisassembler()), JD_DECOMPILER("JD-GUI Decompiler", "jdgui", new JDGUIDecompiler()), JADX_DECOMPILER("JADX Decompiler", "jadx", new JADXDecompiler()), ASM_TEXTIFY_DISASSEMBLER("ASM Disassembler", "asm", new ASMTextifierDisassembler()), ASMIFIER_DECOMPILER("ASMifier Generator", "asmifier", new ASMifierGenerator()), JAVAP_DISASSEMBLER("Javap Disassembler", "javap", new JavapDisassembler()),
|
||||
;
|
||||
|
||||
|
||||
private final String decompilerName;
|
||||
private final String decompilerNameProgrammic;
|
||||
private final InternalDecompiler decompiler;
|
||||
|
||||
|
||||
Decompiler(String decompilerName, String decompilerNameProgrammic, InternalDecompiler decompiler)
|
||||
{
|
||||
this.decompilerName = decompilerName;
|
||||
this.decompilerNameProgrammic = decompilerNameProgrammic;
|
||||
this.decompiler = decompiler;
|
||||
}
|
||||
|
||||
|
||||
public String getDecompilerName()
|
||||
{
|
||||
return decompilerName;
|
||||
}
|
||||
|
||||
|
||||
public String getDecompilerNameProgrammic()
|
||||
{
|
||||
return decompilerNameProgrammic;
|
||||
}
|
||||
|
||||
|
||||
public InternalDecompiler getDecompiler()
|
||||
{
|
||||
return decompiler;
|
||||
|
|
|
@ -18,8 +18,6 @@
|
|||
|
||||
package the.bytecode.club.bytecodeviewer.decompilers.bytecode;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import org.objectweb.asm.Attribute;
|
||||
import org.objectweb.asm.Opcodes;
|
||||
import org.objectweb.asm.tree.ClassNode;
|
||||
|
@ -28,6 +26,9 @@ import org.objectweb.asm.tree.InnerClassNode;
|
|||
import org.objectweb.asm.tree.MethodNode;
|
||||
import the.bytecode.club.bytecodeviewer.BytecodeViewer;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import static the.bytecode.club.bytecodeviewer.Constants.nl;
|
||||
|
||||
/**
|
||||
|
@ -37,24 +38,26 @@ import static the.bytecode.club.bytecodeviewer.Constants.nl;
|
|||
|
||||
public class ClassNodeDecompiler
|
||||
{
|
||||
public static PrefixedStringBuilder decompile(
|
||||
PrefixedStringBuilder sb, List<String> decompiledClasses,
|
||||
ClassNode cn) {
|
||||
public static PrefixedStringBuilder decompile(PrefixedStringBuilder sb, List<String> decompiledClasses, ClassNode cn)
|
||||
{
|
||||
List<String> unableToDecompile = new ArrayList<>();
|
||||
decompiledClasses.add(cn.name);
|
||||
sb.append(getAccessString(cn.access));
|
||||
sb.append(" ");
|
||||
sb.append(cn.name);
|
||||
if (cn.superName != null && !cn.superName.equals("java/lang/Object")) {
|
||||
if (cn.superName != null && !cn.superName.equals("java/lang/Object"))
|
||||
{
|
||||
sb.append(" extends ");
|
||||
sb.append(cn.superName);
|
||||
}
|
||||
|
||||
int amountOfInterfaces = cn.interfaces.size();
|
||||
if (amountOfInterfaces > 0) {
|
||||
if (amountOfInterfaces > 0)
|
||||
{
|
||||
sb.append(" implements ");
|
||||
sb.append(cn.interfaces.get(0));
|
||||
for (int i = 1; i < amountOfInterfaces; i++) {
|
||||
for (int i = 1; i < amountOfInterfaces; i++)
|
||||
{
|
||||
sb.append(", ");
|
||||
sb.append(cn.interfaces.get(i));
|
||||
}
|
||||
|
@ -65,66 +68,80 @@ public class ClassNodeDecompiler
|
|||
sb.append("<ClassVersion=" + cn.version + ">");
|
||||
sb.append(nl);
|
||||
|
||||
if (cn.sourceDebug != null) {
|
||||
if (cn.sourceDebug != null)
|
||||
{
|
||||
sb.append(" ");
|
||||
sb.append("<SourceDebug=" + cn.sourceDebug + ">");
|
||||
sb.append(nl);
|
||||
}
|
||||
|
||||
if (cn.sourceFile != null) {
|
||||
if (cn.sourceFile != null)
|
||||
{
|
||||
sb.append(" ");
|
||||
sb.append("<SourceFile=" + cn.sourceFile + ">");
|
||||
sb.append(nl);
|
||||
}
|
||||
|
||||
if (cn.signature != null) {
|
||||
if (cn.signature != null)
|
||||
{
|
||||
sb.append(" ");
|
||||
sb.append("<Sig=" + cn.signature + ">");
|
||||
}
|
||||
|
||||
for (FieldNode fn : cn.fields) {
|
||||
for (FieldNode fn : cn.fields)
|
||||
{
|
||||
sb.append(nl);
|
||||
sb.append(" ");
|
||||
FieldNodeDecompiler.decompile(sb, fn);
|
||||
}
|
||||
if (cn.fields.size() > 0) {
|
||||
if (cn.fields.size() > 0)
|
||||
{
|
||||
sb.append(nl);
|
||||
}
|
||||
for (MethodNode mn : cn.methods) {
|
||||
for (MethodNode mn : cn.methods)
|
||||
{
|
||||
sb.append(nl);
|
||||
MethodNodeDecompiler.decompile(sb, mn, cn);
|
||||
}
|
||||
|
||||
for (InnerClassNode o : cn.innerClasses) {
|
||||
for (InnerClassNode o : cn.innerClasses)
|
||||
{
|
||||
String innerClassName = o.name;
|
||||
if ((innerClassName != null)
|
||||
&& !decompiledClasses.contains(innerClassName)) {
|
||||
if ((innerClassName != null) && !decompiledClasses.contains(innerClassName))
|
||||
{
|
||||
decompiledClasses.add(innerClassName);
|
||||
ClassNode cn1 = BytecodeViewer.blindlySearchForClassNode(innerClassName);
|
||||
if (cn1 != null) {
|
||||
if (cn1 != null)
|
||||
{
|
||||
sb.appendPrefix(" ");
|
||||
sb.append(nl + nl);
|
||||
sb = decompile(sb, decompiledClasses, cn1);
|
||||
sb.trimPrefix(5);
|
||||
sb.append(nl);
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
unableToDecompile.add(innerClassName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!unableToDecompile.isEmpty()) {
|
||||
if (!unableToDecompile.isEmpty())
|
||||
{
|
||||
sb.append("// The following inner classes couldn't be decompiled: ");
|
||||
for (String s : unableToDecompile) {
|
||||
for (String s : unableToDecompile)
|
||||
{
|
||||
sb.append(s);
|
||||
sb.append(" ");
|
||||
}
|
||||
sb.append(nl);
|
||||
}
|
||||
|
||||
if (cn.attrs != null) {
|
||||
if (cn.attrs != null)
|
||||
{
|
||||
sb.append(nl);
|
||||
for (Attribute attr : cn.attrs) {
|
||||
for (Attribute attr : cn.attrs)
|
||||
{
|
||||
//TODO: finish attributes
|
||||
sb.append(attr.type + ": ");// + attr.content.toString());
|
||||
}
|
||||
|
@ -137,7 +154,8 @@ public class ClassNodeDecompiler
|
|||
return sb;
|
||||
}
|
||||
|
||||
public static String getAccessString(int access) {
|
||||
public static String getAccessString(int access)
|
||||
{
|
||||
List<String> tokens = new ArrayList<>();
|
||||
if ((access & Opcodes.ACC_PUBLIC) != 0)
|
||||
tokens.add("public");
|
||||
|
@ -159,13 +177,13 @@ public class ClassNodeDecompiler
|
|||
tokens.add("enum");
|
||||
if ((access & Opcodes.ACC_ANNOTATION) != 0)
|
||||
tokens.add("annotation");
|
||||
if (!tokens.contains("interface") && !tokens.contains("enum")
|
||||
&& !tokens.contains("annotation"))
|
||||
if (!tokens.contains("interface") && !tokens.contains("enum") && !tokens.contains("annotation"))
|
||||
tokens.add("class");
|
||||
|
||||
// hackery delimeters
|
||||
StringBuilder sb = new StringBuilder(tokens.get(0));
|
||||
for (int i = 1; i < tokens.size(); i++) {
|
||||
for (int i = 1; i < tokens.size(); i++)
|
||||
{
|
||||
sb.append(" ");
|
||||
sb.append(tokens.get(i));
|
||||
}
|
||||
|
|
|
@ -18,21 +18,23 @@
|
|||
|
||||
package the.bytecode.club.bytecodeviewer.decompilers.bytecode;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import org.objectweb.asm.Opcodes;
|
||||
import org.objectweb.asm.Type;
|
||||
import org.objectweb.asm.tree.FieldNode;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author Konloch
|
||||
* @author Bibl
|
||||
*/
|
||||
|
||||
public class FieldNodeDecompiler {
|
||||
public class FieldNodeDecompiler
|
||||
{
|
||||
|
||||
public static PrefixedStringBuilder decompile(PrefixedStringBuilder sb,
|
||||
FieldNode f) {
|
||||
public static PrefixedStringBuilder decompile(PrefixedStringBuilder sb, FieldNode f)
|
||||
{
|
||||
String s = getAccessString(f.access);
|
||||
sb.append(s);
|
||||
if (s.length() > 0)
|
||||
|
@ -40,13 +42,17 @@ public class FieldNodeDecompiler {
|
|||
sb.append(Type.getType(f.desc).getClassName());
|
||||
sb.append(" ");
|
||||
sb.append(f.name);
|
||||
if (f.value != null) {
|
||||
if (f.value != null)
|
||||
{
|
||||
sb.append(" = ");
|
||||
if (f.value instanceof String) {
|
||||
if (f.value instanceof String)
|
||||
{
|
||||
sb.append("\"");
|
||||
sb.append(f.value);
|
||||
sb.append("\"");
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
sb.append(f.value);
|
||||
sb.append(" (");
|
||||
sb.append(f.value.getClass().getCanonicalName());
|
||||
|
@ -57,7 +63,8 @@ public class FieldNodeDecompiler {
|
|||
return sb;
|
||||
}
|
||||
|
||||
private static String getAccessString(int access) {
|
||||
private static String getAccessString(int access)
|
||||
{
|
||||
List<String> tokens = new ArrayList<>();
|
||||
if ((access & Opcodes.ACC_PUBLIC) != 0)
|
||||
tokens.add("public");
|
||||
|
@ -79,10 +86,11 @@ public class FieldNodeDecompiler {
|
|||
return "";
|
||||
// hackery delimeters
|
||||
StringBuilder sb = new StringBuilder(tokens.get(0));
|
||||
for (int i = 1; i < tokens.size(); i++) {
|
||||
for (int i = 1; i < tokens.size(); i++)
|
||||
{
|
||||
sb.append(" ");
|
||||
sb.append(tokens.get(i));
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,35 +20,19 @@ package the.bytecode.club.bytecodeviewer.decompilers.bytecode;
|
|||
|
||||
import eu.bibl.banalysis.filter.InstructionFilter;
|
||||
import eu.bibl.banalysis.filter.OpcodeFilter;
|
||||
import eu.bibl.banalysis.filter.insn.FieldInstructionFilter;
|
||||
import eu.bibl.banalysis.filter.insn.IincInstructionFilter;
|
||||
import eu.bibl.banalysis.filter.insn.InsnInstructionFilter;
|
||||
import eu.bibl.banalysis.filter.insn.JumpInstructionFilter;
|
||||
import eu.bibl.banalysis.filter.insn.LdcInstructionFilter;
|
||||
import eu.bibl.banalysis.filter.insn.MethodInstructionFilter;
|
||||
import eu.bibl.banalysis.filter.insn.MultiANewArrayInstructionFilter;
|
||||
import eu.bibl.banalysis.filter.insn.TypeInstructionFilter;
|
||||
import eu.bibl.banalysis.filter.insn.VarInstructionFilter;
|
||||
import java.util.Arrays;
|
||||
import eu.bibl.banalysis.filter.insn.*;
|
||||
import org.objectweb.asm.Opcodes;
|
||||
import org.objectweb.asm.tree.AbstractInsnNode;
|
||||
import org.objectweb.asm.tree.FieldInsnNode;
|
||||
import org.objectweb.asm.tree.IincInsnNode;
|
||||
import org.objectweb.asm.tree.InsnNode;
|
||||
import org.objectweb.asm.tree.JumpInsnNode;
|
||||
import org.objectweb.asm.tree.LabelNode;
|
||||
import org.objectweb.asm.tree.LdcInsnNode;
|
||||
import org.objectweb.asm.tree.MethodInsnNode;
|
||||
import org.objectweb.asm.tree.MultiANewArrayInsnNode;
|
||||
import org.objectweb.asm.tree.TypeInsnNode;
|
||||
import org.objectweb.asm.tree.VarInsnNode;
|
||||
import org.objectweb.asm.tree.*;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
* Pattern filter holder and stepper.
|
||||
*
|
||||
* @author Bibl
|
||||
*/
|
||||
public class InstructionPattern implements Opcodes {
|
||||
public class InstructionPattern implements Opcodes
|
||||
{
|
||||
|
||||
/**
|
||||
* Last instruction-match position pointer
|
||||
|
@ -68,7 +52,8 @@ public class InstructionPattern implements Opcodes {
|
|||
*
|
||||
* @param insns {@link AbstractInsnNode} pattern array.
|
||||
*/
|
||||
public InstructionPattern(AbstractInsnNode[] insns) {
|
||||
public InstructionPattern(AbstractInsnNode[] insns)
|
||||
{
|
||||
filters = translate(insns);
|
||||
lastMatch = new AbstractInsnNode[insns.length];
|
||||
}
|
||||
|
@ -78,10 +63,12 @@ public class InstructionPattern implements Opcodes {
|
|||
*
|
||||
* @param opcodes Opcodes to convert to {@link OpcodeFilter}s.
|
||||
*/
|
||||
public InstructionPattern(int[] opcodes) {
|
||||
public InstructionPattern(int[] opcodes)
|
||||
{
|
||||
filters = new InstructionFilter[opcodes.length];
|
||||
lastMatch = new AbstractInsnNode[opcodes.length];
|
||||
for (int i = 0; i < opcodes.length; i++) {
|
||||
for (int i = 0; i < opcodes.length; i++)
|
||||
{
|
||||
filters[i] = new OpcodeFilter(opcodes[i]);
|
||||
}
|
||||
}
|
||||
|
@ -91,7 +78,8 @@ public class InstructionPattern implements Opcodes {
|
|||
*
|
||||
* @param filters User-defined {@link InstructionFilter}s.
|
||||
*/
|
||||
public InstructionPattern(InstructionFilter[] filters) {
|
||||
public InstructionPattern(InstructionFilter[] filters)
|
||||
{
|
||||
this.filters = filters;
|
||||
lastMatch = new AbstractInsnNode[filters.length];
|
||||
}
|
||||
|
@ -103,18 +91,23 @@ public class InstructionPattern implements Opcodes {
|
|||
* @param ain {@link AbstractInsnNode} to check.
|
||||
* @return True if this instruction successfully completed the pattern.
|
||||
*/
|
||||
public boolean accept(AbstractInsnNode ain) {
|
||||
public boolean accept(AbstractInsnNode ain)
|
||||
{
|
||||
if (pointer >= filters.length)
|
||||
reset();
|
||||
|
||||
InstructionFilter filter = filters[pointer];
|
||||
if (filter.accept(ain)) {
|
||||
if (filter.accept(ain))
|
||||
{
|
||||
lastMatch[pointer] = ain;
|
||||
if (pointer >= (filters.length - 1)) {
|
||||
if (pointer >= (filters.length - 1))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
pointer++;
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
reset();
|
||||
}
|
||||
return false;
|
||||
|
@ -122,16 +115,18 @@ public class InstructionPattern implements Opcodes {
|
|||
|
||||
/**
|
||||
* @return Last pattern sequence match equivilent from the inputted
|
||||
* {@link AbstractInsnNode}s.
|
||||
* {@link AbstractInsnNode}s.
|
||||
*/
|
||||
public AbstractInsnNode[] getLastMatch() {
|
||||
public AbstractInsnNode[] getLastMatch()
|
||||
{
|
||||
return lastMatch;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets the instruction pointer and clears the last match cache data.
|
||||
*/
|
||||
public void resetMatch() {
|
||||
public void resetMatch()
|
||||
{
|
||||
reset();
|
||||
AbstractInsnNode[] match = lastMatch;
|
||||
lastMatch = new AbstractInsnNode[match.length];
|
||||
|
@ -140,7 +135,8 @@ public class InstructionPattern implements Opcodes {
|
|||
/**
|
||||
* Sets the current instruction pointer to 0 (start of pattern).
|
||||
*/
|
||||
public void reset() {
|
||||
public void reset()
|
||||
{
|
||||
pointer = 0;
|
||||
}
|
||||
|
||||
|
@ -151,9 +147,11 @@ public class InstructionPattern implements Opcodes {
|
|||
* @param ains {@link AbstractInsnNode}s to convert.
|
||||
* @return Array of {@link InstructionFilter}s.
|
||||
*/
|
||||
public static InstructionFilter[] translate(AbstractInsnNode[] ains) {
|
||||
public static InstructionFilter[] translate(AbstractInsnNode[] ains)
|
||||
{
|
||||
InstructionFilter[] filters = new InstructionFilter[ains.length];
|
||||
for (int i = 0; i < ains.length; i++) {
|
||||
for (int i = 0; i < ains.length; i++)
|
||||
{
|
||||
filters[i] = translate(ains[i]);
|
||||
}
|
||||
return filters;
|
||||
|
@ -166,54 +164,66 @@ public class InstructionPattern implements Opcodes {
|
|||
* @param ain Instruction to convert.
|
||||
* @return A filter an an equivilent to the inputted instruction.
|
||||
*/
|
||||
public static InstructionFilter translate(AbstractInsnNode ain) {
|
||||
if (ain instanceof LdcInsnNode) {
|
||||
public static InstructionFilter translate(AbstractInsnNode ain)
|
||||
{
|
||||
if (ain instanceof LdcInsnNode)
|
||||
{
|
||||
return new LdcInstructionFilter(((LdcInsnNode) ain).cst);
|
||||
} else if (ain instanceof TypeInsnNode) {
|
||||
return new TypeInstructionFilter(ain.getOpcode(),
|
||||
((TypeInsnNode) ain).desc);
|
||||
} else if (ain instanceof FieldInsnNode) {
|
||||
return new FieldInstructionFilter(ain.getOpcode(),
|
||||
((FieldInsnNode) ain).owner, ((FieldInsnNode) ain).name,
|
||||
((FieldInsnNode) ain).desc);
|
||||
} else if (ain instanceof MethodInsnNode) {
|
||||
return new MethodInstructionFilter(ain.getOpcode(),
|
||||
((MethodInsnNode) ain).owner, ((MethodInsnNode) ain).name,
|
||||
((MethodInsnNode) ain).desc);
|
||||
} else if (ain instanceof VarInsnNode) {
|
||||
return new VarInstructionFilter(ain.getOpcode(),
|
||||
((VarInsnNode) ain).var);
|
||||
} else if (ain instanceof InsnNode) {
|
||||
}
|
||||
else if (ain instanceof TypeInsnNode)
|
||||
{
|
||||
return new TypeInstructionFilter(ain.getOpcode(), ((TypeInsnNode) ain).desc);
|
||||
}
|
||||
else if (ain instanceof FieldInsnNode)
|
||||
{
|
||||
return new FieldInstructionFilter(ain.getOpcode(), ((FieldInsnNode) ain).owner, ((FieldInsnNode) ain).name, ((FieldInsnNode) ain).desc);
|
||||
}
|
||||
else if (ain instanceof MethodInsnNode)
|
||||
{
|
||||
return new MethodInstructionFilter(ain.getOpcode(), ((MethodInsnNode) ain).owner, ((MethodInsnNode) ain).name, ((MethodInsnNode) ain).desc);
|
||||
}
|
||||
else if (ain instanceof VarInsnNode)
|
||||
{
|
||||
return new VarInstructionFilter(ain.getOpcode(), ((VarInsnNode) ain).var);
|
||||
}
|
||||
else if (ain instanceof InsnNode)
|
||||
{
|
||||
return new InsnInstructionFilter(ain.getOpcode());
|
||||
} else if (ain instanceof IincInsnNode) {
|
||||
return new IincInstructionFilter(((IincInsnNode) ain).incr,
|
||||
((IincInsnNode) ain).var);
|
||||
} else if (ain instanceof JumpInsnNode) {
|
||||
}
|
||||
else if (ain instanceof IincInsnNode)
|
||||
{
|
||||
return new IincInstructionFilter(((IincInsnNode) ain).incr, ((IincInsnNode) ain).var);
|
||||
}
|
||||
else if (ain instanceof JumpInsnNode)
|
||||
{
|
||||
return new JumpInstructionFilter(ain.getOpcode());
|
||||
} else if (ain instanceof LabelNode) {
|
||||
}
|
||||
else if (ain instanceof LabelNode)
|
||||
{
|
||||
return InstructionFilter.ACCEPT_ALL; // TODO: Cache labels and
|
||||
// check. // TODO: That's a
|
||||
// fucking stupid idea.
|
||||
} else if (ain instanceof MultiANewArrayInsnNode) {
|
||||
return new MultiANewArrayInstructionFilter(
|
||||
((MultiANewArrayInsnNode) ain).desc,
|
||||
((MultiANewArrayInsnNode) ain).dims);
|
||||
} else {
|
||||
}
|
||||
else if (ain instanceof MultiANewArrayInsnNode)
|
||||
{
|
||||
return new MultiANewArrayInstructionFilter(((MultiANewArrayInsnNode) ain).desc, ((MultiANewArrayInsnNode) ain).dims);
|
||||
}
|
||||
else
|
||||
{
|
||||
return InstructionFilter.ACCEPT_ALL;
|
||||
}
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
AbstractInsnNode[] ains = new AbstractInsnNode[]{
|
||||
new LdcInsnNode("ldc"), new VarInsnNode(ASTORE, 0),
|
||||
new LdcInsnNode("ldc")};
|
||||
InstructionPattern pattern = new InstructionPattern(
|
||||
new AbstractInsnNode[]{new LdcInsnNode("ldc"),
|
||||
new VarInsnNode(-1, -1)});
|
||||
for (AbstractInsnNode ain : ains) {
|
||||
if (pattern.accept(ain)) {
|
||||
public static void main(String[] args)
|
||||
{
|
||||
AbstractInsnNode[] ains = new AbstractInsnNode[]{new LdcInsnNode("ldc"), new VarInsnNode(ASTORE, 0), new LdcInsnNode("ldc")};
|
||||
InstructionPattern pattern = new InstructionPattern(new AbstractInsnNode[]{new LdcInsnNode("ldc"), new VarInsnNode(-1, -1)});
|
||||
for (AbstractInsnNode ain : ains)
|
||||
{
|
||||
if (pattern.accept(ain))
|
||||
{
|
||||
System.out.println(Arrays.toString(pattern.getLastMatch()));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -38,365 +38,484 @@ import java.util.stream.Collectors;
|
|||
* @author Bibl
|
||||
* @author GraxCode
|
||||
*/
|
||||
public class InstructionPrinter implements Opcodes {
|
||||
public class InstructionPrinter implements Opcodes
|
||||
{
|
||||
|
||||
/**
|
||||
* The MethodNode to print
|
||||
**/
|
||||
private final MethodNode mNode;
|
||||
private final TypeAndName[] args;
|
||||
/**
|
||||
* The MethodNode to print
|
||||
**/
|
||||
private final MethodNode mNode;
|
||||
private final TypeAndName[] args;
|
||||
|
||||
protected int[] pattern;
|
||||
protected boolean match;
|
||||
protected int[] pattern;
|
||||
protected boolean match;
|
||||
|
||||
protected List<AbstractInsnNode> matchedInsns;
|
||||
protected Map<LabelNode, Integer> labels;
|
||||
private boolean firstLabel = false;
|
||||
private final List<String> info = new ArrayList<>();
|
||||
protected List<AbstractInsnNode> matchedInsns;
|
||||
protected Map<LabelNode, Integer> labels;
|
||||
private boolean firstLabel = false;
|
||||
private final List<String> info = new ArrayList<>();
|
||||
|
||||
public InstructionPrinter(MethodNode m, TypeAndName[] args) {
|
||||
this.args = args;
|
||||
mNode = m;
|
||||
labels = new HashMap<>();
|
||||
precalculateLabelIndexes(m);
|
||||
// matchedInsns = new ArrayList<AbstractInsnNode>(); // ingnored because
|
||||
// match = false
|
||||
match = false;
|
||||
}
|
||||
|
||||
public InstructionPrinter(MethodNode m, InstructionPattern pattern, TypeAndName[] args) {
|
||||
this(m, args);
|
||||
InstructionSearcher searcher = new InstructionSearcher(m.instructions, pattern);
|
||||
match = searcher.search();
|
||||
if (match) {
|
||||
for (AbstractInsnNode[] ains : searcher.getMatches()) {
|
||||
Collections.addAll(matchedInsns, ains);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void precalculateLabelIndexes(MethodNode m) {
|
||||
if(m == null)
|
||||
return;
|
||||
|
||||
int lIdx = 0;
|
||||
for (AbstractInsnNode ain : m.instructions) {
|
||||
if (ain.getType() == AbstractInsnNode.LABEL) {
|
||||
labels.put((LabelNode) ain, lIdx++);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the print
|
||||
*
|
||||
* @return The print as an ArrayList
|
||||
*/
|
||||
public List<String> createPrint() {
|
||||
firstLabel = false;
|
||||
info.clear();
|
||||
for (AbstractInsnNode ain : mNode.instructions) {
|
||||
String line = printInstruction(ain);
|
||||
if (!line.isEmpty()) {
|
||||
if (match) if (matchedInsns.contains(ain)) line = " -> " + line;
|
||||
|
||||
info.add(line);
|
||||
}
|
||||
}
|
||||
if (firstLabel && BytecodeViewer.viewer.appendBracketsToLabels.isSelected()) info.add("}");
|
||||
return info;
|
||||
}
|
||||
|
||||
public String printInstruction(AbstractInsnNode ain) {
|
||||
String line = "";
|
||||
if (ain instanceof VarInsnNode) {
|
||||
line = printVarInsnNode((VarInsnNode) ain);
|
||||
} else if (ain instanceof IntInsnNode) {
|
||||
line = printIntInsnNode((IntInsnNode) ain);
|
||||
} else if (ain instanceof FieldInsnNode) {
|
||||
line = printFieldInsnNode((FieldInsnNode) ain);
|
||||
} else if (ain instanceof MethodInsnNode) {
|
||||
line = printMethodInsnNode((MethodInsnNode) ain);
|
||||
} else if (ain instanceof LdcInsnNode) {
|
||||
line = printLdcInsnNode((LdcInsnNode) ain);
|
||||
} else if (ain instanceof InsnNode) {
|
||||
line = printInsnNode((InsnNode) ain);
|
||||
} else if (ain instanceof JumpInsnNode) {
|
||||
line = printJumpInsnNode((JumpInsnNode) ain);
|
||||
} else if (ain instanceof LineNumberNode) {
|
||||
line = printLineNumberNode((LineNumberNode) ain);
|
||||
} else if (ain instanceof LabelNode) {
|
||||
if (firstLabel && BytecodeViewer.viewer.appendBracketsToLabels.isSelected()) info.add("}");
|
||||
|
||||
LabelNode label = (LabelNode) ain;
|
||||
if (mNode.tryCatchBlocks != null) {
|
||||
List<TryCatchBlockNode> tcbs = mNode.tryCatchBlocks;
|
||||
String starting = tcbs.stream().filter(tcb -> tcb.start == label).map(tcb -> "start TCB" + tcbs.indexOf(tcb)).collect(Collectors.joining(", "));
|
||||
String ending = tcbs.stream().filter(tcb -> tcb.end == label).map(tcb -> "end TCB" + tcbs.indexOf(tcb)).collect(Collectors.joining(", "));
|
||||
String handlers = tcbs.stream().filter(tcb -> tcb.handler == label).map(tcb -> "handle TCB" + tcbs.indexOf(tcb)).collect(Collectors.joining(", "));
|
||||
if (!ending.isEmpty()) info.add("// " + ending);
|
||||
if (!starting.isEmpty()) info.add("// " + starting);
|
||||
if (!handlers.isEmpty()) info.add("// " + handlers);
|
||||
}
|
||||
line = printLabelNode((LabelNode) ain);
|
||||
|
||||
if (BytecodeViewer.viewer.appendBracketsToLabels.isSelected()) {
|
||||
if (!firstLabel) firstLabel = true;
|
||||
line += " {";
|
||||
}
|
||||
} else if (ain instanceof TypeInsnNode) {
|
||||
line = printTypeInsnNode((TypeInsnNode) ain);
|
||||
} else if (ain instanceof FrameNode) {
|
||||
line = printFrameNode((FrameNode) ain);
|
||||
} else if (ain instanceof IincInsnNode) {
|
||||
line = printIincInsnNode((IincInsnNode) ain);
|
||||
} else if (ain instanceof TableSwitchInsnNode) {
|
||||
line = printTableSwitchInsnNode((TableSwitchInsnNode) ain);
|
||||
} else if (ain instanceof LookupSwitchInsnNode) {
|
||||
line = printLookupSwitchInsnNode((LookupSwitchInsnNode) ain);
|
||||
} else if (ain instanceof InvokeDynamicInsnNode) {
|
||||
line = printInvokeDynamicInsNode((InvokeDynamicInsnNode) ain);
|
||||
} else if (ain instanceof MultiANewArrayInsnNode) {
|
||||
line = printMultiANewArrayInsNode((MultiANewArrayInsnNode) ain);
|
||||
} else {
|
||||
line += "UNADDED OPCODE: " + nameOpcode(ain.getOpcode()) + " " + ain;
|
||||
public InstructionPrinter(MethodNode m, TypeAndName[] args)
|
||||
{
|
||||
this.args = args;
|
||||
mNode = m;
|
||||
labels = new HashMap<>();
|
||||
precalculateLabelIndexes(m);
|
||||
// matchedInsns = new ArrayList<AbstractInsnNode>(); // ingnored because
|
||||
// match = false
|
||||
match = false;
|
||||
}
|
||||
|
||||
return line;
|
||||
}
|
||||
|
||||
protected String printVarInsnNode(VarInsnNode vin) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append(nameOpcode(vin.getOpcode()));
|
||||
sb.append(" ");
|
||||
sb.append(vin.var);
|
||||
if (BytecodeViewer.viewer.debugHelpers.isSelected()) {
|
||||
if (vin.var == 0 && !Modifier.isStatic(mNode.access)) {
|
||||
sb.append(" // reference to self");
|
||||
} else {
|
||||
final int refIndex = vin.var - (Modifier.isStatic(mNode.access) ? 0 : 1);
|
||||
if (refIndex >= 0 && refIndex < args.length - 1) {
|
||||
sb.append(" // reference to ").append(args[refIndex].name);
|
||||
public InstructionPrinter(MethodNode m, InstructionPattern pattern, TypeAndName[] args)
|
||||
{
|
||||
this(m, args);
|
||||
InstructionSearcher searcher = new InstructionSearcher(m.instructions, pattern);
|
||||
match = searcher.search();
|
||||
if (match)
|
||||
{
|
||||
for (AbstractInsnNode[] ains : searcher.getMatches())
|
||||
{
|
||||
Collections.addAll(matchedInsns, ains);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
private void precalculateLabelIndexes(MethodNode m)
|
||||
{
|
||||
if (m == null)
|
||||
return;
|
||||
|
||||
protected String printIntInsnNode(IntInsnNode iin) {
|
||||
return nameOpcode(iin.getOpcode()) + " " + iin.operand;
|
||||
}
|
||||
|
||||
protected String printFieldInsnNode(FieldInsnNode fin) {
|
||||
String desc = Type.getType(fin.desc).getClassName();
|
||||
if (desc.equals("null")) desc = fin.desc;
|
||||
return nameOpcode(fin.getOpcode()) + " " + fin.owner + "." + fin.name + ":" + desc;
|
||||
}
|
||||
|
||||
protected String printMethodInsnNode(MethodInsnNode min) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append(nameOpcode(min.getOpcode())).append(" ").append(min.owner).append(".").append(min.name);
|
||||
|
||||
String desc = min.desc;
|
||||
try {
|
||||
if (Type.getType(min.desc) != null) desc = Type.getType(min.desc).getClassName();
|
||||
} catch (java.lang.AssertionError e) {
|
||||
//e.printStackTrace();
|
||||
} catch (java.lang.Exception e) {
|
||||
e.printStackTrace();
|
||||
int lIdx = 0;
|
||||
for (AbstractInsnNode ain : m.instructions)
|
||||
{
|
||||
if (ain.getType() == AbstractInsnNode.LABEL)
|
||||
{
|
||||
labels.put((LabelNode) ain, lIdx++);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (desc == null || desc.equals("null")) desc = min.desc;
|
||||
/**
|
||||
* Creates the print
|
||||
*
|
||||
* @return The print as an ArrayList
|
||||
*/
|
||||
public List<String> createPrint()
|
||||
{
|
||||
firstLabel = false;
|
||||
info.clear();
|
||||
for (AbstractInsnNode ain : mNode.instructions)
|
||||
{
|
||||
String line = printInstruction(ain);
|
||||
if (!line.isEmpty())
|
||||
{
|
||||
if (match)
|
||||
if (matchedInsns.contains(ain))
|
||||
line = " -> " + line;
|
||||
|
||||
sb.append(desc);
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
protected String printLdcInsnNode(LdcInsnNode ldc) {
|
||||
if (ldc.cst instanceof String)
|
||||
return nameOpcode(ldc.getOpcode()) + " \"" + StringEscapeUtils.escapeJava(ldc.cst.toString()) + "\" (" + ldc.cst.getClass().getCanonicalName() + ")";
|
||||
|
||||
return nameOpcode(ldc.getOpcode()) + " " + StringEscapeUtils.escapeJava(ldc.cst.toString()) + " (" + ldc.cst.getClass().getCanonicalName() + ")";
|
||||
}
|
||||
|
||||
protected String printInsnNode(InsnNode in) {
|
||||
return nameOpcode(in.getOpcode());
|
||||
}
|
||||
|
||||
protected String printJumpInsnNode(JumpInsnNode jin) {
|
||||
return nameOpcode(jin.getOpcode()) + " L" + resolveLabel(jin.label);
|
||||
}
|
||||
|
||||
protected String printLineNumberNode(LineNumberNode lnn) {
|
||||
if(BytecodeViewer.viewer.printLineNumbers.isSelected())
|
||||
return "// line " + lnn.line;
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
protected String printLabelNode(LabelNode label) {
|
||||
return "L" + resolveLabel(label);
|
||||
}
|
||||
|
||||
protected String printTypeInsnNode(TypeInsnNode tin) {
|
||||
try {
|
||||
String desc = tin.desc;
|
||||
try {
|
||||
if (Type.getType(tin.desc) != null) desc = Type.getType(tin.desc).getClassName();
|
||||
|
||||
if (desc.equals("null")) desc = tin.desc;
|
||||
} catch (java.lang.ArrayIndexOutOfBoundsException ignored) {
|
||||
|
||||
}
|
||||
return nameOpcode(tin.getOpcode()) + " " + desc;
|
||||
} catch (Exception e) {
|
||||
return nameOpcode(tin.getOpcode()) + " " + tin.desc;
|
||||
}
|
||||
}
|
||||
|
||||
protected String printIincInsnNode(IincInsnNode iin) {
|
||||
return nameOpcode(iin.getOpcode()) + " " + iin.var + " " + iin.incr;
|
||||
}
|
||||
|
||||
protected String printTableSwitchInsnNode(TableSwitchInsnNode tin) {
|
||||
StringBuilder line = new StringBuilder(nameOpcode(tin.getOpcode()) + " \n");
|
||||
List<?> labels = tin.labels;
|
||||
int count = 0;
|
||||
for (int i = tin.min; i < tin.max + 1; i++) {
|
||||
line.append(" val: ").append(i).append(" -> ").append("L").append(resolveLabel((LabelNode) labels.get(count++))).append("\n");
|
||||
}
|
||||
line.append(" default" + " -> L").append(resolveLabel(tin.dflt));
|
||||
return line.toString();
|
||||
}
|
||||
|
||||
protected String printLookupSwitchInsnNode(LookupSwitchInsnNode lin) {
|
||||
StringBuilder line = new StringBuilder(nameOpcode(lin.getOpcode()) + ": \n");
|
||||
List<?> keys = lin.keys;
|
||||
List<?> labels = lin.labels;
|
||||
|
||||
for (int i = 0; i < keys.size(); i++) {
|
||||
int key = (Integer) keys.get(i);
|
||||
LabelNode label = (LabelNode) labels.get(i);
|
||||
line.append(" val: ").append(key).append(" -> ").append("L").append(resolveLabel(label)).append("\n");
|
||||
info.add(line);
|
||||
}
|
||||
}
|
||||
if (firstLabel && BytecodeViewer.viewer.appendBracketsToLabels.isSelected())
|
||||
info.add("}");
|
||||
return info;
|
||||
}
|
||||
|
||||
line.append(" default" + " -> L").append(resolveLabel(lin.dflt));
|
||||
return line.toString();
|
||||
}
|
||||
public String printInstruction(AbstractInsnNode ain)
|
||||
{
|
||||
String line = "";
|
||||
if (ain instanceof VarInsnNode)
|
||||
{
|
||||
line = printVarInsnNode((VarInsnNode) ain);
|
||||
}
|
||||
else if (ain instanceof IntInsnNode)
|
||||
{
|
||||
line = printIntInsnNode((IntInsnNode) ain);
|
||||
}
|
||||
else if (ain instanceof FieldInsnNode)
|
||||
{
|
||||
line = printFieldInsnNode((FieldInsnNode) ain);
|
||||
}
|
||||
else if (ain instanceof MethodInsnNode)
|
||||
{
|
||||
line = printMethodInsnNode((MethodInsnNode) ain);
|
||||
}
|
||||
else if (ain instanceof LdcInsnNode)
|
||||
{
|
||||
line = printLdcInsnNode((LdcInsnNode) ain);
|
||||
}
|
||||
else if (ain instanceof InsnNode)
|
||||
{
|
||||
line = printInsnNode((InsnNode) ain);
|
||||
}
|
||||
else if (ain instanceof JumpInsnNode)
|
||||
{
|
||||
line = printJumpInsnNode((JumpInsnNode) ain);
|
||||
}
|
||||
else if (ain instanceof LineNumberNode)
|
||||
{
|
||||
line = printLineNumberNode((LineNumberNode) ain);
|
||||
}
|
||||
else if (ain instanceof LabelNode)
|
||||
{
|
||||
if (firstLabel && BytecodeViewer.viewer.appendBracketsToLabels.isSelected())
|
||||
info.add("}");
|
||||
|
||||
protected String printInvokeDynamicInsNode(InvokeDynamicInsnNode idin) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append(nameOpcode(idin.getOpcode())).append(" ").append(idin.bsm.getOwner()).append('.').append(idin.bsm.getName()).append(idin.bsm.getDesc()).append(" : ").append(idin.name).append(idin.desc);
|
||||
LabelNode label = (LabelNode) ain;
|
||||
if (mNode.tryCatchBlocks != null)
|
||||
{
|
||||
List<TryCatchBlockNode> tcbs = mNode.tryCatchBlocks;
|
||||
String starting = tcbs.stream().filter(tcb -> tcb.start == label).map(tcb -> "start TCB" + tcbs.indexOf(tcb)).collect(Collectors.joining(", "));
|
||||
String ending = tcbs.stream().filter(tcb -> tcb.end == label).map(tcb -> "end TCB" + tcbs.indexOf(tcb)).collect(Collectors.joining(", "));
|
||||
String handlers = tcbs.stream().filter(tcb -> tcb.handler == label).map(tcb -> "handle TCB" + tcbs.indexOf(tcb)).collect(Collectors.joining(", "));
|
||||
if (!ending.isEmpty())
|
||||
info.add("// " + ending);
|
||||
if (!starting.isEmpty())
|
||||
info.add("// " + starting);
|
||||
if (!handlers.isEmpty())
|
||||
info.add("// " + handlers);
|
||||
}
|
||||
line = printLabelNode((LabelNode) ain);
|
||||
|
||||
if (idin.bsmArgs != null) {
|
||||
for (Object o : idin.bsmArgs) {
|
||||
if (BytecodeViewer.viewer.appendBracketsToLabels.isSelected())
|
||||
{
|
||||
if (!firstLabel)
|
||||
firstLabel = true;
|
||||
line += " {";
|
||||
}
|
||||
}
|
||||
else if (ain instanceof TypeInsnNode)
|
||||
{
|
||||
line = printTypeInsnNode((TypeInsnNode) ain);
|
||||
}
|
||||
else if (ain instanceof FrameNode)
|
||||
{
|
||||
line = printFrameNode((FrameNode) ain);
|
||||
}
|
||||
else if (ain instanceof IincInsnNode)
|
||||
{
|
||||
line = printIincInsnNode((IincInsnNode) ain);
|
||||
}
|
||||
else if (ain instanceof TableSwitchInsnNode)
|
||||
{
|
||||
line = printTableSwitchInsnNode((TableSwitchInsnNode) ain);
|
||||
}
|
||||
else if (ain instanceof LookupSwitchInsnNode)
|
||||
{
|
||||
line = printLookupSwitchInsnNode((LookupSwitchInsnNode) ain);
|
||||
}
|
||||
else if (ain instanceof InvokeDynamicInsnNode)
|
||||
{
|
||||
line = printInvokeDynamicInsNode((InvokeDynamicInsnNode) ain);
|
||||
}
|
||||
else if (ain instanceof MultiANewArrayInsnNode)
|
||||
{
|
||||
line = printMultiANewArrayInsNode((MultiANewArrayInsnNode) ain);
|
||||
}
|
||||
else
|
||||
{
|
||||
line += "UNADDED OPCODE: " + nameOpcode(ain.getOpcode()) + " " + ain;
|
||||
}
|
||||
|
||||
return line;
|
||||
}
|
||||
|
||||
protected String printVarInsnNode(VarInsnNode vin)
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append(nameOpcode(vin.getOpcode()));
|
||||
sb.append(" ");
|
||||
sb.append(o.toString());
|
||||
}
|
||||
sb.append(vin.var);
|
||||
if (BytecodeViewer.viewer.debugHelpers.isSelected())
|
||||
{
|
||||
if (vin.var == 0 && !Modifier.isStatic(mNode.access))
|
||||
{
|
||||
sb.append(" // reference to self");
|
||||
}
|
||||
else
|
||||
{
|
||||
final int refIndex = vin.var - (Modifier.isStatic(mNode.access) ? 0 : 1);
|
||||
if (refIndex >= 0 && refIndex < args.length - 1)
|
||||
{
|
||||
sb.append(" // reference to ").append(args[refIndex].name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
protected String printMultiANewArrayInsNode(MultiANewArrayInsnNode mana) {
|
||||
return nameOpcode(mana.getOpcode()) + " " + mana.dims + " : " + mana.desc;
|
||||
}
|
||||
|
||||
private String printFrameNode(FrameNode frame) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append(nameFrameType(frame.type)).append(" ");
|
||||
sb.append("(Locals");
|
||||
if (frame.local != null && !frame.local.isEmpty()) {
|
||||
sb.append("[").append(frame.local.size()).append("]: ");
|
||||
sb.append(frame.local.stream().map(this::printFrameObject).collect(Collectors.joining(", ")));
|
||||
} else {
|
||||
sb.append("[0]");
|
||||
protected String printIntInsnNode(IntInsnNode iin)
|
||||
{
|
||||
return nameOpcode(iin.getOpcode()) + " " + iin.operand;
|
||||
}
|
||||
sb.append(") ");
|
||||
|
||||
sb.append("(Stack");
|
||||
if (frame.stack != null && !frame.stack.isEmpty()) {
|
||||
sb.append("[").append(frame.stack.size()).append("]: ");
|
||||
sb.append(frame.stack.stream().map(this::printFrameObject).collect(Collectors.joining(", ")));
|
||||
} else {
|
||||
sb.append("[0]");
|
||||
protected String printFieldInsnNode(FieldInsnNode fin)
|
||||
{
|
||||
String desc = Type.getType(fin.desc).getClassName();
|
||||
if (desc.equals("null"))
|
||||
desc = fin.desc;
|
||||
return nameOpcode(fin.getOpcode()) + " " + fin.owner + "." + fin.name + ":" + desc;
|
||||
}
|
||||
sb.append(") ");
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
protected String printMethodInsnNode(MethodInsnNode min)
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append(nameOpcode(min.getOpcode())).append(" ").append(min.owner).append(".").append(min.name);
|
||||
|
||||
private String printFrameObject(Object obj) {
|
||||
if (obj instanceof LabelNode) return "label [L" + resolveLabel((LabelNode) obj) + "]";
|
||||
if (obj instanceof Integer) {
|
||||
switch ((int) obj) {
|
||||
case 0:
|
||||
return "top";
|
||||
case 1:
|
||||
return "int";
|
||||
case 2:
|
||||
return "float";
|
||||
case 3:
|
||||
return "double";
|
||||
case 4:
|
||||
return "long";
|
||||
case 5:
|
||||
return "null";
|
||||
case 6:
|
||||
return "uninitialized this";
|
||||
default:
|
||||
return "unknown";
|
||||
}
|
||||
String desc = min.desc;
|
||||
try
|
||||
{
|
||||
if (Type.getType(min.desc) != null)
|
||||
desc = Type.getType(min.desc).getClassName();
|
||||
}
|
||||
catch (java.lang.AssertionError e)
|
||||
{
|
||||
//e.printStackTrace();
|
||||
}
|
||||
catch (java.lang.Exception e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
if (desc == null || desc.equals("null"))
|
||||
desc = min.desc;
|
||||
|
||||
sb.append(desc);
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
if (obj instanceof String) return obj.toString();
|
||||
return "unknown [" + obj.toString() + "]";
|
||||
}
|
||||
|
||||
private String nameFrameType(int type) {
|
||||
switch (type) {
|
||||
case F_NEW:
|
||||
return " f_new";
|
||||
case F_FULL:
|
||||
return " f_full";
|
||||
case F_APPEND:
|
||||
return " f_append";
|
||||
case F_CHOP:
|
||||
return " f_chop";
|
||||
case F_SAME:
|
||||
return " f_same";
|
||||
case F_SAME1:
|
||||
return " f_same1";
|
||||
default:
|
||||
return " f_unknown" + type;
|
||||
protected String printLdcInsnNode(LdcInsnNode ldc)
|
||||
{
|
||||
if (ldc.cst instanceof String)
|
||||
return nameOpcode(ldc.getOpcode()) + " \"" + StringEscapeUtils.escapeJava(ldc.cst.toString()) + "\" (" + ldc.cst.getClass().getCanonicalName() + ")";
|
||||
|
||||
return nameOpcode(ldc.getOpcode()) + " " + StringEscapeUtils.escapeJava(ldc.cst.toString()) + " (" + ldc.cst.getClass().getCanonicalName() + ")";
|
||||
}
|
||||
}
|
||||
|
||||
protected String nameOpcode(int opcode) {
|
||||
return " " + OpcodeInfo.OPCODES.get(opcode).toLowerCase();
|
||||
}
|
||||
protected String printInsnNode(InsnNode in)
|
||||
{
|
||||
return nameOpcode(in.getOpcode());
|
||||
}
|
||||
|
||||
protected int resolveLabel(LabelNode label) {
|
||||
if (labels.containsKey(label)) {
|
||||
return labels.get(label);
|
||||
} else {
|
||||
protected String printJumpInsnNode(JumpInsnNode jin)
|
||||
{
|
||||
return nameOpcode(jin.getOpcode()) + " L" + resolveLabel(jin.label);
|
||||
}
|
||||
|
||||
protected String printLineNumberNode(LineNumberNode lnn)
|
||||
{
|
||||
if (BytecodeViewer.viewer.printLineNumbers.isSelected())
|
||||
return "// line " + lnn.line;
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
protected String printLabelNode(LabelNode label)
|
||||
{
|
||||
return "L" + resolveLabel(label);
|
||||
}
|
||||
|
||||
protected String printTypeInsnNode(TypeInsnNode tin)
|
||||
{
|
||||
try
|
||||
{
|
||||
String desc = tin.desc;
|
||||
try
|
||||
{
|
||||
if (Type.getType(tin.desc) != null)
|
||||
desc = Type.getType(tin.desc).getClassName();
|
||||
|
||||
if (desc.equals("null"))
|
||||
desc = tin.desc;
|
||||
}
|
||||
catch (java.lang.ArrayIndexOutOfBoundsException ignored)
|
||||
{
|
||||
|
||||
}
|
||||
return nameOpcode(tin.getOpcode()) + " " + desc;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
return nameOpcode(tin.getOpcode()) + " " + tin.desc;
|
||||
}
|
||||
}
|
||||
|
||||
protected String printIincInsnNode(IincInsnNode iin)
|
||||
{
|
||||
return nameOpcode(iin.getOpcode()) + " " + iin.var + " " + iin.incr;
|
||||
}
|
||||
|
||||
protected String printTableSwitchInsnNode(TableSwitchInsnNode tin)
|
||||
{
|
||||
StringBuilder line = new StringBuilder(nameOpcode(tin.getOpcode()) + " \n");
|
||||
List<?> labels = tin.labels;
|
||||
int count = 0;
|
||||
for (int i = tin.min; i < tin.max + 1; i++)
|
||||
{
|
||||
line.append(" val: ").append(i).append(" -> ").append("L").append(resolveLabel((LabelNode) labels.get(count++))).append("\n");
|
||||
}
|
||||
line.append(" default" + " -> L").append(resolveLabel(tin.dflt));
|
||||
return line.toString();
|
||||
}
|
||||
|
||||
protected String printLookupSwitchInsnNode(LookupSwitchInsnNode lin)
|
||||
{
|
||||
StringBuilder line = new StringBuilder(nameOpcode(lin.getOpcode()) + ": \n");
|
||||
List<?> keys = lin.keys;
|
||||
List<?> labels = lin.labels;
|
||||
|
||||
for (int i = 0; i < keys.size(); i++)
|
||||
{
|
||||
int key = (Integer) keys.get(i);
|
||||
LabelNode label = (LabelNode) labels.get(i);
|
||||
line.append(" val: ").append(key).append(" -> ").append("L").append(resolveLabel(label)).append("\n");
|
||||
}
|
||||
|
||||
line.append(" default" + " -> L").append(resolveLabel(lin.dflt));
|
||||
return line.toString();
|
||||
}
|
||||
|
||||
protected String printInvokeDynamicInsNode(InvokeDynamicInsnNode idin)
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append(nameOpcode(idin.getOpcode())).append(" ").append(idin.bsm.getOwner()).append('.').append(idin.bsm.getName()).append(idin.bsm.getDesc()).append(" : ").append(idin.name).append(idin.desc);
|
||||
|
||||
if (idin.bsmArgs != null)
|
||||
{
|
||||
for (Object o : idin.bsmArgs)
|
||||
{
|
||||
sb.append(" ");
|
||||
sb.append(o.toString());
|
||||
}
|
||||
}
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
protected String printMultiANewArrayInsNode(MultiANewArrayInsnNode mana)
|
||||
{
|
||||
return nameOpcode(mana.getOpcode()) + " " + mana.dims + " : " + mana.desc;
|
||||
}
|
||||
|
||||
private String printFrameNode(FrameNode frame)
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append(nameFrameType(frame.type)).append(" ");
|
||||
sb.append("(Locals");
|
||||
if (frame.local != null && !frame.local.isEmpty())
|
||||
{
|
||||
sb.append("[").append(frame.local.size()).append("]: ");
|
||||
sb.append(frame.local.stream().map(this::printFrameObject).collect(Collectors.joining(", ")));
|
||||
}
|
||||
else
|
||||
{
|
||||
sb.append("[0]");
|
||||
}
|
||||
sb.append(") ");
|
||||
|
||||
sb.append("(Stack");
|
||||
if (frame.stack != null && !frame.stack.isEmpty())
|
||||
{
|
||||
sb.append("[").append(frame.stack.size()).append("]: ");
|
||||
sb.append(frame.stack.stream().map(this::printFrameObject).collect(Collectors.joining(", ")));
|
||||
}
|
||||
else
|
||||
{
|
||||
sb.append("[0]");
|
||||
}
|
||||
sb.append(") ");
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
private String printFrameObject(Object obj)
|
||||
{
|
||||
if (obj instanceof LabelNode)
|
||||
return "label [L" + resolveLabel((LabelNode) obj) + "]";
|
||||
if (obj instanceof Integer)
|
||||
{
|
||||
switch ((int) obj)
|
||||
{
|
||||
case 0:
|
||||
return "top";
|
||||
case 1:
|
||||
return "int";
|
||||
case 2:
|
||||
return "float";
|
||||
case 3:
|
||||
return "double";
|
||||
case 4:
|
||||
return "long";
|
||||
case 5:
|
||||
return "null";
|
||||
case 6:
|
||||
return "uninitialized this";
|
||||
default:
|
||||
return "unknown";
|
||||
}
|
||||
}
|
||||
if (obj instanceof String)
|
||||
return obj.toString();
|
||||
return "unknown [" + obj.toString() + "]";
|
||||
}
|
||||
|
||||
private String nameFrameType(int type)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case F_NEW:
|
||||
return " f_new";
|
||||
case F_FULL:
|
||||
return " f_full";
|
||||
case F_APPEND:
|
||||
return " f_append";
|
||||
case F_CHOP:
|
||||
return " f_chop";
|
||||
case F_SAME:
|
||||
return " f_same";
|
||||
case F_SAME1:
|
||||
return " f_same1";
|
||||
default:
|
||||
return " f_unknown" + type;
|
||||
}
|
||||
}
|
||||
|
||||
protected String nameOpcode(int opcode)
|
||||
{
|
||||
return " " + OpcodeInfo.OPCODES.get(opcode).toLowerCase();
|
||||
}
|
||||
|
||||
protected int resolveLabel(LabelNode label)
|
||||
{
|
||||
if (labels.containsKey(label))
|
||||
{
|
||||
return labels.get(label);
|
||||
}
|
||||
else
|
||||
{
|
||||
/*int newLabelIndex = labels.size() + 1;
|
||||
labels.put(label, newLabelIndex);
|
||||
return newLabelIndex;*/
|
||||
throw new IllegalStateException("LabelNode index not found. (Label not in InsnList?)");
|
||||
throw new IllegalStateException("LabelNode index not found. (Label not in InsnList?)");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void saveTo(File file, InstructionPrinter printer) {
|
||||
try (FileWriter fw = new FileWriter(file); BufferedWriter bw = new BufferedWriter(fw)) {
|
||||
for (String s : printer.createPrint()) {
|
||||
bw.write(s);
|
||||
bw.newLine();
|
||||
}
|
||||
} catch (IOException e) {
|
||||
BytecodeViewer.handleException(e);
|
||||
public static void saveTo(File file, InstructionPrinter printer)
|
||||
{
|
||||
try (FileWriter fw = new FileWriter(file); BufferedWriter bw = new BufferedWriter(fw))
|
||||
{
|
||||
for (String s : printer.createPrint())
|
||||
{
|
||||
bw.write(s);
|
||||
bw.newLine();
|
||||
}
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
BytecodeViewer.handleException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -18,44 +18,52 @@
|
|||
|
||||
package the.bytecode.club.bytecodeviewer.decompilers.bytecode;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import org.objectweb.asm.Opcodes;
|
||||
import org.objectweb.asm.tree.AbstractInsnNode;
|
||||
import org.objectweb.asm.tree.FrameNode;
|
||||
import org.objectweb.asm.tree.InsnList;
|
||||
import org.objectweb.asm.tree.LineNumberNode;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author Bibl
|
||||
*/
|
||||
|
||||
public class InstructionSearcher implements Opcodes {
|
||||
public class InstructionSearcher implements Opcodes
|
||||
{
|
||||
|
||||
protected InsnList insns;
|
||||
protected InstructionPattern pattern;
|
||||
|
||||
protected List<AbstractInsnNode[]> matches;
|
||||
|
||||
public InstructionSearcher(InsnList insns, int[] opcodes) {
|
||||
public InstructionSearcher(InsnList insns, int[] opcodes)
|
||||
{
|
||||
this(insns, new InstructionPattern(opcodes));
|
||||
}
|
||||
|
||||
public InstructionSearcher(InsnList insns, AbstractInsnNode[] ains) {
|
||||
public InstructionSearcher(InsnList insns, AbstractInsnNode[] ains)
|
||||
{
|
||||
this(insns, new InstructionPattern(ains));
|
||||
}
|
||||
|
||||
public InstructionSearcher(InsnList insns, InstructionPattern pattern) {
|
||||
public InstructionSearcher(InsnList insns, InstructionPattern pattern)
|
||||
{
|
||||
this.insns = insns;
|
||||
this.pattern = pattern;
|
||||
matches = new ArrayList<>();
|
||||
}
|
||||
|
||||
public boolean search() {
|
||||
for (AbstractInsnNode ain : insns.toArray()) {
|
||||
public boolean search()
|
||||
{
|
||||
for (AbstractInsnNode ain : insns.toArray())
|
||||
{
|
||||
if (ain instanceof LineNumberNode || ain instanceof FrameNode)
|
||||
continue;
|
||||
if (pattern.accept(ain)) {
|
||||
if (pattern.accept(ain))
|
||||
{
|
||||
matches.add(pattern.getLastMatch());
|
||||
pattern.resetMatch();
|
||||
}
|
||||
|
@ -63,11 +71,13 @@ public class InstructionSearcher implements Opcodes {
|
|||
return size() != 0;
|
||||
}
|
||||
|
||||
public List<AbstractInsnNode[]> getMatches() {
|
||||
public List<AbstractInsnNode[]> getMatches()
|
||||
{
|
||||
return matches;
|
||||
}
|
||||
|
||||
public int size() {
|
||||
public int size()
|
||||
{
|
||||
return matches.size();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
File diff suppressed because one or more lines are too long
|
@ -18,17 +18,14 @@
|
|||
|
||||
package the.bytecode.club.bytecodeviewer.decompilers.bytecode;
|
||||
|
||||
import org.objectweb.asm.Opcodes;
|
||||
import org.objectweb.asm.Type;
|
||||
import org.objectweb.asm.tree.*;
|
||||
import the.bytecode.club.bytecodeviewer.BytecodeViewer;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import org.objectweb.asm.Opcodes;
|
||||
import org.objectweb.asm.Type;
|
||||
import org.objectweb.asm.tree.AnnotationNode;
|
||||
import org.objectweb.asm.tree.ClassNode;
|
||||
import org.objectweb.asm.tree.LocalVariableNode;
|
||||
import org.objectweb.asm.tree.MethodNode;
|
||||
import org.objectweb.asm.tree.TryCatchBlockNode;
|
||||
import the.bytecode.club.bytecodeviewer.BytecodeViewer;
|
||||
|
||||
import static the.bytecode.club.bytecodeviewer.Constants.nl;
|
||||
|
||||
|
@ -37,14 +34,18 @@ import static the.bytecode.club.bytecodeviewer.Constants.nl;
|
|||
* @author Bibl
|
||||
*/
|
||||
|
||||
public class MethodNodeDecompiler {
|
||||
public class MethodNodeDecompiler
|
||||
{
|
||||
|
||||
public static PrefixedStringBuilder decompile(PrefixedStringBuilder sb,
|
||||
MethodNode m, ClassNode cn) {
|
||||
public static PrefixedStringBuilder decompile(PrefixedStringBuilder sb, MethodNode m, ClassNode cn)
|
||||
{
|
||||
String class_;
|
||||
if (cn.name.contains("/")) {
|
||||
if (cn.name.contains("/"))
|
||||
{
|
||||
class_ = cn.name.substring(cn.name.lastIndexOf("/") + 1);
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
class_ = cn.name;
|
||||
}
|
||||
|
||||
|
@ -54,9 +55,12 @@ public class MethodNodeDecompiler {
|
|||
if (s.length() > 0)
|
||||
sb.append(" ");
|
||||
|
||||
if (m.name.equals("<init>")) {
|
||||
if (m.name.equals("<init>"))
|
||||
{
|
||||
sb.append(class_);
|
||||
} else if (!m.name.equals("<clinit>")) {
|
||||
}
|
||||
else if (!m.name.equals("<clinit>"))
|
||||
{
|
||||
Type returnType = Type.getReturnType(m.desc);
|
||||
sb.append(returnType.getClassName());
|
||||
sb.append(" ");
|
||||
|
@ -65,13 +69,15 @@ public class MethodNodeDecompiler {
|
|||
|
||||
TypeAndName[] args = new TypeAndName[0];
|
||||
|
||||
if (!m.name.equals("<clinit>")) {
|
||||
if (!m.name.equals("<clinit>"))
|
||||
{
|
||||
sb.append("(");
|
||||
|
||||
final Type[] argTypes = Type.getArgumentTypes(m.desc);
|
||||
args = new TypeAndName[argTypes.length];
|
||||
|
||||
for (int i = 0; i < argTypes.length; i++) {
|
||||
for (int i = 0; i < argTypes.length; i++)
|
||||
{
|
||||
final Type type = argTypes[i];
|
||||
|
||||
final TypeAndName tan = new TypeAndName();
|
||||
|
@ -82,33 +88,38 @@ public class MethodNodeDecompiler {
|
|||
|
||||
args[i] = tan;
|
||||
|
||||
sb.append(type.getClassName() + " " + argName
|
||||
+ (i < argTypes.length - 1 ? ", " : ""));
|
||||
sb.append(type.getClassName() + " " + argName + (i < argTypes.length - 1 ? ", " : ""));
|
||||
}
|
||||
|
||||
sb.append(")");
|
||||
}
|
||||
|
||||
int amountOfThrows = m.exceptions.size();
|
||||
if (amountOfThrows > 0) {
|
||||
if (amountOfThrows > 0)
|
||||
{
|
||||
sb.append(" throws ");
|
||||
sb.append(m.exceptions.get(0));// exceptions is list<string>
|
||||
for (int i = 1; i < amountOfThrows; i++) {
|
||||
for (int i = 1; i < amountOfThrows; i++)
|
||||
{
|
||||
sb.append(", ");
|
||||
sb.append(m.exceptions.get(i));
|
||||
}
|
||||
}
|
||||
|
||||
if (s.contains("abstract")) {
|
||||
if (s.contains("abstract"))
|
||||
{
|
||||
sb.append(" {}");
|
||||
sb.append(" //");
|
||||
sb.append(m.desc);
|
||||
sb.append(nl);
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
sb.append(" {");
|
||||
|
||||
if (BytecodeViewer.viewer.debugHelpers.isSelected()) {
|
||||
if (BytecodeViewer.viewer.debugHelpers.isSelected())
|
||||
{
|
||||
if (m.name.equals("<clinit>"))
|
||||
sb.append(" // <clinit>");
|
||||
else if (m.name.equals("<init>"))
|
||||
|
@ -120,12 +131,14 @@ public class MethodNodeDecompiler {
|
|||
|
||||
sb.append(nl);
|
||||
|
||||
if (m.signature != null) {
|
||||
if (m.signature != null)
|
||||
{
|
||||
sb.append(" <sig:").append(m.signature).append(">");
|
||||
sb.append(nl);
|
||||
sb.append(nl);
|
||||
}
|
||||
|
||||
if (m.annotationDefault != null) {
|
||||
if (m.annotationDefault != null)
|
||||
{
|
||||
sb.append(m.annotationDefault);
|
||||
sb.append(nl);
|
||||
}
|
||||
|
@ -134,19 +147,16 @@ public class MethodNodeDecompiler {
|
|||
|
||||
addAttrList(m.attrs, "attr", sb, insnPrinter);
|
||||
addAttrList(m.invisibleAnnotations, "invisAnno", sb, insnPrinter);
|
||||
addAttrList(m.invisibleAnnotations, "invisLocalVarAnno", sb,
|
||||
insnPrinter);
|
||||
addAttrList(m.invisibleTypeAnnotations, "invisTypeAnno", sb,
|
||||
insnPrinter);
|
||||
addAttrList(m.invisibleAnnotations, "invisLocalVarAnno", sb, insnPrinter);
|
||||
addAttrList(m.invisibleTypeAnnotations, "invisTypeAnno", sb, insnPrinter);
|
||||
addAttrList(m.localVariables, "localVar", sb, insnPrinter);
|
||||
addAttrList(m.visibleAnnotations, "visAnno", sb, insnPrinter);
|
||||
addAttrList(m.visibleLocalVariableAnnotations, "visLocalVarAnno",
|
||||
sb, insnPrinter);
|
||||
addAttrList(m.visibleTypeAnnotations, "visTypeAnno", sb,
|
||||
insnPrinter);
|
||||
addAttrList(m.visibleLocalVariableAnnotations, "visLocalVarAnno", sb, insnPrinter);
|
||||
addAttrList(m.visibleTypeAnnotations, "visTypeAnno", sb, insnPrinter);
|
||||
|
||||
List<TryCatchBlockNode> tryCatchBlocks = m.tryCatchBlocks;
|
||||
for (int i = 0; i < tryCatchBlocks.size(); i++) {
|
||||
for (int i = 0; i < tryCatchBlocks.size(); i++)
|
||||
{
|
||||
TryCatchBlockNode o = tryCatchBlocks.get(i);
|
||||
sb.append(" ");
|
||||
sb.append("TryCatch").append(i).append(": L");
|
||||
|
@ -162,7 +172,8 @@ public class MethodNodeDecompiler {
|
|||
sb.append("Type is null.");
|
||||
sb.append(nl);
|
||||
}
|
||||
for (String insn : insnPrinter.createPrint()) {
|
||||
for (String insn : insnPrinter.createPrint())
|
||||
{
|
||||
sb.append(" ");
|
||||
sb.append(insn);
|
||||
sb.append(nl);
|
||||
|
@ -172,12 +183,14 @@ public class MethodNodeDecompiler {
|
|||
return sb;
|
||||
}
|
||||
|
||||
private static void addAttrList(List<?> list, String name,
|
||||
PrefixedStringBuilder sb, InstructionPrinter insnPrinter) {
|
||||
private static void addAttrList(List<?> list, String name, PrefixedStringBuilder sb, InstructionPrinter insnPrinter)
|
||||
{
|
||||
if (list == null)
|
||||
return;
|
||||
if (list.size() > 0) {
|
||||
for (Object o : list) {
|
||||
if (list.size() > 0)
|
||||
{
|
||||
for (Object o : list)
|
||||
{
|
||||
sb.append(" <");
|
||||
sb.append(name);
|
||||
sb.append(":");
|
||||
|
@ -189,22 +202,26 @@ public class MethodNodeDecompiler {
|
|||
}
|
||||
}
|
||||
|
||||
private static String printAttr(Object o, InstructionPrinter insnPrinter) {
|
||||
if (o instanceof LocalVariableNode) {
|
||||
private static String printAttr(Object o, InstructionPrinter insnPrinter)
|
||||
{
|
||||
if (o instanceof LocalVariableNode)
|
||||
{
|
||||
LocalVariableNode lvn = (LocalVariableNode) o;
|
||||
return "index=" + lvn.index + " , name=" + lvn.name + " , desc="
|
||||
+ lvn.desc + ", sig=" + lvn.signature + ", start=L"
|
||||
+ insnPrinter.resolveLabel(lvn.start) + ", end=L"
|
||||
+ insnPrinter.resolveLabel(lvn.end);
|
||||
} else if (o instanceof AnnotationNode) {
|
||||
return "index=" + lvn.index + " , name=" + lvn.name + " , desc=" + lvn.desc + ", sig=" + lvn.signature + ", start=L" + insnPrinter.resolveLabel(lvn.start) + ", end=L" + insnPrinter.resolveLabel(lvn.end);
|
||||
}
|
||||
else if (o instanceof AnnotationNode)
|
||||
{
|
||||
AnnotationNode an = (AnnotationNode) o;
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("desc = ");
|
||||
sb.append(an.desc);
|
||||
sb.append(" , values = ");
|
||||
if (an.values != null) {
|
||||
if (an.values != null)
|
||||
{
|
||||
sb.append(Arrays.toString(an.values.toArray()));
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
sb.append("[]");
|
||||
}
|
||||
return sb.toString();
|
||||
|
@ -214,7 +231,8 @@ public class MethodNodeDecompiler {
|
|||
return o.toString();
|
||||
}
|
||||
|
||||
private static String getAccessString(int access) {
|
||||
private static String getAccessString(int access)
|
||||
{
|
||||
// public, protected, private, abstract, static,
|
||||
// final, synchronized, native & strictfp are permitted
|
||||
List<String> tokens = new ArrayList<>();
|
||||
|
@ -246,7 +264,8 @@ public class MethodNodeDecompiler {
|
|||
return "";
|
||||
// hackery delimeters
|
||||
StringBuilder sb = new StringBuilder(tokens.get(0));
|
||||
for (int i = 1; i < tokens.size(); i++) {
|
||||
for (int i = 1; i < tokens.size(); i++)
|
||||
{
|
||||
sb.append(" ");
|
||||
sb.append(tokens.get(i));
|
||||
}
|
||||
|
|
|
@ -22,16 +22,19 @@ package the.bytecode.club.bytecodeviewer.decompilers.bytecode;
|
|||
* @author Bibl
|
||||
*/
|
||||
|
||||
public class PrefixedStringBuilder {
|
||||
public class PrefixedStringBuilder
|
||||
{
|
||||
|
||||
protected StringBuilder sb;
|
||||
protected String prefix;
|
||||
|
||||
public PrefixedStringBuilder() {
|
||||
public PrefixedStringBuilder()
|
||||
{
|
||||
sb = new StringBuilder();
|
||||
}
|
||||
|
||||
public PrefixedStringBuilder append(String s) {
|
||||
public PrefixedStringBuilder append(String s)
|
||||
{
|
||||
sb.append(s);
|
||||
if (s.contains("\n") && (prefix != null) && (prefix.length() > 0))// insert
|
||||
// the
|
||||
|
@ -45,15 +48,18 @@ public class PrefixedStringBuilder {
|
|||
return this;
|
||||
}
|
||||
|
||||
public PrefixedStringBuilder append(Object o) {
|
||||
public PrefixedStringBuilder append(Object o)
|
||||
{
|
||||
return append(o.toString());
|
||||
}
|
||||
|
||||
public void setPrefix(String prefix) {
|
||||
public void setPrefix(String prefix)
|
||||
{
|
||||
this.prefix = prefix;
|
||||
}
|
||||
|
||||
public void trimPrefix(int amount) {
|
||||
public void trimPrefix(int amount)
|
||||
{
|
||||
if (prefix == null)
|
||||
return;
|
||||
if (prefix.length() < amount)
|
||||
|
@ -61,18 +67,21 @@ public class PrefixedStringBuilder {
|
|||
prefix = prefix.substring(0, prefix.length() - amount);
|
||||
}
|
||||
|
||||
public void appendPrefix(String s) {
|
||||
public void appendPrefix(String s)
|
||||
{
|
||||
if (prefix == null)
|
||||
prefix = "";
|
||||
prefix += s;
|
||||
}
|
||||
|
||||
public String getPrefix() {
|
||||
public String getPrefix()
|
||||
{
|
||||
return prefix;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
public String toString()
|
||||
{
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -27,7 +27,8 @@ import org.objectweb.asm.Type;
|
|||
* @author Waterwolf
|
||||
* @since 10/02/2011
|
||||
*/
|
||||
public class TypeAndName {
|
||||
public class TypeAndName
|
||||
{
|
||||
public Type type = null;
|
||||
public String name = null;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,13 +18,14 @@
|
|||
|
||||
package the.bytecode.club.bytecodeviewer.decompilers.impl;
|
||||
|
||||
import java.io.PrintWriter;
|
||||
import java.io.StringWriter;
|
||||
import org.objectweb.asm.tree.ClassNode;
|
||||
import org.objectweb.asm.util.Textifier;
|
||||
import org.objectweb.asm.util.TraceClassVisitor;
|
||||
import the.bytecode.club.bytecodeviewer.decompilers.InternalDecompiler;
|
||||
|
||||
import java.io.PrintWriter;
|
||||
import java.io.StringWriter;
|
||||
|
||||
/**
|
||||
* Objectweb ASM Textifier output
|
||||
*
|
||||
|
@ -33,14 +34,16 @@ import the.bytecode.club.bytecodeviewer.decompilers.InternalDecompiler;
|
|||
public class ASMTextifierDisassembler extends InternalDecompiler
|
||||
{
|
||||
@Override
|
||||
public String decompileClassNode(ClassNode cn, byte[] b) {
|
||||
public String decompileClassNode(ClassNode cn, byte[] b)
|
||||
{
|
||||
StringWriter writer = new StringWriter();
|
||||
cn.accept(new TraceClassVisitor(null, new Textifier(), new PrintWriter(writer)));
|
||||
return writer.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void decompileToZip(String sourceJar, String zipName) {
|
||||
public void decompileToZip(String sourceJar, String zipName)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,7 +20,6 @@ package the.bytecode.club.bytecodeviewer.decompilers.impl;
|
|||
|
||||
import org.objectweb.asm.tree.ClassNode;
|
||||
import org.objectweb.asm.util.ASMifier;
|
||||
import org.objectweb.asm.util.Textifier;
|
||||
import org.objectweb.asm.util.TraceClassVisitor;
|
||||
import the.bytecode.club.bytecodeviewer.decompilers.InternalDecompiler;
|
||||
|
||||
|
@ -35,13 +34,15 @@ import java.io.StringWriter;
|
|||
public class ASMifierGenerator extends InternalDecompiler
|
||||
{
|
||||
@Override
|
||||
public String decompileClassNode(ClassNode cn, byte[] b) {
|
||||
public String decompileClassNode(ClassNode cn, byte[] b)
|
||||
{
|
||||
StringWriter writer = new StringWriter();
|
||||
cn.accept(new TraceClassVisitor(null, new ASMifier(), new PrintWriter(writer)));
|
||||
return writer.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void decompileToZip(String sourceJar, String zipName) {
|
||||
public void decompileToZip(String sourceJar, String zipName)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,25 +18,27 @@
|
|||
|
||||
package the.bytecode.club.bytecodeviewer.decompilers.impl;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import org.objectweb.asm.tree.ClassNode;
|
||||
import the.bytecode.club.bytecodeviewer.decompilers.InternalDecompiler;
|
||||
import the.bytecode.club.bytecodeviewer.decompilers.bytecode.ClassNodeDecompiler;
|
||||
import the.bytecode.club.bytecodeviewer.decompilers.bytecode.PrefixedStringBuilder;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
/**
|
||||
* @author Konloch
|
||||
* @since 7/3/2021
|
||||
*/
|
||||
public class BytecodeDisassembler extends InternalDecompiler
|
||||
{
|
||||
@Override
|
||||
public String decompileClassNode(ClassNode cn, byte[] b) {
|
||||
return ClassNodeDecompiler.decompile(new PrefixedStringBuilder(),
|
||||
new ArrayList<>(), cn).toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void decompileToZip(String sourceJar, String zipName) {
|
||||
}
|
||||
@Override
|
||||
public String decompileClassNode(ClassNode cn, byte[] b)
|
||||
{
|
||||
return ClassNodeDecompiler.decompile(new PrefixedStringBuilder(), new ArrayList<>(), cn).toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void decompileToZip(String sourceJar, String zipName)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,27 +18,6 @@
|
|||
|
||||
package the.bytecode.club.bytecodeviewer.decompilers.impl;
|
||||
|
||||
import java.io.BufferedOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.PrintWriter;
|
||||
import java.io.StringWriter;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Enumeration;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.jar.JarEntry;
|
||||
import java.util.jar.JarFile;
|
||||
import java.util.zip.ZipException;
|
||||
import java.util.zip.ZipOutputStream;
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.benf.cfr.reader.api.CfrDriver;
|
||||
import org.benf.cfr.reader.api.ClassFileSource;
|
||||
|
@ -55,6 +34,15 @@ import the.bytecode.club.bytecodeviewer.decompilers.InternalDecompiler;
|
|||
import the.bytecode.club.bytecodeviewer.resources.ResourceContainer;
|
||||
import the.bytecode.club.bytecodeviewer.translation.TranslatedStrings;
|
||||
|
||||
import java.io.*;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.*;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.jar.JarEntry;
|
||||
import java.util.jar.JarFile;
|
||||
import java.util.zip.ZipException;
|
||||
import java.util.zip.ZipOutputStream;
|
||||
|
||||
import static the.bytecode.club.bytecodeviewer.Constants.nl;
|
||||
import static the.bytecode.club.bytecodeviewer.translation.TranslatedStrings.CFR;
|
||||
import static the.bytecode.club.bytecodeviewer.translation.TranslatedStrings.ERROR;
|
||||
|
@ -63,19 +51,23 @@ import static the.bytecode.club.bytecodeviewer.translation.TranslatedStrings.ERR
|
|||
* CFR Java Wrapper
|
||||
*
|
||||
* @author GraxCode
|
||||
* Taken mostly out of Threadtear.
|
||||
* Taken mostly out of Threadtear.
|
||||
*/
|
||||
public class CFRDecompiler extends InternalDecompiler {
|
||||
public class CFRDecompiler extends InternalDecompiler
|
||||
{
|
||||
|
||||
private static final String CLASS_SUFFIX = ".class";
|
||||
|
||||
@Override
|
||||
public String decompileClassNode(ClassNode cn, byte[] content) {
|
||||
public String decompileClassNode(ClassNode cn, byte[] content)
|
||||
{
|
||||
return decompile(cn, cn.name, content);
|
||||
}
|
||||
|
||||
private String decompile(ClassNode cn, String name, byte[] content) {
|
||||
try {
|
||||
private String decompile(ClassNode cn, String name, byte[] content)
|
||||
{
|
||||
try
|
||||
{
|
||||
String classPath = name + (name.endsWith(CLASS_SUFFIX) ? "" : CLASS_SUFFIX);
|
||||
|
||||
StringBuilder builder = new StringBuilder();
|
||||
|
@ -83,79 +75,93 @@ public class CFRDecompiler extends InternalDecompiler {
|
|||
|
||||
Options options = generateOptions();
|
||||
ClassFileSource source = new BCVDataSource(options, cn, classPath, content);
|
||||
CfrDriver driver = new CfrDriver.Builder()
|
||||
.withClassFileSource(source)
|
||||
.withBuiltOptions(options)
|
||||
.withOutputSink(new BCVOutputSinkFactory(dumpDecompiled))
|
||||
.build();
|
||||
CfrDriver driver = new CfrDriver.Builder().withClassFileSource(source).withBuiltOptions(options).withOutputSink(new BCVOutputSinkFactory(dumpDecompiled)).build();
|
||||
driver.analyse(Collections.singletonList(name));
|
||||
|
||||
return builder.toString();
|
||||
} catch (Throwable t) {
|
||||
}
|
||||
catch (Throwable t)
|
||||
{
|
||||
t.printStackTrace();
|
||||
StringWriter sw = new StringWriter();
|
||||
PrintWriter pw = new PrintWriter(sw);
|
||||
t.printStackTrace(pw);
|
||||
return CFR + " " + ERROR + "! " + ExceptionUI.SEND_STACKTRACE_TO +
|
||||
nl + nl + TranslatedStrings.SUGGESTED_FIX_DECOMPILER_ERROR +
|
||||
nl + nl + sw;
|
||||
return CFR + " " + ERROR + "! " + ExceptionUI.SEND_STACKTRACE_TO + nl + nl + TranslatedStrings.SUGGESTED_FIX_DECOMPILER_ERROR + nl + nl + sw;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void decompileToZip(String sourceJar, String outJar) {
|
||||
try (JarFile jfile = new JarFile(new File(sourceJar));
|
||||
FileOutputStream dest = new FileOutputStream(outJar);
|
||||
BufferedOutputStream buffDest = new BufferedOutputStream(dest);
|
||||
ZipOutputStream out = new ZipOutputStream(buffDest)) {
|
||||
public void decompileToZip(String sourceJar, String outJar)
|
||||
{
|
||||
try (JarFile jfile = new JarFile(new File(sourceJar)); FileOutputStream dest = new FileOutputStream(outJar); BufferedOutputStream buffDest = new BufferedOutputStream(dest); ZipOutputStream out = new ZipOutputStream(buffDest))
|
||||
{
|
||||
byte[] data = new byte[1024];
|
||||
|
||||
Enumeration<JarEntry> ent = jfile.entries();
|
||||
Set<JarEntry> history = new HashSet<>();
|
||||
while (ent.hasMoreElements()) {
|
||||
while (ent.hasMoreElements())
|
||||
{
|
||||
JarEntry entry = ent.nextElement();
|
||||
if (entry.getName().endsWith(CLASS_SUFFIX)) {
|
||||
if (entry.getName().endsWith(CLASS_SUFFIX))
|
||||
{
|
||||
JarEntry etn = new JarEntry(entry.getName().replace(CLASS_SUFFIX, ".java"));
|
||||
if (history.add(etn)) {
|
||||
if (history.add(etn))
|
||||
{
|
||||
out.putNextEntry(etn);
|
||||
try {
|
||||
IOUtils.write(decompile(null, entry.getName(),
|
||||
IOUtils.toByteArray(jfile.getInputStream(entry))),
|
||||
out, StandardCharsets.UTF_8);
|
||||
} finally {
|
||||
try
|
||||
{
|
||||
IOUtils.write(decompile(null, entry.getName(), IOUtils.toByteArray(jfile.getInputStream(entry))), out, StandardCharsets.UTF_8);
|
||||
}
|
||||
finally
|
||||
{
|
||||
out.closeEntry();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
try {
|
||||
}
|
||||
else
|
||||
{
|
||||
try
|
||||
{
|
||||
JarEntry etn = new JarEntry(entry.getName());
|
||||
if (history.add(etn)) continue;
|
||||
if (history.add(etn))
|
||||
continue;
|
||||
history.add(etn);
|
||||
out.putNextEntry(etn);
|
||||
try (InputStream in = jfile.getInputStream(entry)) {
|
||||
if (in != null) {
|
||||
try (InputStream in = jfile.getInputStream(entry))
|
||||
{
|
||||
if (in != null)
|
||||
{
|
||||
int count;
|
||||
while ((count = in.read(data, 0, 1024)) != -1) {
|
||||
while ((count = in.read(data, 0, 1024)) != -1)
|
||||
{
|
||||
out.write(data, 0, count);
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
}
|
||||
finally
|
||||
{
|
||||
out.closeEntry();
|
||||
}
|
||||
} catch (ZipException ze) {
|
||||
}
|
||||
catch (ZipException ze)
|
||||
{
|
||||
// some jars contain duplicate pom.xml entries: ignore it
|
||||
if (!ze.getMessage().contains("duplicate")) {
|
||||
if (!ze.getMessage().contains("duplicate"))
|
||||
{
|
||||
throw ze;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (StackOverflowError | Exception e) {
|
||||
}
|
||||
catch (StackOverflowError | Exception e)
|
||||
{
|
||||
BytecodeViewer.handleException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public Options generateOptions() {
|
||||
public Options generateOptions()
|
||||
{
|
||||
Map<String, String> options = new HashMap<>();
|
||||
options.put("decodeenumswitch", String.valueOf(BytecodeViewer.viewer.decodeEnumSwitch.isSelected()));
|
||||
options.put("sugarenums", String.valueOf(BytecodeViewer.viewer.sugarEnums.isSelected()));
|
||||
|
@ -164,8 +170,7 @@ public class CFRDecompiler extends InternalDecompiler {
|
|||
options.put("collectioniter", String.valueOf(BytecodeViewer.viewer.collectioniter.isSelected()));
|
||||
options.put("innerclasses", String.valueOf(BytecodeViewer.viewer.innerClasses.isSelected()));
|
||||
options.put("removeboilerplate", String.valueOf(BytecodeViewer.viewer.removeBoilerPlate.isSelected()));
|
||||
options.put("removeinnerclasssynthetics",
|
||||
String.valueOf(BytecodeViewer.viewer.removeInnerClassSynthetics.isSelected()));
|
||||
options.put("removeinnerclasssynthetics", String.valueOf(BytecodeViewer.viewer.removeInnerClassSynthetics.isSelected()));
|
||||
options.put("decodelambdas", String.valueOf(BytecodeViewer.viewer.decodeLambdas.isSelected()));
|
||||
options.put("hidebridgemethods", String.valueOf(BytecodeViewer.viewer.hideBridgeMethods.isSelected()));
|
||||
options.put("liftconstructorinit", String.valueOf(BytecodeViewer.viewer.liftConstructorInit.isSelected()));
|
||||
|
@ -201,51 +206,61 @@ public class CFRDecompiler extends InternalDecompiler {
|
|||
return new OptionsImpl(options);
|
||||
}
|
||||
|
||||
private static class BCVDataSource extends ClassFileSourceImpl {
|
||||
private static class BCVDataSource extends ClassFileSourceImpl
|
||||
{
|
||||
|
||||
private final ResourceContainer container;
|
||||
private final String classFilePath;
|
||||
private final byte[] content;
|
||||
|
||||
private BCVDataSource(Options options, ClassNode cn, String classFilePath, byte[] content) {
|
||||
private BCVDataSource(Options options, ClassNode cn, String classFilePath, byte[] content)
|
||||
{
|
||||
super(options);
|
||||
this.container = BytecodeViewer.getResourceContainers().stream()
|
||||
.filter(rc -> rc.resourceClasses.containsValue(cn))
|
||||
.findFirst().orElse(null);
|
||||
this.container = BytecodeViewer.getResourceContainers().stream().filter(rc -> rc.resourceClasses.containsValue(cn)).findFirst().orElse(null);
|
||||
this.classFilePath = classFilePath;
|
||||
this.content = content;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Pair<byte[], String> getClassFileContent(String classFilePath) throws IOException {
|
||||
if (classFilePath.equals(this.classFilePath) && content != null) return Pair.make(content, classFilePath);
|
||||
if (container == null) return super.getClassFileContent(classFilePath);
|
||||
public Pair<byte[], String> getClassFileContent(String classFilePath) throws IOException
|
||||
{
|
||||
if (classFilePath.equals(this.classFilePath) && content != null)
|
||||
return Pair.make(content, classFilePath);
|
||||
if (container == null)
|
||||
return super.getClassFileContent(classFilePath);
|
||||
byte[] data = container.resourceClassBytes.get(classFilePath);
|
||||
if (data == null) return super.getClassFileContent(classFilePath);
|
||||
if (data == null)
|
||||
return super.getClassFileContent(classFilePath);
|
||||
return Pair.make(data, classFilePath);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static class BCVOutputSinkFactory implements OutputSinkFactory {
|
||||
private static class BCVOutputSinkFactory implements OutputSinkFactory
|
||||
{
|
||||
|
||||
private final Consumer<SinkReturns.Decompiled> dumpDecompiled;
|
||||
|
||||
private BCVOutputSinkFactory(Consumer<SinkReturns.Decompiled> dumpDecompiled) {
|
||||
private BCVOutputSinkFactory(Consumer<SinkReturns.Decompiled> dumpDecompiled)
|
||||
{
|
||||
this.dumpDecompiled = dumpDecompiled;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<SinkClass> getSupportedSinks(SinkType sinkType, Collection<SinkClass> available) {
|
||||
public List<SinkClass> getSupportedSinks(SinkType sinkType, Collection<SinkClass> available)
|
||||
{
|
||||
return Collections.singletonList(SinkClass.DECOMPILED);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> Sink<T> getSink(SinkType sinkType, SinkClass sinkClass) {
|
||||
if (sinkType == SinkType.JAVA && sinkClass == SinkClass.DECOMPILED) {
|
||||
public <T> Sink<T> getSink(SinkType sinkType, SinkClass sinkClass)
|
||||
{
|
||||
if (sinkType == SinkType.JAVA && sinkClass == SinkClass.DECOMPILED)
|
||||
{
|
||||
return x -> dumpDecompiled.accept((SinkReturns.Decompiled) x);
|
||||
}
|
||||
return ignore -> {
|
||||
return ignore ->
|
||||
{
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -18,11 +18,6 @@
|
|||
|
||||
package the.bytecode.club.bytecodeviewer.decompilers.impl;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.PrintWriter;
|
||||
import java.io.StringWriter;
|
||||
import me.konloch.kontainer.io.DiskReader;
|
||||
import org.objectweb.asm.tree.ClassNode;
|
||||
import the.bytecode.club.bytecodeviewer.BytecodeViewer;
|
||||
|
@ -31,10 +26,9 @@ import the.bytecode.club.bytecodeviewer.decompilers.InternalDecompiler;
|
|||
import the.bytecode.club.bytecodeviewer.translation.TranslatedStrings;
|
||||
import the.bytecode.club.bytecodeviewer.util.MiscUtils;
|
||||
|
||||
import static the.bytecode.club.bytecodeviewer.Constants.LAUNCH_DECOMPILERS_IN_NEW_PROCESS;
|
||||
import static the.bytecode.club.bytecodeviewer.Constants.fs;
|
||||
import static the.bytecode.club.bytecodeviewer.Constants.nl;
|
||||
import static the.bytecode.club.bytecodeviewer.Constants.tempDirectory;
|
||||
import java.io.*;
|
||||
|
||||
import static the.bytecode.club.bytecodeviewer.Constants.*;
|
||||
import static the.bytecode.club.bytecodeviewer.translation.TranslatedStrings.ERROR;
|
||||
import static the.bytecode.club.bytecodeviewer.translation.TranslatedStrings.FERNFLOWER;
|
||||
|
||||
|
@ -55,9 +49,13 @@ public class FernFlowerDecompiler extends InternalDecompiler
|
|||
File f = new File(tempDirectory + fs + "temp" + fs);
|
||||
f.mkdir();
|
||||
|
||||
try {
|
||||
try
|
||||
{
|
||||
org.jetbrains.java.decompiler.main.decompiler.ConsoleDecompiler.main(generateMainMethod(tempZip.getAbsolutePath(), tempDirectory + "./temp/"));
|
||||
} catch (StackOverflowError | Exception ignored) { }
|
||||
}
|
||||
catch (StackOverflowError | Exception ignored)
|
||||
{
|
||||
}
|
||||
|
||||
File tempZip2 = new File(tempDirectory + fs + "temp" + fs + tempZip.getName());
|
||||
if (tempZip2.exists())
|
||||
|
@ -72,11 +70,14 @@ public class FernFlowerDecompiler extends InternalDecompiler
|
|||
String start = tempDirectory + fs + MiscUtils.getUniqueName("", ".class");
|
||||
|
||||
final File tempClass = new File(start + ".class");
|
||||
|
||||
|
||||
String exception = "";
|
||||
try (FileOutputStream fos = new FileOutputStream(tempClass)) {
|
||||
try (FileOutputStream fos = new FileOutputStream(tempClass))
|
||||
{
|
||||
fos.write(b);
|
||||
} catch (IOException e) {
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
StringWriter exceptionWriter = new StringWriter();
|
||||
e.printStackTrace(new PrintWriter(exceptionWriter));
|
||||
e.printStackTrace();
|
||||
|
@ -105,34 +106,41 @@ public class FernFlowerDecompiler extends InternalDecompiler
|
|||
}
|
||||
else
|
||||
{
|
||||
try {
|
||||
org.jetbrains.java.decompiler.main.decompiler.ConsoleDecompiler.main(
|
||||
generateMainMethod(tempClass.getAbsolutePath(), new File(tempDirectory).getAbsolutePath()));
|
||||
} catch (Throwable e) {
|
||||
try
|
||||
{
|
||||
org.jetbrains.java.decompiler.main.decompiler.ConsoleDecompiler.main(generateMainMethod(tempClass.getAbsolutePath(), new File(tempDirectory).getAbsolutePath()));
|
||||
}
|
||||
catch (Throwable e)
|
||||
{
|
||||
StringWriter exceptionWriter = new StringWriter();
|
||||
e.printStackTrace(new PrintWriter(exceptionWriter));
|
||||
e.printStackTrace();
|
||||
exception = exceptionWriter.toString();
|
||||
exception = exceptionWriter.toString();
|
||||
}
|
||||
}
|
||||
|
||||
tempClass.delete();
|
||||
|
||||
String javaDir = start;
|
||||
if (BytecodeViewer.viewer.ren.isSelected()) {
|
||||
if (BytecodeViewer.viewer.ren.isSelected())
|
||||
{
|
||||
javaDir = tempDirectory + "class_0";
|
||||
}
|
||||
|
||||
final File outputJava = new File(javaDir + ".java");
|
||||
if (outputJava.exists()) {
|
||||
if (outputJava.exists())
|
||||
{
|
||||
String s;
|
||||
try {
|
||||
try
|
||||
{
|
||||
s = DiskReader.loadAsString(outputJava.getAbsolutePath());
|
||||
|
||||
|
||||
outputJava.delete();
|
||||
|
||||
|
||||
return s;
|
||||
} catch (Exception e) {
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
StringWriter exceptionWriter = new StringWriter();
|
||||
e.printStackTrace(new PrintWriter(exceptionWriter));
|
||||
e.printStackTrace();
|
||||
|
@ -140,40 +148,23 @@ public class FernFlowerDecompiler extends InternalDecompiler
|
|||
exception += nl + nl + exceptionWriter;
|
||||
}
|
||||
}
|
||||
|
||||
return FERNFLOWER + " " + ERROR + "! " + ExceptionUI.SEND_STACKTRACE_TO +
|
||||
nl + nl + TranslatedStrings.SUGGESTED_FIX_DECOMPILER_ERROR +
|
||||
nl + nl + exception;
|
||||
|
||||
return FERNFLOWER + " " + ERROR + "! " + ExceptionUI.SEND_STACKTRACE_TO + nl + nl + TranslatedStrings.SUGGESTED_FIX_DECOMPILER_ERROR + nl + nl + exception;
|
||||
}
|
||||
|
||||
private String[] generateMainMethod(String className, String folder) {
|
||||
return new String[]{
|
||||
"-rbr=" + r(BytecodeViewer.viewer.rbr.isSelected()),
|
||||
"-rsy=" + r(BytecodeViewer.viewer.rsy.isSelected()),
|
||||
"-din=" + r(BytecodeViewer.viewer.din.isSelected()),
|
||||
"-dc4=" + r(BytecodeViewer.viewer.dc4.isSelected()),
|
||||
"-das=" + r(BytecodeViewer.viewer.das.isSelected()),
|
||||
"-hes=" + r(BytecodeViewer.viewer.hes.isSelected()),
|
||||
"-hdc=" + r(BytecodeViewer.viewer.hdc.isSelected()),
|
||||
"-dgs=" + r(BytecodeViewer.viewer.dgs.isSelected()),
|
||||
"-ner=" + r(BytecodeViewer.viewer.ner.isSelected()),
|
||||
"-den=" + r(BytecodeViewer.viewer.den.isSelected()),
|
||||
"-rgn=" + r(BytecodeViewer.viewer.rgn.isSelected()),
|
||||
"-bto=" + r(BytecodeViewer.viewer.bto.isSelected()),
|
||||
"-nns=" + r(BytecodeViewer.viewer.nns.isSelected()),
|
||||
"-uto=" + r(BytecodeViewer.viewer.uto.isSelected()),
|
||||
"-udv=" + r(BytecodeViewer.viewer.udv.isSelected()),
|
||||
"-rer=" + r(BytecodeViewer.viewer.rer.isSelected()),
|
||||
"-fdi=" + r(BytecodeViewer.viewer.fdi.isSelected()),
|
||||
"-asc=" + r(BytecodeViewer.viewer.asc.isSelected()),
|
||||
"-ren=" + r(BytecodeViewer.viewer.ren.isSelected()), className,
|
||||
folder};
|
||||
private String[] generateMainMethod(String className, String folder)
|
||||
{
|
||||
return new String[]{"-rbr=" + r(BytecodeViewer.viewer.rbr.isSelected()), "-rsy=" + r(BytecodeViewer.viewer.rsy.isSelected()), "-din=" + r(BytecodeViewer.viewer.din.isSelected()), "-dc4=" + r(BytecodeViewer.viewer.dc4.isSelected()), "-das=" + r(BytecodeViewer.viewer.das.isSelected()), "-hes=" + r(BytecodeViewer.viewer.hes.isSelected()), "-hdc=" + r(BytecodeViewer.viewer.hdc.isSelected()), "-dgs=" + r(BytecodeViewer.viewer.dgs.isSelected()), "-ner=" + r(BytecodeViewer.viewer.ner.isSelected()), "-den=" + r(BytecodeViewer.viewer.den.isSelected()), "-rgn=" + r(BytecodeViewer.viewer.rgn.isSelected()), "-bto=" + r(BytecodeViewer.viewer.bto.isSelected()), "-nns=" + r(BytecodeViewer.viewer.nns.isSelected()), "-uto=" + r(BytecodeViewer.viewer.uto.isSelected()), "-udv=" + r(BytecodeViewer.viewer.udv.isSelected()), "-rer=" + r(BytecodeViewer.viewer.rer.isSelected()), "-fdi=" + r(BytecodeViewer.viewer.fdi.isSelected()), "-asc=" + r(BytecodeViewer.viewer.asc.isSelected()), "-ren=" + r(BytecodeViewer.viewer.ren.isSelected()), className, folder};
|
||||
}
|
||||
|
||||
private String r(boolean b) {
|
||||
if (b) {
|
||||
private String r(boolean b)
|
||||
{
|
||||
if (b)
|
||||
{
|
||||
return "1";
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
return "0";
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,12 +20,6 @@ package the.bytecode.club.bytecodeviewer.decompilers.impl;
|
|||
|
||||
import jadx.api.JadxArgs;
|
||||
import jadx.api.JadxDecompiler;
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.PrintWriter;
|
||||
import java.io.StringWriter;
|
||||
import java.util.Random;
|
||||
import me.konloch.kontainer.io.DiskReader;
|
||||
import org.objectweb.asm.tree.ClassNode;
|
||||
import the.bytecode.club.bytecodeviewer.BytecodeViewer;
|
||||
|
@ -34,9 +28,10 @@ import the.bytecode.club.bytecodeviewer.decompilers.InternalDecompiler;
|
|||
import the.bytecode.club.bytecodeviewer.translation.TranslatedStrings;
|
||||
import the.bytecode.club.bytecodeviewer.util.MiscUtils;
|
||||
|
||||
import static the.bytecode.club.bytecodeviewer.Constants.fs;
|
||||
import static the.bytecode.club.bytecodeviewer.Constants.nl;
|
||||
import static the.bytecode.club.bytecodeviewer.Constants.tempDirectory;
|
||||
import java.io.*;
|
||||
import java.util.Random;
|
||||
|
||||
import static the.bytecode.club.bytecodeviewer.Constants.*;
|
||||
import static the.bytecode.club.bytecodeviewer.translation.TranslatedStrings.ERROR;
|
||||
import static the.bytecode.club.bytecodeviewer.translation.TranslatedStrings.JADX;
|
||||
|
||||
|
@ -48,24 +43,29 @@ import static the.bytecode.club.bytecodeviewer.translation.TranslatedStrings.JAD
|
|||
public class JADXDecompiler extends InternalDecompiler
|
||||
{
|
||||
private final Random r = new Random();
|
||||
|
||||
|
||||
@Override
|
||||
public String decompileClassNode(ClassNode cn, byte[] b) {
|
||||
public String decompileClassNode(ClassNode cn, byte[] b)
|
||||
{
|
||||
String fileStart = tempDirectory + fs;
|
||||
|
||||
String exception = "";
|
||||
final File tempClass = new File(MiscUtils.getUniqueName(fileStart, ".class") + ".class");
|
||||
|
||||
try (FileOutputStream fos = new FileOutputStream(tempClass)) {
|
||||
try (FileOutputStream fos = new FileOutputStream(tempClass))
|
||||
{
|
||||
fos.write(b);
|
||||
} catch (IOException e) {
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
BytecodeViewer.handleException(e);
|
||||
}
|
||||
|
||||
File fuckery = new File(fuckery(fileStart));
|
||||
fuckery.mkdirs();
|
||||
|
||||
try {
|
||||
|
||||
try
|
||||
{
|
||||
JadxArgs args = new JadxArgs();
|
||||
args.setInputFile(tempClass);
|
||||
args.setOutDir(fuckery);
|
||||
|
@ -75,7 +75,9 @@ public class JADXDecompiler extends InternalDecompiler
|
|||
JadxDecompiler jadx = new JadxDecompiler(args);
|
||||
jadx.load();
|
||||
jadx.saveSources();
|
||||
} catch (StackOverflowError | Exception e) {
|
||||
}
|
||||
catch (StackOverflowError | Exception e)
|
||||
{
|
||||
StringWriter exceptionWriter = new StringWriter();
|
||||
e.printStackTrace(new PrintWriter(exceptionWriter));
|
||||
e.printStackTrace();
|
||||
|
@ -86,13 +88,11 @@ public class JADXDecompiler extends InternalDecompiler
|
|||
|
||||
if (fuckery.exists())
|
||||
return findFile(MiscUtils.listFiles(fuckery));
|
||||
|
||||
if(exception.isEmpty())
|
||||
|
||||
if (exception.isEmpty())
|
||||
exception = "Decompiled source file not found!";
|
||||
|
||||
return JADX + " " + ERROR + "! " + ExceptionUI.SEND_STACKTRACE_TO +
|
||||
nl + nl + TranslatedStrings.SUGGESTED_FIX_DECOMPILER_ERROR +
|
||||
nl + nl + exception;
|
||||
return JADX + " " + ERROR + "! " + ExceptionUI.SEND_STACKTRACE_TO + nl + nl + TranslatedStrings.SUGGESTED_FIX_DECOMPILER_ERROR + nl + nl + exception;
|
||||
}
|
||||
|
||||
//TODO remove
|
||||
|
@ -105,36 +105,41 @@ public class JADXDecompiler extends InternalDecompiler
|
|||
if (!f.exists())
|
||||
return f.toString();
|
||||
}
|
||||
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public String findFile(File[] fA) {
|
||||
for (File f : fA) {
|
||||
public String findFile(File[] fA)
|
||||
{
|
||||
for (File f : fA)
|
||||
{
|
||||
if (f.isDirectory())
|
||||
return findFile(MiscUtils.listFiles(f));
|
||||
else {
|
||||
else
|
||||
{
|
||||
String s;
|
||||
try {
|
||||
try
|
||||
{
|
||||
s = DiskReader.loadAsString(f.getAbsolutePath());
|
||||
} catch (Exception e) {
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
StringWriter sw = new StringWriter();
|
||||
e.printStackTrace(new PrintWriter(sw));
|
||||
e.printStackTrace();
|
||||
String exception = ExceptionUI.SEND_STACKTRACE_TO_NL + sw;
|
||||
|
||||
return JADX + " " + ERROR + "! " + ExceptionUI.SEND_STACKTRACE_TO +
|
||||
nl + nl + TranslatedStrings.SUGGESTED_FIX_DECOMPILER_ERROR +
|
||||
nl + nl + exception;
|
||||
|
||||
return JADX + " " + ERROR + "! " + ExceptionUI.SEND_STACKTRACE_TO + nl + nl + TranslatedStrings.SUGGESTED_FIX_DECOMPILER_ERROR + nl + nl + exception;
|
||||
}
|
||||
return s;
|
||||
}
|
||||
}
|
||||
|
||||
return "JADX error!" +
|
||||
nl + nl + TranslatedStrings.SUGGESTED_FIX_DECOMPILER_ERROR;
|
||||
|
||||
return "JADX error!" + nl + nl + TranslatedStrings.SUGGESTED_FIX_DECOMPILER_ERROR;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void decompileToZip(String sourceJar, String zipName) { }
|
||||
public void decompileToZip(String sourceJar, String zipName)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,12 +18,6 @@
|
|||
|
||||
package the.bytecode.club.bytecodeviewer.decompilers.impl;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.PrintStream;
|
||||
import java.io.PrintWriter;
|
||||
import java.io.StringWriter;
|
||||
import me.konloch.kontainer.io.DiskReader;
|
||||
import org.jd.core.v1.ClassFileToJavaSourceDecompiler;
|
||||
import org.objectweb.asm.tree.ClassNode;
|
||||
|
@ -38,6 +32,8 @@ import the.bytecode.club.bytecodeviewer.decompilers.jdgui.PlainTextPrinter;
|
|||
import the.bytecode.club.bytecodeviewer.translation.TranslatedStrings;
|
||||
import the.bytecode.club.bytecodeviewer.util.MiscUtils;
|
||||
|
||||
import java.io.*;
|
||||
|
||||
import static the.bytecode.club.bytecodeviewer.Constants.fs;
|
||||
import static the.bytecode.club.bytecodeviewer.Constants.nl;
|
||||
import static the.bytecode.club.bytecodeviewer.translation.TranslatedStrings.ERROR;
|
||||
|
@ -54,28 +50,35 @@ public class JDGUIDecompiler extends InternalDecompiler
|
|||
{
|
||||
|
||||
@Override
|
||||
public String decompileClassNode(ClassNode cn, byte[] b) {
|
||||
public String decompileClassNode(ClassNode cn, byte[] b)
|
||||
{
|
||||
String exception;
|
||||
try {
|
||||
try
|
||||
{
|
||||
final File tempDirectory = new File(Constants.tempDirectory + fs + MiscUtils.randomString(32) + fs);
|
||||
tempDirectory.mkdir();
|
||||
|
||||
|
||||
final File tempClass = new File(tempDirectory.getAbsolutePath() + fs + cn.name + ".class");
|
||||
final File tempJava = new File(tempDirectory.getAbsolutePath() + fs + cn.name + ".java");
|
||||
|
||||
if (cn.name.contains("/")) {
|
||||
if (cn.name.contains("/"))
|
||||
{
|
||||
String[] raw = cn.name.split("/");
|
||||
String path = tempDirectory.getAbsolutePath() + fs;
|
||||
for (int i = 0; i < raw.length - 1; i++) {
|
||||
for (int i = 0; i < raw.length - 1; i++)
|
||||
{
|
||||
path += raw[i] + fs;
|
||||
File f = new File(path);
|
||||
f.mkdir();
|
||||
}
|
||||
}
|
||||
|
||||
try (FileOutputStream fos = new FileOutputStream(tempClass)) {
|
||||
try (FileOutputStream fos = new FileOutputStream(tempClass))
|
||||
{
|
||||
fos.write(b);
|
||||
} catch (IOException e) {
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
BytecodeViewer.handleException(e);
|
||||
}
|
||||
|
||||
|
@ -84,14 +87,17 @@ public class JDGUIDecompiler extends InternalDecompiler
|
|||
String directoryPath = JDGUIClassFileUtil.ExtractDirectoryPath(pathToClass);
|
||||
String internalPath = JDGUIClassFileUtil.ExtractInternalPath(directoryPath, pathToClass);
|
||||
|
||||
CommonPreferences preferences = new CommonPreferences() {
|
||||
CommonPreferences preferences = new CommonPreferences()
|
||||
{
|
||||
@Override
|
||||
public boolean isShowLineNumbers() {
|
||||
public boolean isShowLineNumbers()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isMergeEmptyLines() {
|
||||
public boolean isMergeEmptyLines()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
@ -102,26 +108,27 @@ public class JDGUIDecompiler extends InternalDecompiler
|
|||
//HtmlPrinter printer = new HtmlPrinter(ps);
|
||||
org.jd.core.v1.api.Decompiler decompiler = new ClassFileToJavaSourceDecompiler();
|
||||
|
||||
try (PrintStream ps = new PrintStream(tempJava.getAbsolutePath());
|
||||
PlainTextPrinter printer = new PlainTextPrinter(preferences, ps)) {
|
||||
try (PrintStream ps = new PrintStream(tempJava.getAbsolutePath()); PlainTextPrinter printer = new PlainTextPrinter(preferences, ps))
|
||||
{
|
||||
decompiler.decompile(loader, printer, internalPath, preferences.getPreferences());
|
||||
}
|
||||
|
||||
return DiskReader.loadAsString(tempJava.getAbsolutePath());
|
||||
} catch (Exception e) {
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
StringWriter sw = new StringWriter();
|
||||
e.printStackTrace(new PrintWriter(sw));
|
||||
e.printStackTrace();
|
||||
|
||||
exception = ExceptionUI.SEND_STACKTRACE_TO_NL + sw;
|
||||
}
|
||||
|
||||
return JDGUI + " " + ERROR + "! " + ExceptionUI.SEND_STACKTRACE_TO +
|
||||
nl + nl + TranslatedStrings.SUGGESTED_FIX_DECOMPILER_ERROR +
|
||||
nl + nl + exception;
|
||||
|
||||
return JDGUI + " " + ERROR + "! " + ExceptionUI.SEND_STACKTRACE_TO + nl + nl + TranslatedStrings.SUGGESTED_FIX_DECOMPILER_ERROR + nl + nl + exception;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void decompileToZip(String sourceJar, String zipName) {
|
||||
public void decompileToZip(String sourceJar, String zipName)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,10 +18,6 @@
|
|||
|
||||
package the.bytecode.club.bytecodeviewer.decompilers.impl;
|
||||
|
||||
import java.io.File;
|
||||
import java.lang.reflect.Method;
|
||||
import java.net.URL;
|
||||
import java.net.URLClassLoader;
|
||||
import me.konloch.kontainer.io.DiskWriter;
|
||||
import org.objectweb.asm.tree.ClassNode;
|
||||
import the.bytecode.club.bytecodeviewer.BytecodeViewer;
|
||||
|
@ -33,12 +29,17 @@ import the.bytecode.club.bytecodeviewer.resources.ExternalResources;
|
|||
import the.bytecode.club.bytecodeviewer.translation.TranslatedStrings;
|
||||
import the.bytecode.club.bytecodeviewer.util.MiscUtils;
|
||||
|
||||
import java.io.File;
|
||||
import java.lang.reflect.Method;
|
||||
import java.net.URL;
|
||||
import java.net.URLClassLoader;
|
||||
|
||||
import static the.bytecode.club.bytecodeviewer.Constants.fs;
|
||||
import static the.bytecode.club.bytecodeviewer.api.ExceptionUI.SEND_STACKTRACE_TO;
|
||||
|
||||
/**
|
||||
* Javap disassembler
|
||||
*
|
||||
* <p>
|
||||
* https://github.com/Konloch/bytecode-viewer/issues/93
|
||||
*
|
||||
* @author Konloch
|
||||
|
@ -50,46 +51,42 @@ public class JavapDisassembler extends InternalDecompiler
|
|||
@Override
|
||||
public String decompileClassNode(ClassNode cn, byte[] b)
|
||||
{
|
||||
if(!ExternalResources.getSingleton().hasJavaToolsSet())
|
||||
if (!ExternalResources.getSingleton().hasJavaToolsSet())
|
||||
return "Set Java Tools Path!";
|
||||
|
||||
|
||||
return synchronizedDecompilation(cn, b);
|
||||
}
|
||||
|
||||
|
||||
private synchronized String synchronizedDecompilation(ClassNode cn, byte[] b)
|
||||
{
|
||||
final File tempDirectory = new File(Constants.tempDirectory + fs + MiscUtils.randomString(32) + fs);
|
||||
tempDirectory.mkdir();
|
||||
final File tempClass = new File(Constants.tempDirectory + fs + "temp" + MiscUtils.randomString(32) + ".class");
|
||||
|
||||
|
||||
DiskWriter.replaceFileBytes(tempClass.getAbsolutePath(), b, false);
|
||||
|
||||
|
||||
JFrameConsolePrintStream sysOutBuffer = null;
|
||||
try
|
||||
{
|
||||
//load java tools into a temporary classloader
|
||||
URLClassLoader child = new URLClassLoader(
|
||||
new URL[] {new File(Configuration.javaTools).toURI().toURL()},
|
||||
this.getClass().getClassLoader()
|
||||
);
|
||||
|
||||
URLClassLoader child = new URLClassLoader(new URL[]{new File(Configuration.javaTools).toURI().toURL()}, this.getClass().getClassLoader());
|
||||
|
||||
//setup reflection
|
||||
Class<?> javap = child.loadClass("com.sun.tools.javap.Main");
|
||||
Method main = javap.getMethod("main", String[].class);
|
||||
|
||||
|
||||
//pipe sys out
|
||||
sysOutBuffer = new JFrameConsolePrintStream("", false);
|
||||
|
||||
|
||||
//silence security manager debugging
|
||||
BytecodeViewer.sm.silenceExec(true);
|
||||
|
||||
|
||||
//invoke Javap
|
||||
main.invoke(null, (Object) new String[]{
|
||||
"-p", //Shows all classes and members
|
||||
"-c", //Prints out disassembled code
|
||||
//"-l", //Prints out line and local variable tables
|
||||
"-constants", //Shows static final constants
|
||||
tempClass.getAbsolutePath()});
|
||||
main.invoke(null, (Object) new String[]{"-p", //Shows all classes and members
|
||||
"-c", //Prints out disassembled code
|
||||
//"-l", //Prints out line and local variable tables
|
||||
"-constants", //Shows static final constants
|
||||
tempClass.getAbsolutePath()});
|
||||
}
|
||||
catch (IllegalAccessException e)
|
||||
{
|
||||
|
@ -104,16 +101,18 @@ public class JavapDisassembler extends InternalDecompiler
|
|||
BytecodeViewer.sm.silenceExec(false);
|
||||
tempClass.delete();
|
||||
}
|
||||
|
||||
if(sysOutBuffer != null)
|
||||
|
||||
if (sysOutBuffer != null)
|
||||
{
|
||||
sysOutBuffer.finished();
|
||||
return sysOutBuffer.getTextAreaOutputStreamOut().getBuffer().toString();
|
||||
}
|
||||
|
||||
|
||||
return SEND_STACKTRACE_TO;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void decompileToZip(String sourceJar, String zipName) { }
|
||||
public void decompileToZip(String sourceJar, String zipName)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,14 +18,6 @@
|
|||
|
||||
package the.bytecode.club.bytecodeviewer.decompilers.impl;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.File;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.PrintWriter;
|
||||
import java.io.StringWriter;
|
||||
import java.util.Arrays;
|
||||
import java.util.stream.Collectors;
|
||||
import me.konloch.kontainer.io.DiskReader;
|
||||
import org.apache.commons.lang3.ArrayUtils;
|
||||
import org.objectweb.asm.tree.ClassNode;
|
||||
|
@ -40,9 +32,11 @@ import the.bytecode.club.bytecodeviewer.util.JarUtils;
|
|||
import the.bytecode.club.bytecodeviewer.util.MiscUtils;
|
||||
import the.bytecode.club.bytecodeviewer.util.ZipUtils;
|
||||
|
||||
import static the.bytecode.club.bytecodeviewer.Constants.fs;
|
||||
import static the.bytecode.club.bytecodeviewer.Constants.krakatauWorkingDirectory;
|
||||
import static the.bytecode.club.bytecodeviewer.Constants.nl;
|
||||
import java.io.*;
|
||||
import java.util.Arrays;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static the.bytecode.club.bytecodeviewer.Constants.*;
|
||||
|
||||
/**
|
||||
* Krakatau Java Decompiler Wrapper, requires Python 2.7
|
||||
|
@ -67,50 +61,38 @@ public class KrakatauDecompiler extends InternalDecompiler
|
|||
if (files == null || files.length == 0)
|
||||
return "";
|
||||
|
||||
return ";" + Arrays.stream(files).filter(File::isFile)
|
||||
.map(File::getAbsolutePath).collect(Collectors.joining(";"));
|
||||
return ";" + Arrays.stream(files).filter(File::isFile).map(File::getAbsolutePath).collect(Collectors.joining(";"));
|
||||
}
|
||||
|
||||
public String decompileClassNode(File krakatauTempJar, File krakatauTempDir, ClassNode cn)
|
||||
{
|
||||
if(!ExternalResources.getSingleton().hasSetPython2Command())
|
||||
if (!ExternalResources.getSingleton().hasSetPython2Command())
|
||||
return TranslatedStrings.YOU_NEED_TO_SET_YOUR_PYTHON_2_PATH.toString();
|
||||
|
||||
ExternalResources.getSingleton().rtCheck();
|
||||
if (Configuration.rt.isEmpty())
|
||||
{
|
||||
BytecodeViewer.showMessage(TranslatedStrings.YOU_NEED_TO_SET_YOUR_JAVA_RT_PATH_A
|
||||
+ "\r\n" + TranslatedStrings.YOU_NEED_TO_SET_YOUR_JAVA_RT_PATH_B);
|
||||
BytecodeViewer.showMessage(TranslatedStrings.YOU_NEED_TO_SET_YOUR_JAVA_RT_PATH_A + "\r\n" + TranslatedStrings.YOU_NEED_TO_SET_YOUR_JAVA_RT_PATH_B);
|
||||
ExternalResources.getSingleton().selectJRERTLibrary();
|
||||
}
|
||||
|
||||
if (Configuration.rt.isEmpty())
|
||||
{
|
||||
BytecodeViewer.showMessage(TranslatedStrings.YOU_NEED_TO_SET_YOUR_JAVA_RT_PATH_A
|
||||
+ "\r\n" + TranslatedStrings.YOU_NEED_TO_SET_YOUR_JAVA_RT_PATH_B);
|
||||
return TranslatedStrings.YOU_NEED_TO_SET_YOUR_JAVA_RT_PATH_A
|
||||
+ " " + TranslatedStrings.YOU_NEED_TO_SET_YOUR_JAVA_RT_PATH_B;
|
||||
BytecodeViewer.showMessage(TranslatedStrings.YOU_NEED_TO_SET_YOUR_JAVA_RT_PATH_A + "\r\n" + TranslatedStrings.YOU_NEED_TO_SET_YOUR_JAVA_RT_PATH_B);
|
||||
return TranslatedStrings.YOU_NEED_TO_SET_YOUR_JAVA_RT_PATH_A + " " + TranslatedStrings.YOU_NEED_TO_SET_YOUR_JAVA_RT_PATH_B;
|
||||
}
|
||||
|
||||
String s = ExceptionUI.SEND_STACKTRACE_TO_NL;
|
||||
|
||||
try {
|
||||
try
|
||||
{
|
||||
String[] pythonCommands = new String[]{Configuration.python2};
|
||||
if(Configuration.python2Extra)
|
||||
if (Configuration.python2Extra)
|
||||
pythonCommands = ArrayUtils.addAll(pythonCommands, "-2");
|
||||
|
||||
ProcessBuilder pb = new ProcessBuilder(ArrayUtils.addAll(
|
||||
pythonCommands,
|
||||
"-O", //love you storyyeller <3
|
||||
krakatauWorkingDirectory + fs + "decompile.py",
|
||||
"-skip", //love you storyyeller <3
|
||||
"-nauto",
|
||||
"-path",
|
||||
Configuration.rt + ";" + krakatauTempJar.getAbsolutePath() + buildCLIArguments(),
|
||||
"-out",
|
||||
krakatauTempDir.getAbsolutePath(),
|
||||
cn.name + ".class"
|
||||
));
|
||||
|
||||
ProcessBuilder pb = new ProcessBuilder(ArrayUtils.addAll(pythonCommands, "-O", //love you storyyeller <3
|
||||
krakatauWorkingDirectory + fs + "decompile.py", "-skip", //love you storyyeller <3
|
||||
"-nauto", "-path", Configuration.rt + ";" + krakatauTempJar.getAbsolutePath() + buildCLIArguments(), "-out", krakatauTempDir.getAbsolutePath(), cn.name + ".class"));
|
||||
|
||||
Process process = pb.start();
|
||||
BytecodeViewer.createdProcesses.add(process);
|
||||
|
@ -118,22 +100,22 @@ public class KrakatauDecompiler extends InternalDecompiler
|
|||
StringBuilder log = new StringBuilder(TranslatedStrings.PROCESS2 + nl + nl);
|
||||
|
||||
//Read out dir output
|
||||
try (InputStream is = process.getInputStream();
|
||||
InputStreamReader isr = new InputStreamReader(is);
|
||||
BufferedReader br = new BufferedReader(isr)) {
|
||||
try (InputStream is = process.getInputStream(); InputStreamReader isr = new InputStreamReader(is); BufferedReader br = new BufferedReader(isr))
|
||||
{
|
||||
String line;
|
||||
while ((line = br.readLine()) != null) {
|
||||
while ((line = br.readLine()) != null)
|
||||
{
|
||||
log.append(nl).append(line);
|
||||
}
|
||||
}
|
||||
|
||||
log.append(nl).append(nl).append(TranslatedStrings.ERROR2).append(nl).append(nl);
|
||||
|
||||
try (InputStream is = process.getErrorStream();
|
||||
InputStreamReader isr = new InputStreamReader(is);
|
||||
BufferedReader br = new BufferedReader(isr)) {
|
||||
try (InputStream is = process.getErrorStream(); InputStreamReader isr = new InputStreamReader(is); BufferedReader br = new BufferedReader(isr))
|
||||
{
|
||||
String line;
|
||||
while ((line = br.readLine()) != null) {
|
||||
while ((line = br.readLine()) != null)
|
||||
{
|
||||
log.append(nl).append(line);
|
||||
}
|
||||
}
|
||||
|
@ -144,7 +126,9 @@ public class KrakatauDecompiler extends InternalDecompiler
|
|||
|
||||
//if the motherfucker failed this'll fail, aka wont set.
|
||||
s = DiskReader.loadAsString(krakatauTempDir.getAbsolutePath() + fs + cn.name + ".java");
|
||||
} catch (Exception e) {
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
StringWriter sw = new StringWriter();
|
||||
e.printStackTrace(new PrintWriter(sw));
|
||||
e.printStackTrace();
|
||||
|
@ -158,17 +142,18 @@ public class KrakatauDecompiler extends InternalDecompiler
|
|||
public String decompileClassNode(ClassNode cn, byte[] b)
|
||||
{
|
||||
//TODO look into transforming through krakatau as a zip rather than direct classfile
|
||||
|
||||
if(!ExternalResources.getSingleton().hasSetPython2Command())
|
||||
|
||||
if (!ExternalResources.getSingleton().hasSetPython2Command())
|
||||
return TranslatedStrings.YOU_NEED_TO_SET_YOUR_PYTHON_2_PATH.toString();
|
||||
|
||||
if (Configuration.rt.isEmpty()) {
|
||||
BytecodeViewer.showMessage(TranslatedStrings.YOU_NEED_TO_SET_YOUR_JAVA_RT_PATH_A
|
||||
+ "\r\n" + TranslatedStrings.YOU_NEED_TO_SET_YOUR_JAVA_RT_PATH_B);
|
||||
|
||||
if (Configuration.rt.isEmpty())
|
||||
{
|
||||
BytecodeViewer.showMessage(TranslatedStrings.YOU_NEED_TO_SET_YOUR_JAVA_RT_PATH_A + "\r\n" + TranslatedStrings.YOU_NEED_TO_SET_YOUR_JAVA_RT_PATH_B);
|
||||
ExternalResources.getSingleton().selectJRERTLibrary();
|
||||
}
|
||||
|
||||
if (Configuration.rt.isEmpty()) {
|
||||
if (Configuration.rt.isEmpty())
|
||||
{
|
||||
BytecodeViewer.showMessage("You need to set RT.jar!");
|
||||
return "Set your paths";
|
||||
}
|
||||
|
@ -181,23 +166,15 @@ public class KrakatauDecompiler extends InternalDecompiler
|
|||
|
||||
JarUtils.saveAsJarClassesOnly(BytecodeViewer.getLoadedClasses(), tempJar.getAbsolutePath());
|
||||
|
||||
try {
|
||||
try
|
||||
{
|
||||
String[] pythonCommands = new String[]{Configuration.python2};
|
||||
if(Configuration.python2Extra)
|
||||
if (Configuration.python2Extra)
|
||||
pythonCommands = ArrayUtils.addAll(pythonCommands, "-2");
|
||||
|
||||
ProcessBuilder pb = new ProcessBuilder(ArrayUtils.addAll(
|
||||
pythonCommands,
|
||||
"-O", //love you storyyeller <3
|
||||
krakatauWorkingDirectory + fs + "decompile.py",
|
||||
"-skip", //love you storyyeller <3
|
||||
"-nauto",
|
||||
"-path",
|
||||
Configuration.rt + ";" + tempJar.getAbsolutePath() + buildCLIArguments(),
|
||||
"-out",
|
||||
tempDirectory.getAbsolutePath(),
|
||||
cn.name + ".class"
|
||||
));
|
||||
|
||||
ProcessBuilder pb = new ProcessBuilder(ArrayUtils.addAll(pythonCommands, "-O", //love you storyyeller <3
|
||||
krakatauWorkingDirectory + fs + "decompile.py", "-skip", //love you storyyeller <3
|
||||
"-nauto", "-path", Configuration.rt + ";" + tempJar.getAbsolutePath() + buildCLIArguments(), "-out", tempDirectory.getAbsolutePath(), cn.name + ".class"));
|
||||
|
||||
Process process = pb.start();
|
||||
BytecodeViewer.createdProcesses.add(process);
|
||||
|
@ -205,22 +182,22 @@ public class KrakatauDecompiler extends InternalDecompiler
|
|||
StringBuilder log = new StringBuilder(TranslatedStrings.PROCESS2 + nl + nl);
|
||||
|
||||
//Read out dir output
|
||||
try (InputStream is = process.getInputStream();
|
||||
InputStreamReader isr = new InputStreamReader(is);
|
||||
BufferedReader br = new BufferedReader(isr)) {
|
||||
try (InputStream is = process.getInputStream(); InputStreamReader isr = new InputStreamReader(is); BufferedReader br = new BufferedReader(isr))
|
||||
{
|
||||
String line;
|
||||
while ((line = br.readLine()) != null) {
|
||||
while ((line = br.readLine()) != null)
|
||||
{
|
||||
log.append(nl).append(line);
|
||||
}
|
||||
}
|
||||
|
||||
log.append(nl).append(nl).append(TranslatedStrings.ERROR2).append(nl).append(nl);
|
||||
|
||||
try (InputStream is = process.getErrorStream();
|
||||
InputStreamReader isr = new InputStreamReader(is);
|
||||
BufferedReader br = new BufferedReader(isr)) {
|
||||
try (InputStream is = process.getErrorStream(); InputStreamReader isr = new InputStreamReader(is); BufferedReader br = new BufferedReader(isr))
|
||||
{
|
||||
String line;
|
||||
while ((line = br.readLine()) != null) {
|
||||
while ((line = br.readLine()) != null)
|
||||
{
|
||||
log.append(nl).append(line);
|
||||
}
|
||||
}
|
||||
|
@ -233,7 +210,9 @@ public class KrakatauDecompiler extends InternalDecompiler
|
|||
s = DiskReader.loadAsString(tempDirectory.getAbsolutePath() + fs + cn.name + ".java");
|
||||
tempDirectory.delete();
|
||||
tempJar.delete();
|
||||
} catch (Exception e) {
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
StringWriter sw = new StringWriter();
|
||||
e.printStackTrace(new PrintWriter(sw));
|
||||
e.printStackTrace();
|
||||
|
@ -244,14 +223,15 @@ public class KrakatauDecompiler extends InternalDecompiler
|
|||
}
|
||||
|
||||
@Override
|
||||
public void decompileToZip(String sourceJar, String zipName) {
|
||||
if(!ExternalResources.getSingleton().hasSetPython2Command())
|
||||
public void decompileToZip(String sourceJar, String zipName)
|
||||
{
|
||||
if (!ExternalResources.getSingleton().hasSetPython2Command())
|
||||
return;
|
||||
|
||||
|
||||
ExternalResources.getSingleton().rtCheck();
|
||||
if (Configuration.rt.isEmpty()) {
|
||||
BytecodeViewer.showMessage(TranslatedStrings.YOU_NEED_TO_SET_YOUR_JAVA_RT_PATH_A
|
||||
+ "\r\n" + TranslatedStrings.YOU_NEED_TO_SET_YOUR_JAVA_RT_PATH_B);
|
||||
if (Configuration.rt.isEmpty())
|
||||
{
|
||||
BytecodeViewer.showMessage(TranslatedStrings.YOU_NEED_TO_SET_YOUR_JAVA_RT_PATH_A + "\r\n" + TranslatedStrings.YOU_NEED_TO_SET_YOUR_JAVA_RT_PATH_B);
|
||||
ExternalResources.getSingleton().selectJRERTLibrary();
|
||||
}
|
||||
|
||||
|
@ -260,24 +240,16 @@ public class KrakatauDecompiler extends InternalDecompiler
|
|||
tempDirectory.mkdir();
|
||||
|
||||
final File tempJar = new File(sourceJar);
|
||||
|
||||
try {
|
||||
|
||||
try
|
||||
{
|
||||
String[] pythonCommands = new String[]{Configuration.python2};
|
||||
if(Configuration.python2Extra)
|
||||
if (Configuration.python2Extra)
|
||||
pythonCommands = ArrayUtils.addAll(pythonCommands, "-2");
|
||||
|
||||
ProcessBuilder pb = new ProcessBuilder(ArrayUtils.addAll(
|
||||
pythonCommands,
|
||||
"-O", //love you storyyeller <3
|
||||
krakatauWorkingDirectory + fs + "decompile.py",
|
||||
"-skip", //love you storyyeller <3
|
||||
"-nauto",
|
||||
"-path",
|
||||
Configuration.rt + ";" + tempJar.getAbsolutePath(),
|
||||
"-out",
|
||||
tempDirectory.getAbsolutePath(),
|
||||
tempJar.getAbsolutePath()
|
||||
));
|
||||
|
||||
ProcessBuilder pb = new ProcessBuilder(ArrayUtils.addAll(pythonCommands, "-O", //love you storyyeller <3
|
||||
krakatauWorkingDirectory + fs + "decompile.py", "-skip", //love you storyyeller <3
|
||||
"-nauto", "-path", Configuration.rt + ";" + tempJar.getAbsolutePath(), "-out", tempDirectory.getAbsolutePath(), tempJar.getAbsolutePath()));
|
||||
|
||||
Process process = pb.start();
|
||||
BytecodeViewer.createdProcesses.add(process);
|
||||
|
@ -285,7 +257,9 @@ public class KrakatauDecompiler extends InternalDecompiler
|
|||
MiscUtils.printProcess(process);
|
||||
|
||||
ZipUtils.zipFolder(tempDirectory.getAbsolutePath(), zipName, ran);
|
||||
} catch (Exception e) {
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
BytecodeViewer.handleException(e);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,12 +18,6 @@
|
|||
|
||||
package the.bytecode.club.bytecodeviewer.decompilers.impl;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.File;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.PrintWriter;
|
||||
import java.io.StringWriter;
|
||||
import me.konloch.kontainer.io.DiskReader;
|
||||
import org.apache.commons.lang3.ArrayUtils;
|
||||
import org.objectweb.asm.tree.ClassNode;
|
||||
|
@ -38,9 +32,9 @@ import the.bytecode.club.bytecodeviewer.util.JarUtils;
|
|||
import the.bytecode.club.bytecodeviewer.util.MiscUtils;
|
||||
import the.bytecode.club.bytecodeviewer.util.ZipUtils;
|
||||
|
||||
import static the.bytecode.club.bytecodeviewer.Constants.fs;
|
||||
import static the.bytecode.club.bytecodeviewer.Constants.krakatauWorkingDirectory;
|
||||
import static the.bytecode.club.bytecodeviewer.Constants.nl;
|
||||
import java.io.*;
|
||||
|
||||
import static the.bytecode.club.bytecodeviewer.Constants.*;
|
||||
|
||||
/**
|
||||
* Krakatau Java Disassembler Wrapper, requires Python 2.7
|
||||
|
@ -51,8 +45,9 @@ import static the.bytecode.club.bytecodeviewer.Constants.nl;
|
|||
public class KrakatauDisassembler extends InternalDecompiler
|
||||
{
|
||||
@Override
|
||||
public String decompileClassNode(ClassNode cn, byte[] b) {
|
||||
if(!ExternalResources.getSingleton().hasSetPython2Command())
|
||||
public String decompileClassNode(ClassNode cn, byte[] b)
|
||||
{
|
||||
if (!ExternalResources.getSingleton().hasSetPython2Command())
|
||||
return TranslatedStrings.YOU_NEED_TO_SET_YOUR_PYTHON_2_PATH.toString();
|
||||
|
||||
String s = ExceptionUI.SEND_STACKTRACE_TO_NL;
|
||||
|
@ -62,21 +57,14 @@ public class KrakatauDisassembler extends InternalDecompiler
|
|||
final File tempJar = new File(Constants.tempDirectory + fs + "temp" + MiscUtils.randomString(32) + ".jar");
|
||||
JarUtils.saveAsJarClassesOnly(BytecodeViewer.getLoadedClasses(), tempJar.getAbsolutePath());
|
||||
|
||||
try {
|
||||
try
|
||||
{
|
||||
String[] pythonCommands = new String[]{Configuration.python2};
|
||||
if(Configuration.python2Extra)
|
||||
if (Configuration.python2Extra)
|
||||
pythonCommands = ArrayUtils.addAll(pythonCommands, "-2");
|
||||
|
||||
ProcessBuilder pb = new ProcessBuilder(ArrayUtils.addAll(
|
||||
pythonCommands,
|
||||
"-O", //love you storyyeller <3
|
||||
krakatauWorkingDirectory + fs + "disassemble.py",
|
||||
"-path",
|
||||
tempJar.getAbsolutePath(),
|
||||
"-out",
|
||||
tempDirectory.getAbsolutePath(),
|
||||
cn.name + ".class"
|
||||
));
|
||||
|
||||
ProcessBuilder pb = new ProcessBuilder(ArrayUtils.addAll(pythonCommands, "-O", //love you storyyeller <3
|
||||
krakatauWorkingDirectory + fs + "disassemble.py", "-path", tempJar.getAbsolutePath(), "-out", tempDirectory.getAbsolutePath(), cn.name + ".class"));
|
||||
|
||||
Process process = pb.start();
|
||||
BytecodeViewer.createdProcesses.add(process);
|
||||
|
@ -84,22 +72,22 @@ public class KrakatauDisassembler extends InternalDecompiler
|
|||
StringBuilder log = new StringBuilder(TranslatedStrings.PROCESS2 + nl + nl);
|
||||
|
||||
//Read out dir output
|
||||
try (InputStream is = process.getInputStream();
|
||||
InputStreamReader isr = new InputStreamReader(is);
|
||||
BufferedReader br = new BufferedReader(isr)) {
|
||||
try (InputStream is = process.getInputStream(); InputStreamReader isr = new InputStreamReader(is); BufferedReader br = new BufferedReader(isr))
|
||||
{
|
||||
String line;
|
||||
while ((line = br.readLine()) != null) {
|
||||
while ((line = br.readLine()) != null)
|
||||
{
|
||||
log.append(nl).append(line);
|
||||
}
|
||||
}
|
||||
|
||||
log.append(nl).append(nl).append(TranslatedStrings.ERROR2).append(nl).append(nl);
|
||||
|
||||
try (InputStream is = process.getErrorStream();
|
||||
InputStreamReader isr = new InputStreamReader(is);
|
||||
BufferedReader br = new BufferedReader(isr)) {
|
||||
try (InputStream is = process.getErrorStream(); InputStreamReader isr = new InputStreamReader(is); BufferedReader br = new BufferedReader(isr))
|
||||
{
|
||||
String line;
|
||||
while ((line = br.readLine()) != null) {
|
||||
while ((line = br.readLine()) != null)
|
||||
{
|
||||
log.append(nl).append(line);
|
||||
}
|
||||
}
|
||||
|
@ -110,7 +98,9 @@ public class KrakatauDisassembler extends InternalDecompiler
|
|||
|
||||
// if the motherfucker failed this'll fail, aka won't set.
|
||||
s = DiskReader.loadAsString(tempDirectory.getAbsolutePath() + fs + cn.name + ".j");
|
||||
} catch (Exception e) {
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
StringWriter sw = new StringWriter();
|
||||
e.printStackTrace(new PrintWriter(sw));
|
||||
e.printStackTrace();
|
||||
|
@ -120,8 +110,9 @@ public class KrakatauDisassembler extends InternalDecompiler
|
|||
}
|
||||
|
||||
@Override
|
||||
public void decompileToZip(String sourceJar, String zipName) {
|
||||
if(!ExternalResources.getSingleton().hasSetPython2Command())
|
||||
public void decompileToZip(String sourceJar, String zipName)
|
||||
{
|
||||
if (!ExternalResources.getSingleton().hasSetPython2Command())
|
||||
return;
|
||||
|
||||
String ran = MiscUtils.randomString(32);
|
||||
|
@ -130,28 +121,23 @@ public class KrakatauDisassembler extends InternalDecompiler
|
|||
|
||||
final File tempJar = new File(sourceJar);
|
||||
|
||||
try {
|
||||
try
|
||||
{
|
||||
String[] pythonCommands = new String[]{Configuration.python2};
|
||||
if(Configuration.python2Extra)
|
||||
if (Configuration.python2Extra)
|
||||
pythonCommands = ArrayUtils.addAll(pythonCommands, "-2");
|
||||
|
||||
ProcessBuilder pb = new ProcessBuilder(ArrayUtils.addAll(
|
||||
pythonCommands,
|
||||
"-O", //love you storyyeller <3
|
||||
krakatauWorkingDirectory + fs + "disassemble.py",
|
||||
"-path",
|
||||
Configuration.rt + ";" + tempJar.getAbsolutePath(),
|
||||
"-out",
|
||||
tempDirectory.getAbsolutePath(),
|
||||
tempJar.getAbsolutePath()
|
||||
));
|
||||
|
||||
ProcessBuilder pb = new ProcessBuilder(ArrayUtils.addAll(pythonCommands, "-O", //love you storyyeller <3
|
||||
krakatauWorkingDirectory + fs + "disassemble.py", "-path", Configuration.rt + ";" + tempJar.getAbsolutePath(), "-out", tempDirectory.getAbsolutePath(), tempJar.getAbsolutePath()));
|
||||
|
||||
Process process = pb.start();
|
||||
BytecodeViewer.createdProcesses.add(process);
|
||||
process.waitFor();
|
||||
|
||||
ZipUtils.zipFolder(tempDirectory.getAbsolutePath(), zipName, ran);
|
||||
} catch (Exception e) {
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
BytecodeViewer.handleException(e);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,35 +19,12 @@
|
|||
package the.bytecode.club.bytecodeviewer.decompilers.impl;
|
||||
|
||||
import com.strobel.assembler.InputTypeLoader;
|
||||
import com.strobel.assembler.metadata.Buffer;
|
||||
import com.strobel.assembler.metadata.ITypeLoader;
|
||||
import com.strobel.assembler.metadata.JarTypeLoader;
|
||||
import com.strobel.assembler.metadata.MetadataSystem;
|
||||
import com.strobel.assembler.metadata.TypeDefinition;
|
||||
import com.strobel.assembler.metadata.TypeReference;
|
||||
import com.strobel.assembler.metadata.*;
|
||||
import com.strobel.core.StringUtilities;
|
||||
import com.strobel.decompiler.DecompilationOptions;
|
||||
import com.strobel.decompiler.DecompilerSettings;
|
||||
import com.strobel.decompiler.PlainTextOutput;
|
||||
import com.strobel.decompiler.languages.java.JavaFormattingOptions;
|
||||
import java.io.BufferedOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStreamWriter;
|
||||
import java.io.PrintWriter;
|
||||
import java.io.StringWriter;
|
||||
import java.io.Writer;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Enumeration;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.jar.JarEntry;
|
||||
import java.util.jar.JarFile;
|
||||
import java.util.zip.ZipException;
|
||||
import java.util.zip.ZipOutputStream;
|
||||
import org.objectweb.asm.tree.ClassNode;
|
||||
import the.bytecode.club.bytecodeviewer.BytecodeViewer;
|
||||
import the.bytecode.club.bytecodeviewer.api.ExceptionUI;
|
||||
|
@ -56,9 +33,14 @@ import the.bytecode.club.bytecodeviewer.translation.TranslatedStrings;
|
|||
import the.bytecode.club.bytecodeviewer.util.EncodeUtils;
|
||||
import the.bytecode.club.bytecodeviewer.util.MiscUtils;
|
||||
|
||||
import static the.bytecode.club.bytecodeviewer.Constants.fs;
|
||||
import static the.bytecode.club.bytecodeviewer.Constants.nl;
|
||||
import static the.bytecode.club.bytecodeviewer.Constants.tempDirectory;
|
||||
import java.io.*;
|
||||
import java.util.*;
|
||||
import java.util.jar.JarEntry;
|
||||
import java.util.jar.JarFile;
|
||||
import java.util.zip.ZipException;
|
||||
import java.util.zip.ZipOutputStream;
|
||||
|
||||
import static the.bytecode.club.bytecodeviewer.Constants.*;
|
||||
import static the.bytecode.club.bytecodeviewer.translation.TranslatedStrings.ERROR;
|
||||
import static the.bytecode.club.bytecodeviewer.translation.TranslatedStrings.PROCYON;
|
||||
|
||||
|
@ -68,9 +50,11 @@ import static the.bytecode.club.bytecodeviewer.translation.TranslatedStrings.PRO
|
|||
* @author Konloch
|
||||
* @author DeathMarine
|
||||
*/
|
||||
public class ProcyonDecompiler extends InternalDecompiler {
|
||||
public class ProcyonDecompiler extends InternalDecompiler
|
||||
{
|
||||
|
||||
public DecompilerSettings getDecompilerSettings() {
|
||||
public DecompilerSettings getDecompilerSettings()
|
||||
{
|
||||
DecompilerSettings settings = new DecompilerSettings();
|
||||
settings.setAlwaysGenerateExceptionVariableForCatchBlocks(BytecodeViewer.viewer.alwaysGenerateExceptionVars.isSelected());
|
||||
settings.setExcludeNestedTypes(BytecodeViewer.viewer.excludeNestedTypes.isSelected());
|
||||
|
@ -91,16 +75,21 @@ public class ProcyonDecompiler extends InternalDecompiler {
|
|||
}
|
||||
|
||||
@Override
|
||||
public String decompileClassNode(ClassNode cn, byte[] b) {
|
||||
public String decompileClassNode(ClassNode cn, byte[] b)
|
||||
{
|
||||
String exception;
|
||||
try {
|
||||
try
|
||||
{
|
||||
String fileStart = tempDirectory + fs + "temp";
|
||||
|
||||
final File tempClass = new File(MiscUtils.getUniqueName(fileStart, ".class") + ".class");
|
||||
|
||||
try (FileOutputStream fos = new FileOutputStream(tempClass)) {
|
||||
try (FileOutputStream fos = new FileOutputStream(tempClass))
|
||||
{
|
||||
fos.write(b);
|
||||
} catch (IOException e) {
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
BytecodeViewer.handleException(e);
|
||||
}
|
||||
|
||||
|
@ -122,7 +111,9 @@ public class ProcyonDecompiler extends InternalDecompiler {
|
|||
settings.getLanguage().decompileType(resolvedType, new PlainTextOutput(stringwriter), decompilationOptions);
|
||||
|
||||
return EncodeUtils.unicodeToString(stringwriter.toString());
|
||||
} catch (StackOverflowError | Exception e) {
|
||||
}
|
||||
catch (StackOverflowError | Exception e)
|
||||
{
|
||||
StringWriter sw = new StringWriter();
|
||||
e.printStackTrace(new PrintWriter(sw));
|
||||
e.printStackTrace();
|
||||
|
@ -130,16 +121,18 @@ public class ProcyonDecompiler extends InternalDecompiler {
|
|||
exception = ExceptionUI.SEND_STACKTRACE_TO_NL + sw;
|
||||
}
|
||||
|
||||
return PROCYON + " " + ERROR + "! " + ExceptionUI.SEND_STACKTRACE_TO +
|
||||
nl + nl + TranslatedStrings.SUGGESTED_FIX_DECOMPILER_ERROR +
|
||||
nl + nl + exception;
|
||||
return PROCYON + " " + ERROR + "! " + ExceptionUI.SEND_STACKTRACE_TO + nl + nl + TranslatedStrings.SUGGESTED_FIX_DECOMPILER_ERROR + nl + nl + exception;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void decompileToZip(String sourceJar, String zipName) {
|
||||
try {
|
||||
public void decompileToZip(String sourceJar, String zipName)
|
||||
{
|
||||
try
|
||||
{
|
||||
doSaveJarDecompiled(new File(sourceJar), new File(zipName));
|
||||
} catch (StackOverflowError | Exception e) {
|
||||
}
|
||||
catch (StackOverflowError | Exception e)
|
||||
{
|
||||
BytecodeViewer.handleException(e);
|
||||
}
|
||||
}
|
||||
|
@ -147,12 +140,10 @@ public class ProcyonDecompiler extends InternalDecompiler {
|
|||
/**
|
||||
* @author DeathMarine
|
||||
*/
|
||||
private void doSaveJarDecompiled(File inFile, File outFile)
|
||||
throws Exception {
|
||||
try (JarFile jfile = new JarFile(inFile);
|
||||
FileOutputStream dest = new FileOutputStream(outFile);
|
||||
BufferedOutputStream buffDest = new BufferedOutputStream(dest);
|
||||
ZipOutputStream out = new ZipOutputStream(buffDest)) {
|
||||
private void doSaveJarDecompiled(File inFile, File outFile) throws Exception
|
||||
{
|
||||
try (JarFile jfile = new JarFile(inFile); FileOutputStream dest = new FileOutputStream(outFile); BufferedOutputStream buffDest = new BufferedOutputStream(dest); ZipOutputStream out = new ZipOutputStream(buffDest))
|
||||
{
|
||||
byte[] data = new byte[1024];
|
||||
DecompilerSettings settings = getDecompilerSettings();
|
||||
LuytenTypeLoader typeLoader = new LuytenTypeLoader();
|
||||
|
@ -166,52 +157,64 @@ public class ProcyonDecompiler extends InternalDecompiler {
|
|||
|
||||
Enumeration<JarEntry> ent = jfile.entries();
|
||||
Set<JarEntry> history = new HashSet<>();
|
||||
while (ent.hasMoreElements()) {
|
||||
while (ent.hasMoreElements())
|
||||
{
|
||||
JarEntry entry = ent.nextElement();
|
||||
if (entry.getName().endsWith(".class")) {
|
||||
JarEntry etn = new JarEntry(entry.getName().replace(
|
||||
".class", ".java"));
|
||||
if (history.add(etn)) {
|
||||
if (entry.getName().endsWith(".class"))
|
||||
{
|
||||
JarEntry etn = new JarEntry(entry.getName().replace(".class", ".java"));
|
||||
if (history.add(etn))
|
||||
{
|
||||
out.putNextEntry(etn);
|
||||
try {
|
||||
String internalName = StringUtilities.removeRight(
|
||||
entry.getName(), ".class");
|
||||
TypeReference type = metadataSystem
|
||||
.lookupType(internalName);
|
||||
try
|
||||
{
|
||||
String internalName = StringUtilities.removeRight(entry.getName(), ".class");
|
||||
TypeReference type = metadataSystem.lookupType(internalName);
|
||||
TypeDefinition resolvedType;
|
||||
if ((type == null)
|
||||
|| ((resolvedType = type.resolve()) == null)) {
|
||||
if ((type == null) || ((resolvedType = type.resolve()) == null))
|
||||
{
|
||||
throw new Exception("Unable to resolve type.");
|
||||
}
|
||||
Writer writer = new OutputStreamWriter(out);
|
||||
settings.getLanguage().decompileType(resolvedType,
|
||||
new PlainTextOutput(writer),
|
||||
decompilationOptions);
|
||||
settings.getLanguage().decompileType(resolvedType, new PlainTextOutput(writer), decompilationOptions);
|
||||
writer.flush();
|
||||
} finally {
|
||||
}
|
||||
finally
|
||||
{
|
||||
out.closeEntry();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
try {
|
||||
}
|
||||
else
|
||||
{
|
||||
try
|
||||
{
|
||||
JarEntry etn = new JarEntry(entry.getName());
|
||||
if (history.add(etn))
|
||||
continue;
|
||||
history.add(etn);
|
||||
out.putNextEntry(etn);
|
||||
try (InputStream in = jfile.getInputStream(entry)) {
|
||||
if (in != null) {
|
||||
try (InputStream in = jfile.getInputStream(entry))
|
||||
{
|
||||
if (in != null)
|
||||
{
|
||||
int count;
|
||||
while ((count = in.read(data, 0, 1024)) != -1) {
|
||||
while ((count = in.read(data, 0, 1024)) != -1)
|
||||
{
|
||||
out.write(data, 0, count);
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
}
|
||||
finally
|
||||
{
|
||||
out.closeEntry();
|
||||
}
|
||||
} catch (ZipException ze) {
|
||||
}
|
||||
catch (ZipException ze)
|
||||
{
|
||||
// some jars contain duplicate pom.xml entries: ignore it
|
||||
if (!ze.getMessage().contains("duplicate")) {
|
||||
if (!ze.getMessage().contains("duplicate"))
|
||||
{
|
||||
throw ze;
|
||||
}
|
||||
}
|
||||
|
@ -223,23 +226,29 @@ public class ProcyonDecompiler extends InternalDecompiler {
|
|||
/**
|
||||
* @author DeathMarine
|
||||
*/
|
||||
public static final class LuytenTypeLoader implements ITypeLoader {
|
||||
public static final class LuytenTypeLoader implements ITypeLoader
|
||||
{
|
||||
|
||||
private final List<ITypeLoader> _typeLoaders;
|
||||
|
||||
public LuytenTypeLoader() {
|
||||
public LuytenTypeLoader()
|
||||
{
|
||||
_typeLoaders = new ArrayList<>();
|
||||
_typeLoaders.add(new InputTypeLoader());
|
||||
}
|
||||
|
||||
public List<ITypeLoader> getTypeLoaders() {
|
||||
public List<ITypeLoader> getTypeLoaders()
|
||||
{
|
||||
return _typeLoaders;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean tryLoadType(String internalName, Buffer buffer) {
|
||||
for (ITypeLoader typeLoader : _typeLoaders) {
|
||||
if (typeLoader.tryLoadType(internalName, buffer)) {
|
||||
public boolean tryLoadType(String internalName, Buffer buffer)
|
||||
{
|
||||
for (ITypeLoader typeLoader : _typeLoaders)
|
||||
{
|
||||
if (typeLoader.tryLoadType(internalName, buffer))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -19,12 +19,6 @@
|
|||
package the.bytecode.club.bytecodeviewer.decompilers.impl;
|
||||
|
||||
import com.googlecode.d2j.smali.BaksmaliCmd;
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.PrintWriter;
|
||||
import java.io.StringWriter;
|
||||
import java.util.Objects;
|
||||
import me.konloch.kontainer.io.DiskReader;
|
||||
import org.apache.commons.io.FileUtils;
|
||||
import org.objectweb.asm.tree.ClassNode;
|
||||
|
@ -35,12 +29,11 @@ import the.bytecode.club.bytecodeviewer.translation.TranslatedStrings;
|
|||
import the.bytecode.club.bytecodeviewer.util.Dex2Jar;
|
||||
import the.bytecode.club.bytecodeviewer.util.MiscUtils;
|
||||
|
||||
import static the.bytecode.club.bytecodeviewer.Constants.fs;
|
||||
import static the.bytecode.club.bytecodeviewer.Constants.nl;
|
||||
import static the.bytecode.club.bytecodeviewer.Constants.tempDirectory;
|
||||
import static the.bytecode.club.bytecodeviewer.translation.TranslatedStrings.DISASSEMBLER;
|
||||
import static the.bytecode.club.bytecodeviewer.translation.TranslatedStrings.ERROR;
|
||||
import static the.bytecode.club.bytecodeviewer.translation.TranslatedStrings.SMALI;
|
||||
import java.io.*;
|
||||
import java.util.Objects;
|
||||
|
||||
import static the.bytecode.club.bytecodeviewer.Constants.*;
|
||||
import static the.bytecode.club.bytecodeviewer.translation.TranslatedStrings.*;
|
||||
|
||||
/**
|
||||
* Smali Disassembler Wrapper
|
||||
|
@ -63,9 +56,12 @@ public class SmaliDisassembler extends InternalDecompiler
|
|||
final File tempDexOut = new File(start + "-out");
|
||||
final File tempSmali = new File(start + "-smali"); //output directory
|
||||
|
||||
try (FileOutputStream fos = new FileOutputStream(tempClass)) {
|
||||
try (FileOutputStream fos = new FileOutputStream(tempClass))
|
||||
{
|
||||
fos.write(b);
|
||||
} catch (IOException e) {
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
BytecodeViewer.handleException(e);
|
||||
}
|
||||
|
||||
|
@ -73,10 +69,12 @@ public class SmaliDisassembler extends InternalDecompiler
|
|||
|
||||
Dex2Jar.saveAsDex(tempClass, tempDex, true);
|
||||
|
||||
try {
|
||||
BaksmaliCmd.main(tempDex.getAbsolutePath(),
|
||||
"-o", tempDexOut.getAbsolutePath());
|
||||
} catch (Exception e) {
|
||||
try
|
||||
{
|
||||
BaksmaliCmd.main(tempDex.getAbsolutePath(), "-o", tempDexOut.getAbsolutePath());
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
StringWriter sw = new StringWriter();
|
||||
e.printStackTrace(new PrintWriter(sw));
|
||||
e.printStackTrace();
|
||||
|
@ -84,9 +82,12 @@ public class SmaliDisassembler extends InternalDecompiler
|
|||
exception += ExceptionUI.SEND_STACKTRACE_TO_NL + sw;
|
||||
}
|
||||
|
||||
try {
|
||||
try
|
||||
{
|
||||
FileUtils.moveDirectory(tempDexOut, tempSmali);
|
||||
} catch (IOException e) {
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
StringWriter sw = new StringWriter();
|
||||
e.printStackTrace(new PrintWriter(sw));
|
||||
e.printStackTrace();
|
||||
|
@ -98,19 +99,24 @@ public class SmaliDisassembler extends InternalDecompiler
|
|||
|
||||
boolean found = false;
|
||||
File current = tempSmali;
|
||||
while (!found) {
|
||||
while (!found)
|
||||
{
|
||||
File f = Objects.requireNonNull(current.listFiles())[0];
|
||||
if (f.isDirectory())
|
||||
current = f;
|
||||
else {
|
||||
else
|
||||
{
|
||||
outputSmali = f;
|
||||
found = true;
|
||||
}
|
||||
|
||||
}
|
||||
try {
|
||||
try
|
||||
{
|
||||
return DiskReader.loadAsString(outputSmali.getAbsolutePath());
|
||||
} catch (Exception e) {
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
StringWriter sw = new StringWriter();
|
||||
e.printStackTrace(new PrintWriter(sw));
|
||||
e.printStackTrace();
|
||||
|
@ -118,13 +124,12 @@ public class SmaliDisassembler extends InternalDecompiler
|
|||
exception += ExceptionUI.SEND_STACKTRACE_TO_NL + sw;
|
||||
}
|
||||
|
||||
return SMALI + " " + DISASSEMBLER + " " + ERROR + "! " + ExceptionUI.SEND_STACKTRACE_TO +
|
||||
nl + nl + TranslatedStrings.SUGGESTED_FIX_DECOMPILER_ERROR +
|
||||
nl + nl + exception;
|
||||
return SMALI + " " + DISASSEMBLER + " " + ERROR + "! " + ExceptionUI.SEND_STACKTRACE_TO + nl + nl + TranslatedStrings.SUGGESTED_FIX_DECOMPILER_ERROR + nl + nl + exception;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void decompileToZip(String sourceJar, String zipName) {
|
||||
public void decompileToZip(String sourceJar, String zipName)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -21,7 +21,8 @@ package the.bytecode.club.bytecodeviewer.decompilers.jdgui;
|
|||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public class CommonPreferences {
|
||||
public class CommonPreferences
|
||||
{
|
||||
private final Map<String, Object> preferences;
|
||||
protected boolean showDefaultConstructor;
|
||||
protected boolean realignmentLineNumber;
|
||||
|
@ -30,7 +31,8 @@ public class CommonPreferences {
|
|||
protected boolean unicodeEscape;
|
||||
protected boolean showLineNumbers;
|
||||
|
||||
public CommonPreferences() {
|
||||
public CommonPreferences()
|
||||
{
|
||||
this.showPrefixThis = true;
|
||||
this.mergeEmptyLines = false;
|
||||
this.unicodeEscape = false;
|
||||
|
@ -38,10 +40,8 @@ public class CommonPreferences {
|
|||
this.preferences = new HashMap<>();
|
||||
}
|
||||
|
||||
public CommonPreferences(
|
||||
boolean showDefaultConstructor, boolean realignmentLineNumber,
|
||||
boolean showPrefixThis, boolean mergeEmptyLines,
|
||||
boolean unicodeEscape, boolean showLineNumbers) {
|
||||
public CommonPreferences(boolean showDefaultConstructor, boolean realignmentLineNumber, boolean showPrefixThis, boolean mergeEmptyLines, boolean unicodeEscape, boolean showLineNumbers)
|
||||
{
|
||||
this.showDefaultConstructor = showDefaultConstructor;
|
||||
this.realignmentLineNumber = realignmentLineNumber;
|
||||
this.showPrefixThis = showPrefixThis;
|
||||
|
@ -51,31 +51,38 @@ public class CommonPreferences {
|
|||
this.preferences = new HashMap<>();
|
||||
}
|
||||
|
||||
public boolean isShowDefaultConstructor() {
|
||||
public boolean isShowDefaultConstructor()
|
||||
{
|
||||
return showDefaultConstructor;
|
||||
}
|
||||
|
||||
public boolean isRealignmentLineNumber() {
|
||||
public boolean isRealignmentLineNumber()
|
||||
{
|
||||
return realignmentLineNumber;
|
||||
}
|
||||
|
||||
public boolean isShowPrefixThis() {
|
||||
public boolean isShowPrefixThis()
|
||||
{
|
||||
return showPrefixThis;
|
||||
}
|
||||
|
||||
public boolean isMergeEmptyLines() {
|
||||
public boolean isMergeEmptyLines()
|
||||
{
|
||||
return mergeEmptyLines;
|
||||
}
|
||||
|
||||
public boolean isUnicodeEscape() {
|
||||
public boolean isUnicodeEscape()
|
||||
{
|
||||
return unicodeEscape;
|
||||
}
|
||||
|
||||
public boolean isShowLineNumbers() {
|
||||
public boolean isShowLineNumbers()
|
||||
{
|
||||
return showLineNumbers;
|
||||
}
|
||||
|
||||
public Map<String, Object> getPreferences() {
|
||||
public Map<String, Object> getPreferences()
|
||||
{
|
||||
return preferences;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,20 +18,21 @@
|
|||
|
||||
package the.bytecode.club.bytecodeviewer.decompilers.jdgui;
|
||||
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.jd.core.v1.api.loader.Loader;
|
||||
import org.jd.core.v1.api.loader.LoaderException;
|
||||
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.jd.core.v1.api.loader.Loader;
|
||||
import org.jd.core.v1.api.loader.LoaderException;
|
||||
|
||||
public class DirectoryLoader implements Loader
|
||||
{
|
||||
protected String codebase;
|
||||
protected long lastModified;
|
||||
protected boolean isFile;
|
||||
|
||||
|
||||
public DirectoryLoader(File file) throws LoaderException
|
||||
{
|
||||
this.codebase = file.getAbsolutePath();
|
||||
|
@ -43,21 +44,23 @@ public class DirectoryLoader implements Loader
|
|||
}
|
||||
|
||||
@Override
|
||||
public byte[] load(String internalPath)
|
||||
throws LoaderException {
|
||||
public byte[] load(String internalPath) throws LoaderException
|
||||
{
|
||||
File file = new File(this.codebase, internalPath);
|
||||
|
||||
try (FileInputStream fis = new FileInputStream(file);
|
||||
BufferedInputStream bis = new BufferedInputStream(fis)) {
|
||||
try (FileInputStream fis = new FileInputStream(file); BufferedInputStream bis = new BufferedInputStream(fis))
|
||||
{
|
||||
return IOUtils.toByteArray(bis);
|
||||
} catch (IOException e) {
|
||||
throw new LoaderException(
|
||||
"'" + file.getAbsolutePath() + "' not found.");
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
throw new LoaderException("'" + file.getAbsolutePath() + "' not found.");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canLoad(String internalPath) {
|
||||
public boolean canLoad(String internalPath)
|
||||
{
|
||||
File file = new File(this.codebase, internalPath);
|
||||
return file.exists() && file.isFile();
|
||||
}
|
||||
|
|
|
@ -18,17 +18,14 @@
|
|||
|
||||
package the.bytecode.club.bytecodeviewer.decompilers.jdgui;
|
||||
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.DataInputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import org.jd.core.v1.model.classfile.constant.Constant;
|
||||
import org.jd.core.v1.model.classfile.constant.ConstantClass;
|
||||
import org.jd.core.v1.model.classfile.constant.ConstantUtf8;
|
||||
import org.jd.core.v1.service.deserializer.classfile.ClassFileFormatException;
|
||||
import org.jd.core.v1.service.deserializer.classfile.ClassFileReader;
|
||||
|
||||
import java.io.*;
|
||||
|
||||
|
||||
public class JDGUIClassFileUtil
|
||||
{
|
||||
|
@ -39,14 +36,15 @@ public class JDGUIClassFileUtil
|
|||
* Lecture rapide de la structure de la classe et extraction du nom du
|
||||
* repoertoire de base.
|
||||
*/
|
||||
public static String ExtractDirectoryPath(String pathToClass) {
|
||||
public static String ExtractDirectoryPath(String pathToClass)
|
||||
{
|
||||
String directoryPath;
|
||||
|
||||
try (FileInputStream fis = new FileInputStream(pathToClass);
|
||||
BufferedInputStream bis = new BufferedInputStream(fis);
|
||||
DataInputStream dis = new DataInputStream(bis)) {
|
||||
try (FileInputStream fis = new FileInputStream(pathToClass); BufferedInputStream bis = new BufferedInputStream(fis); DataInputStream dis = new DataInputStream(bis))
|
||||
{
|
||||
int magic = dis.readInt();
|
||||
if (magic != ClassFileReader.JAVA_MAGIC_NUMBER) {
|
||||
if (magic != ClassFileReader.JAVA_MAGIC_NUMBER)
|
||||
{
|
||||
throw new ClassFileFormatException("Invalid Java .class file");
|
||||
}
|
||||
|
||||
|
@ -61,32 +59,36 @@ public class JDGUIClassFileUtil
|
|||
dis.readUnsignedShort();
|
||||
int this_class = dis.readUnsignedShort();
|
||||
|
||||
if (this_class > constants.length) {
|
||||
if (this_class > constants.length)
|
||||
{
|
||||
throw new ClassFileFormatException("Unknown Java structure");
|
||||
}
|
||||
Constant c = constants[this_class];
|
||||
if ((c == null) || (c.getTag() != Constant.CONSTANT_Class)) {
|
||||
if ((c == null) || (c.getTag() != Constant.CONSTANT_Class))
|
||||
{
|
||||
throw new ClassFileFormatException("Invalid constant pool");
|
||||
}
|
||||
|
||||
c = constants[((ConstantClass) c).getNameIndex()];
|
||||
if ((c == null) || (c.getTag() != Constant.CONSTANT_Utf8)) {
|
||||
if ((c == null) || (c.getTag() != Constant.CONSTANT_Utf8))
|
||||
{
|
||||
throw new ClassFileFormatException("Invalid constant pool");
|
||||
}
|
||||
|
||||
String internalClassName = ((ConstantUtf8) c).getValue();
|
||||
String pathSuffix = internalClassName.replace(
|
||||
INTERNAL_PACKAGE_SEPARATOR, File.separatorChar) +
|
||||
CLASS_FILE_SUFFIX;
|
||||
String pathSuffix = internalClassName.replace(INTERNAL_PACKAGE_SEPARATOR, File.separatorChar) + CLASS_FILE_SUFFIX;
|
||||
|
||||
int index = pathToClass.indexOf(pathSuffix);
|
||||
|
||||
if (index < 0) {
|
||||
if (index < 0)
|
||||
{
|
||||
throw new ClassFileFormatException("Invalid internal class name");
|
||||
}
|
||||
|
||||
directoryPath = pathToClass.substring(0, index);
|
||||
} catch (IOException e) {
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
directoryPath = null;
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
@ -94,10 +96,9 @@ public class JDGUIClassFileUtil
|
|||
return directoryPath;
|
||||
}
|
||||
|
||||
public static String ExtractInternalPath(
|
||||
String directoryPath, String pathToClass) {
|
||||
if ((directoryPath == null) || (pathToClass == null) ||
|
||||
!pathToClass.startsWith(directoryPath))
|
||||
public static String ExtractInternalPath(String directoryPath, String pathToClass)
|
||||
{
|
||||
if ((directoryPath == null) || (pathToClass == null) || !pathToClass.startsWith(directoryPath))
|
||||
return null;
|
||||
|
||||
String s = pathToClass.substring(directoryPath.length());
|
||||
|
@ -105,46 +106,48 @@ public class JDGUIClassFileUtil
|
|||
return s.replace(File.separatorChar, INTERNAL_PACKAGE_SEPARATOR);
|
||||
}
|
||||
|
||||
private static Constant[] DeserializeConstants(DataInputStream dis)
|
||||
throws IOException {
|
||||
private static Constant[] DeserializeConstants(DataInputStream dis) throws IOException
|
||||
{
|
||||
int count = dis.readUnsignedShort();
|
||||
Constant[] constants = new Constant[count];
|
||||
|
||||
for (int i = 1; i < count; i++) {
|
||||
for (int i = 1; i < count; i++)
|
||||
{
|
||||
byte tag = dis.readByte();
|
||||
|
||||
switch (tag) {
|
||||
case Constant.CONSTANT_Class:
|
||||
constants[i] = new ConstantClass(dis.readUnsignedShort());
|
||||
break;
|
||||
case Constant.CONSTANT_Utf8:
|
||||
constants[i] = new ConstantUtf8(dis.readUTF());
|
||||
break;
|
||||
case Constant.CONSTANT_Long:
|
||||
case Constant.CONSTANT_Double:
|
||||
dis.read();
|
||||
dis.read();
|
||||
dis.read();
|
||||
dis.read();
|
||||
i++;
|
||||
case Constant.CONSTANT_FieldRef:
|
||||
case Constant.CONSTANT_MethodRef:
|
||||
case Constant.CONSTANT_InterfaceMethodRef:
|
||||
case Constant.CONSTANT_InvokeDynamic:
|
||||
case Constant.CONSTANT_NameAndType:
|
||||
case Constant.CONSTANT_Integer:
|
||||
case Constant.CONSTANT_Float:
|
||||
dis.read();
|
||||
case Constant.CONSTANT_MethodHandle:
|
||||
dis.read();
|
||||
case Constant.CONSTANT_String:
|
||||
case Constant.CONSTANT_MethodType:
|
||||
dis.read();
|
||||
dis.read();
|
||||
break;
|
||||
default:
|
||||
//throw new ClassFormatException("Invalid constant pool entry");
|
||||
return constants;
|
||||
switch (tag)
|
||||
{
|
||||
case Constant.CONSTANT_Class:
|
||||
constants[i] = new ConstantClass(dis.readUnsignedShort());
|
||||
break;
|
||||
case Constant.CONSTANT_Utf8:
|
||||
constants[i] = new ConstantUtf8(dis.readUTF());
|
||||
break;
|
||||
case Constant.CONSTANT_Long:
|
||||
case Constant.CONSTANT_Double:
|
||||
dis.read();
|
||||
dis.read();
|
||||
dis.read();
|
||||
dis.read();
|
||||
i++;
|
||||
case Constant.CONSTANT_FieldRef:
|
||||
case Constant.CONSTANT_MethodRef:
|
||||
case Constant.CONSTANT_InterfaceMethodRef:
|
||||
case Constant.CONSTANT_InvokeDynamic:
|
||||
case Constant.CONSTANT_NameAndType:
|
||||
case Constant.CONSTANT_Integer:
|
||||
case Constant.CONSTANT_Float:
|
||||
dis.read();
|
||||
case Constant.CONSTANT_MethodHandle:
|
||||
dis.read();
|
||||
case Constant.CONSTANT_String:
|
||||
case Constant.CONSTANT_MethodType:
|
||||
dis.read();
|
||||
dis.read();
|
||||
break;
|
||||
default:
|
||||
//throw new ClassFormatException("Invalid constant pool entry");
|
||||
return constants;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -18,11 +18,13 @@
|
|||
|
||||
package the.bytecode.club.bytecodeviewer.decompilers.jdgui;
|
||||
|
||||
import java.io.Closeable;
|
||||
import java.io.PrintStream;
|
||||
import org.jd.core.v1.api.printer.Printer;
|
||||
|
||||
public class PlainTextPrinter implements Printer, Closeable {
|
||||
import java.io.Closeable;
|
||||
import java.io.PrintStream;
|
||||
|
||||
public class PlainTextPrinter implements Printer, Closeable
|
||||
{
|
||||
protected static final String TAB = " ";
|
||||
protected static final String NEWLINE = "\n";
|
||||
|
||||
|
@ -38,8 +40,8 @@ public class PlainTextPrinter implements Printer, Closeable {
|
|||
protected int indentationCount;
|
||||
protected boolean display;
|
||||
|
||||
public PlainTextPrinter(
|
||||
CommonPreferences preferences, PrintStream printStream) {
|
||||
public PlainTextPrinter(CommonPreferences preferences, PrintStream printStream)
|
||||
{
|
||||
this.preferences = preferences;
|
||||
this.printStream = printStream;
|
||||
this.maxLineNumber = 0;
|
||||
|
@ -48,49 +50,57 @@ public class PlainTextPrinter implements Printer, Closeable {
|
|||
this.indentationCount = 0;
|
||||
}
|
||||
|
||||
public int getMajorVersion() {
|
||||
public int getMajorVersion()
|
||||
{
|
||||
return majorVersion;
|
||||
}
|
||||
|
||||
public int getMinorVersion() {
|
||||
public int getMinorVersion()
|
||||
{
|
||||
return minorVersion;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - //
|
||||
|
||||
@Override
|
||||
public void printKeyword(String s) {
|
||||
public void printKeyword(String s)
|
||||
{
|
||||
if (this.display)
|
||||
this.printStream.append(s);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void printDeclaration(int type, String internalTypeName, String name, String descriptor) {
|
||||
public void printDeclaration(int type, String internalTypeName, String name, String descriptor)
|
||||
{
|
||||
this.printStream.append(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void printReference(int type, String internalTypeName, String name, String descriptor,
|
||||
String ownerInternalName) {
|
||||
public void printReference(int type, String internalTypeName, String name, String descriptor, String ownerInternalName)
|
||||
{
|
||||
this.printStream.append(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void start(int maxLineNumber, int majorVersion, int minorVersion) {
|
||||
public void start(int maxLineNumber, int majorVersion, int minorVersion)
|
||||
{
|
||||
this.majorVersion = majorVersion;
|
||||
this.minorVersion = minorVersion;
|
||||
this.indentationCount = 0;
|
||||
this.display = true;
|
||||
|
||||
if (this.preferences.isShowLineNumbers()) {
|
||||
if (this.preferences.isShowLineNumbers())
|
||||
{
|
||||
this.maxLineNumber = maxLineNumber;
|
||||
|
||||
if (maxLineNumber > 0) {
|
||||
if (maxLineNumber > 0)
|
||||
{
|
||||
this.digitCount = 1;
|
||||
StringBuilder unknownLineNumberPrefixBuilder = new StringBuilder(" ");
|
||||
int maximum = 9;
|
||||
|
||||
while (maximum < maxLineNumber) {
|
||||
while (maximum < maxLineNumber)
|
||||
{
|
||||
this.digitCount++;
|
||||
unknownLineNumberPrefixBuilder.append(' ');
|
||||
maximum = maximum * 10 + 9;
|
||||
|
@ -99,12 +109,16 @@ public class PlainTextPrinter implements Printer, Closeable {
|
|||
this.unknownLineNumberPrefix = unknownLineNumberPrefixBuilder.toString();
|
||||
this.lineNumberBeginPrefix = "/* ";
|
||||
this.lineNumberEndPrefix = " */ ";
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
this.unknownLineNumberPrefix = "";
|
||||
this.lineNumberBeginPrefix = "";
|
||||
this.lineNumberEndPrefix = "";
|
||||
}
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
this.maxLineNumber = 0;
|
||||
this.unknownLineNumberPrefix = "";
|
||||
this.lineNumberBeginPrefix = "";
|
||||
|
@ -113,44 +127,55 @@ public class PlainTextPrinter implements Printer, Closeable {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void end() {
|
||||
public void end()
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
public void printText(String s) {
|
||||
public void printText(String s)
|
||||
{
|
||||
if (this.display)
|
||||
printEscape(s);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void printNumericConstant(String s) {
|
||||
public void printNumericConstant(String s)
|
||||
{
|
||||
this.printStream.append(s);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void printStringConstant(String s, String s1) {
|
||||
public void printStringConstant(String s, String s1)
|
||||
{
|
||||
this.printStream.append(s);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void indent() {
|
||||
public void indent()
|
||||
{
|
||||
this.indentationCount++;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unindent() {
|
||||
public void unindent()
|
||||
{
|
||||
if (this.indentationCount > 0)
|
||||
this.indentationCount--;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void startLine(int lineNumber) {
|
||||
if (this.maxLineNumber > 0) {
|
||||
public void startLine(int lineNumber)
|
||||
{
|
||||
if (this.maxLineNumber > 0)
|
||||
{
|
||||
this.printStream.append(this.lineNumberBeginPrefix);
|
||||
|
||||
if (lineNumber == UNKNOWN_LINE_NUMBER) {
|
||||
if (lineNumber == UNKNOWN_LINE_NUMBER)
|
||||
{
|
||||
this.printStream.append(this.unknownLineNumberPrefix);
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
int left = 0;
|
||||
|
||||
left = printDigit(5, lineNumber, 10000, left);
|
||||
|
@ -168,15 +193,20 @@ public class PlainTextPrinter implements Printer, Closeable {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void endLine() {
|
||||
public void endLine()
|
||||
{
|
||||
this.printStream.append(NEWLINE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void extraLine(int count) {
|
||||
if (!this.preferences.isMergeEmptyLines()) {
|
||||
while (count-- > 0) {
|
||||
if (this.maxLineNumber > 0) {
|
||||
public void extraLine(int count)
|
||||
{
|
||||
if (!this.preferences.isMergeEmptyLines())
|
||||
{
|
||||
while (count-- > 0)
|
||||
{
|
||||
if (this.maxLineNumber > 0)
|
||||
{
|
||||
this.printStream.append(this.lineNumberBeginPrefix);
|
||||
this.printStream.append(this.unknownLineNumberPrefix);
|
||||
this.printStream.append(this.lineNumberEndPrefix);
|
||||
|
@ -188,30 +218,40 @@ public class PlainTextPrinter implements Printer, Closeable {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void startMarker(int i) {
|
||||
public void startMarker(int i)
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
public void endMarker(int i) {
|
||||
public void endMarker(int i)
|
||||
{
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - //
|
||||
|
||||
protected void printEscape(String s) {
|
||||
if (this.preferences.isUnicodeEscape()) {
|
||||
protected void printEscape(String s)
|
||||
{
|
||||
if (this.preferences.isUnicodeEscape())
|
||||
{
|
||||
int length = s.length();
|
||||
|
||||
for (int i = 0; i < length; i++) {
|
||||
for (int i = 0; i < length; i++)
|
||||
{
|
||||
char c = s.charAt(i);
|
||||
|
||||
if (c == '\t') {
|
||||
if (c == '\t')
|
||||
{
|
||||
this.printStream.append('\t');
|
||||
} else if (c < 32) {
|
||||
}
|
||||
else if (c < 32)
|
||||
{
|
||||
// Write octal format
|
||||
this.printStream.append("\\0");
|
||||
this.printStream.append((char) ('0' + (c >> 3)));
|
||||
this.printStream.append((char) ('0' + (c & 0x7)));
|
||||
} else if (c > 127) {
|
||||
}
|
||||
else if (c > 127)
|
||||
{
|
||||
// Write octal format
|
||||
this.printStream.append("\\u");
|
||||
|
||||
|
@ -223,20 +263,29 @@ public class PlainTextPrinter implements Printer, Closeable {
|
|||
this.printStream.append((char) ((z <= 9) ? ('0' + z) : (('A' - 10) + z)));
|
||||
z = (c & 0xF);
|
||||
this.printStream.append((char) ((z <= 9) ? ('0' + z) : (('A' - 10) + z)));
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
this.printStream.append(c);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
this.printStream.append(s);
|
||||
}
|
||||
}
|
||||
|
||||
protected int printDigit(int dcv, int lineNumber, int divisor, int left) {
|
||||
if (this.digitCount >= dcv) {
|
||||
if (lineNumber < divisor) {
|
||||
protected int printDigit(int dcv, int lineNumber, int divisor, int left)
|
||||
{
|
||||
if (this.digitCount >= dcv)
|
||||
{
|
||||
if (lineNumber < divisor)
|
||||
{
|
||||
this.printStream.append(' ');
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
int e = (lineNumber - left) / divisor;
|
||||
this.printStream.append((char) ('0' + e));
|
||||
left += e * divisor;
|
||||
|
@ -247,7 +296,8 @@ public class PlainTextPrinter implements Printer, Closeable {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
public void close()
|
||||
{
|
||||
if (this.printStream != null)
|
||||
this.printStream.close();
|
||||
}
|
||||
|
|
|
@ -18,25 +18,11 @@
|
|||
|
||||
package the.bytecode.club.bytecodeviewer.gui;
|
||||
|
||||
import java.awt.*;
|
||||
import java.io.File;
|
||||
import java.util.*;
|
||||
import java.util.List;
|
||||
import javax.swing.*;
|
||||
import javax.swing.event.ChangeEvent;
|
||||
import javax.swing.event.ChangeListener;
|
||||
|
||||
import the.bytecode.club.bytecodeviewer.BytecodeViewer;
|
||||
import the.bytecode.club.bytecodeviewer.Configuration;
|
||||
import the.bytecode.club.bytecodeviewer.Constants;
|
||||
import the.bytecode.club.bytecodeviewer.SettingsSerializer;
|
||||
import the.bytecode.club.bytecodeviewer.gui.components.AboutWindow;
|
||||
import the.bytecode.club.bytecodeviewer.gui.components.FileChooser;
|
||||
import the.bytecode.club.bytecodeviewer.gui.components.MultipleChoiceDialog;
|
||||
import the.bytecode.club.bytecodeviewer.gui.components.RunOptions;
|
||||
import the.bytecode.club.bytecodeviewer.gui.components.SettingsDialog;
|
||||
import the.bytecode.club.bytecodeviewer.gui.components.VisibleComponent;
|
||||
import the.bytecode.club.bytecodeviewer.gui.components.WaitBusyIcon;
|
||||
import the.bytecode.club.bytecodeviewer.gui.components.*;
|
||||
import the.bytecode.club.bytecodeviewer.gui.plugins.MaliciousCodeScannerOptions;
|
||||
import the.bytecode.club.bytecodeviewer.gui.plugins.ReplaceStringsOptions;
|
||||
import the.bytecode.club.bytecodeviewer.gui.resourcelist.ResourceListPane;
|
||||
|
@ -52,16 +38,7 @@ import the.bytecode.club.bytecodeviewer.obfuscators.rename.RenameFields;
|
|||
import the.bytecode.club.bytecodeviewer.obfuscators.rename.RenameMethods;
|
||||
import the.bytecode.club.bytecodeviewer.plugin.PluginManager;
|
||||
import the.bytecode.club.bytecodeviewer.plugin.PluginTemplate;
|
||||
import the.bytecode.club.bytecodeviewer.plugin.preinstalled.AllatoriStringDecrypter;
|
||||
import the.bytecode.club.bytecodeviewer.plugin.preinstalled.ChangeClassFileVersions;
|
||||
import the.bytecode.club.bytecodeviewer.plugin.preinstalled.CodeSequenceDiagram;
|
||||
import the.bytecode.club.bytecodeviewer.plugin.preinstalled.ShowAllStrings;
|
||||
import the.bytecode.club.bytecodeviewer.plugin.preinstalled.ShowMainMethods;
|
||||
import the.bytecode.club.bytecodeviewer.plugin.preinstalled.StackFramesRemover;
|
||||
import the.bytecode.club.bytecodeviewer.plugin.preinstalled.ViewAPKAndroidPermissions;
|
||||
import the.bytecode.club.bytecodeviewer.plugin.preinstalled.ViewManifest;
|
||||
import the.bytecode.club.bytecodeviewer.plugin.preinstalled.ZKMStringDecrypter;
|
||||
import the.bytecode.club.bytecodeviewer.plugin.preinstalled.ZStringArrayDecrypter;
|
||||
import the.bytecode.club.bytecodeviewer.plugin.preinstalled.*;
|
||||
import the.bytecode.club.bytecodeviewer.resources.ExternalResources;
|
||||
import the.bytecode.club.bytecodeviewer.resources.IconResources;
|
||||
import the.bytecode.club.bytecodeviewer.resources.ResourceContainer;
|
||||
|
@ -74,12 +51,15 @@ import the.bytecode.club.bytecodeviewer.translation.components.TranslatedJCheckB
|
|||
import the.bytecode.club.bytecodeviewer.translation.components.TranslatedJMenu;
|
||||
import the.bytecode.club.bytecodeviewer.translation.components.TranslatedJMenuItem;
|
||||
import the.bytecode.club.bytecodeviewer.translation.components.TranslatedJRadioButtonMenuItem;
|
||||
import the.bytecode.club.bytecodeviewer.util.DialogUtils;
|
||||
import the.bytecode.club.bytecodeviewer.util.KeyEventDispatch;
|
||||
import the.bytecode.club.bytecodeviewer.util.LazyNameUtil;
|
||||
import the.bytecode.club.bytecodeviewer.util.MiscUtils;
|
||||
import the.bytecode.club.bytecodeviewer.util.WindowClosingAdapter;
|
||||
import the.bytecode.club.bytecodeviewer.util.WindowStateChangeAdapter;
|
||||
import the.bytecode.club.bytecodeviewer.util.*;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.awt.*;
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import static the.bytecode.club.bytecodeviewer.Configuration.useNewSettingsDialog;
|
||||
import static the.bytecode.club.bytecodeviewer.Constants.VERSION;
|
||||
|
@ -94,7 +74,7 @@ public class MainViewerGUI extends JFrame
|
|||
{
|
||||
public boolean isMaximized;
|
||||
public final List<JMenuItem> waitIcons = new ArrayList<>();
|
||||
|
||||
|
||||
//main UI components
|
||||
public final List<VisibleComponent> uiComponents = new ArrayList<>();
|
||||
public final Workspace workPane = new Workspace();
|
||||
|
@ -105,7 +85,7 @@ public class MainViewerGUI extends JFrame
|
|||
|
||||
//the root menu bar
|
||||
public final JMenuBar rootMenu = new JMenuBar();
|
||||
|
||||
|
||||
//all of the files main menu components
|
||||
public final JMenu fileMainMenu = new TranslatedJMenu("File", TranslatedComponents.FILE);
|
||||
public final JMenuItem addResource = new TranslatedJMenuItem("Add...", TranslatedComponents.ADD);
|
||||
|
@ -122,13 +102,13 @@ public class MainViewerGUI extends JFrame
|
|||
public final JMenu recentFilesSecondaryMenu = new TranslatedJMenu("Recent Files", TranslatedComponents.RECENT_FILES);
|
||||
public final JMenuItem about = new TranslatedJMenuItem("About", TranslatedComponents.ABOUT);
|
||||
public final JMenuItem exit = new TranslatedJMenuItem("Exit", TranslatedComponents.EXIT);
|
||||
|
||||
|
||||
//all of the view main menu components
|
||||
public final JMenu viewMainMenu = new TranslatedJMenu("View", TranslatedComponents.VIEW);
|
||||
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 TranslatedJMenu("Plugins", TranslatedComponents.PLUGINS);
|
||||
public final JMenuItem openExternalPlugin = new TranslatedJMenuItem("Open Plugin...", TranslatedComponents.OPEN_PLUGIN);
|
||||
|
@ -147,7 +127,7 @@ public class MainViewerGUI extends JFrame
|
|||
public final JMenuItem viewAPKAndroidPermissions = new TranslatedJMenuItem("View Android Permissions", TranslatedComponents.VIEW_ANDROID_PERMISSIONS);
|
||||
public final JMenuItem viewManifest = new TranslatedJMenuItem("View Manifest", TranslatedComponents.VIEW_MANIFEST);
|
||||
public final JMenuItem changeClassFileVersions = new TranslatedJMenuItem("Change ClassFile Versions", TranslatedComponents.CHANGE_CLASSFILE_VERSIONS);
|
||||
|
||||
|
||||
//all of the settings main menu components
|
||||
public final JMenu rstaTheme = new TranslatedJMenu("Text Area Theme", TranslatedComponents.TEXT_AREA_THEME);
|
||||
public final JMenuItem rstaThemeSettings = new TranslatedJMenuItem("Text Area Theme", TranslatedComponents.TEXT_AREA_THEME);
|
||||
|
@ -163,7 +143,7 @@ public class MainViewerGUI extends JFrame
|
|||
public final Map<RSTATheme, JRadioButtonMenuItem> rstaThemes = new HashMap<>();
|
||||
public final Map<LAFTheme, JRadioButtonMenuItem> lafThemes = new HashMap<>();
|
||||
public final Map<Language, JRadioButtonMenuItem> languages = new HashMap<>();
|
||||
|
||||
|
||||
//BCV settings
|
||||
public final JCheckBoxMenuItem refreshOnChange = new TranslatedJCheckBoxMenuItem("Refresh On View Change", TranslatedComponents.REFRESH_ON_VIEW_CHANGE);
|
||||
private final JCheckBoxMenuItem deleteForeignOutdatedLibs = new TranslatedJCheckBoxMenuItem("Delete Foreign/Outdated Libs", TranslatedComponents.DELETE_UNKNOWN_LIBS);
|
||||
|
@ -183,7 +163,7 @@ public class MainViewerGUI extends JFrame
|
|||
public final JCheckBoxMenuItem decodeAPKResources = new TranslatedJCheckBoxMenuItem("Decode APK Resources", TranslatedComponents.DECODE_APK_RESOURCES);
|
||||
public final JCheckBoxMenuItem synchronizedViewing = new TranslatedJCheckBoxMenuItem("Synchronized Viewing", TranslatedComponents.SYNCHRONIZED_VIEWING);
|
||||
public final JCheckBoxMenuItem showClassMethods = new TranslatedJCheckBoxMenuItem("Show Class Methods", TranslatedComponents.SHOW_CLASS_METHODS);
|
||||
|
||||
|
||||
//apk conversion settings
|
||||
public final JMenu apkConversionSecondaryMenu = new TranslatedJMenu("APK Conversion/Decoding", TranslatedComponents.APK_CONVERSION_DECODING);
|
||||
public final JMenuItem apkConversionSettings = new TranslatedJMenuItem("APK Conversion/Decoding", TranslatedComponents.APK_CONVERSION_DECODING);
|
||||
|
@ -191,7 +171,7 @@ public class MainViewerGUI extends JFrame
|
|||
public final ButtonGroup apkConversionGroup = new ButtonGroup();
|
||||
public final JRadioButtonMenuItem apkConversionDex = new JRadioButtonMenuItem("Dex2Jar");
|
||||
public final JRadioButtonMenuItem apkConversionEnjarify = new JRadioButtonMenuItem("Enjarify");
|
||||
|
||||
|
||||
//CFIDE settings
|
||||
public final JMenu bytecodeDecompilerSettingsSecondaryMenu = new TranslatedJMenu("Bytecode Decompiler", TranslatedComponents.BYTECODE_DECOMPILER);
|
||||
public final JMenuItem bytecodeDecompilerSettings = new TranslatedJMenuItem("Bytecode Decompiler", TranslatedComponents.BYTECODE_DECOMPILER);
|
||||
|
@ -199,7 +179,7 @@ public class MainViewerGUI extends JFrame
|
|||
public final JCheckBoxMenuItem appendBracketsToLabels = new TranslatedJCheckBoxMenuItem("Append Brackets To Labels", TranslatedComponents.APPEND_BRACKETS_TO_LABEL);
|
||||
public JCheckBoxMenuItem debugHelpers = new TranslatedJCheckBoxMenuItem("Debug Helpers", TranslatedComponents.DEBUG_HELPERS);
|
||||
public final JCheckBoxMenuItem printLineNumbers = new TranslatedJCheckBoxMenuItem("Print Line Numbers", TranslatedComponents.PRINT_LINE_NUMBERS);
|
||||
|
||||
|
||||
//FernFlower settings
|
||||
public final JMenu fernFlowerSettingsSecondaryMenu = new TranslatedJMenu("FernFlower Settings", TranslatedComponents.FERNFLOWER_SETTINGS);
|
||||
public final JMenuItem fernFlowerSettings = new TranslatedJMenuItem("FernFlower Settings", TranslatedComponents.FERNFLOWER_SETTINGS);
|
||||
|
@ -223,7 +203,7 @@ public class MainViewerGUI extends JFrame
|
|||
public TranslatedJCheckBoxMenuItem fdi = new TranslatedJCheckBoxMenuItem("Deinline finally structures", TranslatedComponents.DEINLINE_FINALLY_STRUCTURES);
|
||||
public TranslatedJCheckBoxMenuItem asc = new TranslatedJCheckBoxMenuItem("Allow only ASCII characters in strings", TranslatedComponents.ALLOW_ONLY_ASCII_CHARACTERS_IN_STRINGS);
|
||||
public TranslatedJCheckBoxMenuItem ren = new TranslatedJCheckBoxMenuItem("Rename ambiguous classes and class elements", TranslatedComponents.RENAME_AMBIGUOUS_CLASSES_AND_CLASS_ELEMENTS);
|
||||
|
||||
|
||||
//Procyon
|
||||
public final JMenu procyonSettingsSecondaryMenu = new TranslatedJMenu("Procyon Settings", TranslatedComponents.PROCYON_SETTINGS);
|
||||
public final JMenuItem procyonSettings = new TranslatedJMenuItem("Procyon Settings", TranslatedComponents.PROCYON_SETTINGS);
|
||||
|
@ -242,7 +222,7 @@ public class MainViewerGUI extends JFrame
|
|||
public final JCheckBoxMenuItem retainPointlessSwitches = new TranslatedJCheckBoxMenuItem("Retain Pointless Switches", TranslatedComponents.RETAIN_POINTLESS_SWITCHES);
|
||||
public final JCheckBoxMenuItem retainRedunantCasts = new TranslatedJCheckBoxMenuItem("Retain Redundant Casts", TranslatedComponents.RETAIN_REDUNDANT_CASTS);
|
||||
public final JCheckBoxMenuItem unicodeOutputEnabled = new TranslatedJCheckBoxMenuItem("Unicode Output Enabled", TranslatedComponents.UNICODE_OUTPUT_ENABLED);
|
||||
|
||||
|
||||
//CFR
|
||||
public final JMenu cfrSettingsSecondaryMenu = new TranslatedJMenu("CFR Settings", TranslatedComponents.CFR_SETTINGS);
|
||||
public final JMenuItem cfrSettings = new TranslatedJMenuItem("CFR Settings", TranslatedComponents.CFR_SETTINGS);
|
||||
|
@ -312,7 +292,7 @@ public class MainViewerGUI extends JFrame
|
|||
{
|
||||
setIconImages(IconResources.iconList);
|
||||
setSize(new Dimension(800, 488));
|
||||
|
||||
|
||||
setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
|
||||
KeyboardFocusManager.getCurrentKeyboardFocusManager().addKeyEventDispatcher(new KeyEventDispatch());
|
||||
addWindowStateListener(new WindowStateChangeAdapter(this));
|
||||
|
@ -325,7 +305,7 @@ public class MainViewerGUI extends JFrame
|
|||
buildPluginMenu();
|
||||
buildObfuscateMenu();
|
||||
defaultSettings();
|
||||
|
||||
|
||||
setTitle("Bytecode Viewer " + VERSION + " - https://bytecodeviewer.com | https://the.bytecode.club - @Konloch");
|
||||
|
||||
getContentPane().setLayout(new BoxLayout(getContentPane(), BoxLayout.X_AXIS));
|
||||
|
@ -333,7 +313,7 @@ public class MainViewerGUI extends JFrame
|
|||
resourcePane.setMinimumSize(new Dimension(200, 50));
|
||||
resourcePane.setPreferredSize(new Dimension(200, 50));
|
||||
resourcePane.setMaximumSize(new Dimension(200, 2147483647));
|
||||
|
||||
|
||||
searchBoxPane.setPreferredSize(new Dimension(200, 50));
|
||||
searchBoxPane.setMinimumSize(new Dimension(200, 50));
|
||||
searchBoxPane.setMaximumSize(new Dimension(200, 2147483647));
|
||||
|
@ -346,7 +326,7 @@ public class MainViewerGUI extends JFrame
|
|||
getContentPane().add(splitPane2);
|
||||
splitPane2.setResizeWeight(0.05);
|
||||
splitPane1.setResizeWeight(0.5);
|
||||
|
||||
|
||||
uiComponents.add(resourcePane);
|
||||
uiComponents.add(searchBoxPane);
|
||||
uiComponents.add(workPane);
|
||||
|
@ -357,12 +337,12 @@ public class MainViewerGUI extends JFrame
|
|||
|
||||
this.setLocationRelativeTo(null);
|
||||
}
|
||||
|
||||
|
||||
public void buildMenuBar()
|
||||
{
|
||||
setJMenuBar(rootMenu);
|
||||
}
|
||||
|
||||
|
||||
public void buildFileMenu()
|
||||
{
|
||||
rootMenu.add(fileMainMenu);
|
||||
|
@ -386,9 +366,9 @@ public class MainViewerGUI extends JFrame
|
|||
fileMainMenu.add(new JSeparator());
|
||||
fileMainMenu.add(about);
|
||||
fileMainMenu.add(exit);
|
||||
|
||||
|
||||
saveAsZip.setActionCommand("");
|
||||
|
||||
|
||||
addResource.addActionListener(e -> selectFile());
|
||||
newWorkSpace.addActionListener(e -> BytecodeViewer.resetWorkspace(true));
|
||||
reloadResources.addActionListener(arg0 -> reloadResources());
|
||||
|
@ -403,7 +383,7 @@ public class MainViewerGUI extends JFrame
|
|||
about.addActionListener(arg0 -> new AboutWindow().setVisible(true));
|
||||
exit.addActionListener(arg0 -> askBeforeExiting());
|
||||
}
|
||||
|
||||
|
||||
public void buildViewMenu()
|
||||
{
|
||||
rootMenu.add(viewMainMenu);
|
||||
|
@ -412,17 +392,17 @@ public class MainViewerGUI extends JFrame
|
|||
viewMainMenu.add(viewPane2.getMenu());
|
||||
viewMainMenu.add(viewPane3.getMenu());
|
||||
}
|
||||
|
||||
|
||||
public void buildSettingsMenu()
|
||||
{
|
||||
rootMenu.add(settingsMainMenu);
|
||||
|
||||
|
||||
//settingsMainMenu.add(visualSettings);
|
||||
//settingsMainMenu.add(new JSeparator());
|
||||
settingsMainMenu.add(compileOnSave);
|
||||
settingsMainMenu.add(autoCompileOnRefresh);
|
||||
settingsMainMenu.add(refreshOnChange);
|
||||
|
||||
|
||||
settingsMainMenu.add(new JSeparator());
|
||||
settingsMainMenu.add(updateCheck);
|
||||
settingsMainMenu.add(forcePureAsciiAsText);
|
||||
|
@ -433,39 +413,41 @@ public class MainViewerGUI extends JFrame
|
|||
settingsMainMenu.add(setOptionalLibrary);
|
||||
settingsMainMenu.add(setJavac);
|
||||
settingsMainMenu.add(new JSeparator());
|
||||
|
||||
|
||||
//TODO the dialog below works but for 3 options,
|
||||
// it might be better to leave it as a secondary menu
|
||||
settingsMainMenu.add(apkConversionSecondaryMenu);
|
||||
//settingsMainMenu.add(useNewSettingsDialog ? apkConversionSettings : apkConversionMenu);
|
||||
|
||||
|
||||
//Smali minSdkVersion
|
||||
minSdkVersionSpinner.setPreferredSize(new Dimension(60, 24));
|
||||
minSdkVersionSpinner.setMinimumSize(new Dimension(60, 24));
|
||||
minSdkVersionSpinner.setModel(new SpinnerNumberModel(26, 1, null, 1));
|
||||
minSdkVersionMenu.add(minSdkVersionSpinner);
|
||||
settingsMainMenu.add(minSdkVersionMenu);
|
||||
|
||||
|
||||
settingsMainMenu.add(new JSeparator());
|
||||
|
||||
|
||||
fontSpinner.setPreferredSize(new Dimension(60, 24));
|
||||
fontSpinner.setMinimumSize(new Dimension(60, 24));
|
||||
fontSpinner.setModel(new SpinnerNumberModel(12, 1, null, 1));
|
||||
fontSpinner.addChangeListener(e -> {
|
||||
JSpinner spinner = (JSpinner) e.getSource();
|
||||
Font font = UIManager.getFont("defaultFont");
|
||||
if (font == null) {
|
||||
font = UIManager.getFont("Label.font");
|
||||
}
|
||||
fontSpinner.addChangeListener(e ->
|
||||
{
|
||||
JSpinner spinner = (JSpinner) e.getSource();
|
||||
Font font = UIManager.getFont("defaultFont");
|
||||
if (font == null)
|
||||
{
|
||||
font = UIManager.getFont("Label.font");
|
||||
}
|
||||
|
||||
font = font.deriveFont((float) (int) spinner.getValue());
|
||||
font = font.deriveFont((float) (int) spinner.getValue());
|
||||
|
||||
BytecodeViewer.updateAllFonts(font);
|
||||
BytecodeViewer.updateUI();
|
||||
BytecodeViewer.updateAllFonts(font);
|
||||
BytecodeViewer.updateUI();
|
||||
BytecodeViewer.refreshAllTabs();
|
||||
});
|
||||
});
|
||||
fontSize.add(fontSpinner);
|
||||
|
||||
|
||||
apkConversionSecondaryMenu.add(decodeAPKResources);
|
||||
apkConversionSecondaryMenu.add(apkConversionDex);
|
||||
apkConversionSecondaryMenu.add(apkConversionEnjarify);
|
||||
|
@ -473,17 +455,17 @@ public class MainViewerGUI extends JFrame
|
|||
apkConversionGroup.add(apkConversionEnjarify);
|
||||
apkConversionGroup.setSelected(apkConversionDex.getModel(), true);
|
||||
//apkConversionSettingsDialog = new SettingsDialogue(apkConversionSecondaryMenu, new JPanel());
|
||||
apkConversionSettings.addActionListener((e)-> apkConversionSettingsDialog.showDialog());
|
||||
|
||||
apkConversionSettings.addActionListener((e) -> apkConversionSettingsDialog.showDialog());
|
||||
|
||||
ButtonGroup rstaGroup = new ButtonGroup();
|
||||
for (RSTATheme t : RSTATheme.values())
|
||||
{
|
||||
JRadioButtonMenuItem item = new TranslatedJRadioButtonMenuItem(t.getReadableName(), t.getTranslation());
|
||||
if (Configuration.rstaTheme.equals(t))
|
||||
item.setSelected(true);
|
||||
|
||||
|
||||
rstaGroup.add(item);
|
||||
|
||||
|
||||
item.addActionListener(e ->
|
||||
{
|
||||
Configuration.rstaTheme = t;
|
||||
|
@ -491,23 +473,23 @@ public class MainViewerGUI extends JFrame
|
|||
SettingsSerializer.saveSettingsAsync();
|
||||
updateTabTheme();
|
||||
});
|
||||
|
||||
|
||||
rstaThemes.put(t, item);
|
||||
rstaTheme.add(item);
|
||||
}
|
||||
|
||||
|
||||
rstaThemeSettingsDialog = new SettingsDialog(rstaTheme, new JPanel());
|
||||
rstaThemeSettings.addActionListener((e)-> rstaThemeSettingsDialog.showDialog());
|
||||
|
||||
rstaThemeSettings.addActionListener((e) -> rstaThemeSettingsDialog.showDialog());
|
||||
|
||||
ButtonGroup lafGroup = new ButtonGroup();
|
||||
for (LAFTheme theme : LAFTheme.values())
|
||||
{
|
||||
JRadioButtonMenuItem item = new TranslatedJRadioButtonMenuItem(theme.getReadableName(), theme.getTranslation());
|
||||
if (Configuration.lafTheme.equals(theme))
|
||||
item.setSelected(true);
|
||||
|
||||
|
||||
lafGroup.add(item);
|
||||
|
||||
|
||||
item.addActionListener(e ->
|
||||
{
|
||||
Configuration.lafTheme = theme;
|
||||
|
@ -515,7 +497,7 @@ public class MainViewerGUI extends JFrame
|
|||
rstaThemes.get(Configuration.rstaTheme).setSelected(true);
|
||||
item.setSelected(true);
|
||||
SettingsSerializer.saveSettingsAsync();
|
||||
|
||||
|
||||
try
|
||||
{
|
||||
theme.setLAF();
|
||||
|
@ -526,36 +508,36 @@ public class MainViewerGUI extends JFrame
|
|||
ex.printStackTrace();
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
lafThemes.put(theme, item);
|
||||
lafTheme.add(item);
|
||||
}
|
||||
|
||||
|
||||
lafThemeSettingsDialog = new SettingsDialog(lafTheme, new JPanel());
|
||||
lafThemeSettings.addActionListener((e)-> lafThemeSettingsDialog.showDialog());
|
||||
|
||||
lafThemeSettings.addActionListener((e) -> lafThemeSettingsDialog.showDialog());
|
||||
|
||||
ButtonGroup languageGroup = new ButtonGroup();
|
||||
for (Language l : Language.values())
|
||||
{
|
||||
JRadioButtonMenuItem item = new JRadioButtonMenuItem(l.getReadableName());
|
||||
if (Configuration.language.equals(l))
|
||||
item.setSelected(true);
|
||||
|
||||
|
||||
languageGroup.add(item);
|
||||
|
||||
|
||||
item.addActionListener(e ->
|
||||
{
|
||||
SettingsSerializer.saveSettingsAsync();
|
||||
MiscUtils.setLanguage(l);
|
||||
});
|
||||
|
||||
|
||||
languages.put(l, item);
|
||||
language.add(item);
|
||||
}
|
||||
|
||||
|
||||
languageSettingsDialog = new SettingsDialog(language, new JPanel());
|
||||
languageSettings.addActionListener((e)-> languageSettingsDialog.showDialog());
|
||||
|
||||
languageSettings.addActionListener((e) -> languageSettingsDialog.showDialog());
|
||||
|
||||
visualSettings.add(useNewSettingsDialog ? lafThemeSettings : lafTheme);
|
||||
visualSettings.add(useNewSettingsDialog ? rstaThemeSettings : rstaTheme);
|
||||
visualSettings.add(useNewSettingsDialog ? languageSettings : language);
|
||||
|
@ -564,7 +546,7 @@ public class MainViewerGUI extends JFrame
|
|||
visualSettings.add(simplifyNameInTabTitle);
|
||||
visualSettings.add(synchronizedViewing);
|
||||
visualSettings.add(showClassMethods);
|
||||
|
||||
|
||||
//PROCYON SETTINGS
|
||||
settingsMainMenu.add(useNewSettingsDialog ? procyonSettings : procyonSettingsSecondaryMenu);
|
||||
procyonSettingsSecondaryMenu.add(alwaysGenerateExceptionVars);
|
||||
|
@ -582,8 +564,8 @@ public class MainViewerGUI extends JFrame
|
|||
procyonSettingsSecondaryMenu.add(retainRedunantCasts);
|
||||
procyonSettingsSecondaryMenu.add(unicodeOutputEnabled);
|
||||
procyonSettingsDialog = new SettingsDialog(procyonSettingsSecondaryMenu, new JPanel());
|
||||
procyonSettings.addActionListener((e)-> procyonSettingsDialog.showDialog());
|
||||
|
||||
procyonSettings.addActionListener((e) -> procyonSettingsDialog.showDialog());
|
||||
|
||||
//CFR SETTINGS
|
||||
settingsMainMenu.add(useNewSettingsDialog ? cfrSettings : cfrSettingsSecondaryMenu);
|
||||
cfrSettingsSecondaryMenu.add(decodeEnumSwitch);
|
||||
|
@ -631,8 +613,8 @@ public class MainViewerGUI extends JFrame
|
|||
cfrSettingsSecondaryMenu.add(forceTurningIFs);
|
||||
cfrSettingsSecondaryMenu.add(forLoopAGGCapture);
|
||||
cfrSettingsDialog = new SettingsDialog(cfrSettingsSecondaryMenu, new JPanel());
|
||||
cfrSettings.addActionListener((e)-> cfrSettingsDialog.showDialog());
|
||||
|
||||
cfrSettings.addActionListener((e) -> cfrSettingsDialog.showDialog());
|
||||
|
||||
//FERNFLOWER SETTINGS
|
||||
settingsMainMenu.add(useNewSettingsDialog ? fernFlowerSettings : fernFlowerSettingsSecondaryMenu);
|
||||
fernFlowerSettingsSecondaryMenu.add(ren);
|
||||
|
@ -655,16 +637,16 @@ public class MainViewerGUI extends JFrame
|
|||
fernFlowerSettingsSecondaryMenu.add(fdi);
|
||||
fernFlowerSettingsSecondaryMenu.add(asc);
|
||||
fernFlowerSettingsDialog = new SettingsDialog(fernFlowerSettingsSecondaryMenu, new JPanel());
|
||||
fernFlowerSettings.addActionListener((e)-> fernFlowerSettingsDialog.showDialog());
|
||||
|
||||
fernFlowerSettings.addActionListener((e) -> fernFlowerSettingsDialog.showDialog());
|
||||
|
||||
//CFIDE SETTINGS
|
||||
settingsMainMenu.add(useNewSettingsDialog ? bytecodeDecompilerSettings : bytecodeDecompilerSettingsSecondaryMenu);
|
||||
bytecodeDecompilerSettingsSecondaryMenu.add(debugHelpers);
|
||||
bytecodeDecompilerSettingsSecondaryMenu.add(appendBracketsToLabels);
|
||||
bytecodeDecompilerSettingsSecondaryMenu.add(printLineNumbers);
|
||||
bytecodeDecompilerSettingsDialog = new SettingsDialog(bytecodeDecompilerSettingsSecondaryMenu, new JPanel());
|
||||
bytecodeDecompilerSettings.addActionListener((e)-> bytecodeDecompilerSettingsDialog.showDialog());
|
||||
|
||||
bytecodeDecompilerSettings.addActionListener((e) -> bytecodeDecompilerSettingsDialog.showDialog());
|
||||
|
||||
deleteForeignOutdatedLibs.addActionListener(arg0 -> showForeignLibraryWarning());
|
||||
forcePureAsciiAsText.addActionListener(arg0 -> SettingsSerializer.saveSettingsAsync());
|
||||
setPython2.addActionListener(arg0 -> ExternalResources.getSingleton().selectPython2());
|
||||
|
@ -672,18 +654,20 @@ public class MainViewerGUI extends JFrame
|
|||
setPython3.addActionListener(arg0 -> ExternalResources.getSingleton().selectPython3());
|
||||
setOptionalLibrary.addActionListener(arg0 -> ExternalResources.getSingleton().selectOptionalLibraryFolder());
|
||||
setJavac.addActionListener(arg0 -> ExternalResources.getSingleton().selectJavac());
|
||||
showFileInTabTitle.addActionListener(arg0 -> {
|
||||
showFileInTabTitle.addActionListener(arg0 ->
|
||||
{
|
||||
Configuration.displayParentInTab = BytecodeViewer.viewer.showFileInTabTitle.isSelected();
|
||||
SettingsSerializer.saveSettingsAsync();
|
||||
BytecodeViewer.refreshAllTabTitles();
|
||||
});
|
||||
simplifyNameInTabTitle.addActionListener(arg0 -> {
|
||||
simplifyNameInTabTitle.addActionListener(arg0 ->
|
||||
{
|
||||
Configuration.simplifiedTabNames = BytecodeViewer.viewer.simplifyNameInTabTitle.isSelected();
|
||||
SettingsSerializer.saveSettingsAsync();
|
||||
BytecodeViewer.refreshAllTabTitles();
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
public void buildPluginMenu()
|
||||
{
|
||||
rootMenu.add(pluginsMainMenu);
|
||||
|
@ -704,13 +688,13 @@ public class MainViewerGUI extends JFrame
|
|||
pluginsMainMenu.add(replaceStrings);
|
||||
pluginsMainMenu.add(stackFramesRemover);
|
||||
pluginsMainMenu.add(changeClassFileVersions);
|
||||
|
||||
|
||||
//allatori is disabled since they are just placeholders
|
||||
//ZKM and ZStringArray decrypter are disabled until deobfuscation has been extended
|
||||
//mnNewMenu_1.add(mntmNewMenuItem_2);
|
||||
//mnNewMenu_1.add(mntmStartZkmString);
|
||||
//pluginsMainMenu.add(zStringArrayDecrypter);
|
||||
|
||||
|
||||
openExternalPlugin.addActionListener(arg0 -> openExternalPlugin());
|
||||
newJavaPlugin.addActionListener(arg0 -> PluginTemplate.JAVA.openEditorExceptionHandled());
|
||||
newJavascriptPlugin.addActionListener(arg0 -> PluginTemplate.JAVASCRIPT.openEditorExceptionHandled());
|
||||
|
@ -727,12 +711,12 @@ public class MainViewerGUI extends JFrame
|
|||
viewManifest.addActionListener(arg0 -> PluginManager.runPlugin(new ViewManifest()));
|
||||
changeClassFileVersions.addActionListener(arg0 -> PluginManager.runPlugin(new ChangeClassFileVersions()));
|
||||
}
|
||||
|
||||
|
||||
public void buildObfuscateMenu()
|
||||
{
|
||||
//hide obfuscation menu since it's currently not being used
|
||||
obfuscate.setVisible(false);
|
||||
|
||||
|
||||
rootMenu.add(obfuscate);
|
||||
obfuscate.add(strongObf);
|
||||
obfuscate.add(lightObf);
|
||||
|
@ -743,16 +727,16 @@ public class MainViewerGUI extends JFrame
|
|||
obfuscate.add(renameClasses);
|
||||
obfuscate.add(controlFlow);
|
||||
obfuscate.add(junkCode);
|
||||
|
||||
|
||||
obfuscatorGroup.add(strongObf);
|
||||
obfuscatorGroup.add(lightObf);
|
||||
obfuscatorGroup.setSelected(strongObf.getModel(), true);
|
||||
|
||||
|
||||
renameFields.addActionListener(arg0 -> RenameFields.open());
|
||||
renameClasses.addActionListener(arg0 -> RenameClasses.open());
|
||||
renameMethods.addActionListener(arg0 -> RenameMethods.open());
|
||||
}
|
||||
|
||||
|
||||
public void defaultSettings()
|
||||
{
|
||||
compileOnSave.setSelected(false);
|
||||
|
@ -761,16 +745,16 @@ public class MainViewerGUI extends JFrame
|
|||
updateCheck.setSelected(true);
|
||||
forcePureAsciiAsText.setSelected(true);
|
||||
showSyntheticMembers.setSelected(true);
|
||||
|
||||
|
||||
showFileInTabTitle.setSelected(false);
|
||||
showClassMethods.setSelected(false);
|
||||
|
||||
|
||||
simplifyNameInTabTitle.setEnabled(true);
|
||||
|
||||
|
||||
moveAllClassesIntoRoot.setEnabled(false);
|
||||
controlFlow.setEnabled(false);
|
||||
junkCode.setEnabled(false);
|
||||
|
||||
|
||||
// cfr
|
||||
decodeEnumSwitch.setSelected(true);
|
||||
sugarEnums.setSelected(true);
|
||||
|
@ -816,7 +800,7 @@ public class MainViewerGUI extends JFrame
|
|||
recoveryTypehInts.setSelected(true);
|
||||
forceTurningIFs.setSelected(true);
|
||||
forLoopAGGCapture.setSelected(true);
|
||||
|
||||
|
||||
// fernflower
|
||||
rbr.setSelected(true);
|
||||
rsy.setSelected(false);
|
||||
|
@ -837,17 +821,18 @@ public class MainViewerGUI extends JFrame
|
|||
rer.setSelected(true);
|
||||
hes.setSelected(true);
|
||||
hdc.setSelected(true);
|
||||
|
||||
|
||||
//CFIDE
|
||||
debugHelpers.setSelected(true);
|
||||
appendBracketsToLabels.setSelected(true);
|
||||
printLineNumbers.setSelected(false);
|
||||
}
|
||||
|
||||
public void calledAfterLoad() {
|
||||
|
||||
public void calledAfterLoad()
|
||||
{
|
||||
deleteForeignOutdatedLibs.setSelected(Configuration.deleteForeignLibraries);
|
||||
}
|
||||
|
||||
|
||||
public int getFontSize()
|
||||
{
|
||||
return (int) fontSpinner.getValue();
|
||||
|
@ -857,17 +842,17 @@ public class MainViewerGUI extends JFrame
|
|||
{
|
||||
return (int) minSdkVersionSpinner.getValue();
|
||||
}
|
||||
|
||||
|
||||
public synchronized void clearBusyStatus()
|
||||
{
|
||||
SwingUtilities.invokeLater(()->
|
||||
SwingUtilities.invokeLater(() ->
|
||||
{
|
||||
int length = waitIcons.size();
|
||||
for (int i = 0; i < length; i++)
|
||||
updateBusyStatus(false);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
public synchronized void updateBusyStatus(boolean busy)
|
||||
{
|
||||
SwingUtilities.invokeLater(() ->
|
||||
|
@ -875,149 +860,137 @@ public class MainViewerGUI extends JFrame
|
|||
if (busy)
|
||||
{
|
||||
JMenuItem waitIcon = new WaitBusyIcon();
|
||||
|
||||
|
||||
rootMenu.add(waitIcon);
|
||||
waitIcons.add(waitIcon);
|
||||
}
|
||||
else
|
||||
{
|
||||
if(waitIcons.isEmpty())
|
||||
if (waitIcons.isEmpty())
|
||||
return;
|
||||
|
||||
|
||||
JMenuItem waitIcon = waitIcons.get(0);
|
||||
waitIcons.remove(0);
|
||||
rootMenu.remove(waitIcon);
|
||||
|
||||
|
||||
//re-enable the Refresh Button incase it gets stuck
|
||||
if(waitIcons.isEmpty() && !workPane.refreshClass.isEnabled())
|
||||
if (waitIcons.isEmpty() && !workPane.refreshClass.isEnabled())
|
||||
workPane.refreshClass.setEnabled(true);
|
||||
}
|
||||
|
||||
|
||||
rootMenu.updateUI();
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
public void compileOnNewThread()
|
||||
{
|
||||
Thread t = new Thread(() -> BytecodeViewer.compile(true, true), "Compile");
|
||||
t.start();
|
||||
}
|
||||
|
||||
|
||||
public void runResources()
|
||||
{
|
||||
if (BytecodeViewer.promptIfNoLoadedClasses())
|
||||
return;
|
||||
|
||||
|
||||
new RunOptions().setVisible(true);
|
||||
}
|
||||
|
||||
|
||||
public void reloadResources()
|
||||
{
|
||||
MultipleChoiceDialog dialog = new MultipleChoiceDialog(TranslatedStrings.RELOAD_RESOURCES_TITLE.toString(),
|
||||
TranslatedStrings.RELOAD_RESOURCES_CONFIRM.toString(),
|
||||
new String[]{TranslatedStrings.YES.toString(), TranslatedStrings.NO.toString()});
|
||||
|
||||
MultipleChoiceDialog dialog = new MultipleChoiceDialog(TranslatedStrings.RELOAD_RESOURCES_TITLE.toString(), TranslatedStrings.RELOAD_RESOURCES_CONFIRM.toString(), new String[]{TranslatedStrings.YES.toString(), TranslatedStrings.NO.toString()});
|
||||
|
||||
if (dialog.promptChoice() == 0)
|
||||
{
|
||||
LazyNameUtil.reset();
|
||||
List<File> reopen = new ArrayList<>();
|
||||
|
||||
|
||||
for (ResourceContainer container : BytecodeViewer.resourceContainers.values())
|
||||
{
|
||||
File newFile = new File(container.file.getParent() + fs + container.name);
|
||||
if (!container.file.getAbsolutePath().equals(newFile.getAbsolutePath()) &&
|
||||
(container.file.getAbsolutePath().endsWith(".apk") || container.file.getAbsolutePath().endsWith(".dex"))) //APKs & dex get renamed
|
||||
if (!container.file.getAbsolutePath().equals(newFile.getAbsolutePath()) && (container.file.getAbsolutePath().endsWith(".apk") || container.file.getAbsolutePath().endsWith(".dex"))) //APKs & dex get renamed
|
||||
{
|
||||
container.file.renameTo(newFile);
|
||||
container.file = newFile;
|
||||
}
|
||||
reopen.add(container.file);
|
||||
}
|
||||
|
||||
|
||||
BytecodeViewer.viewer.resourcePane.treeRoot.removeAllChildren();
|
||||
BytecodeViewer.resourceContainers.clear();
|
||||
|
||||
|
||||
for (File f : reopen)
|
||||
{
|
||||
BytecodeViewer.openFiles(new File[]{f}, false);
|
||||
}
|
||||
|
||||
|
||||
//refresh panes
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void selectFile()
|
||||
{
|
||||
final File file = DialogUtils.fileChooser(TranslatedStrings.SELECT_FILE_TITLE.toString(),
|
||||
TranslatedStrings.SELECT_FILE_DESCRIPTION.toString(),
|
||||
Constants.SUPPORTED_FILE_EXTENSIONS);
|
||||
|
||||
if(file == null)
|
||||
final File file = DialogUtils.fileChooser(TranslatedStrings.SELECT_FILE_TITLE.toString(), TranslatedStrings.SELECT_FILE_DESCRIPTION.toString(), Constants.SUPPORTED_FILE_EXTENSIONS);
|
||||
|
||||
if (file == null)
|
||||
return;
|
||||
|
||||
|
||||
BytecodeViewer.updateBusyStatus(true);
|
||||
BytecodeViewer.openFiles(new File[]{file}, true);
|
||||
BytecodeViewer.updateBusyStatus(false);
|
||||
}
|
||||
|
||||
|
||||
public void openExternalPlugin()
|
||||
{
|
||||
final File file = DialogUtils.fileChooser(TranslatedStrings.SELECT_EXTERNAL_PLUGIN_TITLE.toString(),
|
||||
TranslatedStrings.SELECT_EXTERNAL_PLUGIN_DESCRIPTION.toString(),
|
||||
Configuration.getLastPluginDirectory(),
|
||||
PluginManager.fileFilter(),
|
||||
Configuration::setLastPluginDirectory,
|
||||
FileChooser.EVERYTHING);
|
||||
|
||||
if(file == null)
|
||||
final File file = DialogUtils.fileChooser(TranslatedStrings.SELECT_EXTERNAL_PLUGIN_TITLE.toString(), TranslatedStrings.SELECT_EXTERNAL_PLUGIN_DESCRIPTION.toString(), Configuration.getLastPluginDirectory(), PluginManager.fileFilter(), Configuration::setLastPluginDirectory, FileChooser.EVERYTHING);
|
||||
|
||||
if (file == null)
|
||||
return;
|
||||
|
||||
|
||||
BytecodeViewer.updateBusyStatus(true);
|
||||
BytecodeViewer.startPlugin(file);
|
||||
BytecodeViewer.updateBusyStatus(false);
|
||||
SettingsSerializer.saveSettingsAsync();
|
||||
}
|
||||
|
||||
|
||||
public void askBeforeExiting()
|
||||
{
|
||||
MultipleChoiceDialog dialog = new MultipleChoiceDialog(TranslatedStrings.EXIT_TITLE.toString(),
|
||||
TranslatedStrings.EXIT_CONFIRM.toString(),
|
||||
new String[]{TranslatedStrings.YES.toString(), TranslatedStrings.NO.toString()});
|
||||
|
||||
MultipleChoiceDialog dialog = new MultipleChoiceDialog(TranslatedStrings.EXIT_TITLE.toString(), TranslatedStrings.EXIT_CONFIRM.toString(), new String[]{TranslatedStrings.YES.toString(), TranslatedStrings.NO.toString()});
|
||||
|
||||
if (dialog.promptChoice() == 0)
|
||||
{
|
||||
Configuration.canExit = true;
|
||||
System.exit(0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void showForeignLibraryWarning()
|
||||
{
|
||||
if (!deleteForeignOutdatedLibs.isSelected())
|
||||
BytecodeViewer.showMessage(TranslatedStrings.FOREIGN_LIBRARY_WARNING.toString());
|
||||
|
||||
|
||||
Configuration.deleteForeignLibraries = deleteForeignOutdatedLibs.isSelected();
|
||||
}
|
||||
|
||||
|
||||
public void updateTabTheme()
|
||||
{
|
||||
try
|
||||
{
|
||||
for(Component viewerComponent : BytecodeViewer.viewer.workPane.tabs.getComponents())
|
||||
for (Component viewerComponent : BytecodeViewer.viewer.workPane.tabs.getComponents())
|
||||
{
|
||||
if(!(viewerComponent instanceof ResourceViewer))
|
||||
if (!(viewerComponent instanceof ResourceViewer))
|
||||
continue;
|
||||
|
||||
|
||||
ResourceViewer viewerResource = (ResourceViewer) viewerComponent;
|
||||
if(!(viewerResource instanceof ClassViewer))
|
||||
if (!(viewerResource instanceof ClassViewer))
|
||||
continue;
|
||||
|
||||
|
||||
ClassViewer viewerClass = (ClassViewer) viewerResource;
|
||||
Configuration.rstaTheme.apply(viewerClass.bytecodeViewPanel1.textArea);
|
||||
Configuration.rstaTheme.apply(viewerClass.bytecodeViewPanel2.textArea);
|
||||
Configuration.rstaTheme.apply(viewerClass.bytecodeViewPanel3.textArea);
|
||||
}
|
||||
|
||||
|
||||
SwingUtilities.updateComponentTreeUI(BytecodeViewer.viewer);
|
||||
}
|
||||
catch (Exception ex)
|
||||
|
@ -1025,6 +998,6 @@ public class MainViewerGUI extends JFrame
|
|||
ex.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static final long serialVersionUID = 1851409230530948543L;
|
||||
}
|
||||
|
|
|
@ -18,14 +18,14 @@
|
|||
|
||||
package the.bytecode.club.bytecodeviewer.gui.components;
|
||||
|
||||
import java.awt.CardLayout;
|
||||
import java.io.IOException;
|
||||
import javax.swing.JFrame;
|
||||
import javax.swing.JScrollPane;
|
||||
import the.bytecode.club.bytecodeviewer.bootloader.InitialBootScreen;
|
||||
import the.bytecode.club.bytecodeviewer.resources.IconResources;
|
||||
import the.bytecode.club.bytecodeviewer.translation.TranslatedStrings;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.awt.*;
|
||||
import java.io.IOException;
|
||||
|
||||
import static the.bytecode.club.bytecodeviewer.Configuration.language;
|
||||
|
||||
/**
|
||||
|
@ -42,10 +42,10 @@ public class AboutWindow extends JFrame
|
|||
setSize(InitialBootScreen.getSafeSize());
|
||||
setTitle(TranslatedStrings.ABOUT_TITLE.toString());
|
||||
getContentPane().setLayout(new CardLayout(0, 0));
|
||||
|
||||
|
||||
JScrollPane scrollPane = new JScrollPane();
|
||||
getContentPane().add(scrollPane);
|
||||
|
||||
|
||||
try
|
||||
{
|
||||
scrollPane.setViewportView(HTMLPane.fromResource(language.getHTMLPath("intro")));
|
||||
|
@ -54,7 +54,7 @@ public class AboutWindow extends JFrame
|
|||
{
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
|
||||
this.setLocationRelativeTo(null);
|
||||
}
|
||||
|
||||
|
|
|
@ -18,17 +18,14 @@
|
|||
|
||||
package the.bytecode.club.bytecodeviewer.gui.components;
|
||||
|
||||
import javax.swing.ButtonGroup;
|
||||
import javax.swing.JCheckBoxMenuItem;
|
||||
import javax.swing.JMenu;
|
||||
import javax.swing.JRadioButtonMenuItem;
|
||||
import javax.swing.JSeparator;
|
||||
import the.bytecode.club.bytecodeviewer.decompilers.Decompiler;
|
||||
import the.bytecode.club.bytecodeviewer.gui.resourceviewer.WorkspaceRefreshEvent;
|
||||
import the.bytecode.club.bytecodeviewer.translation.TranslatedComponents;
|
||||
import the.bytecode.club.bytecodeviewer.translation.components.TranslatedJCheckBoxMenuItem;
|
||||
import the.bytecode.club.bytecodeviewer.translation.components.TranslatedJRadioButtonMenuItem;
|
||||
|
||||
import javax.swing.*;
|
||||
|
||||
import static the.bytecode.club.bytecodeviewer.gui.components.DecompilerViewComponent.DecompilerComponentType.*;
|
||||
|
||||
/**
|
||||
|
@ -37,87 +34,83 @@ import static the.bytecode.club.bytecodeviewer.gui.components.DecompilerViewComp
|
|||
*/
|
||||
public class DecompilerViewComponent
|
||||
{
|
||||
private final String name;
|
||||
private final JMenu menu;
|
||||
private final DecompilerComponentType type;
|
||||
private final Decompiler[] decompilers;
|
||||
private final JRadioButtonMenuItem java;
|
||||
private final JRadioButtonMenuItem bytecode;
|
||||
private final JCheckBoxMenuItem editable;
|
||||
|
||||
public DecompilerViewComponent(String name, DecompilerComponentType type, Decompiler... decompilers)
|
||||
{
|
||||
this.name = name;
|
||||
this.menu = new JMenu(name);
|
||||
this.type = type;
|
||||
this.decompilers = decompilers;
|
||||
this.java = new TranslatedJRadioButtonMenuItem("Java", TranslatedComponents.JAVA);
|
||||
this.bytecode = new TranslatedJRadioButtonMenuItem("Bytecode", TranslatedComponents.BYTECODE);
|
||||
this.editable = new TranslatedJCheckBoxMenuItem( "Editable", TranslatedComponents.EDITABLE);
|
||||
|
||||
createMenu();
|
||||
}
|
||||
|
||||
private void createMenu()
|
||||
{
|
||||
if(type == JAVA || type == JAVA_NON_EDITABLE || type == JAVA_AND_BYTECODE)
|
||||
menu.add(java);
|
||||
if(type == BYTECODE || type == JAVA_AND_BYTECODE || type == BYTECODE_NON_EDITABLE)
|
||||
menu.add(bytecode);
|
||||
|
||||
if(type != JAVA_NON_EDITABLE && type != BYTECODE_NON_EDITABLE)
|
||||
{
|
||||
menu.add(new JSeparator());
|
||||
menu.add(editable);
|
||||
}
|
||||
|
||||
java.addActionListener(new WorkspaceRefreshEvent());
|
||||
}
|
||||
|
||||
public void addToGroup(ButtonGroup group)
|
||||
{
|
||||
if(type == JAVA || type == JAVA_NON_EDITABLE || type == JAVA_AND_BYTECODE)
|
||||
group.add(java);
|
||||
if(type == BYTECODE || type == JAVA_AND_BYTECODE || type == BYTECODE_NON_EDITABLE)
|
||||
group.add(bytecode);
|
||||
}
|
||||
|
||||
public JMenu getMenu()
|
||||
{
|
||||
return menu;
|
||||
}
|
||||
|
||||
public JRadioButtonMenuItem getJava()
|
||||
{
|
||||
return java;
|
||||
}
|
||||
|
||||
public JRadioButtonMenuItem getBytecode()
|
||||
{
|
||||
return bytecode;
|
||||
}
|
||||
|
||||
public JCheckBoxMenuItem getEditable()
|
||||
{
|
||||
return editable;
|
||||
}
|
||||
|
||||
public DecompilerComponentType getType()
|
||||
{
|
||||
return type;
|
||||
}
|
||||
|
||||
public Decompiler[] getDecompilers()
|
||||
{
|
||||
return decompilers;
|
||||
}
|
||||
|
||||
public enum DecompilerComponentType
|
||||
{
|
||||
JAVA,
|
||||
JAVA_NON_EDITABLE,
|
||||
BYTECODE,
|
||||
BYTECODE_NON_EDITABLE,
|
||||
JAVA_AND_BYTECODE
|
||||
}
|
||||
private final String name;
|
||||
private final JMenu menu;
|
||||
private final DecompilerComponentType type;
|
||||
private final Decompiler[] decompilers;
|
||||
private final JRadioButtonMenuItem java;
|
||||
private final JRadioButtonMenuItem bytecode;
|
||||
private final JCheckBoxMenuItem editable;
|
||||
|
||||
public DecompilerViewComponent(String name, DecompilerComponentType type, Decompiler... decompilers)
|
||||
{
|
||||
this.name = name;
|
||||
this.menu = new JMenu(name);
|
||||
this.type = type;
|
||||
this.decompilers = decompilers;
|
||||
this.java = new TranslatedJRadioButtonMenuItem("Java", TranslatedComponents.JAVA);
|
||||
this.bytecode = new TranslatedJRadioButtonMenuItem("Bytecode", TranslatedComponents.BYTECODE);
|
||||
this.editable = new TranslatedJCheckBoxMenuItem("Editable", TranslatedComponents.EDITABLE);
|
||||
|
||||
createMenu();
|
||||
}
|
||||
|
||||
private void createMenu()
|
||||
{
|
||||
if (type == JAVA || type == JAVA_NON_EDITABLE || type == JAVA_AND_BYTECODE)
|
||||
menu.add(java);
|
||||
if (type == BYTECODE || type == JAVA_AND_BYTECODE || type == BYTECODE_NON_EDITABLE)
|
||||
menu.add(bytecode);
|
||||
|
||||
if (type != JAVA_NON_EDITABLE && type != BYTECODE_NON_EDITABLE)
|
||||
{
|
||||
menu.add(new JSeparator());
|
||||
menu.add(editable);
|
||||
}
|
||||
|
||||
java.addActionListener(new WorkspaceRefreshEvent());
|
||||
}
|
||||
|
||||
public void addToGroup(ButtonGroup group)
|
||||
{
|
||||
if (type == JAVA || type == JAVA_NON_EDITABLE || type == JAVA_AND_BYTECODE)
|
||||
group.add(java);
|
||||
if (type == BYTECODE || type == JAVA_AND_BYTECODE || type == BYTECODE_NON_EDITABLE)
|
||||
group.add(bytecode);
|
||||
}
|
||||
|
||||
public JMenu getMenu()
|
||||
{
|
||||
return menu;
|
||||
}
|
||||
|
||||
public JRadioButtonMenuItem getJava()
|
||||
{
|
||||
return java;
|
||||
}
|
||||
|
||||
public JRadioButtonMenuItem getBytecode()
|
||||
{
|
||||
return bytecode;
|
||||
}
|
||||
|
||||
public JCheckBoxMenuItem getEditable()
|
||||
{
|
||||
return editable;
|
||||
}
|
||||
|
||||
public DecompilerComponentType getType()
|
||||
{
|
||||
return type;
|
||||
}
|
||||
|
||||
public Decompiler[] getDecompilers()
|
||||
{
|
||||
return decompilers;
|
||||
}
|
||||
|
||||
public enum DecompilerComponentType
|
||||
{
|
||||
JAVA, JAVA_NON_EDITABLE, BYTECODE, BYTECODE_NON_EDITABLE, JAVA_AND_BYTECODE
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,16 +18,12 @@
|
|||
|
||||
package the.bytecode.club.bytecodeviewer.gui.components;
|
||||
|
||||
import java.awt.Dimension;
|
||||
import javax.swing.BoxLayout;
|
||||
import javax.swing.JButton;
|
||||
import javax.swing.JFrame;
|
||||
import javax.swing.JLabel;
|
||||
import javax.swing.JScrollPane;
|
||||
import javax.swing.JTextArea;
|
||||
import the.bytecode.club.bytecodeviewer.BytecodeViewer;
|
||||
import the.bytecode.club.bytecodeviewer.util.JarUtils;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.awt.*;
|
||||
|
||||
/**
|
||||
* The export as Jar UI.
|
||||
*
|
||||
|
@ -74,4 +70,4 @@ public class ExportJar extends JFrame
|
|||
}
|
||||
|
||||
private static final long serialVersionUID = -2662514582647810868L;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,27 +18,12 @@
|
|||
|
||||
package the.bytecode.club.bytecodeviewer.gui.components;
|
||||
|
||||
import java.awt.Component;
|
||||
import java.awt.Dimension;
|
||||
import java.awt.HeadlessException;
|
||||
import javax.swing.Icon;
|
||||
import javax.swing.JDialog;
|
||||
import javax.swing.JOptionPane;
|
||||
import javax.swing.JRootPane;
|
||||
import javax.swing.JScrollPane;
|
||||
import javax.swing.UIManager;
|
||||
import the.bytecode.club.bytecodeviewer.BytecodeViewer;
|
||||
|
||||
import static javax.swing.JOptionPane.CLOSED_OPTION;
|
||||
import static javax.swing.JOptionPane.DEFAULT_OPTION;
|
||||
import static javax.swing.JOptionPane.ERROR_MESSAGE;
|
||||
import static javax.swing.JOptionPane.INFORMATION_MESSAGE;
|
||||
import static javax.swing.JOptionPane.OK_CANCEL_OPTION;
|
||||
import static javax.swing.JOptionPane.PLAIN_MESSAGE;
|
||||
import static javax.swing.JOptionPane.QUESTION_MESSAGE;
|
||||
import static javax.swing.JOptionPane.UNINITIALIZED_VALUE;
|
||||
import static javax.swing.JOptionPane.WARNING_MESSAGE;
|
||||
import static javax.swing.JOptionPane.getRootFrame;
|
||||
import javax.swing.*;
|
||||
import java.awt.*;
|
||||
|
||||
import static javax.swing.JOptionPane.*;
|
||||
|
||||
/**
|
||||
* Extends the JOptionPane
|
||||
|
@ -51,192 +36,165 @@ import static javax.swing.JOptionPane.getRootFrame;
|
|||
|
||||
public class ExtendedJOptionPane
|
||||
{
|
||||
public static void showMessageDialog(Component parentComponent,
|
||||
Object message) throws HeadlessException
|
||||
{
|
||||
showMessageDialog(parentComponent, message, UIManager.getString(
|
||||
"OptionPane.messageDialogTitle", parentComponent.getLocale()),
|
||||
INFORMATION_MESSAGE);
|
||||
}
|
||||
|
||||
public static void showMessageDialog(Component parentComponent,
|
||||
Object message, String title, int messageType)
|
||||
throws HeadlessException
|
||||
{
|
||||
showMessageDialog(parentComponent, message, title, messageType, null);
|
||||
}
|
||||
|
||||
public static void showMessageDialog(Component parentComponent,
|
||||
Object message, String title, int messageType, Icon icon)
|
||||
throws HeadlessException
|
||||
{
|
||||
showOptionDialog(parentComponent, message, title, DEFAULT_OPTION,
|
||||
messageType, icon, null, null);
|
||||
}
|
||||
|
||||
public static String showInputDialog(Object message)
|
||||
throws HeadlessException {
|
||||
return showInputDialog(null, message);
|
||||
}
|
||||
|
||||
public static String showInputDialog(Object message, Object initialSelectionValue) {
|
||||
return showInputDialog(null, message, initialSelectionValue);
|
||||
}
|
||||
|
||||
public static String showInputDialog(Component parentComponent,
|
||||
Object message) throws HeadlessException {
|
||||
return showInputDialog(parentComponent, message, UIManager.getString(
|
||||
"OptionPane.inputDialogTitle", parentComponent.getLocale()), QUESTION_MESSAGE);
|
||||
}
|
||||
|
||||
public static String showInputDialog(Component parentComponent, Object message,
|
||||
Object initialSelectionValue) {
|
||||
return (String)showInputDialog(parentComponent, message,
|
||||
UIManager.getString("OptionPane.inputDialogTitle",
|
||||
parentComponent.getLocale()), QUESTION_MESSAGE, null, null,
|
||||
initialSelectionValue);
|
||||
}
|
||||
|
||||
public static String showInputDialog(Component parentComponent,
|
||||
Object message, String title, int messageType)
|
||||
throws HeadlessException {
|
||||
return (String)showInputDialog(parentComponent, message, title,
|
||||
messageType, null, null, null);
|
||||
}
|
||||
|
||||
public static int showOptionDialog(Component parentComponent,
|
||||
Object message, String title, int optionType, int messageType,
|
||||
Icon icon, Object[] options, Object initialValue)
|
||||
throws HeadlessException
|
||||
{
|
||||
JOptionPane pane = new JOptionPane(message, messageType,
|
||||
optionType, icon,
|
||||
options, initialValue);
|
||||
|
||||
pane.setInitialValue(initialValue);
|
||||
pane.setComponentOrientation(((parentComponent == null) ?
|
||||
getRootFrame() : parentComponent).getComponentOrientation());
|
||||
|
||||
int style = styleFromMessageType(messageType);
|
||||
JDialog dialog = createNewJDialog(parentComponent, pane, title, style, (d)->
|
||||
pane.selectInitialValue());
|
||||
|
||||
pane.selectInitialValue();
|
||||
|
||||
Object selectedValue = pane.getValue();
|
||||
|
||||
if(selectedValue == null)
|
||||
return CLOSED_OPTION;
|
||||
|
||||
if(options == null)
|
||||
{
|
||||
if(selectedValue instanceof Integer)
|
||||
return (Integer) selectedValue;
|
||||
return CLOSED_OPTION;
|
||||
}
|
||||
|
||||
for(int counter = 0, maxCounter = options.length;
|
||||
counter < maxCounter; counter++)
|
||||
{
|
||||
if(options[counter].equals(selectedValue))
|
||||
return counter;
|
||||
}
|
||||
|
||||
return CLOSED_OPTION;
|
||||
}
|
||||
|
||||
public static Object showInputDialog(Component parentComponent,
|
||||
Object message, String title, int messageType, Icon icon,
|
||||
Object[] selectionValues, Object initialSelectionValue)
|
||||
throws HeadlessException {
|
||||
JOptionPane pane = new JOptionPane(message, messageType,
|
||||
OK_CANCEL_OPTION, icon,
|
||||
null, null);
|
||||
|
||||
pane.setWantsInput(true);
|
||||
pane.setSelectionValues(selectionValues);
|
||||
pane.setInitialSelectionValue(initialSelectionValue);
|
||||
pane.setComponentOrientation(((parentComponent == null) ?
|
||||
getRootFrame() : parentComponent).getComponentOrientation());
|
||||
|
||||
int style = styleFromMessageType(messageType);
|
||||
JDialog dialog = createNewJDialog(parentComponent, pane, title, style, (d)->
|
||||
pane.selectInitialValue());
|
||||
|
||||
pane.selectInitialValue();
|
||||
|
||||
Object value = pane.getInputValue();
|
||||
|
||||
if (value == UNINITIALIZED_VALUE)
|
||||
return null;
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
public static void showJPanelDialog(Component parentComponent, JScrollPane panel, int minimumHeight, OnCreate onCreate)
|
||||
throws HeadlessException
|
||||
{
|
||||
//create a new option pane with a empty text and just 'ok'
|
||||
JOptionPane pane = new JOptionPane("");
|
||||
pane.add(panel, 0);
|
||||
public static void showMessageDialog(Component parentComponent, Object message) throws HeadlessException
|
||||
{
|
||||
showMessageDialog(parentComponent, message, UIManager.getString("OptionPane.messageDialogTitle", parentComponent.getLocale()), INFORMATION_MESSAGE);
|
||||
}
|
||||
|
||||
JDialog dialog = createNewJDialog(parentComponent, pane, panel.getName(), ERROR_MESSAGE, (d)->
|
||||
{
|
||||
int newHeight = Math.min(minimumHeight, d.getHeight());
|
||||
d.setMinimumSize(new Dimension(d.getWidth(), newHeight));
|
||||
d.setSize(new Dimension(d.getWidth(), newHeight));
|
||||
|
||||
if(onCreate != null)
|
||||
onCreate.onCreate(d);
|
||||
});
|
||||
}
|
||||
|
||||
private static JDialog createNewJDialog(Component parentComponent, JOptionPane pane, String title, int style, OnCreate onCreate)
|
||||
{
|
||||
JDialog dialog = pane.createDialog(parentComponent, title);
|
||||
if (JDialog.isDefaultLookAndFeelDecorated()) {
|
||||
boolean supportsWindowDecorations =
|
||||
UIManager.getLookAndFeel().getSupportsWindowDecorations();
|
||||
if (supportsWindowDecorations) {
|
||||
dialog.setUndecorated(true);
|
||||
pane.getRootPane().setWindowDecorationStyle(style);
|
||||
}
|
||||
}
|
||||
public static void showMessageDialog(Component parentComponent, Object message, String title, int messageType) throws HeadlessException
|
||||
{
|
||||
showMessageDialog(parentComponent, message, title, messageType, null);
|
||||
}
|
||||
|
||||
onCreate.onCreate(dialog);
|
||||
|
||||
//check if the dialog is in a poor location, attempt to correct
|
||||
if (dialog.getLocation().getY() == 0 || dialog.getLocation().getY() == 1)
|
||||
dialog.setLocationRelativeTo(null); //TODO check if BytecodeViewer.viewer is better on multi monitor for this edgecase
|
||||
else
|
||||
dialog.setLocationRelativeTo(BytecodeViewer.viewer);
|
||||
|
||||
dialog.setVisible(true);
|
||||
dialog.dispose();
|
||||
|
||||
return dialog;
|
||||
}
|
||||
|
||||
private static int styleFromMessageType(int messageType)
|
||||
{
|
||||
switch (messageType)
|
||||
{
|
||||
case ERROR_MESSAGE:
|
||||
return JRootPane.ERROR_DIALOG;
|
||||
case QUESTION_MESSAGE:
|
||||
return JRootPane.QUESTION_DIALOG;
|
||||
case WARNING_MESSAGE:
|
||||
return JRootPane.WARNING_DIALOG;
|
||||
case INFORMATION_MESSAGE:
|
||||
return JRootPane.INFORMATION_DIALOG;
|
||||
case PLAIN_MESSAGE:
|
||||
default:
|
||||
return JRootPane.PLAIN_DIALOG;
|
||||
}
|
||||
}
|
||||
|
||||
interface OnCreate
|
||||
{
|
||||
void onCreate(JDialog dialog);
|
||||
}
|
||||
public static void showMessageDialog(Component parentComponent, Object message, String title, int messageType, Icon icon) throws HeadlessException
|
||||
{
|
||||
showOptionDialog(parentComponent, message, title, DEFAULT_OPTION, messageType, icon, null, null);
|
||||
}
|
||||
|
||||
public static String showInputDialog(Object message) throws HeadlessException
|
||||
{
|
||||
return showInputDialog(null, message);
|
||||
}
|
||||
|
||||
public static String showInputDialog(Object message, Object initialSelectionValue)
|
||||
{
|
||||
return showInputDialog(null, message, initialSelectionValue);
|
||||
}
|
||||
|
||||
public static String showInputDialog(Component parentComponent, Object message) throws HeadlessException
|
||||
{
|
||||
return showInputDialog(parentComponent, message, UIManager.getString("OptionPane.inputDialogTitle", parentComponent.getLocale()), QUESTION_MESSAGE);
|
||||
}
|
||||
|
||||
public static String showInputDialog(Component parentComponent, Object message, Object initialSelectionValue)
|
||||
{
|
||||
return (String) showInputDialog(parentComponent, message, UIManager.getString("OptionPane.inputDialogTitle", parentComponent.getLocale()), QUESTION_MESSAGE, null, null, initialSelectionValue);
|
||||
}
|
||||
|
||||
public static String showInputDialog(Component parentComponent, Object message, String title, int messageType) throws HeadlessException
|
||||
{
|
||||
return (String) showInputDialog(parentComponent, message, title, messageType, null, null, null);
|
||||
}
|
||||
|
||||
public static int showOptionDialog(Component parentComponent, Object message, String title, int optionType, int messageType, Icon icon, Object[] options, Object initialValue) throws HeadlessException
|
||||
{
|
||||
JOptionPane pane = new JOptionPane(message, messageType, optionType, icon, options, initialValue);
|
||||
|
||||
pane.setInitialValue(initialValue);
|
||||
pane.setComponentOrientation(((parentComponent == null) ? getRootFrame() : parentComponent).getComponentOrientation());
|
||||
|
||||
int style = styleFromMessageType(messageType);
|
||||
JDialog dialog = createNewJDialog(parentComponent, pane, title, style, (d) -> pane.selectInitialValue());
|
||||
|
||||
pane.selectInitialValue();
|
||||
|
||||
Object selectedValue = pane.getValue();
|
||||
|
||||
if (selectedValue == null)
|
||||
return CLOSED_OPTION;
|
||||
|
||||
if (options == null)
|
||||
{
|
||||
if (selectedValue instanceof Integer)
|
||||
return (Integer) selectedValue;
|
||||
return CLOSED_OPTION;
|
||||
}
|
||||
|
||||
for (int counter = 0, maxCounter = options.length; counter < maxCounter; counter++)
|
||||
{
|
||||
if (options[counter].equals(selectedValue))
|
||||
return counter;
|
||||
}
|
||||
|
||||
return CLOSED_OPTION;
|
||||
}
|
||||
|
||||
public static Object showInputDialog(Component parentComponent, Object message, String title, int messageType, Icon icon, Object[] selectionValues, Object initialSelectionValue) throws HeadlessException
|
||||
{
|
||||
JOptionPane pane = new JOptionPane(message, messageType, OK_CANCEL_OPTION, icon, null, null);
|
||||
|
||||
pane.setWantsInput(true);
|
||||
pane.setSelectionValues(selectionValues);
|
||||
pane.setInitialSelectionValue(initialSelectionValue);
|
||||
pane.setComponentOrientation(((parentComponent == null) ? getRootFrame() : parentComponent).getComponentOrientation());
|
||||
|
||||
int style = styleFromMessageType(messageType);
|
||||
JDialog dialog = createNewJDialog(parentComponent, pane, title, style, (d) -> pane.selectInitialValue());
|
||||
|
||||
pane.selectInitialValue();
|
||||
|
||||
Object value = pane.getInputValue();
|
||||
|
||||
if (value == UNINITIALIZED_VALUE)
|
||||
return null;
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
public static void showJPanelDialog(Component parentComponent, JScrollPane panel, int minimumHeight, OnCreate onCreate) throws HeadlessException
|
||||
{
|
||||
//create a new option pane with a empty text and just 'ok'
|
||||
JOptionPane pane = new JOptionPane("");
|
||||
pane.add(panel, 0);
|
||||
|
||||
JDialog dialog = createNewJDialog(parentComponent, pane, panel.getName(), ERROR_MESSAGE, (d) ->
|
||||
{
|
||||
int newHeight = Math.min(minimumHeight, d.getHeight());
|
||||
d.setMinimumSize(new Dimension(d.getWidth(), newHeight));
|
||||
d.setSize(new Dimension(d.getWidth(), newHeight));
|
||||
|
||||
if (onCreate != null)
|
||||
onCreate.onCreate(d);
|
||||
});
|
||||
}
|
||||
|
||||
private static JDialog createNewJDialog(Component parentComponent, JOptionPane pane, String title, int style, OnCreate onCreate)
|
||||
{
|
||||
JDialog dialog = pane.createDialog(parentComponent, title);
|
||||
if (JDialog.isDefaultLookAndFeelDecorated())
|
||||
{
|
||||
boolean supportsWindowDecorations = UIManager.getLookAndFeel().getSupportsWindowDecorations();
|
||||
if (supportsWindowDecorations)
|
||||
{
|
||||
dialog.setUndecorated(true);
|
||||
pane.getRootPane().setWindowDecorationStyle(style);
|
||||
}
|
||||
}
|
||||
|
||||
onCreate.onCreate(dialog);
|
||||
|
||||
//check if the dialog is in a poor location, attempt to correct
|
||||
if (dialog.getLocation().getY() == 0 || dialog.getLocation().getY() == 1)
|
||||
dialog.setLocationRelativeTo(null); //TODO check if BytecodeViewer.viewer is better on multi monitor for this edgecase
|
||||
else
|
||||
dialog.setLocationRelativeTo(BytecodeViewer.viewer);
|
||||
|
||||
dialog.setVisible(true);
|
||||
dialog.dispose();
|
||||
|
||||
return dialog;
|
||||
}
|
||||
|
||||
private static int styleFromMessageType(int messageType)
|
||||
{
|
||||
switch (messageType)
|
||||
{
|
||||
case ERROR_MESSAGE:
|
||||
return JRootPane.ERROR_DIALOG;
|
||||
case QUESTION_MESSAGE:
|
||||
return JRootPane.QUESTION_DIALOG;
|
||||
case WARNING_MESSAGE:
|
||||
return JRootPane.WARNING_DIALOG;
|
||||
case INFORMATION_MESSAGE:
|
||||
return JRootPane.INFORMATION_DIALOG;
|
||||
case PLAIN_MESSAGE:
|
||||
default:
|
||||
return JRootPane.PLAIN_DIALOG;
|
||||
}
|
||||
}
|
||||
|
||||
interface OnCreate
|
||||
{
|
||||
void onCreate(JDialog dialog);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,13 +18,14 @@
|
|||
|
||||
package the.bytecode.club.bytecodeviewer.gui.components;
|
||||
|
||||
import the.bytecode.club.bytecodeviewer.util.MiscUtils;
|
||||
|
||||
import javax.swing.*;
|
||||
import javax.swing.filechooser.FileFilter;
|
||||
import java.io.File;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import javax.swing.JFileChooser;
|
||||
import javax.swing.filechooser.FileFilter;
|
||||
import the.bytecode.club.bytecodeviewer.util.MiscUtils;
|
||||
|
||||
/**
|
||||
* @author Konloch
|
||||
|
@ -32,46 +33,51 @@ import the.bytecode.club.bytecodeviewer.util.MiscUtils;
|
|||
*/
|
||||
public class FileChooser extends JFileChooser
|
||||
{
|
||||
public static final String EVERYTHING = "everything";
|
||||
|
||||
public FileChooser(File file, String title, String description, String... extensions)
|
||||
{
|
||||
this(false, file, title, description, extensions);
|
||||
}
|
||||
|
||||
public FileChooser(boolean skipFileFilter, File file, String title, String description, String... extensions)
|
||||
{
|
||||
Set<String> extensionSet = new HashSet<>(Arrays.asList(extensions));
|
||||
|
||||
setFileSelectionMode(JFileChooser.FILES_AND_DIRECTORIES);
|
||||
try {
|
||||
setSelectedFile(file);
|
||||
} catch (Exception ignored) { }
|
||||
|
||||
setDialogTitle(title);
|
||||
setFileHidingEnabled(false);
|
||||
setAcceptAllFileFilterUsed(false);
|
||||
if(!skipFileFilter)
|
||||
{
|
||||
public static final String EVERYTHING = "everything";
|
||||
|
||||
public FileChooser(File file, String title, String description, String... extensions)
|
||||
{
|
||||
this(false, file, title, description, extensions);
|
||||
}
|
||||
|
||||
public FileChooser(boolean skipFileFilter, File file, String title, String description, String... extensions)
|
||||
{
|
||||
Set<String> extensionSet = new HashSet<>(Arrays.asList(extensions));
|
||||
|
||||
setFileSelectionMode(JFileChooser.FILES_AND_DIRECTORIES);
|
||||
try
|
||||
{
|
||||
setSelectedFile(file);
|
||||
}
|
||||
catch (Exception ignored)
|
||||
{
|
||||
}
|
||||
|
||||
setDialogTitle(title);
|
||||
setFileHidingEnabled(false);
|
||||
setAcceptAllFileFilterUsed(false);
|
||||
if (!skipFileFilter)
|
||||
{
|
||||
addChoosableFileFilter(new FileFilter()
|
||||
{
|
||||
@Override
|
||||
public boolean accept(File f)
|
||||
{
|
||||
if (f.isDirectory())
|
||||
return true;
|
||||
|
||||
if(extensions[0].equals(EVERYTHING))
|
||||
return true;
|
||||
|
||||
return extensionSet.contains(MiscUtils.extension(f.getAbsolutePath()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDescription() {
|
||||
return description;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
{
|
||||
@Override
|
||||
public boolean accept(File f)
|
||||
{
|
||||
if (f.isDirectory())
|
||||
return true;
|
||||
|
||||
if (extensions[0].equals(EVERYTHING))
|
||||
return true;
|
||||
|
||||
return extensionSet.contains(MiscUtils.extension(f.getAbsolutePath()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDescription()
|
||||
{
|
||||
return description;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,20 +18,16 @@
|
|||
|
||||
package the.bytecode.club.bytecodeviewer.gui.components;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.Scanner;
|
||||
import javax.swing.JEditorPane;
|
||||
import javax.swing.text.html.HTMLEditorKit;
|
||||
import the.bytecode.club.bytecodeviewer.Configuration;
|
||||
import the.bytecode.club.bytecodeviewer.bootloader.InitialBootScreen;
|
||||
|
||||
import static the.bytecode.club.bytecodeviewer.Constants.BCVDir;
|
||||
import static the.bytecode.club.bytecodeviewer.Constants.FAT_JAR;
|
||||
import static the.bytecode.club.bytecodeviewer.Constants.enjarifyVersion;
|
||||
import static the.bytecode.club.bytecodeviewer.Constants.enjarifyWorkingDirectory;
|
||||
import static the.bytecode.club.bytecodeviewer.Constants.krakatauVersion;
|
||||
import static the.bytecode.club.bytecodeviewer.Constants.krakatauWorkingDirectory;
|
||||
import javax.swing.*;
|
||||
import javax.swing.text.html.HTMLEditorKit;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.Scanner;
|
||||
|
||||
import static the.bytecode.club.bytecodeviewer.Constants.*;
|
||||
|
||||
/**
|
||||
* @author Konloch
|
||||
|
@ -39,52 +35,53 @@ import static the.bytecode.club.bytecodeviewer.Constants.krakatauWorkingDirector
|
|||
*/
|
||||
public class HTMLPane extends JEditorPane
|
||||
{
|
||||
private HTMLPane()
|
||||
{
|
||||
setEditorKit(new HTMLEditorKit());
|
||||
setEditable(false);
|
||||
}
|
||||
|
||||
public static HTMLPane fromResource(String resourcePath) throws IOException
|
||||
{
|
||||
try (InputStream is = InitialBootScreen.class.getClassLoader().getResourceAsStream(resourcePath)) {
|
||||
return fromString(convertStreamToString(is));
|
||||
}
|
||||
}
|
||||
|
||||
public static HTMLPane fromString(String text)
|
||||
{
|
||||
if (text == null)
|
||||
return null;
|
||||
|
||||
HTMLPane pane = new HTMLPane();
|
||||
|
||||
text = text.replace("{fatJar}", String.valueOf(FAT_JAR));
|
||||
text = text.replace("{java}", Configuration.java);
|
||||
text = text.replace("{javac}", Configuration.javac);
|
||||
text = text.replace("{bcvDir}", BCVDir.getAbsolutePath());
|
||||
text = text.replace("{python}", Configuration.python2+" " + (Configuration.python2Extra ? "-2" : ""));
|
||||
text = text.replace("{python3}", Configuration.python3 + " " + (Configuration.python3Extra ? "-3" : ""));
|
||||
text = text.replace("{rt}", Configuration.rt);
|
||||
text = text.replace("{lib}", Configuration.library);
|
||||
text = text.replace("{krakatauVersion}", krakatauVersion);
|
||||
text = text.replace("{krakatauDir}", krakatauWorkingDirectory);
|
||||
text = text.replace("{enjarifyVersion}", enjarifyVersion);
|
||||
text = text.replace("{enjarifyDir}", enjarifyWorkingDirectory);
|
||||
|
||||
pane.setText(text);
|
||||
pane.setCaretPosition(0);
|
||||
|
||||
return pane;
|
||||
}
|
||||
|
||||
public static String convertStreamToString(InputStream is) throws IOException
|
||||
{
|
||||
if (is == null)
|
||||
return null;
|
||||
try (InputStream stream = is;
|
||||
Scanner s = new Scanner(stream, "UTF-8").useDelimiter("\\A")) {
|
||||
return s.hasNext() ? s.next() : "";
|
||||
}
|
||||
}
|
||||
private HTMLPane()
|
||||
{
|
||||
setEditorKit(new HTMLEditorKit());
|
||||
setEditable(false);
|
||||
}
|
||||
|
||||
public static HTMLPane fromResource(String resourcePath) throws IOException
|
||||
{
|
||||
try (InputStream is = InitialBootScreen.class.getClassLoader().getResourceAsStream(resourcePath))
|
||||
{
|
||||
return fromString(convertStreamToString(is));
|
||||
}
|
||||
}
|
||||
|
||||
public static HTMLPane fromString(String text)
|
||||
{
|
||||
if (text == null)
|
||||
return null;
|
||||
|
||||
HTMLPane pane = new HTMLPane();
|
||||
|
||||
text = text.replace("{fatJar}", String.valueOf(FAT_JAR));
|
||||
text = text.replace("{java}", Configuration.java);
|
||||
text = text.replace("{javac}", Configuration.javac);
|
||||
text = text.replace("{bcvDir}", BCVDir.getAbsolutePath());
|
||||
text = text.replace("{python}", Configuration.python2 + " " + (Configuration.python2Extra ? "-2" : ""));
|
||||
text = text.replace("{python3}", Configuration.python3 + " " + (Configuration.python3Extra ? "-3" : ""));
|
||||
text = text.replace("{rt}", Configuration.rt);
|
||||
text = text.replace("{lib}", Configuration.library);
|
||||
text = text.replace("{krakatauVersion}", krakatauVersion);
|
||||
text = text.replace("{krakatauDir}", krakatauWorkingDirectory);
|
||||
text = text.replace("{enjarifyVersion}", enjarifyVersion);
|
||||
text = text.replace("{enjarifyDir}", enjarifyWorkingDirectory);
|
||||
|
||||
pane.setText(text);
|
||||
pane.setCaretPosition(0);
|
||||
|
||||
return pane;
|
||||
}
|
||||
|
||||
public static String convertStreamToString(InputStream is) throws IOException
|
||||
{
|
||||
if (is == null)
|
||||
return null;
|
||||
try (InputStream stream = is; Scanner s = new Scanner(stream, "UTF-8").useDelimiter("\\A"))
|
||||
{
|
||||
return s.hasNext() ? s.next() : "";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,9 +18,8 @@
|
|||
|
||||
package the.bytecode.club.bytecodeviewer.gui.components;
|
||||
|
||||
import java.awt.Image;
|
||||
import javax.swing.ImageIcon;
|
||||
import javax.swing.JLabel;
|
||||
import javax.swing.*;
|
||||
import java.awt.*;
|
||||
|
||||
/**
|
||||
* Display an image on a JLabel element
|
||||
|
@ -30,8 +29,8 @@ import javax.swing.JLabel;
|
|||
*/
|
||||
public class ImageJLabel extends JLabel
|
||||
{
|
||||
public ImageJLabel(Image image)
|
||||
{
|
||||
super("", new ImageIcon(image), JLabel.CENTER);
|
||||
}
|
||||
public ImageJLabel(Image image)
|
||||
{
|
||||
super("", new ImageIcon(image), JLabel.CENTER);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,13 +18,13 @@
|
|||
|
||||
package the.bytecode.club.bytecodeviewer.gui.components;
|
||||
|
||||
import java.awt.BorderLayout;
|
||||
import java.awt.Dimension;
|
||||
import java.io.File;
|
||||
import javax.swing.JFrame;
|
||||
import me.konloch.kontainer.io.DiskWriter;
|
||||
import the.bytecode.club.bytecodeviewer.resources.IconResources;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.awt.*;
|
||||
import java.io.File;
|
||||
|
||||
import static the.bytecode.club.bytecodeviewer.Constants.tempDirectory;
|
||||
|
||||
/**
|
||||
|
@ -35,127 +35,122 @@ import static the.bytecode.club.bytecodeviewer.Constants.tempDirectory;
|
|||
*/
|
||||
public class JFrameConsole extends JFrame
|
||||
{
|
||||
private String containerName;
|
||||
private int consoleID;
|
||||
private final SearchableJTextArea textArea;
|
||||
|
||||
public JFrameConsole()
|
||||
{
|
||||
this("");
|
||||
}
|
||||
|
||||
public JFrameConsole(String title)
|
||||
{
|
||||
setIconImages(IconResources.iconList);
|
||||
setTitle(title);
|
||||
setSize(new Dimension(542, 316));
|
||||
|
||||
textArea = new SearchableJTextArea();
|
||||
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(trimConsoleText(t));
|
||||
textArea.setCaretPosition(0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the SearchableJTextArea pane
|
||||
*/
|
||||
public SearchableJTextArea getTextArea()
|
||||
{
|
||||
return textArea;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the console ID
|
||||
*/
|
||||
public int getConsoleID()
|
||||
{
|
||||
return consoleID;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current container name
|
||||
*/
|
||||
public String getContainerName()
|
||||
{
|
||||
return containerName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the console ID
|
||||
*/
|
||||
public void setConsoleID(int consoleID)
|
||||
{
|
||||
this.consoleID = consoleID;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the container name
|
||||
*/
|
||||
public void setContainerName(String containerName)
|
||||
{
|
||||
this.containerName = containerName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Trims the console text to prevent killing the swing thread
|
||||
*/
|
||||
public String trimConsoleText(String s)
|
||||
{
|
||||
int len = s.length();
|
||||
|
||||
//TODO this should also be a setting eventually
|
||||
int max = 500_000;
|
||||
if(len >= max)
|
||||
{
|
||||
//TODO if two consoles are ran at the same time and exceed the maximum this file will be overwritten
|
||||
|
||||
final File tempFile = new File(tempDirectory, "console_" + consoleID + ".log");
|
||||
|
||||
//TODO this needs to be rewritten, it doesn't work for a plugin that causes multiple exception UIs
|
||||
new Thread(()->
|
||||
{
|
||||
//save to disk
|
||||
DiskWriter.replaceFile(tempFile.getAbsolutePath(), s, false);
|
||||
}, "Console Log Saving").start();
|
||||
|
||||
//trim
|
||||
int skipped = len - max;
|
||||
String trimmed = s.substring(0, max);
|
||||
|
||||
if(!trimmed.startsWith("WARNING: Skipping"))
|
||||
trimmed = ("WARNING: Skipping " + skipped + " chars, allowing " + max + "\n\r")
|
||||
+ "Full log saved to: " + tempFile.getAbsolutePath() + "\n\r\n\r"
|
||||
+ trimmed;
|
||||
|
||||
return trimmed;
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
private static final long serialVersionUID = -5056940543411437508L;
|
||||
private String containerName;
|
||||
private int consoleID;
|
||||
private final SearchableJTextArea textArea;
|
||||
|
||||
public JFrameConsole()
|
||||
{
|
||||
this("");
|
||||
}
|
||||
|
||||
public JFrameConsole(String title)
|
||||
{
|
||||
setIconImages(IconResources.iconList);
|
||||
setTitle(title);
|
||||
setSize(new Dimension(542, 316));
|
||||
|
||||
textArea = new SearchableJTextArea();
|
||||
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(trimConsoleText(t));
|
||||
textArea.setCaretPosition(0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the SearchableJTextArea pane
|
||||
*/
|
||||
public SearchableJTextArea getTextArea()
|
||||
{
|
||||
return textArea;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the console ID
|
||||
*/
|
||||
public int getConsoleID()
|
||||
{
|
||||
return consoleID;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current container name
|
||||
*/
|
||||
public String getContainerName()
|
||||
{
|
||||
return containerName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the console ID
|
||||
*/
|
||||
public void setConsoleID(int consoleID)
|
||||
{
|
||||
this.consoleID = consoleID;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the container name
|
||||
*/
|
||||
public void setContainerName(String containerName)
|
||||
{
|
||||
this.containerName = containerName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Trims the console text to prevent killing the swing thread
|
||||
*/
|
||||
public String trimConsoleText(String s)
|
||||
{
|
||||
int len = s.length();
|
||||
|
||||
//TODO this should also be a setting eventually
|
||||
int max = 500_000;
|
||||
if (len >= max)
|
||||
{
|
||||
//TODO if two consoles are ran at the same time and exceed the maximum this file will be overwritten
|
||||
|
||||
final File tempFile = new File(tempDirectory, "console_" + consoleID + ".log");
|
||||
|
||||
//TODO this needs to be rewritten, it doesn't work for a plugin that causes multiple exception UIs
|
||||
new Thread(() ->
|
||||
{
|
||||
//save to disk
|
||||
DiskWriter.replaceFile(tempFile.getAbsolutePath(), s, false);
|
||||
}, "Console Log Saving").start();
|
||||
|
||||
//trim
|
||||
int skipped = len - max;
|
||||
String trimmed = s.substring(0, max);
|
||||
|
||||
if (!trimmed.startsWith("WARNING: Skipping"))
|
||||
trimmed = ("WARNING: Skipping " + skipped + " chars, allowing " + max + "\n\r") + "Full log saved to: " + tempFile.getAbsolutePath() + "\n\r\n\r" + trimmed;
|
||||
|
||||
return trimmed;
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
private static final long serialVersionUID = -5056940543411437508L;
|
||||
}
|
||||
|
|
|
@ -18,10 +18,11 @@
|
|||
|
||||
package the.bytecode.club.bytecodeviewer.gui.components;
|
||||
|
||||
import java.io.PrintStream;
|
||||
import javax.swing.SwingUtilities;
|
||||
import the.bytecode.club.bytecodeviewer.Constants;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.io.PrintStream;
|
||||
|
||||
import static the.bytecode.club.bytecodeviewer.Constants.nl;
|
||||
|
||||
/**
|
||||
|
@ -32,110 +33,114 @@ import static the.bytecode.club.bytecodeviewer.Constants.nl;
|
|||
*/
|
||||
public class JFrameConsolePrintStream extends JFrameConsole
|
||||
{
|
||||
private final JTextAreaOutputStream textAreaOutputStreamOut;
|
||||
private final JTextAreaOutputStream textAreaOutputStreamErr;
|
||||
private Thread updateThread;
|
||||
private boolean finished;
|
||||
private long lastUpdate = 0;
|
||||
|
||||
public JFrameConsolePrintStream(String title)
|
||||
{
|
||||
this(title, true);
|
||||
}
|
||||
|
||||
public JFrameConsolePrintStream(String title, boolean preserveOriginalOutput)
|
||||
{
|
||||
super(title);
|
||||
|
||||
textAreaOutputStreamOut = new JTextAreaOutputStream(getTextArea(), preserveOriginalOutput ? System.out : null);
|
||||
textAreaOutputStreamErr = new JTextAreaOutputStream(getTextArea(), preserveOriginalOutput ? System.err : null);
|
||||
|
||||
System.setOut(new PrintStream(textAreaOutputStreamOut));
|
||||
System.setErr(new PrintStream(textAreaOutputStreamErr));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setVisible(boolean b)
|
||||
{
|
||||
super.setVisible(b);
|
||||
|
||||
if(b && updateThread == null)
|
||||
{
|
||||
updateThread = new Thread(() ->
|
||||
{
|
||||
while (isVisible() && !finished)
|
||||
{
|
||||
update();
|
||||
|
||||
try {
|
||||
Thread.sleep(10);
|
||||
} catch (InterruptedException ignored) { }
|
||||
}
|
||||
|
||||
lastUpdate = 0;
|
||||
update();
|
||||
}, "Lazy Console Update");
|
||||
|
||||
updateThread.start();
|
||||
}
|
||||
}
|
||||
|
||||
public void finished()
|
||||
{
|
||||
finished = true;
|
||||
System.setErr(Constants.ERR);
|
||||
System.setOut(Constants.OUT);
|
||||
}
|
||||
|
||||
public JTextAreaOutputStream getTextAreaOutputStreamErr()
|
||||
{
|
||||
return textAreaOutputStreamErr;
|
||||
}
|
||||
|
||||
public JTextAreaOutputStream getTextAreaOutputStreamOut()
|
||||
{
|
||||
return textAreaOutputStreamOut;
|
||||
}
|
||||
|
||||
private void update()
|
||||
{
|
||||
if(System.currentTimeMillis()-lastUpdate <= 50)
|
||||
return;
|
||||
|
||||
lastUpdate = System.currentTimeMillis();
|
||||
|
||||
//update only if required
|
||||
if(textAreaOutputStreamErr.noUpdateRequired() && textAreaOutputStreamOut.noUpdateRequired())
|
||||
return;
|
||||
|
||||
SwingUtilities.invokeLater(()->
|
||||
{
|
||||
//print output to the pane
|
||||
textAreaOutputStreamOut.update();
|
||||
|
||||
//print error to the pane
|
||||
textAreaOutputStreamErr.update();
|
||||
|
||||
//reformat the pane
|
||||
String content = getTextArea().getText();
|
||||
if(content.contains("File `"))
|
||||
{
|
||||
String[] test = content.split("\r?\n");
|
||||
|
||||
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());
|
||||
}
|
||||
});
|
||||
}
|
||||
private final JTextAreaOutputStream textAreaOutputStreamOut;
|
||||
private final JTextAreaOutputStream textAreaOutputStreamErr;
|
||||
private Thread updateThread;
|
||||
private boolean finished;
|
||||
private long lastUpdate = 0;
|
||||
|
||||
public JFrameConsolePrintStream(String title)
|
||||
{
|
||||
this(title, true);
|
||||
}
|
||||
|
||||
public JFrameConsolePrintStream(String title, boolean preserveOriginalOutput)
|
||||
{
|
||||
super(title);
|
||||
|
||||
textAreaOutputStreamOut = new JTextAreaOutputStream(getTextArea(), preserveOriginalOutput ? System.out : null);
|
||||
textAreaOutputStreamErr = new JTextAreaOutputStream(getTextArea(), preserveOriginalOutput ? System.err : null);
|
||||
|
||||
System.setOut(new PrintStream(textAreaOutputStreamOut));
|
||||
System.setErr(new PrintStream(textAreaOutputStreamErr));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setVisible(boolean b)
|
||||
{
|
||||
super.setVisible(b);
|
||||
|
||||
if (b && updateThread == null)
|
||||
{
|
||||
updateThread = new Thread(() ->
|
||||
{
|
||||
while (isVisible() && !finished)
|
||||
{
|
||||
update();
|
||||
|
||||
try
|
||||
{
|
||||
Thread.sleep(10);
|
||||
}
|
||||
catch (InterruptedException ignored)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
lastUpdate = 0;
|
||||
update();
|
||||
}, "Lazy Console Update");
|
||||
|
||||
updateThread.start();
|
||||
}
|
||||
}
|
||||
|
||||
public void finished()
|
||||
{
|
||||
finished = true;
|
||||
System.setErr(Constants.ERR);
|
||||
System.setOut(Constants.OUT);
|
||||
}
|
||||
|
||||
public JTextAreaOutputStream getTextAreaOutputStreamErr()
|
||||
{
|
||||
return textAreaOutputStreamErr;
|
||||
}
|
||||
|
||||
public JTextAreaOutputStream getTextAreaOutputStreamOut()
|
||||
{
|
||||
return textAreaOutputStreamOut;
|
||||
}
|
||||
|
||||
private void update()
|
||||
{
|
||||
if (System.currentTimeMillis() - lastUpdate <= 50)
|
||||
return;
|
||||
|
||||
lastUpdate = System.currentTimeMillis();
|
||||
|
||||
//update only if required
|
||||
if (textAreaOutputStreamErr.noUpdateRequired() && textAreaOutputStreamOut.noUpdateRequired())
|
||||
return;
|
||||
|
||||
SwingUtilities.invokeLater(() ->
|
||||
{
|
||||
//print output to the pane
|
||||
textAreaOutputStreamOut.update();
|
||||
|
||||
//print error to the pane
|
||||
textAreaOutputStreamErr.update();
|
||||
|
||||
//reformat the pane
|
||||
String content = getTextArea().getText();
|
||||
if (content.contains("File `"))
|
||||
{
|
||||
String[] test = content.split("\r?\n");
|
||||
|
||||
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());
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,13 +18,11 @@
|
|||
|
||||
package the.bytecode.club.bytecodeviewer.gui.components;
|
||||
|
||||
import java.awt.BorderLayout;
|
||||
import java.awt.Component;
|
||||
import java.awt.Dimension;
|
||||
import javax.swing.JFrame;
|
||||
import javax.swing.JTabbedPane;
|
||||
import the.bytecode.club.bytecodeviewer.resources.IconResources;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.awt.*;
|
||||
|
||||
/**
|
||||
* @author Konloch
|
||||
* @since 7/14/2021
|
||||
|
@ -32,27 +30,27 @@ import the.bytecode.club.bytecodeviewer.resources.IconResources;
|
|||
|
||||
public class JFrameConsoleTabbed extends JFrame
|
||||
{
|
||||
private final JTabbedPane tabbedPane;
|
||||
|
||||
public JFrameConsoleTabbed(String title)
|
||||
{
|
||||
setIconImages(IconResources.iconList);
|
||||
setTitle(title);
|
||||
setSize(new Dimension(542, 316));
|
||||
|
||||
tabbedPane = new JTabbedPane();
|
||||
getContentPane().add(tabbedPane, BorderLayout.CENTER);
|
||||
|
||||
this.setLocationRelativeTo(null);
|
||||
}
|
||||
|
||||
public void addConsole(Component console, String containerName)
|
||||
{
|
||||
tabbedPane.add(console, containerName);
|
||||
}
|
||||
|
||||
public JTabbedPane getTabbedPane()
|
||||
{
|
||||
return tabbedPane;
|
||||
}
|
||||
private final JTabbedPane tabbedPane;
|
||||
|
||||
public JFrameConsoleTabbed(String title)
|
||||
{
|
||||
setIconImages(IconResources.iconList);
|
||||
setTitle(title);
|
||||
setSize(new Dimension(542, 316));
|
||||
|
||||
tabbedPane = new JTabbedPane();
|
||||
getContentPane().add(tabbedPane, BorderLayout.CENTER);
|
||||
|
||||
this.setLocationRelativeTo(null);
|
||||
}
|
||||
|
||||
public void addConsole(Component console, String containerName)
|
||||
{
|
||||
tabbedPane.add(console, containerName);
|
||||
}
|
||||
|
||||
public JTabbedPane getTabbedPane()
|
||||
{
|
||||
return tabbedPane;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,11 +18,8 @@
|
|||
|
||||
package the.bytecode.club.bytecodeviewer.gui.components;
|
||||
|
||||
import java.awt.Dimension;
|
||||
import java.awt.Graphics;
|
||||
import javax.swing.Icon;
|
||||
import javax.swing.JMenuItem;
|
||||
import javax.swing.UIManager;
|
||||
import javax.swing.*;
|
||||
import java.awt.*;
|
||||
|
||||
/**
|
||||
* @author Konloch
|
||||
|
@ -30,24 +27,24 @@ import javax.swing.UIManager;
|
|||
*/
|
||||
public class JMenuItemIcon extends JMenuItem
|
||||
{
|
||||
public JMenuItemIcon(Icon icon)
|
||||
{
|
||||
super("");
|
||||
|
||||
setIcon(icon);
|
||||
setAlignmentY(0.65f);
|
||||
Dimension size = new Dimension((int) (icon.getIconWidth()*1.4), icon.getIconHeight());
|
||||
setSize(size);
|
||||
setPreferredSize(size);
|
||||
setMinimumSize(size);
|
||||
setMaximumSize(size);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void paint(Graphics g)
|
||||
{
|
||||
g.setColor(UIManager.getColor("Panel.background"));
|
||||
g.fillRect(0, 0, getWidth(), getHeight());
|
||||
super.paint(g);
|
||||
}
|
||||
public JMenuItemIcon(Icon icon)
|
||||
{
|
||||
super("");
|
||||
|
||||
setIcon(icon);
|
||||
setAlignmentY(0.65f);
|
||||
Dimension size = new Dimension((int) (icon.getIconWidth() * 1.4), icon.getIconHeight());
|
||||
setSize(size);
|
||||
setPreferredSize(size);
|
||||
setMinimumSize(size);
|
||||
setMaximumSize(size);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void paint(Graphics g)
|
||||
{
|
||||
g.setColor(UIManager.getColor("Panel.background"));
|
||||
g.fillRect(0, 0, getWidth(), getHeight());
|
||||
super.paint(g);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,10 +18,10 @@
|
|||
|
||||
package the.bytecode.club.bytecodeviewer.gui.components;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.io.Closeable;
|
||||
import java.io.OutputStream;
|
||||
import java.io.PrintStream;
|
||||
import javax.swing.JTextArea;
|
||||
|
||||
/**
|
||||
* @author Konloch
|
||||
|
@ -29,43 +29,44 @@ import javax.swing.JTextArea;
|
|||
*/
|
||||
public class JTextAreaOutputStream extends OutputStream implements Closeable
|
||||
{
|
||||
private StringBuilder sb = new StringBuilder();
|
||||
private final JTextArea textArea;
|
||||
private final PrintStream og;
|
||||
|
||||
public JTextAreaOutputStream(JTextArea textArea, PrintStream og)
|
||||
{
|
||||
this.textArea = textArea;
|
||||
this.og = og;
|
||||
}
|
||||
|
||||
public boolean noUpdateRequired()
|
||||
{
|
||||
return sb.length() <= 0;
|
||||
}
|
||||
|
||||
public void update()
|
||||
{
|
||||
textArea.append(sb.toString());
|
||||
sb = new StringBuilder();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(int b)
|
||||
{
|
||||
sb.append((char) b);
|
||||
if(og != null)
|
||||
og.write(b);
|
||||
}
|
||||
|
||||
public StringBuilder getBuffer()
|
||||
{
|
||||
return sb;
|
||||
}
|
||||
private StringBuilder sb = new StringBuilder();
|
||||
private final JTextArea textArea;
|
||||
private final PrintStream og;
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
if (og != null)
|
||||
og.close();
|
||||
}
|
||||
public JTextAreaOutputStream(JTextArea textArea, PrintStream og)
|
||||
{
|
||||
this.textArea = textArea;
|
||||
this.og = og;
|
||||
}
|
||||
|
||||
public boolean noUpdateRequired()
|
||||
{
|
||||
return sb.length() <= 0;
|
||||
}
|
||||
|
||||
public void update()
|
||||
{
|
||||
textArea.append(sb.toString());
|
||||
sb = new StringBuilder();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(int b)
|
||||
{
|
||||
sb.append((char) b);
|
||||
if (og != null)
|
||||
og.write(b);
|
||||
}
|
||||
|
||||
public StringBuilder getBuffer()
|
||||
{
|
||||
return sb;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close()
|
||||
{
|
||||
if (og != null)
|
||||
og.close();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,8 +18,8 @@
|
|||
|
||||
package the.bytecode.club.bytecodeviewer.gui.components;
|
||||
|
||||
import java.awt.Dimension;
|
||||
import javax.swing.JLabel;
|
||||
import javax.swing.*;
|
||||
import java.awt.*;
|
||||
|
||||
/**
|
||||
* @author Konloch
|
||||
|
@ -27,25 +27,25 @@ import javax.swing.JLabel;
|
|||
*/
|
||||
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;
|
||||
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;
|
||||
}
|
||||
|
|
|
@ -18,16 +18,14 @@
|
|||
|
||||
package the.bytecode.club.bytecodeviewer.gui.components;
|
||||
|
||||
import java.awt.Component;
|
||||
import java.util.List;
|
||||
import javax.swing.JLabel;
|
||||
import javax.swing.JList;
|
||||
import javax.swing.ListCellRenderer;
|
||||
|
||||
import the.bytecode.club.bytecodeviewer.gui.resourceviewer.BytecodeViewPanel;
|
||||
import the.bytecode.club.bytecodeviewer.gui.util.BytecodeViewPanelUpdater;
|
||||
import the.bytecode.club.bytecodeviewer.util.MethodParser;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.awt.*;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author Konloch
|
||||
* @author Waterwolf
|
||||
|
@ -35,29 +33,31 @@ import the.bytecode.club.bytecodeviewer.util.MethodParser;
|
|||
*/
|
||||
public class MethodsRenderer extends JLabel implements ListCellRenderer<Object>
|
||||
{
|
||||
private final BytecodeViewPanelUpdater bytecodeViewPanelUpdater;
|
||||
|
||||
public MethodsRenderer(BytecodeViewPanelUpdater bytecodeViewPanelUpdater)
|
||||
{
|
||||
this.bytecodeViewPanelUpdater = bytecodeViewPanelUpdater;
|
||||
setOpaque(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Component getListCellRendererComponent(JList<?> list, Object value, int index, boolean isSelected,
|
||||
boolean cellHasFocus)
|
||||
{
|
||||
int methodIndex = (Integer) value;
|
||||
MethodParser methods;
|
||||
List<MethodParser> methodParsers = bytecodeViewPanelUpdater.viewer.methods;
|
||||
BytecodeViewPanel bytecodeViewPanel = bytecodeViewPanelUpdater.bytecodeViewPanel;
|
||||
try {
|
||||
methods = methodParsers.get(bytecodeViewPanel.decompiler.ordinal());
|
||||
} catch (ArrayIndexOutOfBoundsException e) {
|
||||
methods = methodParsers.get(bytecodeViewPanel.panelIndex);
|
||||
}
|
||||
MethodParser.Method method = methods.getMethod(methodIndex);
|
||||
setText(method.toString());
|
||||
return this;
|
||||
}
|
||||
private final BytecodeViewPanelUpdater bytecodeViewPanelUpdater;
|
||||
|
||||
public MethodsRenderer(BytecodeViewPanelUpdater bytecodeViewPanelUpdater)
|
||||
{
|
||||
this.bytecodeViewPanelUpdater = bytecodeViewPanelUpdater;
|
||||
setOpaque(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Component getListCellRendererComponent(JList<?> list, Object value, int index, boolean isSelected, boolean cellHasFocus)
|
||||
{
|
||||
int methodIndex = (Integer) value;
|
||||
MethodParser methods;
|
||||
List<MethodParser> methodParsers = bytecodeViewPanelUpdater.viewer.methods;
|
||||
BytecodeViewPanel bytecodeViewPanel = bytecodeViewPanelUpdater.bytecodeViewPanel;
|
||||
try
|
||||
{
|
||||
methods = methodParsers.get(bytecodeViewPanel.decompiler.ordinal());
|
||||
}
|
||||
catch (ArrayIndexOutOfBoundsException e)
|
||||
{
|
||||
methods = methodParsers.get(bytecodeViewPanel.panelIndex);
|
||||
}
|
||||
MethodParser.Method method = methods.getMethod(methodIndex);
|
||||
setText(method.toString());
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,39 +18,39 @@
|
|||
|
||||
package the.bytecode.club.bytecodeviewer.gui.components;
|
||||
|
||||
import javax.swing.JDialog;
|
||||
import javax.swing.JOptionPane;
|
||||
import the.bytecode.club.bytecodeviewer.BytecodeViewer;
|
||||
|
||||
import javax.swing.*;
|
||||
|
||||
/**
|
||||
* @author Konloch
|
||||
* @since 6/26/2021
|
||||
*/
|
||||
public class MultipleChoiceDialog
|
||||
{
|
||||
private final String title;
|
||||
private final String description;
|
||||
private final String[] options;
|
||||
|
||||
public MultipleChoiceDialog(String title, String description, String[] options)
|
||||
{
|
||||
this.title = title;
|
||||
this.description = description;
|
||||
this.options = options;
|
||||
}
|
||||
|
||||
public int promptChoice()
|
||||
{
|
||||
JOptionPane pane = new JOptionPane(description);
|
||||
pane.setOptions(options);
|
||||
JDialog dialog = pane.createDialog(BytecodeViewer.viewer, title);
|
||||
dialog.setVisible(true);
|
||||
Object obj = pane.getValue();
|
||||
int result = -1;
|
||||
for (int k = 0; k < options.length; k++)
|
||||
if (options[k].equals(obj))
|
||||
result = k;
|
||||
|
||||
return result;
|
||||
}
|
||||
private final String title;
|
||||
private final String description;
|
||||
private final String[] options;
|
||||
|
||||
public MultipleChoiceDialog(String title, String description, String[] options)
|
||||
{
|
||||
this.title = title;
|
||||
this.description = description;
|
||||
this.options = options;
|
||||
}
|
||||
|
||||
public int promptChoice()
|
||||
{
|
||||
JOptionPane pane = new JOptionPane(description);
|
||||
pane.setOptions(options);
|
||||
JDialog dialog = pane.createDialog(BytecodeViewer.viewer, title);
|
||||
dialog.setVisible(true);
|
||||
Object obj = pane.getValue();
|
||||
int result = -1;
|
||||
for (int k = 0; k < options.length; k++)
|
||||
if (options[k].equals(obj))
|
||||
result = k;
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -50,369 +50,375 @@ import java.util.Map;
|
|||
*/
|
||||
public class MyErrorStripe extends JPanel
|
||||
{
|
||||
private final RSyntaxTextArea textArea;
|
||||
private final transient Listener listener;
|
||||
private final RSyntaxTextArea textArea;
|
||||
private final transient Listener listener;
|
||||
|
||||
public MyErrorStripe(RSyntaxTextArea textArea)
|
||||
{
|
||||
this.textArea = textArea;
|
||||
setLayout(null);
|
||||
listener = new Listener();
|
||||
addMouseListener(listener);
|
||||
}
|
||||
public MyErrorStripe(RSyntaxTextArea textArea)
|
||||
{
|
||||
this.textArea = textArea;
|
||||
setLayout(null);
|
||||
listener = new Listener();
|
||||
addMouseListener(listener);
|
||||
}
|
||||
|
||||
private int lineToY(int line, Rectangle r)
|
||||
{
|
||||
if (r == null)
|
||||
r = new Rectangle();
|
||||
private int lineToY(int line, Rectangle r)
|
||||
{
|
||||
if (r == null)
|
||||
r = new Rectangle();
|
||||
|
||||
textArea.computeVisibleRect(r);
|
||||
int h = r.height;
|
||||
float lineCount = textArea.getLineCount();
|
||||
int lineHeight = textArea.getLineHeight();
|
||||
int linesPerVisibleRect = h / lineHeight;
|
||||
return Math.round((h - 1) * line / Math.max(lineCount, linesPerVisibleRect));
|
||||
}
|
||||
textArea.computeVisibleRect(r);
|
||||
int h = r.height;
|
||||
float lineCount = textArea.getLineCount();
|
||||
int lineHeight = textArea.getLineHeight();
|
||||
int linesPerVisibleRect = h / lineHeight;
|
||||
return Math.round((h - 1) * line / Math.max(lineCount, linesPerVisibleRect));
|
||||
}
|
||||
|
||||
private int yToLine(int y)
|
||||
{
|
||||
int line = -1;
|
||||
int h = textArea.getVisibleRect().height;
|
||||
int lineHeight = textArea.getLineHeight();
|
||||
int linesPerVisibleRect = h / lineHeight;
|
||||
int lineCount = textArea.getLineCount();
|
||||
if (y < h)
|
||||
{
|
||||
float at = y / (float) h;
|
||||
line = Math.round((Math.max(lineCount, linesPerVisibleRect) - 1) * at);
|
||||
}
|
||||
private int yToLine(int y)
|
||||
{
|
||||
int line = -1;
|
||||
int h = textArea.getVisibleRect().height;
|
||||
int lineHeight = textArea.getLineHeight();
|
||||
int linesPerVisibleRect = h / lineHeight;
|
||||
int lineCount = textArea.getLineCount();
|
||||
if (y < h)
|
||||
{
|
||||
float at = y / (float) h;
|
||||
line = Math.round((Math.max(lineCount, linesPerVisibleRect) - 1) * at);
|
||||
}
|
||||
|
||||
return line;
|
||||
}
|
||||
return line;
|
||||
}
|
||||
|
||||
private void paintParserNoticeMarker(Graphics2D g, ParserNotice notice, int width, int height)
|
||||
{
|
||||
Color borderColor = notice.getColor();
|
||||
if (borderColor == null)
|
||||
borderColor = Color.BLACK;
|
||||
private void paintParserNoticeMarker(Graphics2D g, ParserNotice notice, int width, int height)
|
||||
{
|
||||
Color borderColor = notice.getColor();
|
||||
if (borderColor == null)
|
||||
borderColor = Color.BLACK;
|
||||
|
||||
Color fillColor = borderColor.brighter();
|
||||
g.setColor(fillColor);
|
||||
g.fillRect(0, 0, width, height);
|
||||
Color fillColor = borderColor.brighter();
|
||||
g.setColor(fillColor);
|
||||
g.fillRect(0, 0, width, height);
|
||||
|
||||
g.setColor(borderColor);
|
||||
g.drawRect(0, 0, width - 1, height - 1);
|
||||
}
|
||||
g.setColor(borderColor);
|
||||
g.drawRect(0, 0, width - 1, height - 1);
|
||||
}
|
||||
|
||||
public void refreshMarkers()
|
||||
{
|
||||
removeAll();
|
||||
Map<Integer, Marker> markerMap = new HashMap<>();
|
||||
List<DocumentRange> occurrences = textArea.getMarkedOccurrences();
|
||||
addMarkersForRanges(occurrences, markerMap, textArea.getMarkOccurrencesColor());
|
||||
revalidate();
|
||||
repaint();
|
||||
}
|
||||
public void refreshMarkers()
|
||||
{
|
||||
removeAll();
|
||||
Map<Integer, Marker> markerMap = new HashMap<>();
|
||||
List<DocumentRange> occurrences = textArea.getMarkedOccurrences();
|
||||
addMarkersForRanges(occurrences, markerMap, textArea.getMarkOccurrencesColor());
|
||||
revalidate();
|
||||
repaint();
|
||||
}
|
||||
|
||||
private void addMarkersForRanges(List<DocumentRange> occurrences, Map<Integer, Marker> markerMap, Color color)
|
||||
{
|
||||
for (DocumentRange range : occurrences)
|
||||
{
|
||||
int line;
|
||||
try
|
||||
{
|
||||
line = textArea.getLineOfOffset(range.getStartOffset());
|
||||
} catch (BadLocationException e)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
private void addMarkersForRanges(List<DocumentRange> occurrences, Map<Integer, Marker> markerMap, Color color)
|
||||
{
|
||||
for (DocumentRange range : occurrences)
|
||||
{
|
||||
int line;
|
||||
try
|
||||
{
|
||||
line = textArea.getLineOfOffset(range.getStartOffset());
|
||||
}
|
||||
catch (BadLocationException e)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
ParserNotice notice = new MarkedOccurrenceNotice(range, color);
|
||||
Integer key = line;
|
||||
Marker m = markerMap.get(key);
|
||||
if (m == null)
|
||||
{
|
||||
m = new Marker(notice);
|
||||
m.addMouseListener(listener);
|
||||
markerMap.put(key, m);
|
||||
add(m);
|
||||
} else
|
||||
{
|
||||
if (!m.containsMarkedOccurrence())
|
||||
m.addNotice(notice);
|
||||
}
|
||||
}
|
||||
}
|
||||
ParserNotice notice = new MarkedOccurrenceNotice(range, color);
|
||||
Integer key = line;
|
||||
Marker m = markerMap.get(key);
|
||||
if (m == null)
|
||||
{
|
||||
m = new Marker(notice);
|
||||
m.addMouseListener(listener);
|
||||
markerMap.put(key, m);
|
||||
add(m);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!m.containsMarkedOccurrence())
|
||||
m.addNotice(notice);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateUI()
|
||||
{
|
||||
super.updateUI();
|
||||
}
|
||||
@Override
|
||||
public void updateUI()
|
||||
{
|
||||
super.updateUI();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void paintComponent(Graphics g)
|
||||
{
|
||||
super.paintComponent(g);
|
||||
}
|
||||
@Override
|
||||
protected void paintComponent(Graphics g)
|
||||
{
|
||||
super.paintComponent(g);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void paintChildren(Graphics g)
|
||||
{
|
||||
super.paintChildren(g);
|
||||
}
|
||||
@Override
|
||||
protected void paintChildren(Graphics g)
|
||||
{
|
||||
super.paintChildren(g);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Dimension getPreferredSize()
|
||||
{
|
||||
return new Dimension(14, textArea.getPreferredScrollableViewportSize().height);
|
||||
}
|
||||
@Override
|
||||
public Dimension getPreferredSize()
|
||||
{
|
||||
return new Dimension(14, textArea.getPreferredScrollableViewportSize().height);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doLayout()
|
||||
{
|
||||
for (int i = 0; i < getComponentCount(); i++)
|
||||
{
|
||||
Marker m = (Marker) getComponent(i);
|
||||
m.updateLocation();
|
||||
}
|
||||
}
|
||||
@Override
|
||||
public void doLayout()
|
||||
{
|
||||
for (int i = 0; i < getComponentCount(); i++)
|
||||
{
|
||||
Marker m = (Marker) getComponent(i);
|
||||
m.updateLocation();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addNotify()
|
||||
{
|
||||
super.addNotify();
|
||||
refreshMarkers();
|
||||
}
|
||||
@Override
|
||||
public void addNotify()
|
||||
{
|
||||
super.addNotify();
|
||||
refreshMarkers();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeNotify()
|
||||
{
|
||||
super.removeNotify();
|
||||
}
|
||||
@Override
|
||||
public void removeNotify()
|
||||
{
|
||||
super.removeNotify();
|
||||
}
|
||||
|
||||
private class Listener extends MouseAdapter
|
||||
{
|
||||
private final Rectangle r = new Rectangle();
|
||||
private class Listener extends MouseAdapter
|
||||
{
|
||||
private final Rectangle r = new Rectangle();
|
||||
|
||||
@Override
|
||||
public void mouseClicked(@NotNull MouseEvent e)
|
||||
{
|
||||
Component source = (Component) e.getSource();
|
||||
if (source instanceof MyErrorStripe.Marker)
|
||||
{
|
||||
Marker m = (Marker) source;
|
||||
m.mouseClicked(e);
|
||||
return;
|
||||
}
|
||||
@Override
|
||||
public void mouseClicked(@NotNull MouseEvent e)
|
||||
{
|
||||
Component source = (Component) e.getSource();
|
||||
if (source instanceof MyErrorStripe.Marker)
|
||||
{
|
||||
Marker m = (Marker) source;
|
||||
m.mouseClicked(e);
|
||||
return;
|
||||
}
|
||||
|
||||
int line = yToLine(e.getY());
|
||||
if (line > -1)
|
||||
{
|
||||
try
|
||||
{
|
||||
int offset = textArea.getLineOfOffset(line);
|
||||
textArea.setCaretPosition(offset);
|
||||
RSyntaxUtilities.selectAndPossiblyCenter(textArea, new DocumentRange(offset, offset), false);
|
||||
} catch (BadLocationException exception)
|
||||
{
|
||||
UIManager.getLookAndFeel().provideErrorFeedback(textArea);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
int line = yToLine(e.getY());
|
||||
if (line > -1)
|
||||
{
|
||||
try
|
||||
{
|
||||
int offset = textArea.getLineOfOffset(line);
|
||||
textArea.setCaretPosition(offset);
|
||||
RSyntaxUtilities.selectAndPossiblyCenter(textArea, new DocumentRange(offset, offset), false);
|
||||
}
|
||||
catch (BadLocationException exception)
|
||||
{
|
||||
UIManager.getLookAndFeel().provideErrorFeedback(textArea);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class MarkedOccurrenceNotice implements ParserNotice
|
||||
{
|
||||
private final DocumentRange range;
|
||||
private final Color color;
|
||||
private class MarkedOccurrenceNotice implements ParserNotice
|
||||
{
|
||||
private final DocumentRange range;
|
||||
private final Color color;
|
||||
|
||||
MarkedOccurrenceNotice(DocumentRange range, Color color)
|
||||
{
|
||||
this.range = range;
|
||||
this.color = color;
|
||||
}
|
||||
MarkedOccurrenceNotice(DocumentRange range, Color color)
|
||||
{
|
||||
this.range = range;
|
||||
this.color = color;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsPosition(int pos)
|
||||
{
|
||||
return pos >= range.getStartOffset() && pos < range.getEndOffset();
|
||||
}
|
||||
@Override
|
||||
public boolean containsPosition(int pos)
|
||||
{
|
||||
return pos >= range.getStartOffset() && pos < range.getEndOffset();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Color getColor()
|
||||
{
|
||||
return color;
|
||||
}
|
||||
@Override
|
||||
public Color getColor()
|
||||
{
|
||||
return color;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getLength()
|
||||
{
|
||||
return range.getEndOffset() - range.getStartOffset();
|
||||
}
|
||||
@Override
|
||||
public int getLength()
|
||||
{
|
||||
return range.getEndOffset() - range.getStartOffset();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Level getLevel()
|
||||
{
|
||||
return Level.INFO;
|
||||
}
|
||||
@Override
|
||||
public Level getLevel()
|
||||
{
|
||||
return Level.INFO;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getLine()
|
||||
{
|
||||
try
|
||||
{
|
||||
return textArea.getLineOfOffset(range.getStartOffset()) + 1;
|
||||
} catch (BadLocationException e)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@Override
|
||||
public int getLine()
|
||||
{
|
||||
try
|
||||
{
|
||||
return textArea.getLineOfOffset(range.getStartOffset()) + 1;
|
||||
}
|
||||
catch (BadLocationException e)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean getKnowsOffsetAndLength()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
@Override
|
||||
public boolean getKnowsOffsetAndLength()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
@Contract(pure = true)
|
||||
@Override
|
||||
public @NotNull String getMessage()
|
||||
{
|
||||
return "";
|
||||
}
|
||||
@Contract(pure = true)
|
||||
@Override
|
||||
public @NotNull String getMessage()
|
||||
{
|
||||
return "";
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getOffset()
|
||||
{
|
||||
return range.getStartOffset();
|
||||
}
|
||||
@Override
|
||||
public int getOffset()
|
||||
{
|
||||
return range.getStartOffset();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Parser getParser()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
@Override
|
||||
public Parser getParser()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean getShowInEditor()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
@Override
|
||||
public boolean getShowInEditor()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getToolTipText()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
@Override
|
||||
public String getToolTipText()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(@NotNull ParserNotice o)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
@Override
|
||||
public int compareTo(@NotNull ParserNotice o)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@Override
|
||||
public int hashCode()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
private static final int MARKER_HEIGHT = 3;
|
||||
private static final int MARKER_HEIGHT = 3;
|
||||
|
||||
private class Marker extends JComponent
|
||||
{
|
||||
private final java.util.List<ParserNotice> notices;
|
||||
private class Marker extends JComponent
|
||||
{
|
||||
private final java.util.List<ParserNotice> notices;
|
||||
|
||||
Marker(ParserNotice notice)
|
||||
{
|
||||
notices = new ArrayList<>();
|
||||
addNotice(notice);
|
||||
setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
|
||||
setSize(getPreferredSize());
|
||||
}
|
||||
Marker(ParserNotice notice)
|
||||
{
|
||||
notices = new ArrayList<>();
|
||||
addNotice(notice);
|
||||
setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
|
||||
setSize(getPreferredSize());
|
||||
}
|
||||
|
||||
private void addNotice(ParserNotice notice)
|
||||
{
|
||||
notices.add(notice);
|
||||
}
|
||||
private void addNotice(ParserNotice notice)
|
||||
{
|
||||
notices.add(notice);
|
||||
}
|
||||
|
||||
@Contract(value = " -> new", pure = true)
|
||||
@Override
|
||||
public @NotNull Dimension getPreferredSize()
|
||||
{
|
||||
return new Dimension(12, MARKER_HEIGHT);
|
||||
}
|
||||
@Contract(value = " -> new", pure = true)
|
||||
@Override
|
||||
public @NotNull Dimension getPreferredSize()
|
||||
{
|
||||
return new Dimension(12, MARKER_HEIGHT);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void paintComponent(Graphics g)
|
||||
{
|
||||
final ParserNotice notice = getHighestPriorityNotice();
|
||||
if (notice != null)
|
||||
paintParserNoticeMarker((Graphics2D) g, notice, getWidth(), getHeight());
|
||||
}
|
||||
@Override
|
||||
protected void paintComponent(Graphics g)
|
||||
{
|
||||
final ParserNotice notice = getHighestPriorityNotice();
|
||||
if (notice != null)
|
||||
paintParserNoticeMarker((Graphics2D) g, notice, getWidth(), getHeight());
|
||||
}
|
||||
|
||||
protected void mouseClicked(MouseEvent e)
|
||||
{
|
||||
ParserNotice pn = notices.get(0);
|
||||
int offs = pn.getOffset();
|
||||
int len = pn.getLength();
|
||||
if (offs > -1 && len > -1) // These values are optional
|
||||
{
|
||||
DocumentRange range = new DocumentRange(offs, offs + len);
|
||||
RSyntaxUtilities.selectAndPossiblyCenter(textArea, range, true);
|
||||
} else
|
||||
{
|
||||
int line = pn.getLine();
|
||||
try
|
||||
{
|
||||
offs = textArea.getLineStartOffset(line);
|
||||
textArea.getFoldManager().ensureOffsetNotInClosedFold(offs);
|
||||
textArea.setCaretPosition(offs);
|
||||
} catch (BadLocationException ble) // Never happens
|
||||
{
|
||||
UIManager.getLookAndFeel().provideErrorFeedback(textArea);
|
||||
}
|
||||
}
|
||||
}
|
||||
protected void mouseClicked(MouseEvent e)
|
||||
{
|
||||
ParserNotice pn = notices.get(0);
|
||||
int offs = pn.getOffset();
|
||||
int len = pn.getLength();
|
||||
if (offs > -1 && len > -1) // These values are optional
|
||||
{
|
||||
DocumentRange range = new DocumentRange(offs, offs + len);
|
||||
RSyntaxUtilities.selectAndPossiblyCenter(textArea, range, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
int line = pn.getLine();
|
||||
try
|
||||
{
|
||||
offs = textArea.getLineStartOffset(line);
|
||||
textArea.getFoldManager().ensureOffsetNotInClosedFold(offs);
|
||||
textArea.setCaretPosition(offs);
|
||||
}
|
||||
catch (BadLocationException ble) // Never happens
|
||||
{
|
||||
UIManager.getLookAndFeel().provideErrorFeedback(textArea);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public boolean containsMarkedOccurrence()
|
||||
{
|
||||
boolean result = false;
|
||||
for (ParserNotice notice : notices)
|
||||
{
|
||||
if (notice instanceof MarkedOccurrenceNotice)
|
||||
{
|
||||
result = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
public boolean containsMarkedOccurrence()
|
||||
{
|
||||
boolean result = false;
|
||||
for (ParserNotice notice : notices)
|
||||
{
|
||||
if (notice instanceof MarkedOccurrenceNotice)
|
||||
{
|
||||
result = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public ParserNotice getHighestPriorityNotice()
|
||||
{
|
||||
ParserNotice selectedNotice = null;
|
||||
int lowestLevel = Integer.MAX_VALUE;
|
||||
for (ParserNotice notice : notices)
|
||||
{
|
||||
if (notice.getLevel().getNumericValue() < lowestLevel)
|
||||
{
|
||||
lowestLevel = notice.getLevel().getNumericValue();
|
||||
selectedNotice = notice;
|
||||
}
|
||||
}
|
||||
public ParserNotice getHighestPriorityNotice()
|
||||
{
|
||||
ParserNotice selectedNotice = null;
|
||||
int lowestLevel = Integer.MAX_VALUE;
|
||||
for (ParserNotice notice : notices)
|
||||
{
|
||||
if (notice.getLevel().getNumericValue() < lowestLevel)
|
||||
{
|
||||
lowestLevel = notice.getLevel().getNumericValue();
|
||||
selectedNotice = notice;
|
||||
}
|
||||
}
|
||||
|
||||
return selectedNotice;
|
||||
}
|
||||
return selectedNotice;
|
||||
}
|
||||
|
||||
public void updateLocation()
|
||||
{
|
||||
int line = notices.get(0).getLine();
|
||||
int y = lineToY(line - 1, null);
|
||||
setLocation(2, y);
|
||||
}
|
||||
}
|
||||
public void updateLocation()
|
||||
{
|
||||
int line = notices.get(0).getLine();
|
||||
int y = lineToY(line - 1, null);
|
||||
setLocation(2, y);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -43,90 +43,90 @@ import java.util.List;
|
|||
*/
|
||||
public class RSyntaxTextAreaHighlighterEx extends RSyntaxTextAreaHighlighter
|
||||
{
|
||||
private final List<SyntaxLayeredHighlightInfoImpl> markedOccurrences = new ArrayList<>();
|
||||
private static final Color DEFAULT_PARSER_NOTICE_COLOR = Color.RED;
|
||||
private final List<SyntaxLayeredHighlightInfoImpl> markedOccurrences = new ArrayList<>();
|
||||
private static final Color DEFAULT_PARSER_NOTICE_COLOR = Color.RED;
|
||||
|
||||
public Object addMarkedOccurrenceHighlight(int start, int end, @NotNull SmartHighlightPainter p) throws BadLocationException
|
||||
{
|
||||
Document doc = textArea.getDocument();
|
||||
TextUI mapper = textArea.getUI();
|
||||
// Always layered highlights for marked occurrences.
|
||||
SyntaxLayeredHighlightInfoImpl i = new SyntaxLayeredHighlightInfoImpl();
|
||||
p.setPaint(UIManager.getColor("ScrollBar.thumb"));
|
||||
i.setPainter(p);
|
||||
i.setStartOffset(doc.createPosition(start));
|
||||
// HACK: Use "end-1" to prevent chars the user types at the "end" of
|
||||
// the highlight to be absorbed into the highlight (default Highlight
|
||||
// behavior).
|
||||
i.setEndOffset(doc.createPosition(end - 1));
|
||||
markedOccurrences.add(i);
|
||||
mapper.damageRange(textArea, start, end);
|
||||
return i;
|
||||
}
|
||||
public Object addMarkedOccurrenceHighlight(int start, int end, @NotNull SmartHighlightPainter p) throws BadLocationException
|
||||
{
|
||||
Document doc = textArea.getDocument();
|
||||
TextUI mapper = textArea.getUI();
|
||||
// Always layered highlights for marked occurrences.
|
||||
SyntaxLayeredHighlightInfoImpl i = new SyntaxLayeredHighlightInfoImpl();
|
||||
p.setPaint(UIManager.getColor("ScrollBar.thumb"));
|
||||
i.setPainter(p);
|
||||
i.setStartOffset(doc.createPosition(start));
|
||||
// HACK: Use "end-1" to prevent chars the user types at the "end" of
|
||||
// the highlight to be absorbed into the highlight (default Highlight
|
||||
// behavior).
|
||||
i.setEndOffset(doc.createPosition(end - 1));
|
||||
markedOccurrences.add(i);
|
||||
mapper.damageRange(textArea, start, end);
|
||||
return i;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<DocumentRange> getMarkedOccurrences()
|
||||
{
|
||||
List<DocumentRange> list = new ArrayList<>(markedOccurrences.size());
|
||||
for (HighlightInfo info : markedOccurrences)
|
||||
{
|
||||
int start = info.getStartOffset();
|
||||
int end = info.getEndOffset() + 1; // HACK
|
||||
if (start <= end)
|
||||
{
|
||||
// Occasionally a Marked Occurrence can have a lost end offset
|
||||
// but not start offset (replacing entire text content with
|
||||
// new content, and a marked occurrence is on the last token
|
||||
// in the document).
|
||||
DocumentRange range = new DocumentRange(start, end);
|
||||
list.add(range);
|
||||
}
|
||||
}
|
||||
@Override
|
||||
public List<DocumentRange> getMarkedOccurrences()
|
||||
{
|
||||
List<DocumentRange> list = new ArrayList<>(markedOccurrences.size());
|
||||
for (HighlightInfo info : markedOccurrences)
|
||||
{
|
||||
int start = info.getStartOffset();
|
||||
int end = info.getEndOffset() + 1; // HACK
|
||||
if (start <= end)
|
||||
{
|
||||
// Occasionally a Marked Occurrence can have a lost end offset
|
||||
// but not start offset (replacing entire text content with
|
||||
// new content, and a marked occurrence is on the last token
|
||||
// in the document).
|
||||
DocumentRange range = new DocumentRange(start, end);
|
||||
list.add(range);
|
||||
}
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
public void clearMarkOccurrencesHighlights()
|
||||
{
|
||||
// Don't remove via an iterator; since our List is an ArrayList, this
|
||||
// implies tons of System.arrayCopy()s
|
||||
for (HighlightInfo info : markedOccurrences)
|
||||
{
|
||||
repaintListHighlight(info);
|
||||
}
|
||||
public void clearMarkOccurrencesHighlights()
|
||||
{
|
||||
// Don't remove via an iterator; since our List is an ArrayList, this
|
||||
// implies tons of System.arrayCopy()s
|
||||
for (HighlightInfo info : markedOccurrences)
|
||||
{
|
||||
repaintListHighlight(info);
|
||||
}
|
||||
|
||||
markedOccurrences.clear();
|
||||
}
|
||||
markedOccurrences.clear();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void paintLayeredHighlights(Graphics g, int lineStart, int lineEnd, Shape viewBounds, JTextComponent editor, View view)
|
||||
{
|
||||
paintListLayered(g, lineStart, lineEnd, viewBounds, editor, view, markedOccurrences);
|
||||
super.paintLayeredHighlights(g, lineStart, lineEnd, viewBounds, editor, view);
|
||||
}
|
||||
@Override
|
||||
public void paintLayeredHighlights(Graphics g, int lineStart, int lineEnd, Shape viewBounds, JTextComponent editor, View view)
|
||||
{
|
||||
paintListLayered(g, lineStart, lineEnd, viewBounds, editor, view, markedOccurrences);
|
||||
super.paintLayeredHighlights(g, lineStart, lineEnd, viewBounds, editor, view);
|
||||
}
|
||||
|
||||
private static class SyntaxLayeredHighlightInfoImpl extends LayeredHighlightInfoImpl
|
||||
{
|
||||
private ParserNotice notice;
|
||||
private static class SyntaxLayeredHighlightInfoImpl extends LayeredHighlightInfoImpl
|
||||
{
|
||||
private ParserNotice notice;
|
||||
|
||||
@Override
|
||||
public Color getColor()
|
||||
{
|
||||
Color color = null;
|
||||
if (notice != null)
|
||||
{
|
||||
color = notice.getColor();
|
||||
if (color == null)
|
||||
color = DEFAULT_PARSER_NOTICE_COLOR;
|
||||
}
|
||||
@Override
|
||||
public Color getColor()
|
||||
{
|
||||
Color color = null;
|
||||
if (notice != null)
|
||||
{
|
||||
color = notice.getColor();
|
||||
if (color == null)
|
||||
color = DEFAULT_PARSER_NOTICE_COLOR;
|
||||
}
|
||||
|
||||
return color;
|
||||
}
|
||||
return color;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
return "[SyntaxLayeredHighlightInfoImpl: startOffs=" + getStartOffset() + ", endOffs=" + getEndOffset() + ", color=" + getColor() + "]";
|
||||
}
|
||||
}
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
return "[SyntaxLayeredHighlightInfoImpl: startOffs=" + getStartOffset() + ", endOffs=" + getEndOffset() + ", color=" + getColor() + "]";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,17 +18,14 @@
|
|||
|
||||
package the.bytecode.club.bytecodeviewer.gui.components;
|
||||
|
||||
import java.awt.Dimension;
|
||||
import javax.swing.JButton;
|
||||
import javax.swing.JCheckBox;
|
||||
import javax.swing.JFrame;
|
||||
import javax.swing.JLabel;
|
||||
import javax.swing.JTextField;
|
||||
import the.bytecode.club.bytecodeviewer.api.ASMResourceUtil;
|
||||
import the.bytecode.club.bytecodeviewer.plugin.PluginManager;
|
||||
import the.bytecode.club.bytecodeviewer.plugin.preinstalled.EZInjection;
|
||||
import the.bytecode.club.bytecodeviewer.resources.IconResources;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.awt.*;
|
||||
|
||||
/**
|
||||
* The UI for File>Run aka EZ-Injection plugin.
|
||||
*
|
||||
|
@ -41,7 +38,7 @@ public class RunOptions extends JFrame
|
|||
private final JCheckBox debugMethodCalls;
|
||||
private final JTextField debugClasses;
|
||||
private final JTextField socksProxy;
|
||||
|
||||
|
||||
public RunOptions()
|
||||
{
|
||||
this.setIconImages(IconResources.iconList);
|
||||
|
@ -114,16 +111,9 @@ public class RunOptions extends JFrame
|
|||
printToCommandLine.setBounds(6, 315, 232, 23);
|
||||
getContentPane().add(printToCommandLine);
|
||||
this.setLocationRelativeTo(null);
|
||||
btnNewButton.addActionListener(arg0 -> {
|
||||
PluginManager.runPlugin(new EZInjection(accessModifiers
|
||||
.isSelected(), injectHooks.isSelected(),
|
||||
debugMethodCalls.isSelected(), invokeMethod
|
||||
.isSelected(),
|
||||
mainMethodFQN.getText(), false, false, debugClasses
|
||||
.getText(), this.socksProxy.getText(), forceProxy
|
||||
.isSelected(),
|
||||
launchReflectionKit.isSelected(), console.isSelected(),
|
||||
printToCommandLine.isSelected()));
|
||||
btnNewButton.addActionListener(arg0 ->
|
||||
{
|
||||
PluginManager.runPlugin(new EZInjection(accessModifiers.isSelected(), injectHooks.isSelected(), debugMethodCalls.isSelected(), invokeMethod.isSelected(), mainMethodFQN.getText(), false, false, debugClasses.getText(), this.socksProxy.getText(), forceProxy.isSelected(), launchReflectionKit.isSelected(), console.isSelected(), printToCommandLine.isSelected()));
|
||||
dispose();
|
||||
});
|
||||
}
|
||||
|
|
|
@ -18,18 +18,6 @@
|
|||
|
||||
package the.bytecode.club.bytecodeviewer.gui.components;
|
||||
|
||||
import java.awt.BorderLayout;
|
||||
import java.awt.Font;
|
||||
import java.awt.event.InputEvent;
|
||||
import java.awt.event.KeyEvent;
|
||||
import java.awt.event.MouseWheelListener;
|
||||
import javax.swing.JButton;
|
||||
import javax.swing.JCheckBox;
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.JScrollPane;
|
||||
import javax.swing.JTextArea;
|
||||
import javax.swing.JTextField;
|
||||
import javax.swing.SwingUtilities;
|
||||
import the.bytecode.club.bytecodeviewer.BytecodeViewer;
|
||||
import the.bytecode.club.bytecodeviewer.GlobalHotKeys;
|
||||
import the.bytecode.club.bytecodeviewer.gui.components.listeners.PressKeyListener;
|
||||
|
@ -39,6 +27,12 @@ import the.bytecode.club.bytecodeviewer.translation.TranslatedComponents;
|
|||
import the.bytecode.club.bytecodeviewer.translation.components.TranslatedJCheckBox;
|
||||
import the.bytecode.club.bytecodeviewer.util.JTextAreaUtils;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.awt.*;
|
||||
import java.awt.event.InputEvent;
|
||||
import java.awt.event.KeyEvent;
|
||||
import java.awt.event.MouseWheelListener;
|
||||
|
||||
/**
|
||||
* Searching on a JTextArea using swing highlighting
|
||||
*
|
||||
|
@ -47,123 +41,123 @@ import the.bytecode.club.bytecodeviewer.util.JTextAreaUtils;
|
|||
*/
|
||||
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 TranslatedJCheckBox("Match case", TranslatedComponents.MATCH_CASE);
|
||||
|
||||
public SearchableJTextArea()
|
||||
{
|
||||
scrollPane.setViewportView(this);
|
||||
scrollPane.setColumnHeaderView(searchPanel);
|
||||
|
||||
JButton searchNext = new JButton();
|
||||
searchNext.setIcon(IconResources.nextIcon);
|
||||
|
||||
JButton searchPrev = new JButton();
|
||||
searchPrev.setIcon(IconResources.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.getModifiersEx() & KeyEvent.CTRL_DOWN_MASK) != 0))
|
||||
searchInput.requestFocus();
|
||||
|
||||
GlobalHotKeys.keyPressed(keyEvent);
|
||||
}));
|
||||
|
||||
final Font newFont = getFont().deriveFont((float) BytecodeViewer.viewer.getFontSize());
|
||||
|
||||
//set number-bar font
|
||||
setFont(newFont);
|
||||
|
||||
SwingUtilities.invokeLater(()-> {
|
||||
//attach CTRL + Mouse Wheel Zoom
|
||||
attachCtrlMouseWheelZoom();
|
||||
|
||||
//set text font
|
||||
setFont(newFont);
|
||||
});
|
||||
}
|
||||
|
||||
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 void attachCtrlMouseWheelZoom()
|
||||
{
|
||||
//get the existing scroll event
|
||||
MouseWheelListener ogListener = scrollPane.getMouseWheelListeners().length > 0 ?
|
||||
scrollPane.getMouseWheelListeners()[0] : null;
|
||||
|
||||
//remove the existing event
|
||||
if(ogListener != null)
|
||||
scrollPane.removeMouseWheelListener(ogListener);
|
||||
|
||||
//add a new event
|
||||
scrollPane.addMouseWheelListener(e ->
|
||||
{
|
||||
if (getText().isEmpty())
|
||||
return;
|
||||
|
||||
if ((e.getModifiersEx() & InputEvent.CTRL_DOWN_MASK) != 0)
|
||||
{
|
||||
Font font = getFont();
|
||||
int size = font.getSize();
|
||||
|
||||
if (e.getWheelRotation() > 0) //Up
|
||||
setFont(new Font(font.getName(), font.getStyle(), --size >= 2 ? --size : 2));
|
||||
else //Down
|
||||
setFont(new Font(font.getName(), font.getStyle(), ++size));
|
||||
|
||||
e.consume();
|
||||
}
|
||||
else if(ogListener != null)
|
||||
{
|
||||
ogListener.mouseWheelMoved(e);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public JScrollPane getScrollPane()
|
||||
{
|
||||
return scrollPane;
|
||||
}
|
||||
|
||||
public JPanel getSearchPanel()
|
||||
{
|
||||
return searchPanel;
|
||||
}
|
||||
|
||||
public JTextField getSearchInput()
|
||||
{
|
||||
return searchInput;
|
||||
}
|
||||
|
||||
public JCheckBox getCaseSensitiveSearch()
|
||||
{
|
||||
return caseSensitiveSearch;
|
||||
}
|
||||
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 TranslatedJCheckBox("Match case", TranslatedComponents.MATCH_CASE);
|
||||
|
||||
public SearchableJTextArea()
|
||||
{
|
||||
scrollPane.setViewportView(this);
|
||||
scrollPane.setColumnHeaderView(searchPanel);
|
||||
|
||||
JButton searchNext = new JButton();
|
||||
searchNext.setIcon(IconResources.nextIcon);
|
||||
|
||||
JButton searchPrev = new JButton();
|
||||
searchPrev.setIcon(IconResources.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.getModifiersEx() & KeyEvent.CTRL_DOWN_MASK) != 0))
|
||||
searchInput.requestFocus();
|
||||
|
||||
GlobalHotKeys.keyPressed(keyEvent);
|
||||
}));
|
||||
|
||||
final Font newFont = getFont().deriveFont((float) BytecodeViewer.viewer.getFontSize());
|
||||
|
||||
//set number-bar font
|
||||
setFont(newFont);
|
||||
|
||||
SwingUtilities.invokeLater(() ->
|
||||
{
|
||||
//attach CTRL + Mouse Wheel Zoom
|
||||
attachCtrlMouseWheelZoom();
|
||||
|
||||
//set text font
|
||||
setFont(newFont);
|
||||
});
|
||||
}
|
||||
|
||||
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 void attachCtrlMouseWheelZoom()
|
||||
{
|
||||
//get the existing scroll event
|
||||
MouseWheelListener ogListener = scrollPane.getMouseWheelListeners().length > 0 ? scrollPane.getMouseWheelListeners()[0] : null;
|
||||
|
||||
//remove the existing event
|
||||
if (ogListener != null)
|
||||
scrollPane.removeMouseWheelListener(ogListener);
|
||||
|
||||
//add a new event
|
||||
scrollPane.addMouseWheelListener(e ->
|
||||
{
|
||||
if (getText().isEmpty())
|
||||
return;
|
||||
|
||||
if ((e.getModifiersEx() & InputEvent.CTRL_DOWN_MASK) != 0)
|
||||
{
|
||||
Font font = getFont();
|
||||
int size = font.getSize();
|
||||
|
||||
if (e.getWheelRotation() > 0) //Up
|
||||
setFont(new Font(font.getName(), font.getStyle(), --size >= 2 ? --size : 2));
|
||||
else //Down
|
||||
setFont(new Font(font.getName(), font.getStyle(), ++size));
|
||||
|
||||
e.consume();
|
||||
}
|
||||
else if (ogListener != null)
|
||||
{
|
||||
ogListener.mouseWheelMoved(e);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public JScrollPane getScrollPane()
|
||||
{
|
||||
return scrollPane;
|
||||
}
|
||||
|
||||
public JPanel getSearchPanel()
|
||||
{
|
||||
return searchPanel;
|
||||
}
|
||||
|
||||
public JTextField getSearchInput()
|
||||
{
|
||||
return searchInput;
|
||||
}
|
||||
|
||||
public JCheckBox getCaseSensitiveSearch()
|
||||
{
|
||||
return caseSensitiveSearch;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -58,7 +58,8 @@ public class SearchableRSyntaxTextArea extends RSyntaxTextArea
|
|||
scrollPane.getHorizontalScrollBar().setForeground(blackScrollForeground);
|
||||
scrollPane.getVerticalScrollBar().setBackground(blackScrollBackground);
|
||||
scrollPane.getVerticalScrollBar().setForeground(blackScrollForeground);
|
||||
} else if (Configuration.lafTheme.isDark())
|
||||
}
|
||||
else if (Configuration.lafTheme.isDark())
|
||||
{
|
||||
//this fixes the white border on the jScrollBar panes
|
||||
scrollPane.getHorizontalScrollBar().setBackground(darkScrollBackground);
|
||||
|
@ -108,7 +109,8 @@ public class SearchableRSyntaxTextArea extends RSyntaxTextArea
|
|||
//set number-bar font
|
||||
setFont(newFont);
|
||||
|
||||
SwingUtilities.invokeLater(() -> {
|
||||
SwingUtilities.invokeLater(() ->
|
||||
{
|
||||
//attach CTRL + Mouse Wheel Zoom
|
||||
attachCtrlMouseWheelZoom();
|
||||
|
||||
|
@ -130,8 +132,10 @@ public class SearchableRSyntaxTextArea extends RSyntaxTextArea
|
|||
|
||||
public void attachCtrlMouseWheelZoom()
|
||||
{
|
||||
scrollPane.addMouseWheelListener(e -> {
|
||||
if (getText().isEmpty()) return;
|
||||
scrollPane.addMouseWheelListener(e ->
|
||||
{
|
||||
if (getText().isEmpty())
|
||||
return;
|
||||
if ((e.getModifiersEx() & InputEvent.CTRL_DOWN_MASK) != 0)
|
||||
{
|
||||
Font font = getFont();
|
||||
|
@ -176,7 +180,8 @@ public class SearchableRSyntaxTextArea extends RSyntaxTextArea
|
|||
int end = getLineEndOffset(line);
|
||||
return getText(start, end - start).trim();
|
||||
}
|
||||
} catch (BadLocationException ignored)
|
||||
}
|
||||
catch (BadLocationException ignored)
|
||||
{
|
||||
}
|
||||
return "";
|
||||
|
|
|
@ -18,16 +18,10 @@
|
|||
|
||||
package the.bytecode.club.bytecodeviewer.gui.components;
|
||||
|
||||
import java.awt.Component;
|
||||
import javax.swing.*;
|
||||
import java.awt.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import javax.swing.BoxLayout;
|
||||
import javax.swing.JComponent;
|
||||
import javax.swing.JDialog;
|
||||
import javax.swing.JMenu;
|
||||
import javax.swing.JMenuItem;
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.JScrollPane;
|
||||
|
||||
import static the.bytecode.club.bytecodeviewer.Configuration.useNewSettingsDialog;
|
||||
|
||||
|
@ -38,67 +32,67 @@ import static the.bytecode.club.bytecodeviewer.Configuration.useNewSettingsDialo
|
|||
|
||||
public class SettingsDialog extends JScrollPane
|
||||
{
|
||||
public static final List<JComponent> components = new ArrayList<>();
|
||||
public static final List<JDialog> dialogs = new ArrayList<>();
|
||||
private final List<JMenuItem> options = new ArrayList<>();
|
||||
private final JMenu menu;
|
||||
private final JPanel display;
|
||||
|
||||
public SettingsDialog(JMenu menu, JPanel display)
|
||||
{
|
||||
super(display);
|
||||
|
||||
this.menu = menu;
|
||||
this.display = display;
|
||||
|
||||
if(!useNewSettingsDialog)
|
||||
return;
|
||||
|
||||
List<JMenuItem> options = new ArrayList<>();
|
||||
for(Component child : menu.getMenuComponents())
|
||||
{
|
||||
if(!(child instanceof JMenuItem))
|
||||
continue;
|
||||
|
||||
JMenuItem menuItem = (JMenuItem) child;
|
||||
|
||||
options.add(menuItem);
|
||||
|
||||
//force unselect after a selection has been made
|
||||
//this fixes a graphical bug from forcing menu items on non-menus
|
||||
menuItem.addActionListener(e -> unselectAll());
|
||||
}
|
||||
|
||||
this.options.addAll(options);
|
||||
|
||||
buildPanel();
|
||||
|
||||
components.add(this);
|
||||
}
|
||||
|
||||
public void unselectAll()
|
||||
{
|
||||
options.forEach(jMenuItem -> jMenuItem.setArmed(false));
|
||||
}
|
||||
|
||||
public void showDialog()
|
||||
{
|
||||
ExtendedJOptionPane.showJPanelDialog(null, this, 460, dialogs::add);
|
||||
}
|
||||
|
||||
private void buildPanel()
|
||||
{
|
||||
display.setLayout(new BoxLayout(display, BoxLayout.Y_AXIS));
|
||||
for(JMenuItem menuItem : options)
|
||||
display.add(menuItem);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName()
|
||||
{
|
||||
if(menu == null)
|
||||
return "ERROR: Dialog missing menu";
|
||||
|
||||
return menu.getText();
|
||||
}
|
||||
public static final List<JComponent> components = new ArrayList<>();
|
||||
public static final List<JDialog> dialogs = new ArrayList<>();
|
||||
private final List<JMenuItem> options = new ArrayList<>();
|
||||
private final JMenu menu;
|
||||
private final JPanel display;
|
||||
|
||||
public SettingsDialog(JMenu menu, JPanel display)
|
||||
{
|
||||
super(display);
|
||||
|
||||
this.menu = menu;
|
||||
this.display = display;
|
||||
|
||||
if (!useNewSettingsDialog)
|
||||
return;
|
||||
|
||||
List<JMenuItem> options = new ArrayList<>();
|
||||
for (Component child : menu.getMenuComponents())
|
||||
{
|
||||
if (!(child instanceof JMenuItem))
|
||||
continue;
|
||||
|
||||
JMenuItem menuItem = (JMenuItem) child;
|
||||
|
||||
options.add(menuItem);
|
||||
|
||||
//force unselect after a selection has been made
|
||||
//this fixes a graphical bug from forcing menu items on non-menus
|
||||
menuItem.addActionListener(e -> unselectAll());
|
||||
}
|
||||
|
||||
this.options.addAll(options);
|
||||
|
||||
buildPanel();
|
||||
|
||||
components.add(this);
|
||||
}
|
||||
|
||||
public void unselectAll()
|
||||
{
|
||||
options.forEach(jMenuItem -> jMenuItem.setArmed(false));
|
||||
}
|
||||
|
||||
public void showDialog()
|
||||
{
|
||||
ExtendedJOptionPane.showJPanelDialog(null, this, 460, dialogs::add);
|
||||
}
|
||||
|
||||
private void buildPanel()
|
||||
{
|
||||
display.setLayout(new BoxLayout(display, BoxLayout.Y_AXIS));
|
||||
for (JMenuItem menuItem : options)
|
||||
display.add(menuItem);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName()
|
||||
{
|
||||
if (menu == null)
|
||||
return "ERROR: Dialog missing menu";
|
||||
|
||||
return menu.getText();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,12 +19,12 @@
|
|||
package the.bytecode.club.bytecodeviewer.gui.components;
|
||||
|
||||
import com.github.weisj.darklaf.iconset.AllIcons;
|
||||
import javax.swing.BorderFactory;
|
||||
import javax.swing.JInternalFrame;
|
||||
import the.bytecode.club.bytecodeviewer.Configuration;
|
||||
import the.bytecode.club.bytecodeviewer.gui.theme.LAFTheme;
|
||||
import the.bytecode.club.bytecodeviewer.resources.IconResources;
|
||||
|
||||
import javax.swing.*;
|
||||
|
||||
/**
|
||||
* Used to represent all the panes inside of Bytecode Viewer.
|
||||
*
|
||||
|
@ -42,7 +42,8 @@ public abstract class VisibleComponent extends JInternalFrame
|
|||
}
|
||||
|
||||
@Override
|
||||
public void updateUI() {
|
||||
public void updateUI()
|
||||
{
|
||||
if (Configuration.lafTheme != LAFTheme.SYSTEM)
|
||||
setBorder(BorderFactory.createEmptyBorder());
|
||||
else
|
||||
|
@ -52,15 +53,18 @@ public abstract class VisibleComponent extends JInternalFrame
|
|||
|
||||
public void setDefaultIcon()
|
||||
{
|
||||
try {
|
||||
if(Configuration.showDarkLAFComponentIcons)
|
||||
try
|
||||
{
|
||||
if (Configuration.showDarkLAFComponentIcons)
|
||||
setFrameIcon(AllIcons.Window.Frame.get(16, 16));
|
||||
else
|
||||
setFrameIcon(IconResources.jarIcon);
|
||||
} catch (Exception e) {
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private static final long serialVersionUID = -6453413772343643526L;
|
||||
}
|
||||
|
|
|
@ -18,15 +18,11 @@
|
|||
|
||||
package the.bytecode.club.bytecodeviewer.gui.components;
|
||||
|
||||
import javax.swing.Icon;
|
||||
|
||||
import com.github.weisj.darklaf.components.RotatableIconAnimator;
|
||||
import com.github.weisj.darklaf.components.loading.LoadingIndicator;
|
||||
import com.github.weisj.darklaf.iconset.AllIcons;
|
||||
import com.github.weisj.darklaf.properties.icons.RotatableIcon;
|
||||
import the.bytecode.club.bytecodeviewer.resources.IconResources;
|
||||
|
||||
import java.awt.event.*;
|
||||
import java.awt.event.HierarchyEvent;
|
||||
|
||||
/**
|
||||
* @author Konloch
|
||||
|
@ -34,20 +30,21 @@ import java.awt.event.*;
|
|||
*/
|
||||
public class WaitBusyIcon extends JMenuItemIcon
|
||||
{
|
||||
private final RotatableIconAnimator animator;
|
||||
private final RotatableIconAnimator animator;
|
||||
|
||||
public WaitBusyIcon()
|
||||
{
|
||||
super(new RotatableIcon(IconResources.busyIcon));
|
||||
animator = new RotatableIconAnimator(8, (RotatableIcon) getIcon(), this);
|
||||
addHierarchyListener(e -> {
|
||||
if ((e.getChangeFlags() & HierarchyEvent.PARENT_CHANGED) != 0)
|
||||
{
|
||||
if (getParent() == null)
|
||||
animator.stop();
|
||||
else
|
||||
animator.start();
|
||||
}
|
||||
});
|
||||
}
|
||||
public WaitBusyIcon()
|
||||
{
|
||||
super(new RotatableIcon(IconResources.busyIcon));
|
||||
animator = new RotatableIconAnimator(8, (RotatableIcon) getIcon(), this);
|
||||
addHierarchyListener(e ->
|
||||
{
|
||||
if ((e.getChangeFlags() & HierarchyEvent.PARENT_CHANGED) != 0)
|
||||
{
|
||||
if (getParent() == null)
|
||||
animator.stop();
|
||||
else
|
||||
animator.start();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -42,7 +42,8 @@ public class GoToAction extends AbstractAction
|
|||
int line = textArea.getCaretLineNumber() + 1;
|
||||
int column = textArea.getCaretOffsetFromLineStart();
|
||||
|
||||
container.fieldMembers.values().forEach(fields -> fields.forEach(field -> {
|
||||
container.fieldMembers.values().forEach(fields -> fields.forEach(field ->
|
||||
{
|
||||
if (field.line == line && field.columnStart - 1 <= column && field.columnEnd >= column)
|
||||
{
|
||||
Element root = textArea.getDocument().getDefaultRootElement();
|
||||
|
@ -59,7 +60,8 @@ public class GoToAction extends AbstractAction
|
|||
}
|
||||
}));
|
||||
|
||||
container.methodParameterMembers.values().forEach(parameters -> parameters.forEach(parameter -> {
|
||||
container.methodParameterMembers.values().forEach(parameters -> parameters.forEach(parameter ->
|
||||
{
|
||||
if (parameter.line == line && parameter.columnStart - 1 <= column && parameter.columnEnd >= column)
|
||||
{
|
||||
Element root = textArea.getDocument().getDefaultRootElement();
|
||||
|
@ -67,10 +69,12 @@ public class GoToAction extends AbstractAction
|
|||
{
|
||||
int startOffset = root.getElement(parameter.line - 1).getStartOffset() + (parameter.columnStart - 1);
|
||||
textArea.setCaretPosition(startOffset);
|
||||
} else
|
||||
}
|
||||
else
|
||||
{
|
||||
String method = parameter.method;
|
||||
parameters.stream().filter(classParameterLocation -> classParameterLocation.method.equals(method)).forEach(classParameterLocation -> {
|
||||
parameters.stream().filter(classParameterLocation -> classParameterLocation.method.equals(method)).forEach(classParameterLocation ->
|
||||
{
|
||||
if (classParameterLocation.decRef.equalsIgnoreCase("declaration"))
|
||||
{
|
||||
int startOffset = root.getElement(classParameterLocation.line - 1).getStartOffset() + (classParameterLocation.columnStart - 1);
|
||||
|
@ -81,7 +85,8 @@ public class GoToAction extends AbstractAction
|
|||
}
|
||||
}));
|
||||
|
||||
container.methodLocalMembers.values().forEach(localMembers -> localMembers.forEach(localMember -> {
|
||||
container.methodLocalMembers.values().forEach(localMembers -> localMembers.forEach(localMember ->
|
||||
{
|
||||
if (localMember.line == line && localMember.columnStart - 1 <= column && localMember.columnEnd >= column)
|
||||
{
|
||||
Element root = textArea.getDocument().getDefaultRootElement();
|
||||
|
@ -89,10 +94,12 @@ public class GoToAction extends AbstractAction
|
|||
{
|
||||
int startOffset = root.getElement(localMember.line - 1).getStartOffset() + (localMember.columnStart - 1);
|
||||
textArea.setCaretPosition(startOffset);
|
||||
} else
|
||||
}
|
||||
else
|
||||
{
|
||||
String method = localMember.method;
|
||||
localMembers.stream().filter(classLocalVariableLocation -> classLocalVariableLocation.method.equals(method)).forEach(classLocalVariableLocation -> {
|
||||
localMembers.stream().filter(classLocalVariableLocation -> classLocalVariableLocation.method.equals(method)).forEach(classLocalVariableLocation ->
|
||||
{
|
||||
if (classLocalVariableLocation.decRef.equalsIgnoreCase("declaration"))
|
||||
{
|
||||
int startOffset = root.getElement(classLocalVariableLocation.line - 1).getStartOffset() + (classLocalVariableLocation.columnStart - 1);
|
||||
|
@ -103,7 +110,8 @@ public class GoToAction extends AbstractAction
|
|||
}
|
||||
}));
|
||||
|
||||
container.methodMembers.values().forEach(methods -> methods.forEach(method -> {
|
||||
container.methodMembers.values().forEach(methods -> methods.forEach(method ->
|
||||
{
|
||||
if (method.line == line && method.columnStart - 1 <= column && method.columnEnd >= column)
|
||||
{
|
||||
Element root = textArea.getDocument().getDefaultRootElement();
|
||||
|
@ -111,9 +119,11 @@ public class GoToAction extends AbstractAction
|
|||
{
|
||||
int startOffset = root.getElement(method.line - 1).getStartOffset() + (method.columnStart - 1);
|
||||
textArea.setCaretPosition(startOffset);
|
||||
} else
|
||||
}
|
||||
else
|
||||
{
|
||||
methods.stream().filter(classMethodLocation -> classMethodLocation.owner.equals(method.owner)).forEach(classMethodLocation -> {
|
||||
methods.stream().filter(classMethodLocation -> classMethodLocation.owner.equals(method.owner)).forEach(classMethodLocation ->
|
||||
{
|
||||
if (classMethodLocation.decRef.equalsIgnoreCase("declaration"))
|
||||
{
|
||||
int startOffset = root.getElement(classMethodLocation.line - 1).getStartOffset() + (classMethodLocation.columnStart - 1);
|
||||
|
@ -127,7 +137,8 @@ public class GoToAction extends AbstractAction
|
|||
}
|
||||
}));
|
||||
|
||||
container.classReferences.values().forEach(classes -> classes.forEach(clazz -> {
|
||||
container.classReferences.values().forEach(classes -> classes.forEach(clazz ->
|
||||
{
|
||||
String name;
|
||||
if (clazz.line == line && clazz.columnStart - 1 <= column && clazz.columnEnd - 1 >= column)
|
||||
{
|
||||
|
@ -137,9 +148,11 @@ public class GoToAction extends AbstractAction
|
|||
{
|
||||
int startOffset = root.getElement(clazz.line - 1).getStartOffset() + (clazz.columnStart - 1);
|
||||
textArea.setCaretPosition(startOffset);
|
||||
} else
|
||||
}
|
||||
else
|
||||
{
|
||||
classes.stream().filter(classReferenceLocation -> classReferenceLocation.owner.equals(name)).forEach(classReferenceLocation -> {
|
||||
classes.stream().filter(classReferenceLocation -> classReferenceLocation.owner.equals(name)).forEach(classReferenceLocation ->
|
||||
{
|
||||
if (classReferenceLocation.type.equals("declaration"))
|
||||
{
|
||||
int startOffset = root.getElement(classReferenceLocation.line - 1).getStartOffset() + (classReferenceLocation.columnStart - 1);
|
||||
|
@ -170,14 +183,16 @@ public class GoToAction extends AbstractAction
|
|||
ClassViewer activeResource = (ClassViewer) BytecodeViewer.viewer.workPane.getActiveResource();
|
||||
HashMap<String, ClassFileContainer> classFiles = BytecodeViewer.viewer.workPane.classFiles;
|
||||
return wait(classFiles, activeResource);
|
||||
} else if (method)
|
||||
}
|
||||
else if (method)
|
||||
{
|
||||
ClassMethodLocation classMethodLocation = container.getMethodLocationsFor(lexeme).get(0);
|
||||
ClassReferenceLocation classReferenceLocation = null;
|
||||
try
|
||||
{
|
||||
classReferenceLocation = container.getClassReferenceLocationsFor(classMethodLocation.owner).get(0);
|
||||
} catch (Exception ignored)
|
||||
}
|
||||
catch (Exception ignored)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -196,7 +211,8 @@ public class GoToAction extends AbstractAction
|
|||
HashMap<String, ClassFileContainer> classFiles = BytecodeViewer.viewer.workPane.classFiles;
|
||||
return wait(classFiles, activeResource);
|
||||
}
|
||||
} else
|
||||
}
|
||||
else
|
||||
{
|
||||
ClassReferenceLocation classReferenceLocation = container.getClassReferenceLocationsFor(lexeme).get(0);
|
||||
String packagePath = classReferenceLocation.packagePath;
|
||||
|
@ -218,7 +234,8 @@ public class GoToAction extends AbstractAction
|
|||
|
||||
private void open(RSyntaxTextArea textArea, boolean isClass, boolean isField, boolean isMethod)
|
||||
{
|
||||
Thread thread = new Thread(() -> {
|
||||
Thread thread = new Thread(() ->
|
||||
{
|
||||
Token token = textArea.modelToToken(textArea.getCaretPosition());
|
||||
token = TokenUtil.getToken(textArea, token);
|
||||
String lexeme = token.getLexeme();
|
||||
|
@ -229,10 +246,12 @@ public class GoToAction extends AbstractAction
|
|||
if (classFileContainer == null)
|
||||
return;
|
||||
|
||||
classFileContainer.classReferences.forEach((className, classReference) -> {
|
||||
classFileContainer.classReferences.forEach((className, classReference) ->
|
||||
{
|
||||
if (className.equals(lexeme))
|
||||
{
|
||||
classReference.forEach(classReferenceLocation -> {
|
||||
classReference.forEach(classReferenceLocation ->
|
||||
{
|
||||
if (classReferenceLocation.type.equals("declaration"))
|
||||
{
|
||||
moveCursor(classReferenceLocation.line, classReferenceLocation.columnStart);
|
||||
|
@ -240,16 +259,19 @@ public class GoToAction extends AbstractAction
|
|||
});
|
||||
}
|
||||
});
|
||||
} else if (isField)
|
||||
}
|
||||
else if (isField)
|
||||
{
|
||||
classFileContainer = openClass(lexeme, true, false);
|
||||
if (classFileContainer == null)
|
||||
return;
|
||||
|
||||
classFileContainer.fieldMembers.forEach((fieldName, fields) -> {
|
||||
classFileContainer.fieldMembers.forEach((fieldName, fields) ->
|
||||
{
|
||||
if (fieldName.equals(lexeme))
|
||||
{
|
||||
fields.forEach(classFieldLocation -> {
|
||||
fields.forEach(classFieldLocation ->
|
||||
{
|
||||
if (classFieldLocation.type.equals("declaration"))
|
||||
{
|
||||
moveCursor(classFieldLocation.line, classFieldLocation.columnStart);
|
||||
|
@ -257,16 +279,19 @@ public class GoToAction extends AbstractAction
|
|||
});
|
||||
}
|
||||
});
|
||||
} else if (isMethod)
|
||||
}
|
||||
else if (isMethod)
|
||||
{
|
||||
classFileContainer = openClass(lexeme, false, true);
|
||||
if (classFileContainer == null)
|
||||
return;
|
||||
|
||||
classFileContainer.methodMembers.forEach((methodName, methods) -> {
|
||||
classFileContainer.methodMembers.forEach((methodName, methods) ->
|
||||
{
|
||||
if (methodName.equals(lexeme))
|
||||
{
|
||||
methods.forEach(method -> {
|
||||
methods.forEach(method ->
|
||||
{
|
||||
if (method.decRef.equalsIgnoreCase("declaration"))
|
||||
{
|
||||
moveCursor(method.line, method.columnStart);
|
||||
|
@ -285,22 +310,26 @@ public class GoToAction extends AbstractAction
|
|||
try
|
||||
{
|
||||
BytecodeViewer.updateBusyStatus(true);
|
||||
Thread.getAllStackTraces().forEach((name, stackTrace) -> {
|
||||
Thread.getAllStackTraces().forEach((name, stackTrace) ->
|
||||
{
|
||||
if (name.getName().equals("Pane Update"))
|
||||
{
|
||||
try
|
||||
{
|
||||
name.join();
|
||||
} catch (InterruptedException e)
|
||||
}
|
||||
catch (InterruptedException e)
|
||||
{
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
});
|
||||
} catch (Exception e)
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
throw new RuntimeException(e);
|
||||
} finally
|
||||
}
|
||||
finally
|
||||
{
|
||||
BytecodeViewer.updateBusyStatus(false);
|
||||
}
|
||||
|
|
|
@ -20,7 +20,6 @@ package the.bytecode.club.bytecodeviewer.gui.components.listeners;
|
|||
|
||||
import java.awt.event.MouseAdapter;
|
||||
import java.awt.event.MouseEvent;
|
||||
import java.awt.event.MouseListener;
|
||||
|
||||
/**
|
||||
* @author Konloch
|
||||
|
@ -28,21 +27,22 @@ import java.awt.event.MouseListener;
|
|||
*/
|
||||
public class MouseClickedListener extends MouseAdapter
|
||||
{
|
||||
private final MouseClickedEvent mouseClickedEvent;
|
||||
|
||||
public MouseClickedListener(MouseClickedEvent mouseClickedEvent)
|
||||
{
|
||||
this.mouseClickedEvent = mouseClickedEvent;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mouseClicked(MouseEvent e) {
|
||||
mouseClickedEvent.mouseClicked(e);
|
||||
super.mouseClicked(e);
|
||||
}
|
||||
|
||||
public interface MouseClickedEvent
|
||||
{
|
||||
void mouseClicked(MouseEvent e);
|
||||
}
|
||||
private final MouseClickedEvent mouseClickedEvent;
|
||||
|
||||
public MouseClickedListener(MouseClickedEvent mouseClickedEvent)
|
||||
{
|
||||
this.mouseClickedEvent = mouseClickedEvent;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mouseClicked(MouseEvent e)
|
||||
{
|
||||
mouseClickedEvent.mouseClicked(e);
|
||||
super.mouseClicked(e);
|
||||
}
|
||||
|
||||
public interface MouseClickedEvent
|
||||
{
|
||||
void mouseClicked(MouseEvent e);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -27,24 +27,31 @@ import java.awt.event.KeyListener;
|
|||
*/
|
||||
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);
|
||||
}
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -27,24 +27,31 @@ import java.awt.event.KeyListener;
|
|||
*/
|
||||
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);
|
||||
}
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,16 +18,17 @@
|
|||
|
||||
package the.bytecode.club.bytecodeviewer.gui.contextmenu;
|
||||
|
||||
import javax.swing.JPopupMenu;
|
||||
import javax.swing.tree.TreePath;
|
||||
import the.bytecode.club.bytecodeviewer.gui.resourcelist.ResourceTree;
|
||||
import the.bytecode.club.bytecodeviewer.searching.LDCSearchTreeNodeResult;
|
||||
|
||||
import javax.swing.*;
|
||||
import javax.swing.tree.TreePath;
|
||||
|
||||
/**
|
||||
* @author Konloch
|
||||
* @since 7/26/2021
|
||||
*/
|
||||
public interface BuildContextMenuItem
|
||||
{
|
||||
void buildMenu(ResourceTree tree, TreePath selPath, LDCSearchTreeNodeResult result, JPopupMenu menu);
|
||||
void buildMenu(ResourceTree tree, TreePath selPath, LDCSearchTreeNodeResult result, JPopupMenu menu);
|
||||
}
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user