Code Style Update

This commit is contained in:
Konloch 2024-09-25 21:40:07 -06:00
parent c85a8a21f3
commit fda1ecab66

AI 샘플 코드 생성 중입니다

Loading...
350 changed files with 26760 additions and 27726 deletions

View File

@ -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);
}

View File

@ -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++;
}

View File

@ -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);
}
}

View File

@ -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;

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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);
}
}
}
}
}

View 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);
}
}
}
}

View File

@ -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));

View File

@ -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
}
}
}
}
}

View File

@ -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;
}
}

View File

@ -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();
}
}

View File

@ -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;

View File

@ -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;
}

View File

@ -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

View File

@ -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;
}

View File

@ -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();
}

View File

@ -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,
}

View File

@ -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;
}

View File

@ -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();
}
}
}

View File

@ -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();
}
}

View File

@ -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);
}
}

View File

@ -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);
}
}
}

View File

@ -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;
}
}
}

View File

@ -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;
}
}
}

View File

@ -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<>();
}
}
}

View File

@ -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();
}
}

View File

@ -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);
}
}
}

View File

@ -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);
}
}
}

View File

@ -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;
}
}

View File

@ -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;
}

View File

@ -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();
}
}

View File

@ -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();
}
}

View File

@ -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();
}
}

View File

@ -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);
}

View File

@ -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();
}
}
}

View File

@ -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;
}
}
}

View File

@ -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);
}
}
}

View File

@ -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;
}
}
}

View File

@ -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;
}
}
}
}

View File

@ -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;
}
}
}

View File

@ -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;

View File

@ -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);
}

View File

@ -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());
}

View File

@ -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);
}

View File

@ -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;

View File

@ -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));
}

View File

@ -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();
}
}
}

View File

@ -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()));
}
}
}
}
}

View File

@ -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);
}
}
}
}

View File

@ -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();
}
}
}

View File

@ -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));
}

View File

@ -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();
}
}
}

View File

@ -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;
}
}

View File

@ -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)
{
}
}

View File

@ -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)
{
}
}

View File

@ -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)
{
}
}

View File

@ -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 ->
{
};
}

View File

@ -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";
}
}

View File

@ -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)
{
}
}

View File

@ -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)
{
}
}

View File

@ -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)
{
}
}

View File

@ -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);
}
}

View File

@ -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);
}
}

View File

@ -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;
}

View File

@ -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)
{
}
}

View File

@ -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;
}
}

View File

@ -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();
}

View File

@ -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;
}
}

View File

@ -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();
}

View File

@ -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;
}

View File

@ -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);
}

View File

@ -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
}
}

View File

@ -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;
}
}

View File

@ -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);
}
}

View File

@ -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;
}
});
}
}
}

View File

@ -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() : "";
}
}
}

View File

@ -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);
}
}

View File

@ -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;
}

View File

@ -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());
}
});
}
}

View File

@ -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;
}
}

View File

@ -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);
}
}

View File

@ -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();
}
}

View File

@ -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;
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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);
}
}
}

View File

@ -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() + "]";
}
}
}

View File

@ -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();
});
}

View File

@ -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;
}
}

View File

@ -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 "";

View File

@ -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();
}
}

View File

@ -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;
}

View File

@ -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();
}
});
}
}

View File

@ -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);
}

View File

@ -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);
}
}

View File

@ -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);
}
}

View File

@ -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);
}
}

View File

@ -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