Tabbed Console
A better solution to the plugin console for when you have multiple resources inside of BCV
This commit is contained in:
parent
3e82f29b59
commit
ced48c76fd
8 changed files with 174 additions and 25 deletions
|
@ -86,7 +86,6 @@ import static the.bytecode.club.bytecodeviewer.util.MiscUtils.guessLanguage;
|
||||||
* + Fix hook inject for EZ-Injection
|
* + Fix hook inject for EZ-Injection
|
||||||
*
|
*
|
||||||
* TODO FEATURES:
|
* TODO FEATURES:
|
||||||
* + Console Plugin needs tabbed consoles instead of creating a new window for each console
|
|
||||||
* + CLI Headless needs to be supported
|
* + CLI Headless needs to be supported
|
||||||
* + Add stackmapframes to bytecode decompiler
|
* + Add stackmapframes to bytecode decompiler
|
||||||
* + Add JEB decompiler optionally, requires them to add jeb library jar
|
* + Add JEB decompiler optionally, requires them to add jeb library jar
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package the.bytecode.club.bytecodeviewer.api;
|
package the.bytecode.club.bytecodeviewer.api;
|
||||||
|
|
||||||
import the.bytecode.club.bytecodeviewer.gui.components.SystemConsole;
|
import the.bytecode.club.bytecodeviewer.gui.components.SystemConsole;
|
||||||
|
import the.bytecode.club.bytecodeviewer.plugin.PluginManager;
|
||||||
|
|
||||||
/***************************************************************************
|
/***************************************************************************
|
||||||
* Bytecode Viewer (BCV) - Java & Android Reverse Engineering Suite *
|
* Bytecode Viewer (BCV) - Java & Android Reverse Engineering Suite *
|
||||||
|
@ -28,10 +29,24 @@ import the.bytecode.club.bytecodeviewer.gui.components.SystemConsole;
|
||||||
|
|
||||||
public class PluginConsole extends SystemConsole
|
public class PluginConsole extends SystemConsole
|
||||||
{
|
{
|
||||||
|
private boolean showWindow;
|
||||||
|
|
||||||
public PluginConsole(String pluginName)
|
public PluginConsole(String pluginName)
|
||||||
{
|
{
|
||||||
super("Bytecode Viewer - Plugin Console - " + pluginName);
|
super("Bytecode Viewer - Plugin Console - " + pluginName);
|
||||||
|
|
||||||
|
PluginManager.addConsole(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setVisible(boolean b)
|
||||||
|
{
|
||||||
|
//do nothing
|
||||||
|
if(!showWindow)
|
||||||
|
return;
|
||||||
|
|
||||||
|
super.setVisible(b);
|
||||||
|
}
|
||||||
|
|
||||||
private static final long serialVersionUID = -6556940545421437508L;
|
private static final long serialVersionUID = -6556940545421437508L;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,15 +1,12 @@
|
||||||
package the.bytecode.club.bytecodeviewer.gui.components;
|
package the.bytecode.club.bytecodeviewer.gui.components;
|
||||||
|
|
||||||
import me.konloch.kontainer.io.DiskWriter;
|
import me.konloch.kontainer.io.DiskWriter;
|
||||||
import the.bytecode.club.bytecodeviewer.Configuration;
|
|
||||||
import the.bytecode.club.bytecodeviewer.Constants;
|
|
||||||
import the.bytecode.club.bytecodeviewer.resources.IconResources;
|
import the.bytecode.club.bytecodeviewer.resources.IconResources;
|
||||||
|
|
||||||
import javax.swing.*;
|
import javax.swing.*;
|
||||||
import java.awt.*;
|
import java.awt.*;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
|
||||||
import static the.bytecode.club.bytecodeviewer.Constants.fs;
|
|
||||||
import static the.bytecode.club.bytecodeviewer.Constants.tempDirectory;
|
import static the.bytecode.club.bytecodeviewer.Constants.tempDirectory;
|
||||||
|
|
||||||
/***************************************************************************
|
/***************************************************************************
|
||||||
|
@ -38,14 +35,17 @@ import static the.bytecode.club.bytecodeviewer.Constants.tempDirectory;
|
||||||
*/
|
*/
|
||||||
public class JFrameConsole extends JFrame
|
public class JFrameConsole extends JFrame
|
||||||
{
|
{
|
||||||
private final SearchableJTextArea textArea = new SearchableJTextArea();
|
private String containerName;
|
||||||
|
private int consoleID;
|
||||||
|
private final SearchableJTextArea textArea;
|
||||||
|
|
||||||
public JFrameConsole(String title)
|
public JFrameConsole(String title)
|
||||||
{
|
{
|
||||||
this.setIconImages(IconResources.iconList);
|
setIconImages(IconResources.iconList);
|
||||||
setTitle(title);
|
setTitle(title);
|
||||||
setSize(new Dimension(542, 316));
|
setSize(new Dimension(542, 316));
|
||||||
|
|
||||||
|
textArea = new SearchableJTextArea();
|
||||||
getContentPane().add(textArea.getScrollPane(), BorderLayout.CENTER);
|
getContentPane().add(textArea.getScrollPane(), BorderLayout.CENTER);
|
||||||
|
|
||||||
this.setLocationRelativeTo(null);
|
this.setLocationRelativeTo(null);
|
||||||
|
@ -71,33 +71,78 @@ public class JFrameConsole extends JFrame
|
||||||
*/
|
*/
|
||||||
public void setText(String t)
|
public void setText(String t)
|
||||||
{
|
{
|
||||||
textArea.setText(trim(t));
|
textArea.setText(trimConsoleText(t));
|
||||||
textArea.setCaretPosition(0);
|
textArea.setCaretPosition(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the SearchableJTextArea pane
|
||||||
|
*/
|
||||||
public SearchableJTextArea getTextArea()
|
public SearchableJTextArea getTextArea()
|
||||||
{
|
{
|
||||||
return textArea;
|
return textArea;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String trim(String s)
|
/**
|
||||||
|
* 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(final String s)
|
||||||
{
|
{
|
||||||
int len = s.length();
|
int len = s.length();
|
||||||
int max = 500_000; //TODO this can be increased to 1,000,000 the lower number was chosen to be safe
|
|
||||||
|
//TODO this should also be a setting eventually
|
||||||
|
int max = 500_000;
|
||||||
if(len >= max)
|
if(len >= max)
|
||||||
{
|
{
|
||||||
//TODO if two consoles are ran at the same time and exceed the maximum this file will be overwritten
|
//TODO if two consoles are ran at the same time and exceed the maximum this file will be overwritten
|
||||||
|
|
||||||
//save to disk
|
final File tempFile = new File(tempDirectory, "console_" + consoleID + ".log");
|
||||||
File tempFile = new File(tempDirectory+fs+"console.log");
|
new Thread(()->
|
||||||
DiskWriter.replaceFile(tempFile.getAbsolutePath(), s, false);
|
{
|
||||||
|
//save to disk
|
||||||
|
DiskWriter.replaceFile(tempFile.getAbsolutePath(), s, false);
|
||||||
|
}, "Console Log Saving").start();
|
||||||
|
|
||||||
//trim
|
//trim
|
||||||
int skipped = len - max;
|
int skipped = len - max;
|
||||||
s = s.substring(0, max);
|
String trimmed = s.substring(0, max);
|
||||||
s = ("Skipping " + skipped + " chars, allowing " + max + "\n\r")
|
trimmed = ("WARNING: Skipping " + skipped + " chars, allowing " + max + "\n\r")
|
||||||
+ "Full log saved to: " + tempFile.getAbsolutePath() + "\n\r"
|
+ "Full log saved to: " + tempFile.getAbsolutePath() + "\n\r\n\r"
|
||||||
+ s;
|
+ trimmed;
|
||||||
|
|
||||||
|
return trimmed;
|
||||||
}
|
}
|
||||||
|
|
||||||
return s;
|
return s;
|
||||||
|
|
|
@ -0,0 +1,51 @@
|
||||||
|
package the.bytecode.club.bytecodeviewer.gui.components;
|
||||||
|
|
||||||
|
import the.bytecode.club.bytecodeviewer.resources.IconResources;
|
||||||
|
|
||||||
|
import javax.swing.*;
|
||||||
|
import java.awt.*;
|
||||||
|
|
||||||
|
/***************************************************************************
|
||||||
|
* Bytecode Viewer (BCV) - Java & Android Reverse Engineering Suite *
|
||||||
|
* Copyright (C) 2014 Kalen 'Konloch' Kinloch - http://bytecodeviewer.com *
|
||||||
|
* *
|
||||||
|
* This program is free software: you can redistribute it and/or modify *
|
||||||
|
* it under the terms of the GNU General Public License as published by *
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or *
|
||||||
|
* (at your option) any later version. *
|
||||||
|
* *
|
||||||
|
* This program is distributed in the hope that it will be useful, *
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||||
|
* GNU General Public License for more details. *
|
||||||
|
* *
|
||||||
|
* You should have received a copy of the GNU General Public License *
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Konloch
|
||||||
|
* @since 7/14/2021
|
||||||
|
*/
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
|
@ -18,8 +18,6 @@ package the.bytecode.club.bytecodeviewer.gui.components;
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
|
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
|
||||||
***************************************************************************/
|
***************************************************************************/
|
||||||
|
|
||||||
import the.bytecode.club.bytecodeviewer.BytecodeViewer;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A simple console GUI.
|
* A simple console GUI.
|
||||||
*
|
*
|
||||||
|
|
|
@ -301,7 +301,7 @@ public class ResourceListPane extends TranslatedVisibleComponent implements File
|
||||||
if (c.name.equals(cheapHax))
|
if (c.name.equals(cheapHax))
|
||||||
container = c;
|
container = c;
|
||||||
}
|
}
|
||||||
|
|
||||||
String name = nameBuffer.toString();
|
String name = nameBuffer.toString();
|
||||||
|
|
||||||
//TODO add file header check
|
//TODO add file header check
|
||||||
|
@ -311,13 +311,13 @@ public class ResourceListPane extends TranslatedVisibleComponent implements File
|
||||||
name.substring(0, name.length() - ".class".length()));
|
name.substring(0, name.length() - ".class".length()));
|
||||||
|
|
||||||
if (cn != null)
|
if (cn != null)
|
||||||
BytecodeViewer.viewer.workPane.addClassResource(container, nameBuffer.toString());
|
BytecodeViewer.viewer.workPane.addClassResource(container, name);
|
||||||
else
|
else
|
||||||
BytecodeViewer.viewer.workPane.addFileResource(container, nameBuffer.toString());
|
BytecodeViewer.viewer.workPane.addFileResource(container, name);
|
||||||
}
|
}
|
||||||
else
|
else if(container.resourceFiles.containsKey(name))
|
||||||
{
|
{
|
||||||
BytecodeViewer.viewer.workPane.addFileResource(container, nameBuffer.toString());
|
BytecodeViewer.viewer.workPane.addFileResource(container, name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -23,6 +23,10 @@ public class TabRemovalEvent implements ContainerListener
|
||||||
public void componentRemoved(ContainerEvent e)
|
public void componentRemoved(ContainerEvent e)
|
||||||
{
|
{
|
||||||
final Component c = e.getChild();
|
final Component c = e.getChild();
|
||||||
|
|
||||||
|
if(!(c instanceof ResourceViewer))
|
||||||
|
return;
|
||||||
|
|
||||||
String workingName = ((ResourceViewer) c).resource.workingName;
|
String workingName = ((ResourceViewer) c).resource.workingName;
|
||||||
BytecodeViewer.viewer.workPane.openedTabs.remove(workingName);
|
BytecodeViewer.viewer.workPane.openedTabs.remove(workingName);
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,6 +5,8 @@ import java.util.*;
|
||||||
import javax.swing.filechooser.FileFilter;
|
import javax.swing.filechooser.FileFilter;
|
||||||
import the.bytecode.club.bytecodeviewer.BytecodeViewer;
|
import the.bytecode.club.bytecodeviewer.BytecodeViewer;
|
||||||
import the.bytecode.club.bytecodeviewer.api.Plugin;
|
import the.bytecode.club.bytecodeviewer.api.Plugin;
|
||||||
|
import the.bytecode.club.bytecodeviewer.api.PluginConsole;
|
||||||
|
import the.bytecode.club.bytecodeviewer.gui.components.JFrameConsoleTabbed;
|
||||||
import the.bytecode.club.bytecodeviewer.plugin.strategies.*;
|
import the.bytecode.club.bytecodeviewer.plugin.strategies.*;
|
||||||
import the.bytecode.club.bytecodeviewer.util.MiscUtils;
|
import the.bytecode.club.bytecodeviewer.util.MiscUtils;
|
||||||
|
|
||||||
|
@ -35,11 +37,20 @@ import the.bytecode.club.bytecodeviewer.util.MiscUtils;
|
||||||
* @author Bibl
|
* @author Bibl
|
||||||
* @since 01/16/16, 14:36, Adaptable PluginLaunchStrategy system.
|
* @since 01/16/16, 14:36, Adaptable PluginLaunchStrategy system.
|
||||||
*/
|
*/
|
||||||
public final class PluginManager {
|
|
||||||
|
|
||||||
|
public final class PluginManager
|
||||||
|
{
|
||||||
private static final Map<String, PluginLaunchStrategy> launchStrategies = new HashMap<>();
|
private static final Map<String, PluginLaunchStrategy> launchStrategies = new HashMap<>();
|
||||||
private static final PluginFileFilter filter = new PluginFileFilter();
|
private static final PluginFileFilter filter = new PluginFileFilter();
|
||||||
private static List<Plugin> pluginInstances = new ArrayList<>();
|
private static List<Plugin> pluginInstances = new ArrayList<>();
|
||||||
|
|
||||||
|
//TODO this system needs to be redone, currently it will conflict if more than one plugin is ran at the same time
|
||||||
|
// the solution is to tie the plugin object into the plugin console,
|
||||||
|
// then move all of this into the plugin class as non-static objects
|
||||||
|
|
||||||
|
private static Plugin activePlugin;
|
||||||
|
private static JFrameConsoleTabbed activeTabbedConsole;
|
||||||
|
private static int consoleCount = 0;
|
||||||
|
|
||||||
static
|
static
|
||||||
{
|
{
|
||||||
|
@ -67,6 +78,15 @@ public final class PluginManager {
|
||||||
*/
|
*/
|
||||||
public static void runPlugin(Plugin newPluginInstance)
|
public static void runPlugin(Plugin newPluginInstance)
|
||||||
{
|
{
|
||||||
|
//reset the console count
|
||||||
|
consoleCount = 0;
|
||||||
|
|
||||||
|
//reset the active tabbed console
|
||||||
|
activeTabbedConsole = null;
|
||||||
|
|
||||||
|
//reset the active plugin
|
||||||
|
activePlugin = newPluginInstance;
|
||||||
|
|
||||||
//clean the plugin list from dead threads
|
//clean the plugin list from dead threads
|
||||||
pluginInstances.removeIf(Plugin::isFinished);
|
pluginInstances.removeIf(Plugin::isFinished);
|
||||||
|
|
||||||
|
@ -96,6 +116,23 @@ public final class PluginManager {
|
||||||
if (p != null)
|
if (p != null)
|
||||||
runPlugin(p);
|
runPlugin(p);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add an active console from a plugin being ran
|
||||||
|
*/
|
||||||
|
public static void addConsole(PluginConsole console)
|
||||||
|
{
|
||||||
|
int id = consoleCount++;
|
||||||
|
|
||||||
|
if(activeTabbedConsole == null)
|
||||||
|
{
|
||||||
|
activeTabbedConsole = new JFrameConsoleTabbed(console.getTitle());
|
||||||
|
activeTabbedConsole.setVisible(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
console.setConsoleID(id);
|
||||||
|
activeTabbedConsole.addConsole(console.getComponent(0), activePlugin.activeContainer.name);
|
||||||
|
}
|
||||||
|
|
||||||
public static void register(String name, PluginLaunchStrategy strat) {
|
public static void register(String name, PluginLaunchStrategy strat) {
|
||||||
launchStrategies.put(name, strat);
|
launchStrategies.put(name, strat);
|
||||||
|
|
Loading…
Reference in a new issue