Code Cleanup

This commit is contained in:
Konloch 2021-06-22 11:05:25 -07:00
parent b0f3e5832a
commit 5581a343f5
13 changed files with 835 additions and 694 deletions

View file

@ -24,7 +24,7 @@ import the.bytecode.club.bootloader.Boot;
import the.bytecode.club.bytecodeviewer.api.ClassNodeLoader;
import the.bytecode.club.bytecodeviewer.compilers.Compilers;
import the.bytecode.club.bytecodeviewer.gui.ClassViewer;
import the.bytecode.club.bytecodeviewer.gui.resourceviewer.ResourceListPane;
import the.bytecode.club.bytecodeviewer.gui.resourcelist.ResourceListPane;
import the.bytecode.club.bytecodeviewer.gui.MainViewerGUI;
import the.bytecode.club.bytecodeviewer.gui.extras.RunOptions;
import the.bytecode.club.bytecodeviewer.gui.SearchBoxPane;
@ -104,7 +104,7 @@ public class BytecodeViewer
public static Refactorer refactorer = new Refactorer();
public static List<FileContainer> files = new ArrayList<>(); //all of BCV's loaded files/classes/etc
public static List<Process> createdProcesses = new ArrayList<>();
public static final boolean EXPERIMENTAL_DRAG_TABS = false;
public static final boolean EXPERIMENTAL_TAB_CODE = false;
/**
* The version checker thread

View file

@ -32,7 +32,7 @@ import the.bytecode.club.bytecodeviewer.gui.extras.AboutWindow;
import the.bytecode.club.bytecodeviewer.gui.extras.RunOptions;
import the.bytecode.club.bytecodeviewer.gui.plugins.MaliciousCodeScannerOptions;
import the.bytecode.club.bytecodeviewer.gui.plugins.ReplaceStringsOptions;
import the.bytecode.club.bytecodeviewer.gui.resourceviewer.ResourceListPane;
import the.bytecode.club.bytecodeviewer.gui.resourcelist.ResourceListPane;
import the.bytecode.club.bytecodeviewer.obfuscators.rename.RenameClasses;
import the.bytecode.club.bytecodeviewer.obfuscators.rename.RenameFields;
import the.bytecode.club.bytecodeviewer.obfuscators.rename.RenameMethods;
@ -177,7 +177,7 @@ public class MainViewerGUI extends JFrame {
public JCheckBoxMenuItem asc = new JCheckBoxMenuItem("Allow only ASCII characters in strings");
public JCheckBoxMenuItem ren = new JCheckBoxMenuItem("Rename ambiguous classes and class elements");
//Proycon
public final JMenu proyconSettingsSecondaryMenu = new JMenu("Procyon");
public final JMenu procyonSettingsSecondaryMenu = new JMenu("Procyon");
public final JCheckBoxMenuItem alwaysGenerateExceptionVars = new JCheckBoxMenuItem("Always Generate Exception Variable For Catch Blocks");
public final JCheckBoxMenuItem excludeNestedTypes = new JCheckBoxMenuItem("Exclude Nested Types");
public final JCheckBoxMenuItem showDebugLineNumbers = new JCheckBoxMenuItem("Show Debug Line Numbers");
@ -426,21 +426,21 @@ public class MainViewerGUI extends JFrame {
visualSettings.add(showClassMethods);
//PROCYON SETTINGS
settingsMainMenu.add(proyconSettingsSecondaryMenu);
proyconSettingsSecondaryMenu.add(alwaysGenerateExceptionVars);
proyconSettingsSecondaryMenu.add(excludeNestedTypes);
proyconSettingsSecondaryMenu.add(showDebugLineNumbers);
proyconSettingsSecondaryMenu.add(includeLineNumbersInBytecode);
proyconSettingsSecondaryMenu.add(includeErrorDiagnostics);
proyconSettingsSecondaryMenu.add(showSyntheticMembers);
proyconSettingsSecondaryMenu.add(simplifyMemberReferences);
proyconSettingsSecondaryMenu.add(mergeVariables);
proyconSettingsSecondaryMenu.add(forceExplicitTypeArguments);
proyconSettingsSecondaryMenu.add(forceExplicitImports);
proyconSettingsSecondaryMenu.add(flattenSwitchBlocks);
proyconSettingsSecondaryMenu.add(retainPointlessSwitches);
proyconSettingsSecondaryMenu.add(retainRedunantCasts);
proyconSettingsSecondaryMenu.add(unicodeOutputEnabled);
settingsMainMenu.add(procyonSettingsSecondaryMenu);
procyonSettingsSecondaryMenu.add(alwaysGenerateExceptionVars);
procyonSettingsSecondaryMenu.add(excludeNestedTypes);
procyonSettingsSecondaryMenu.add(showDebugLineNumbers);
procyonSettingsSecondaryMenu.add(includeLineNumbersInBytecode);
procyonSettingsSecondaryMenu.add(includeErrorDiagnostics);
procyonSettingsSecondaryMenu.add(showSyntheticMembers);
procyonSettingsSecondaryMenu.add(simplifyMemberReferences);
procyonSettingsSecondaryMenu.add(mergeVariables);
procyonSettingsSecondaryMenu.add(forceExplicitTypeArguments);
procyonSettingsSecondaryMenu.add(forceExplicitImports);
procyonSettingsSecondaryMenu.add(flattenSwitchBlocks);
procyonSettingsSecondaryMenu.add(retainPointlessSwitches);
procyonSettingsSecondaryMenu.add(retainRedunantCasts);
procyonSettingsSecondaryMenu.add(unicodeOutputEnabled);
//CFR SETTINGS
settingsMainMenu.add(cfrSettingsSecondaryMenu);

View file

@ -18,7 +18,7 @@ import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.TreePath;
import org.objectweb.asm.tree.ClassNode;
import the.bytecode.club.bytecodeviewer.BytecodeViewer;
import the.bytecode.club.bytecodeviewer.gui.resourceviewer.ResourceListPane;
import the.bytecode.club.bytecodeviewer.gui.resourcelist.ResourceListPane;
import the.bytecode.club.bytecodeviewer.searching.BackgroundSearchThread;
import the.bytecode.club.bytecodeviewer.searching.FieldCallSearch;
import the.bytecode.club.bytecodeviewer.searching.LDCSearch;
@ -61,13 +61,13 @@ public class SearchBoxPane extends VisibleComponent {
public static final SearchRadius[] SEARCH_RADII = SearchRadius.values();
public static final SearchType[] SEARCH_TYPES = SearchType.values();
JCheckBox exact = new JCheckBox("Exact");
DefaultMutableTreeNode treeRoot = new DefaultMutableTreeNode("Results");
JTree tree;
JComboBox typeBox;
public final JCheckBox exact = new JCheckBox("Exact");
public final DefaultMutableTreeNode treeRoot = new DefaultMutableTreeNode("Results");
public final JTree tree;
public final JComboBox typeBox;
SearchType searchType = null;
JComboBox searchRadiusBox;
public SearchType searchType = null;
public final JComboBox searchRadiusBox;
public JButton search = new JButton("Search");
BackgroundSearchThread t = new BackgroundSearchThread(true) {
@ -75,7 +75,6 @@ public class SearchBoxPane extends VisibleComponent {
public void doSearch() {
// empty
}
};
@SuppressWarnings("unchecked")
@ -83,9 +82,7 @@ public class SearchBoxPane extends VisibleComponent {
super("Search");
final JPanel optionPanel = new JPanel(new BorderLayout());
final JPanel searchRadiusOpt = new JPanel(new BorderLayout());
final JPanel searchOpts = new JPanel(new GridLayout(2, 1));
searchRadiusOpt.add(new JLabel("Search from "), BorderLayout.WEST);
@ -96,15 +93,12 @@ public class SearchBoxPane extends VisibleComponent {
}
searchRadiusBox = new JComboBox(model);
searchRadiusOpt.add(searchRadiusBox, BorderLayout.CENTER);
searchOpts.add(searchRadiusOpt);
model = new DefaultComboBoxModel();
for (final SearchType st : SEARCH_TYPES) {
for (final SearchType st : SEARCH_TYPES)
model.addElement(st);
}
typeBox = new JComboBox(model);
final JPanel searchOptPanel = new JPanel();
@ -160,8 +154,7 @@ public class SearchBoxPane extends VisibleComponent {
final ClassNode fN = Objects.requireNonNull(container).getClassNode(className);
if (fN != null) {
Objects.requireNonNull(MainViewerGUI.getComponent(ResourceListPane.class))
.openClassFileToWorkSpace(container, className + ".class", fN);
BytecodeViewer.viewer.openClassFile(container, className + ".class", fN);
}
});

View file

@ -89,18 +89,6 @@ public class TabbedPane extends JPanel {
}
};
this.addMouseListener(new MouseAdapter() {
@Override
public void mouseReleased(MouseEvent e) {
if (e.getButton() == MouseEvent.BUTTON2) {
final int i = pane.indexOfTabComponent(TabbedPane.this);
if (i != -1) {
pane.remove(i);
}
}
}
});
this.add(label);
// add more space between the label and the button
label.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 5));
@ -167,7 +155,8 @@ public class TabbedPane extends JPanel {
}
});
if(BytecodeViewer.EXPERIMENTAL_DRAG_TABS)
//tab dragging
if(BytecodeViewer.EXPERIMENTAL_TAB_CODE)
{
/*label.addMouseListener(new MouseListener() {
@Override public void mouseClicked(MouseEvent e) {}
@ -197,6 +186,22 @@ public class TabbedPane extends JPanel {
}
});
}
//middle click close
if(BytecodeViewer.EXPERIMENTAL_TAB_CODE)
{
this.addMouseListener(new MouseAdapter() {
@Override
public void mouseReleased(MouseEvent e) {
if (e.getButton() == MouseEvent.BUTTON2) {
final int i = pane.indexOfTabComponent(TabbedPane.this);
if (i != -1) {
pane.remove(i);
}
}
}
});
}
}
private void stopDragging(int mouseX, int mouseY) {

View file

@ -0,0 +1,38 @@
package the.bytecode.club.bytecodeviewer.gui.extras;
import java.awt.*;
import java.awt.font.FontRenderContext;
import java.awt.geom.Rectangle2D;
/**
* @author http://stackoverflow.com/a/18450804
*/
public class StringMetricsUtil
{
Font font;
FontRenderContext context;
public StringMetricsUtil(Graphics2D g2)
{
font = g2.getFont();
context = g2.getFontRenderContext();
}
public Rectangle2D getBounds(String message)
{
return font.getStringBounds(message, context);
}
public double getWidth(String message)
{
Rectangle2D bounds = getBounds(message);
return bounds.getWidth();
}
public double getHeight(String message)
{
Rectangle2D bounds = getBounds(message);
return bounds.getHeight();
}
}

View file

@ -1,4 +1,4 @@
package the.bytecode.club.bytecodeviewer.gui.resourceviewer;
package the.bytecode.club.bytecodeviewer.gui.resourcelist;
import the.bytecode.club.bytecodeviewer.Resources;
@ -24,9 +24,9 @@ public class ImageRenderer extends DefaultTreeCellRenderer
Component ret = super.getTreeCellRendererComponent(tree, value, selected, expanded, leaf, row, hasFocus);
if (value instanceof ResourceListPane.MyTreeNode)
if (value instanceof ResourceTreeNode)
{
ResourceListPane.MyTreeNode node = (ResourceListPane.MyTreeNode) value;
ResourceTreeNode node = (ResourceTreeNode) value;
String name = node.toString().toLowerCase();
if (name.endsWith(".jar") || name.endsWith(".war"))

View file

@ -0,0 +1,435 @@
package the.bytecode.club.bytecodeviewer.gui.resourcelist;
//TODO fix for Java 9+
import com.sun.java.swing.plaf.windows.WindowsTreeUI;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.event.ActionEvent;
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.io.File;
import java.util.Enumeration;
import java.util.Map.Entry;
import java.util.Objects;
import javax.swing.AbstractAction;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JPanel;
import javax.swing.JPopupMenu;
import javax.swing.JScrollPane;
import javax.swing.JTextField;
import javax.swing.JTree;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.TreeNode;
import javax.swing.tree.TreePath;
import org.objectweb.asm.tree.ClassNode;
import the.bytecode.club.bytecodeviewer.BytecodeViewer;
import the.bytecode.club.bytecodeviewer.gui.VisibleComponent;
import the.bytecode.club.bytecodeviewer.util.FileContainer;
import the.bytecode.club.bytecodeviewer.util.FileDrop;
import the.bytecode.club.bytecodeviewer.util.LazyNameUtil;
/***************************************************************************
* Bytecode Viewer (BCV) - Java & Android Reverse Engineering Suite *
* Copyright (C) 2014 Kalen 'Konloch' Kinloch - http://bytecodeviewer.com *
* *
* This program is free software: you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation, either version 3 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
***************************************************************************/
/**
* The file navigation pane.
*
* @author Konloch
* @author WaterWolf
* @author afffsdd
*/
public class ResourceListPane extends VisibleComponent implements FileDrop.Listener
{
public final JPopupMenu rightClickMenu = new JPopupMenu();
public final JCheckBox exact = new JCheckBox("Exact");
public final JButton open = new JButton("+");
public final JButton close = new JButton("-");
public final ResourceTreeNode treeRoot = new ResourceTreeNode("Loaded Files:");
public final ResourceTree tree = new ResourceTree(treeRoot);
public final String quickSearchText = "Quick file search (no file extension)";
public final JTextField quickSearch = new JTextField(quickSearchText);
public final FileDrop fileDrop;
public boolean cancel = false;
public final KeyAdapter search = new SearchKeyAdapter(this);
private void showPopMenu(ResourceTree tree, TreePath selPath, int x, int y) {
if (selPath == null)
return;
rightClickMenu.removeAll();
rightClickMenu.add(new ResourceListRightClickRemove(this, x, y, tree));
//TODO fix for Java 9+
// You can replace this with any Icon loaded from disk,
// they could be re-used for the plus and minus symbols on the resource list too
rightClickMenu.add(new AbstractAction("Expand", WindowsTreeUI.ExpandedIcon.createExpandedIcon()) {
@Override
public void actionPerformed(ActionEvent e) {
TreePath selPath = ResourceListPane.this.tree.getPathForLocation(x, y);
expandAll(tree, Objects.requireNonNull(selPath), true);
}
});
rightClickMenu.add(new AbstractAction("Collapse", WindowsTreeUI.CollapsedIcon.createCollapsedIcon()) {
@Override
public void actionPerformed(ActionEvent e) {
TreePath selPath = ResourceListPane.this.tree.getPathForLocation(x, y);
expandAll(tree, Objects.requireNonNull(selPath), false);
}
});
rightClickMenu.show(this.tree, x, y);
}
//used to remove resources from the resource list
public void removeFile(FileContainer fileContainer)
{
BytecodeViewer.files.remove(fileContainer);
LazyNameUtil.removeName(fileContainer.name);
}
public ResourceListPane()
{
super("ClassNavigation");
tree.setRootVisible(false);
tree.setShowsRootHandles(true);
quickSearch.setForeground(Color.gray);
setTitle("Files");
attachTreeListeners();
attachQuickSearchListeners();
getContentPane().setLayout(new BorderLayout());
getContentPane().add(new JScrollPane(tree), BorderLayout.CENTER);
JPanel exactPanel = new JPanel(new BorderLayout());
JPanel quickSearchPanel = new JPanel();
JPanel buttonPanel = new JPanel(new BorderLayout());
quickSearchPanel.setLayout(new BorderLayout());
quickSearchPanel.add(quickSearch, BorderLayout.NORTH);
exactPanel.add(exact, BorderLayout.WEST);
buttonPanel.add(open, BorderLayout.EAST);
buttonPanel.add(close, BorderLayout.WEST);
exactPanel.add(buttonPanel, BorderLayout.EAST);
quickSearchPanel.add(exactPanel, BorderLayout.SOUTH);
getContentPane().add(quickSearchPanel, BorderLayout.SOUTH);
this.setVisible(true);
fileDrop = new FileDrop(this, this);
}
@Override
public void filesDropped(final File[] files)
{
if (files.length < 1)
return;
BytecodeViewer.openFiles(files, true);
}
public void updateTree()
{
try
{
treeRoot.removeAllChildren();
for (FileContainer container : BytecodeViewer.files)
{
ResourceTreeNode root = new ResourceTreeNode(container.name);
treeRoot.add(root);
ImageRenderer renderer = new ImageRenderer();
tree.setCellRenderer(renderer);
if (!container.classes.isEmpty())
{
for (ClassNode c : container.classes)
{
String name = c.name;
final String[] spl = name.split("/");
if (spl.length < 2)
{
root.add(new ResourceTreeNode(name + ".class"));
}
else
{
ResourceTreeNode parent = root;
for (int i1 = 0; i1 < spl.length; i1++)
{
String s = spl[i1];
if (i1 == spl.length - 1)
s += ".class";
ResourceTreeNode child = null;
for (int i = 0; i < parent.getChildCount(); i++)
{
if (((ResourceTreeNode) parent.getChildAt(i)).getUserObject().equals(s))
{
child = (ResourceTreeNode) parent.getChildAt(i);
break;
}
}
if (child == null)
{
child = new ResourceTreeNode(s);
parent.add(child);
}
parent = child;
}
}
}
}
if (!container.files.isEmpty())
{
for (final Entry<String, byte[]> entry : container.files.entrySet())
{
String name = entry.getKey();
final String[] spl = name.split("/");
if (spl.length < 2)
{
root.add(new ResourceTreeNode(name));
}
else
{
ResourceTreeNode parent = root;
for (final String s : spl)
{
ResourceTreeNode child = null;
for (int i = 0; i < parent.getChildCount(); i++)
{
if (((ResourceTreeNode) parent.getChildAt(i)).getUserObject().equals(s))
{
child = (ResourceTreeNode) parent.getChildAt(i);
break;
}
}
if (child == null)
{
child = new ResourceTreeNode(s);
parent.add(child);
}
parent = child;
}
}
}
}
}
treeRoot.sort();
tree.expandPath(new TreePath(tree.getModel().getRoot()));
tree.updateUI();
} catch (java.util.ConcurrentModificationException e) {
//ignore, the last file will reset everything
}
//TODO add a setting for this
// expandAll(tree, true);
}
@SuppressWarnings("rawtypes")
private void expandAll(final JTree tree, final TreePath parent,
final boolean expand) {
// Traverse children
final TreeNode node = (TreeNode) parent.getLastPathComponent();
if (node.getChildCount() >= 0) {
for (final Enumeration e = node.children(); e.hasMoreElements(); ) {
final TreeNode n = (TreeNode) e.nextElement();
final TreePath path = parent.pathByAddingChild(n);
expandAll(tree, path, expand);
}
}
// Expansion or collapse must be done bottom-up
if (expand) {
tree.expandPath(parent);
} else {
tree.collapsePath(parent);
}
}
public void resetWorkspace()
{
treeRoot.removeAllChildren();
tree.repaint();
tree.updateUI();
}
public void openPath(TreePath path)
{
if (path == null || path.getPathCount() == 1)
return;
final StringBuilder nameBuffer = new StringBuilder();
for (int i = 2; i < path.getPathCount(); i++)
{
nameBuffer.append(path.getPathComponent(i));
if (i < path.getPathCount() - 1)
nameBuffer.append("/");
}
String cheapHax = path.getPathComponent(1).toString();
FileContainer container = null;
for (FileContainer c : BytecodeViewer.files)
{
if (c.name.equals(cheapHax))
container = c;
}
String name = nameBuffer.toString();
if (name.endsWith(".class"))
{
final ClassNode cn = BytecodeViewer.getClassNode(Objects.requireNonNull(container),
name.substring(0, name.length() - ".class".length()));
if (cn != null)
BytecodeViewer.viewer.openClassFile(container, nameBuffer.toString(), cn);
else
BytecodeViewer.viewer.openFile(container, nameBuffer.toString(),
BytecodeViewer.getFileContents(nameBuffer.toString()));
}
else
{
BytecodeViewer.viewer.openFile(container, nameBuffer.toString(),
BytecodeViewer.getFileContents(nameBuffer.toString()));
}
}
public void attachTreeListeners()
{
tree.addMouseListener(new MouseAdapter()
{
@Override
public void mouseReleased(MouseEvent e)
{
if (e.isMetaDown())
{
ResourceTree tree = (ResourceTree) e.getSource();
TreePath selPath = ResourceListPane.this.tree.getPathForLocation(e.getX(), e.getY());
if (selPath == null)
return;
DefaultMutableTreeNode selectNode = (DefaultMutableTreeNode) selPath.getLastPathComponent();
Enumeration<?> enumeration = treeRoot.children();
while (enumeration.hasMoreElements())
{
DefaultMutableTreeNode node = (DefaultMutableTreeNode) enumeration.nextElement();
if (node.isNodeAncestor(selectNode))
{
//rightClickMenu.show(tree, e.getX(), e.getY());
showPopMenu(tree, selPath, e.getX(), e.getY());
break;
}
}
}
}
});
this.open.addActionListener(e -> {
final TreeNode root = (TreeNode) tree.getModel().getRoot();
expandAll(tree, new TreePath(root), true);
});
this.close.addActionListener(e -> {
final TreeNode root = (TreeNode) tree.getModel().getRoot();
final TreePath path = new TreePath(root);
expandAll(tree, path, false);
tree.expandPath(path);
});
this.tree.addMouseListener(new MouseAdapter() {
@Override
public void mousePressed(MouseEvent e) {
openPath(tree.getPathForLocation(e.getX(), e.getY()));
}
});
this.tree.addTreeSelectionListener(arg0 -> {
if (cancel) {
cancel = false;
return;
}
openPath(arg0.getPath());
});
this.tree.addKeyListener(new KeyListener()
{
@Override
public void keyReleased(KeyEvent e) { }
@Override
public void keyTyped(KeyEvent e) { }
@Override
public void keyPressed(KeyEvent e) {
if (e.getKeyCode() == KeyEvent.VK_ENTER) {
if (e.getSource() instanceof ResourceTree) {
ResourceTree tree = (ResourceTree) e.getSource();
openPath(tree.getSelectionPath());
}
} else if ((int) e.getKeyChar() != 0 && (int) e.getKeyChar() != 8 && (int) e.getKeyChar() != 127 && (int) e.getKeyChar() != 65535 && !e.isControlDown() && !e.isAltDown()) {
quickSearch.grabFocus();
quickSearch.setText("" + e.getKeyChar());
cancel = true;
} else if (e.isControlDown() && (int) e.getKeyChar() == 6) //ctrl + f
{
quickSearch.grabFocus();
} else {
cancel = true;
}
}
});
}
public void attachQuickSearchListeners()
{
quickSearch.addKeyListener(search);
quickSearch.addFocusListener(new FocusListener() {
@Override
public void focusGained(final FocusEvent arg0) {
if (quickSearch.getText().equals(quickSearchText)) {
quickSearch.setText("");
quickSearch.setForeground(Color.black);
}
}
@Override
public void focusLost(final FocusEvent arg0) {
if (quickSearch.getText().isEmpty()) {
quickSearch.setText(quickSearchText);
quickSearch.setForeground(Color.gray);
}
}
});
}
}

View file

@ -0,0 +1,61 @@
package the.bytecode.club.bytecodeviewer.gui.resourcelist;
import the.bytecode.club.bytecodeviewer.BytecodeViewer;
import the.bytecode.club.bytecodeviewer.util.FileContainer;
import javax.swing.*;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.TreePath;
import java.awt.event.ActionEvent;
import java.util.Enumeration;
import java.util.Objects;
/**
* @author Konloch
* @since 6/22/2021
*/
public class ResourceListRightClickRemove extends AbstractAction
{
private final ResourceListPane resourceListPane;
private final int x;
private final int y;
private final ResourceTree tree;
public ResourceListRightClickRemove(ResourceListPane resourceListPane, int x, int y, ResourceTree tree)
{
super("Remove");
this.resourceListPane = resourceListPane;
this.x = x;
this.y = y;
this.tree = tree;
}
@Override
public void actionPerformed(ActionEvent e)
{
TreePath selPath = resourceListPane.tree.getPathForLocation(x, y);
DefaultMutableTreeNode selectNode = (DefaultMutableTreeNode) Objects.requireNonNull(selPath).getLastPathComponent();
Enumeration<?> enumeration = resourceListPane.treeRoot.children();
while (enumeration.hasMoreElements())
{
DefaultMutableTreeNode node = (DefaultMutableTreeNode) enumeration.nextElement();
if (node.isNodeAncestor(selectNode))
{
DefaultMutableTreeNode root = (DefaultMutableTreeNode) tree.getModel().getRoot();
root.remove(node);
for (FileContainer fileContainer : BytecodeViewer.files)
{
if (fileContainer.name.equals(selectNode.toString()))
{
resourceListPane.removeFile(fileContainer);
break;
}
}
resourceListPane.updateTree();
return;
}
}
}
}

View file

@ -0,0 +1,51 @@
package the.bytecode.club.bytecodeviewer.gui.resourcelist;
import the.bytecode.club.bytecodeviewer.gui.extras.StringMetricsUtil;
import javax.swing.*;
import javax.swing.tree.DefaultMutableTreeNode;
import java.awt.*;
/**
* @author Konloch
* @since 6/22/2021
*/
public class ResourceTree extends JTree
{
private static final long serialVersionUID = -2355167326094772096L;
DefaultMutableTreeNode treeRoot;
public ResourceTree(final DefaultMutableTreeNode treeRoot)
{
super(treeRoot);
this.treeRoot = treeRoot;
}
StringMetricsUtil m = null;
@Override
public void paint(final Graphics g)
{
try
{
super.paint(g);
if (m == null)
{
m = new StringMetricsUtil((Graphics2D) g);
}
if (treeRoot.getChildCount() < 1)
{
g.setColor(new Color(0, 0, 0, 100));
g.fillRect(0, 0, getWidth(), getHeight());
g.setColor(Color.white);
String s = "Drag class/jar/zip/APK/DEX here";
g.drawString(s,
((int) ((getWidth() / 2) - (m.getWidth(s) / 2))),
getHeight() / 2);
}
}
catch (InternalError | NullPointerException ignored)
{
}
}
}

View file

@ -0,0 +1,70 @@
package the.bytecode.club.bytecodeviewer.gui.resourcelist;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.MutableTreeNode;
import java.util.Comparator;
/**
* @author Konloch
* @since 6/22/2021
*/
public class ResourceTreeNode extends DefaultMutableTreeNode
{
private static final long serialVersionUID = -8817777566176729571L;
public ResourceTreeNode(final Object o)
{
super(o);
}
@Override
public void insert(final MutableTreeNode newChild, final int childIndex)
{
super.insert(newChild, childIndex);
}
public void sort()
{
recursiveSort(this);
}
@SuppressWarnings("unchecked")
private void recursiveSort(final ResourceTreeNode node)
{
node.children.sort(nodeComparator);
for (ResourceTreeNode nextNode : (Iterable<ResourceTreeNode>) node.children)
{
if (nextNode.getChildCount() > 0)
{
recursiveSort(nextNode);
}
}
}
protected Comparator<ResourceTreeNode> nodeComparator = new Comparator<ResourceTreeNode>()
{
@Override
public int compare(final ResourceTreeNode o1, final ResourceTreeNode o2)
{
// To make sure nodes with children are always on top
final int firstOffset = o1.getChildCount() > 0 ? -1000 : 0;
final int secondOffset = o2.getChildCount() > 0 ? 1000 : 0;
return o1.toString().compareToIgnoreCase(o2.toString())
+ firstOffset + secondOffset;
}
@Override
public boolean equals(final Object obj)
{
return false;
}
@Override
public int hashCode()
{
return 7;
}
};
}

View file

@ -0,0 +1,129 @@
package the.bytecode.club.bytecodeviewer.gui.resourcelist;
import the.bytecode.club.bytecodeviewer.BytecodeViewer;
import javax.swing.tree.TreeNode;
import javax.swing.tree.TreePath;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.util.Enumeration;
/**
* @author Konloch
* @since 6/22/2021
*/
public class SearchKeyAdapter extends KeyAdapter
{
private final ResourceListPane resourceListPane;
public SearchKeyAdapter(ResourceListPane resourceListPane) {this.resourceListPane = resourceListPane;}
@Override
public void keyPressed(final KeyEvent ke)
{
//only trigger on enter
if (ke.getKeyCode() != KeyEvent.VK_ENTER)
return;
final String qt = resourceListPane.quickSearch.getText();
resourceListPane.quickSearch.setText("");
if (qt.isEmpty()) //NOPE
return;
String[] path;
int found = 0;
if (qt.contains("."))
{
path = qt.split("\\.");
}
else
{
path = new String[]{qt};
}
ResourceTreeNode curNode = resourceListPane.treeRoot;
if (resourceListPane.exact.isSelected())
{
pathLoop:
for (int i = 0; i < path.length; i++)
{
final String pathName = path[i];
final boolean isLast = i == path.length - 1;
for (int c = 0; c < curNode.getChildCount(); c++)
{
final ResourceTreeNode child = (ResourceTreeNode) curNode.getChildAt(c);
System.out.println(pathName + ":" + child.getUserObject());
if (child.getUserObject().equals(pathName))
{
curNode = child;
if (isLast)
{
System.out.println("Found! " + curNode);
found++;
final TreePath pathn = new TreePath(curNode.getPath());
resourceListPane.tree.setSelectionPath(pathn);
resourceListPane.tree.makeVisible(pathn);
resourceListPane.tree.scrollPathToVisible(pathn);
resourceListPane.openPath(pathn); //auto open
break pathLoop;
}
continue pathLoop;
}
}
System.out.println("Could not find " + pathName);
break;
}
}
else
{
@SuppressWarnings("unchecked")
Enumeration<ResourceTreeNode> enums = curNode.depthFirstEnumeration();
while (enums != null && enums.hasMoreElements())
{
ResourceTreeNode node = enums.nextElement();
if (node.isLeaf())
{
if (((String) (node.getUserObject())).toLowerCase().contains(path[path.length - 1].toLowerCase()))
{
TreeNode[] pathArray = node.getPath();
int k = 0;
StringBuilder fullPath = new StringBuilder();
while (pathArray != null
&& k < pathArray.length)
{
ResourceTreeNode n = (ResourceTreeNode) pathArray[k];
String s = (String) (n.getUserObject());
fullPath.append(s);
if (k++ != pathArray.length - 1)
{
fullPath.append(".");
}
}
String fullPathString = fullPath.toString();
if (fullPathString.toLowerCase().contains(qt.toLowerCase()))
{
System.out.println("Found! " + node);
found++;
if (found >= 30)
{ //TODO probably make this a setting, no real reason it's 30
BytecodeViewer.showMessage("Uh oh, there could be more results but you've"
+ " triggered the 30 classes at once limit. Try refining your search.");
return;
}
final TreePath pathn = new TreePath(node.getPath());
resourceListPane.tree.setSelectionPath(pathn.getParentPath());
resourceListPane.tree.setSelectionPath(pathn);
resourceListPane.tree.makeVisible(pathn);
resourceListPane.tree.scrollPathToVisible(pathn);
}
}
}
}
}
}
}

View file

@ -1,641 +0,0 @@
package the.bytecode.club.bytecodeviewer.gui.resourceviewer;
//TODO fix for Java 9+
import com.sun.java.swing.plaf.windows.WindowsTreeUI;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.ActionEvent;
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.font.FontRenderContext;
import java.awt.geom.Rectangle2D;
import java.io.File;
import java.util.Comparator;
import java.util.Enumeration;
import java.util.Map.Entry;
import java.util.Objects;
import javax.swing.AbstractAction;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JPanel;
import javax.swing.JPopupMenu;
import javax.swing.JScrollPane;
import javax.swing.JTextField;
import javax.swing.JTree;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.MutableTreeNode;
import javax.swing.tree.TreeNode;
import javax.swing.tree.TreePath;
import org.objectweb.asm.tree.ClassNode;
import the.bytecode.club.bytecodeviewer.BytecodeViewer;
import the.bytecode.club.bytecodeviewer.gui.VisibleComponent;
import the.bytecode.club.bytecodeviewer.util.FileContainer;
import the.bytecode.club.bytecodeviewer.util.FileDrop;
import the.bytecode.club.bytecodeviewer.util.LazyNameUtil;
/***************************************************************************
* Bytecode Viewer (BCV) - Java & Android Reverse Engineering Suite *
* Copyright (C) 2014 Kalen 'Konloch' Kinloch - http://bytecodeviewer.com *
* *
* This program is free software: you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation, either version 3 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
***************************************************************************/
/**
* The file navigation pane.
*
* @author Konloch
* @author WaterWolf
* @author afffsdd
*/
public class ResourceListPane extends VisibleComponent implements FileDrop.Listener
{
JCheckBox exact = new JCheckBox("Exact");
JButton open = new JButton("+");
JButton close = new JButton("-");
MyTreeNode treeRoot = new MyTreeNode("Loaded Files:");
public MyTree tree = new MyTree(treeRoot);
final String quickSearchText = "Quick file search (no file extension)";
final JTextField quickSearch = new JTextField(quickSearchText);
boolean cancel = false;
public KeyAdapter search = new KeyAdapter() {
@Override
public void keyPressed(final KeyEvent ke) {
if (ke.getKeyCode() == KeyEvent.VK_ENTER) {
final String qt = quickSearch.getText();
quickSearch.setText("");
if (qt.isEmpty()) //NOPE
return;
String[] path;
int found = 0;
if (qt.contains(".")) {
path = qt.split("\\.");
/*String[] path2 = new String[path.length];
for (int i = 0; i < path.length; i++) {
path2[i] = path[i];
if (i + 2 == path.length) {
path2[i + 1] = "." + path[i + 1];
}
}*/
} else {
path = new String[]{qt};
}
MyTreeNode curNode = treeRoot;
if (exact.isSelected()) {
pathLoop:
for (int i = 0; i < path.length; i++) {
final String pathName = path[i];
final boolean isLast = i == path.length - 1;
for (int c = 0; c < curNode.getChildCount(); c++) {
final MyTreeNode child = (MyTreeNode) curNode.getChildAt(c);
System.out.println(pathName + ":" + child.getUserObject());
if (child.getUserObject().equals(pathName)) {
curNode = child;
if (isLast) {
System.out.println("Found! " + curNode);
found++;
final TreePath pathn = new TreePath(curNode.getPath());
tree.setSelectionPath(pathn);
tree.makeVisible(pathn);
tree.scrollPathToVisible(pathn);
openPath(pathn); //auto open
break pathLoop;
}
continue pathLoop;
}
}
System.out.println("Could not find " + pathName);
break;
}
} else {
{
@SuppressWarnings("unchecked")
Enumeration<MyTreeNode> enums = curNode.depthFirstEnumeration();
while (enums != null && enums.hasMoreElements()) {
MyTreeNode node = enums.nextElement();
if (node.isLeaf()) {
if (((String) (node.getUserObject())).toLowerCase().contains(path[path.length - 1].toLowerCase())) {
TreeNode[] pathArray = node.getPath();
int k = 0;
StringBuilder fullPath = new StringBuilder();
while (pathArray != null
&& k < pathArray.length) {
MyTreeNode n = (MyTreeNode) pathArray[k];
String s = (String) (n.getUserObject());
fullPath.append(s);
if (k++ != pathArray.length - 1) {
fullPath.append(".");
}
}
String fullPathString = fullPath.toString();
if (fullPathString.toLowerCase().contains(qt.toLowerCase())) {
System.out.println("Found! " + node);
found++;
if (found >= 30) {
BytecodeViewer.showMessage("Uh oh, there could be more results but you've"
+ " triggered the 30 classes at once limit. Try refining your "
+ "search.");
return;
}
final TreePath pathn = new TreePath(node.getPath());
tree.setSelectionPath(pathn.getParentPath());
tree.setSelectionPath(pathn);
tree.makeVisible(pathn);
tree.scrollPathToVisible(pathn);
}
}
}
}
}
}
}
}
};
private void showPopMenu(MyTree tree, TreePath selPath, int x, int y) {
if (selPath == null) {
return;
}
final JPopupMenu pop = new JPopupMenu();
pop.add(new AbstractAction("Remove") {
@Override
public void actionPerformed(ActionEvent e) {
TreePath selPath = ResourceListPane.this.tree.getPathForLocation(x, y);
DefaultMutableTreeNode selectNode =
(DefaultMutableTreeNode) Objects.requireNonNull(selPath).getLastPathComponent();
Enumeration<?> enumeration = treeRoot.children();
while (enumeration.hasMoreElements()) {
DefaultMutableTreeNode node = (DefaultMutableTreeNode) enumeration.nextElement();
if (node.isNodeAncestor(selectNode)) {
DefaultMutableTreeNode root = (DefaultMutableTreeNode) tree.getModel().getRoot();
root.remove(node);
for (FileContainer fileContainer : BytecodeViewer.files) {
if (fileContainer.name.equals(selectNode.toString())) {
removeFile(fileContainer);
break;
}
}
updateTree();
return;
}
}
}
});
//TODO fix for Java 9+
pop.add(new AbstractAction("Expand", WindowsTreeUI.ExpandedIcon.createExpandedIcon()) {
@Override
public void actionPerformed(ActionEvent e) {
TreePath selPath = ResourceListPane.this.tree.getPathForLocation(x, y);
expandAll(tree, Objects.requireNonNull(selPath), true);
}
});
pop.add(new AbstractAction("Collapse", WindowsTreeUI.CollapsedIcon.createCollapsedIcon()) {
@Override
public void actionPerformed(ActionEvent e) {
TreePath selPath = ResourceListPane.this.tree.getPathForLocation(x, y);
expandAll(tree, Objects.requireNonNull(selPath), false);
}
});
pop.show(this.tree, x, y);
}
private void removeFile(FileContainer fileContainer) {
BytecodeViewer.files.remove(fileContainer);
LazyNameUtil.removeName(fileContainer.name);
}
public ResourceListPane() {
super("ClassNavigation");
tree.setRootVisible(false);
tree.setShowsRootHandles(true);
quickSearch.setForeground(Color.gray);
setTitle("Files");
tree.addMouseListener(new MouseAdapter() {
@Override
public void mouseReleased(MouseEvent e) {
if (e.isMetaDown()) {
MyTree tree = (MyTree) e.getSource();
TreePath selPath = ResourceListPane.this.tree.getPathForLocation(e.getX(), e.getY());
if (selPath == null) {
return;
}
DefaultMutableTreeNode selectNode = (DefaultMutableTreeNode) selPath.getLastPathComponent();
Enumeration<?> enumeration = treeRoot.children();
while (enumeration.hasMoreElements()) {
DefaultMutableTreeNode node = (DefaultMutableTreeNode) enumeration.nextElement();
if (node.isNodeAncestor(selectNode)) {
// pop.show(tree, e.getX(), e.getY());
showPopMenu(tree, selPath, e.getX(), e.getY());
break;
}
}
}
}
});
this.open.addActionListener(e -> {
final TreeNode root = (TreeNode) tree.getModel().getRoot();
expandAll(tree, new TreePath(root), true);
});
this.close.addActionListener(e -> {
final TreeNode root = (TreeNode) tree.getModel().getRoot();
final TreePath path = new TreePath(root);
expandAll(tree, path, false);
tree.expandPath(path);
});
this.tree.addMouseListener(new MouseAdapter() {
@Override
public void mousePressed(MouseEvent e) {
openPath(tree.getPathForLocation(e.getX(), e.getY()));
}
});
this.tree.addTreeSelectionListener(arg0 -> {
if (cancel) {
cancel = false;
return;
}
openPath(arg0.getPath());
});
this.tree.addKeyListener(new KeyListener() {
@Override
public void keyReleased(KeyEvent e) {
}
@Override
public void keyTyped(KeyEvent e) {
}
@Override
public void keyPressed(KeyEvent e) {
if (e.getKeyCode() == KeyEvent.VK_ENTER) {
if (e.getSource() instanceof MyTree) {
MyTree tree = (MyTree) e.getSource();
openPath(tree.getSelectionPath());
}
} else if ((int) e.getKeyChar() != 0 && (int) e.getKeyChar() != 8 && (int) e.getKeyChar() != 127 && (int) e.getKeyChar() != 65535 && !e.isControlDown() && !e.isAltDown()) {
quickSearch.grabFocus();
quickSearch.setText("" + e.getKeyChar());
cancel = true;
} else if (e.isControlDown() && (int) e.getKeyChar() == 6) //ctrl + f
{
quickSearch.grabFocus();
} else {
cancel = true;
}
}
});
quickSearch.addKeyListener(search);
quickSearch.addFocusListener(new FocusListener() {
@Override
public void focusGained(final FocusEvent arg0) {
if (quickSearch.getText().equals(quickSearchText)) {
quickSearch.setText("");
quickSearch.setForeground(Color.black);
}
}
@Override
public void focusLost(final FocusEvent arg0) {
if (quickSearch.getText().isEmpty()) {
quickSearch.setText(quickSearchText);
quickSearch.setForeground(Color.gray);
}
}
});
getContentPane().setLayout(new BorderLayout());
getContentPane().add(new JScrollPane(tree), BorderLayout.CENTER);
JPanel p2 = new JPanel();
p2.setLayout(new BorderLayout());
p2.add(quickSearch, BorderLayout.NORTH);
JPanel p3 = new JPanel(new BorderLayout());
p3.add(exact, BorderLayout.WEST);
JPanel p4 = new JPanel(new BorderLayout());
p4.add(open, BorderLayout.EAST);
p4.add(close, BorderLayout.WEST);
p3.add(p4, BorderLayout.EAST);
p2.add(p3, BorderLayout.SOUTH);
getContentPane().add(p2, BorderLayout.SOUTH);
this.setVisible(true);
new FileDrop(this, this);
}
public void openClassFileToWorkSpace(final FileContainer container, final String name, final ClassNode node) {
BytecodeViewer.viewer.openClassFile(container, name, node);
}
public void openFileToWorkSpace(final FileContainer container, String name, byte[] contents) {
BytecodeViewer.viewer.openFile(container, name, contents);
}
@Override
public void filesDropped(final File[] files) {
if (files.length < 1)
return;
BytecodeViewer.openFiles(files, true);
}
public void updateTree() {
try {
treeRoot.removeAllChildren();
for (FileContainer container : BytecodeViewer.files) {
MyTreeNode root = new MyTreeNode(container.name);
treeRoot.add(root);
ImageRenderer renderer = new ImageRenderer();
tree.setCellRenderer(renderer);
if (!container.classes.isEmpty()) {
for (ClassNode c : container.classes) {
String name = c.name;
final String[] spl = name.split("/");
if (spl.length < 2) {
root.add(new MyTreeNode(name + ".class"));
} else {
MyTreeNode parent = root;
for (int i1 = 0; i1 < spl.length; i1++) {
String s = spl[i1];
if (i1 == spl.length - 1)
s += ".class";
MyTreeNode child = null;
for (int i = 0; i < parent.getChildCount(); i++) {
if (((MyTreeNode) parent.getChildAt(i)).getUserObject()
.equals(s)) {
child = (MyTreeNode) parent.getChildAt(i);
break;
}
}
if (child == null) {
child = new MyTreeNode(s);
parent.add(child);
}
parent = child;
}
}
}
}
if (!container.files.isEmpty()) {
for (final Entry<String, byte[]> entry : container.files.entrySet()) {
String name = entry.getKey();
final String[] spl = name.split("/");
if (spl.length < 2) {
root.add(new MyTreeNode(name));
} else {
MyTreeNode parent = root;
for (final String s : spl) {
MyTreeNode child = null;
for (int i = 0; i < parent.getChildCount(); i++) {
if (((MyTreeNode) parent.getChildAt(i)).getUserObject()
.equals(s)) {
child = (MyTreeNode) parent.getChildAt(i);
break;
}
}
if (child == null) {
child = new MyTreeNode(s);
parent.add(child);
}
parent = child;
}
}
}
}
}
treeRoot.sort();
tree.expandPath(new TreePath(tree.getModel().getRoot()));
tree.updateUI();
} catch (java.util.ConcurrentModificationException e) {
//ignore, the last file will reset everything
}
// expandAll(tree, true);
}
@SuppressWarnings("rawtypes")
private void expandAll(final JTree tree, final TreePath parent,
final boolean expand) {
// Traverse children
final TreeNode node = (TreeNode) parent.getLastPathComponent();
if (node.getChildCount() >= 0) {
for (final Enumeration e = node.children(); e.hasMoreElements(); ) {
final TreeNode n = (TreeNode) e.nextElement();
final TreePath path = parent.pathByAddingChild(n);
expandAll(tree, path, expand);
}
}
// Expansion or collapse must be done bottom-up
if (expand) {
tree.expandPath(parent);
} else {
tree.collapsePath(parent);
}
}
public class MyTree extends JTree {
private static final long serialVersionUID = -2355167326094772096L;
DefaultMutableTreeNode treeRoot;
public MyTree(final DefaultMutableTreeNode treeRoot) {
super(treeRoot);
this.treeRoot = treeRoot;
}
StringMetrics m = null;
@Override
public void paint(final Graphics g) {
try {
super.paint(g);
if (m == null) {
m = new StringMetrics((Graphics2D) g);
}
if (treeRoot.getChildCount() < 1) {
g.setColor(new Color(0, 0, 0, 100));
g.fillRect(0, 0, getWidth(), getHeight());
g.setColor(Color.white);
String s = "Drag class/jar/zip/APK/DEX here";
g.drawString(s,
((int) ((getWidth() / 2) - (m.getWidth(s) / 2))),
getHeight() / 2);
}
} catch (java.lang.InternalError | java.lang.NullPointerException ignored) {
}
}
}
public static class MyTreeNode extends DefaultMutableTreeNode {
private static final long serialVersionUID = -8817777566176729571L;
public MyTreeNode(final Object o) {
super(o);
}
@Override
public void insert(final MutableTreeNode newChild, final int childIndex) {
super.insert(newChild, childIndex);
}
public void sort() {
recursiveSort(this);
}
@SuppressWarnings("unchecked")
private void recursiveSort(final MyTreeNode node) {
node.children.sort(nodeComparator);
for (MyTreeNode nextNode : (Iterable<MyTreeNode>) node.children) {
if (nextNode.getChildCount() > 0) {
recursiveSort(nextNode);
}
}
}
protected Comparator<MyTreeNode> nodeComparator = new Comparator<MyTreeNode>() {
@Override
public int compare(final MyTreeNode o1, final MyTreeNode o2) {
// To make sure nodes with children are always on top
final int firstOffset = o1.getChildCount() > 0 ? -1000 : 0;
final int secondOffset = o2.getChildCount() > 0 ? 1000 : 0;
return o1.toString().compareToIgnoreCase(o2.toString())
+ firstOffset + secondOffset;
}
@Override
public boolean equals(final Object obj) {
return false;
}
@Override
public int hashCode() {
return 7;
}
};
}
/**
* @author http://stackoverflow.com/a/18450804
*/
static class StringMetrics {
Font font;
FontRenderContext context;
public StringMetrics(Graphics2D g2) {
font = g2.getFont();
context = g2.getFontRenderContext();
}
Rectangle2D getBounds(String message) {
return font.getStringBounds(message, context);
}
double getWidth(String message) {
Rectangle2D bounds = getBounds(message);
return bounds.getWidth();
}
double getHeight(String message) {
Rectangle2D bounds = getBounds(message);
return bounds.getHeight();
}
}
public void resetWorkspace() {
treeRoot.removeAllChildren();
tree.repaint();
tree.updateUI();
}
public void openPath(TreePath path) {
if (path == null || path.getPathCount() == 1) {
return;
}
final StringBuilder nameBuffer = new StringBuilder();
for (int i = 2; i < path.getPathCount(); i++) {
nameBuffer.append(path.getPathComponent(i));
if (i < path.getPathCount() - 1) {
nameBuffer.append("/");
}
}
String cheapHax = path.getPathComponent(1).toString();
FileContainer container = null;
for (FileContainer c : BytecodeViewer.files) {
if (c.name.equals(cheapHax))
container = c;
}
String name = nameBuffer.toString();
if (name.endsWith(".class")) {
final ClassNode cn = BytecodeViewer.getClassNode(Objects.requireNonNull(container), name.substring(0,
name.length() - ".class".length()));
if (cn != null) {
openClassFileToWorkSpace(container, nameBuffer.toString(), cn);
} else {
openFileToWorkSpace(container, nameBuffer.toString(),
BytecodeViewer.getFileContents(nameBuffer.toString()));
}
} else {
openFileToWorkSpace(container, nameBuffer.toString(),
BytecodeViewer.getFileContents(nameBuffer.toString()));
}
}
}

View file

@ -4,7 +4,7 @@ import org.apache.commons.io.FileUtils;
import org.objectweb.asm.tree.ClassNode;
import the.bytecode.club.bytecodeviewer.BytecodeViewer;
import the.bytecode.club.bytecodeviewer.api.ExceptionUI;
import the.bytecode.club.bytecodeviewer.gui.resourceviewer.ResourceListPane;
import the.bytecode.club.bytecodeviewer.gui.resourcelist.ResourceListPane;
import the.bytecode.club.bytecodeviewer.gui.MainViewerGUI;
import java.io.File;