Improved Resource Updating

Still a work in progress
This commit is contained in:
Konloch 2021-07-14 04:33:20 -07:00
parent 434d5cd58f
commit b9b8d44cc1
12 changed files with 193 additions and 235 deletions

View file

@ -438,18 +438,18 @@ public class BytecodeViewer
{ {
ClassViewer cv = (ClassViewer) c; ClassViewer cv = (ClassViewer) c;
if(noErrors && !cv.resourceViewPanel1.compile()) if(noErrors && !cv.bytecodeViewPanel1.compile())
noErrors = false; noErrors = false;
if(noErrors && !cv.resourceViewPanel2.compile()) if(noErrors && !cv.bytecodeViewPanel2.compile())
noErrors = false; noErrors = false;
if(noErrors && !cv.resourceViewPanel3.compile()) if(noErrors && !cv.bytecodeViewPanel3.compile())
noErrors = false; noErrors = false;
if(cv.resourceViewPanel1.textArea != null && cv.resourceViewPanel1.textArea.isEditable()) if(cv.bytecodeViewPanel1.textArea != null && cv.bytecodeViewPanel1.textArea.isEditable())
actuallyTried = true; actuallyTried = true;
if(cv.resourceViewPanel2.textArea != null && cv.resourceViewPanel2.textArea.isEditable()) if(cv.bytecodeViewPanel2.textArea != null && cv.bytecodeViewPanel2.textArea.isEditable())
actuallyTried = true; actuallyTried = true;
if(cv.resourceViewPanel3.textArea != null && cv.resourceViewPanel3.textArea.isEditable()) if(cv.bytecodeViewPanel3.textArea != null && cv.bytecodeViewPanel3.textArea.isEditable())
actuallyTried = true; actuallyTried = true;
} }
} }

View file

@ -26,5 +26,5 @@ package the.bytecode.club.bytecodeviewer.compilers;
public abstract class InternalCompiler public abstract class InternalCompiler
{ {
public abstract byte[] compile(String contents, String name); public abstract byte[] compile(String contents, String fullyQualifiedName);
} }

View file

@ -42,14 +42,14 @@ import static the.bytecode.club.bytecodeviewer.Constants.*;
public class JavaCompiler extends InternalCompiler public class JavaCompiler extends InternalCompiler
{ {
@Override @Override
public byte[] compile(String contents, String name) public byte[] compile(String contents, String fullyQualifiedName)
{ {
String fileStart = tempDirectory + fs + "temp" + MiscUtils.randomString(12) + fs; String fileStart = tempDirectory + fs + "temp" + MiscUtils.randomString(12) + fs;
String fileStart2 = tempDirectory + fs + "temp" + MiscUtils.randomString(12) + fs; String fileStart2 = tempDirectory + fs + "temp" + MiscUtils.randomString(12) + fs;
File java = new File(fileStart + fs + name + ".java"); File java = new File(fileStart + fs + fullyQualifiedName + ".java");
File clazz = new File(fileStart2 + fs + name + ".class"); File clazz = new File(fileStart2 + fs + fullyQualifiedName + ".class");
File cp = new File(tempDirectory + fs + "cpath_" + MiscUtils.randomString(12) + ".jar"); File cp = new File(tempDirectory + fs + "cpath_" + MiscUtils.randomString(12) + ".jar");
File tempD = new File(fileStart + fs + name.substring(0, name.length() - name.split("/")[name.split("/").length - 1].length())); File tempD = new File(fileStart + fs + fullyQualifiedName.substring(0, fullyQualifiedName.length() - fullyQualifiedName.split("/")[fullyQualifiedName.split("/").length - 1].length()));
tempD.mkdirs(); tempD.mkdirs();
new File(fileStart2).mkdirs(); new File(fileStart2).mkdirs();

View file

@ -44,9 +44,9 @@ import static the.bytecode.club.bytecodeviewer.Constants.*;
*/ */
public class KrakatauAssembler extends InternalCompiler public class KrakatauAssembler extends InternalCompiler
{ {
@Override @Override
public byte[] compile(String contents, String name) { public byte[] compile(String contents, String fullyQualifiedName)
{
if(!ExternalResources.getSingleton().hasSetPython2Command()) if(!ExternalResources.getSingleton().hasSetPython2Command())
return null; return null;
@ -55,7 +55,7 @@ public class KrakatauAssembler extends InternalCompiler
File tempD = new File(Constants.tempDirectory + fs + MiscUtils.randomString(32) + fs); File tempD = new File(Constants.tempDirectory + fs + MiscUtils.randomString(32) + fs);
tempD.mkdir(); tempD.mkdir();
File tempJ = new File(tempD.getAbsolutePath() + fs + name + ".j"); File tempJ = new File(tempD.getAbsolutePath() + fs + fullyQualifiedName + ".j");
DiskWriter.replaceFile(tempJ.getAbsolutePath(), contents, true); DiskWriter.replaceFile(tempJ.getAbsolutePath(), contents, true);
final File tempDirectory = new File(Constants.tempDirectory + fs + MiscUtils.randomString(32) + fs); final File tempDirectory = new File(Constants.tempDirectory + fs + MiscUtils.randomString(32) + fs);

View file

@ -40,7 +40,7 @@ import static the.bytecode.club.bytecodeviewer.Constants.*;
public class SmaliAssembler extends InternalCompiler public class SmaliAssembler extends InternalCompiler
{ {
@Override @Override
public byte[] compile(String contents, String name) public byte[] compile(String contents, String fullyQualifiedName)
{ {
String fileStart = tempDirectory + fs + "temp"; String fileStart = tempDirectory + fs + "temp";
int fileNumber = MiscUtils.getClassNumber(fileStart, ".dex"); int fileNumber = MiscUtils.getClassNumber(fileStart, ".dex");

View file

@ -908,9 +908,9 @@ public class MainViewerGUI extends JFrame
continue; continue;
ClassViewer viewerClass = (ClassViewer) viewerResource; ClassViewer viewerClass = (ClassViewer) viewerResource;
Configuration.rstaTheme.apply(viewerClass.resourceViewPanel1.textArea); Configuration.rstaTheme.apply(viewerClass.bytecodeViewPanel1.textArea);
Configuration.rstaTheme.apply(viewerClass.resourceViewPanel2.textArea); Configuration.rstaTheme.apply(viewerClass.bytecodeViewPanel2.textArea);
Configuration.rstaTheme.apply(viewerClass.resourceViewPanel3.textArea); Configuration.rstaTheme.apply(viewerClass.bytecodeViewPanel3.textArea);
} }
SwingUtilities.updateComponentTreeUI(BytecodeViewer.viewer); SwingUtilities.updateComponentTreeUI(BytecodeViewer.viewer);
} }

View file

@ -1,6 +1,6 @@
package the.bytecode.club.bytecodeviewer.gui.components; package the.bytecode.club.bytecodeviewer.gui.components;
import the.bytecode.club.bytecodeviewer.gui.util.PaneUpdaterThread; import the.bytecode.club.bytecodeviewer.gui.util.BytecodeViewPanelUpdater;
import the.bytecode.club.bytecodeviewer.util.MethodParser; import the.bytecode.club.bytecodeviewer.util.MethodParser;
import javax.swing.*; import javax.swing.*;
@ -31,11 +31,11 @@ import java.awt.*;
*/ */
public class MethodsRenderer extends JLabel implements ListCellRenderer<Object> public class MethodsRenderer extends JLabel implements ListCellRenderer<Object>
{ {
private final PaneUpdaterThread paneUpdaterThread; private final BytecodeViewPanelUpdater bytecodeViewPanelUpdater;
public MethodsRenderer(PaneUpdaterThread paneUpdaterThread) public MethodsRenderer(BytecodeViewPanelUpdater bytecodeViewPanelUpdater)
{ {
this.paneUpdaterThread = paneUpdaterThread; this.bytecodeViewPanelUpdater = bytecodeViewPanelUpdater;
setOpaque(true); setOpaque(true);
} }
@ -43,7 +43,7 @@ public class MethodsRenderer extends JLabel implements ListCellRenderer<Object>
public Component getListCellRendererComponent(JList<?> list, Object value, int index, boolean isSelected, public Component getListCellRendererComponent(JList<?> list, Object value, int index, boolean isSelected,
boolean cellHasFocus) boolean cellHasFocus)
{ {
MethodParser methods = paneUpdaterThread.viewer.methods.get(paneUpdaterThread.resourceViewPanel.decompiler.ordinal()); MethodParser methods = bytecodeViewPanelUpdater.viewer.methods.get(bytecodeViewPanelUpdater.bytecodeViewPanel.decompiler.ordinal());
MethodParser.Method method = methods.getMethod((Integer) value); MethodParser.Method method = methods.getMethod((Integer) value);
setText(method.toString()); setText(method.toString());
return this; return this;

View file

@ -6,7 +6,7 @@ import the.bytecode.club.bytecodeviewer.decompilers.Decompiler;
import the.bytecode.club.bytecodeviewer.gui.components.SearchableRSyntaxTextArea; import the.bytecode.club.bytecodeviewer.gui.components.SearchableRSyntaxTextArea;
import the.bytecode.club.bytecodeviewer.gui.components.SystemConsole; import the.bytecode.club.bytecodeviewer.gui.components.SystemConsole;
import the.bytecode.club.bytecodeviewer.gui.resourceviewer.viewer.ClassViewer; import the.bytecode.club.bytecodeviewer.gui.resourceviewer.viewer.ClassViewer;
import the.bytecode.club.bytecodeviewer.gui.util.PaneUpdaterThread; import the.bytecode.club.bytecodeviewer.gui.util.BytecodeViewPanelUpdater;
import the.bytecode.club.bytecodeviewer.translation.TranslatedStrings; import the.bytecode.club.bytecodeviewer.translation.TranslatedStrings;
import the.bytecode.club.bytecodeviewer.util.JarUtils; import the.bytecode.club.bytecodeviewer.util.JarUtils;
@ -34,22 +34,25 @@ import static the.bytecode.club.bytecodeviewer.Constants.nl;
***************************************************************************/ ***************************************************************************/
/** /**
* Represents a Bytecode/ClassFile View Panel
*
* @author Konloch * @author Konloch
* @since 6/24/2021 * @since 6/24/2021
*/ */
public class ResourceViewPanel public class BytecodeViewPanel
{ {
public final JPanel panel = new JPanel(new BorderLayout()); public final JPanel panel = new JPanel(new BorderLayout());
public final int panelIndex; public final int panelIndex;
public final ClassViewer viewer; public final ClassViewer viewer;
public Decompiler decompiler = Decompiler.NONE;
public SearchableRSyntaxTextArea textArea; public SearchableRSyntaxTextArea textArea;
public PaneUpdaterThread updateThread; public BytecodeViewPanelUpdater updateThread;
public Decompiler decompiler = Decompiler.NONE;
public Compiler compiler = Compiler.JAVA_COMPILER;
public Compiler compileMode = Compiler.JAVA_COMPILER; public BytecodeViewPanel(int panelIndex, ClassViewer viewer)
{
public ResourceViewPanel(int panelIndex, ClassViewer viewer) {this.panelIndex = panelIndex; this.panelIndex = panelIndex;
this.viewer = viewer; this.viewer = viewer;
} }
@ -59,14 +62,12 @@ public class ResourceViewPanel
textArea = null; textArea = null;
if(viewer.viewerClassNode == null) if(viewer.viewerClassNode == null)
{
panel.add(new JLabel("ERROR: Resource Viewer Corrupt ClassNode")); panel.add(new JLabel("ERROR: Resource Viewer Corrupt ClassNode"));
} }
}
public void updatePane(ClassViewer cv, byte[] b, JButton button, boolean isPanelEditable) public void updatePane(ClassViewer cv, byte[] b, JButton button, boolean isPanelEditable)
{ {
updateThread = new ResourceViewProcessing(this, cv, b, isPanelEditable, button); updateThread = new BytecodeViewPanelUpdater(this, cv, b, isPanelEditable, button);
} }
public boolean compile() public boolean compile()
@ -83,12 +84,12 @@ public class ResourceViewPanel
try try
{ {
String text = textArea.getText(); String text = textArea.getText();
byte[] compiledClass = compileMode.getCompiler().compile(text, viewer.viewerClassNode.name); byte[] compiledClass = compiler.getCompiler().compile(text, viewer.viewerClassNode.name);
if (compiledClass != null) if (compiledClass != null)
{ {
ClassNode newNode = JarUtils.getNode(compiledClass); ClassNode newNode = JarUtils.getNode(compiledClass);
viewer.container.updateNode(viewer.viewerClassNode, newNode); viewer.container.updateNode(viewer.name, newNode);
errConsole.finished(); errConsole.finished();
return true; return true;
} }

View file

@ -1,121 +0,0 @@
package the.bytecode.club.bytecodeviewer.gui.resourceviewer;
import org.objectweb.asm.ClassWriter;
import the.bytecode.club.bytecodeviewer.BytecodeViewer;
import the.bytecode.club.bytecodeviewer.decompilers.Decompiler;
import the.bytecode.club.bytecodeviewer.gui.hexviewer.JHexEditor;
import the.bytecode.club.bytecodeviewer.gui.resourceviewer.viewer.ClassViewer;
import the.bytecode.club.bytecodeviewer.gui.util.PaneUpdaterThread;
import javax.swing.*;
import java.awt.*;
/***************************************************************************
* 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/>. *
***************************************************************************/
/**
* All classfile resources get preprocessed through this class, from there the specified UI panel is used to display the data
*
* @author Konloch
* @since 6/27/2021
*/
public class ResourceViewProcessing extends PaneUpdaterThread
{
private final ResourceViewPanel resourceViewPanel;
private final byte[] b;
private final JButton button;
public boolean waitingFor;
public ResourceViewProcessing(ResourceViewPanel resourceViewPanel, ClassViewer cv, byte[] b, boolean isPanelEditable, JButton button)
{
super(cv, resourceViewPanel);
this.resourceViewPanel = resourceViewPanel;
this.b = b;
this.isPanelEditable = isPanelEditable;
this.button = button;
waitingFor = true;
}
@Override
public void processDisplay()
{
try
{
BytecodeViewer.updateBusyStatus(true);
if (resourceViewPanel.decompiler != Decompiler.NONE)
{
//hex viewer
if (resourceViewPanel.decompiler == Decompiler.HEXCODE_VIEWER)
{
final ClassWriter cw = new ClassWriter(0);
viewer.viewerClassNode.accept(cw);
SwingUtilities.invokeLater(() ->
{
final JHexEditor hex = new JHexEditor(cw.toByteArray());
hex.setFont(new Font(Font.MONOSPACED, Font.PLAIN, (int) BytecodeViewer.viewer.fontSpinner.getValue()));
resourceViewPanel.panel.add(hex);
});
}
else
{
final Decompiler decompiler = resourceViewPanel.decompiler;
//perform decompiling inside of this thread
final String decompiledSource = decompiler.getDecompiler().decompileClassNode(viewer.viewerClassNode, b);
//set the swing components on the swing thread
SwingUtilities.invokeLater(() ->
{
buildTextArea(decompiler, decompiledSource);
waitingFor = false;
});
//hold this thread until the swing thread has finished attaching the components
while (waitingFor)
{
try {
Thread.sleep(1);
} catch (Exception e) {}
}
}
}
}
catch (IndexOutOfBoundsException | NullPointerException e)
{
//ignore
}
catch (Exception e)
{
BytecodeViewer.handleException(e);
}
finally
{
viewer.resetDivider();
BytecodeViewer.updateBusyStatus(false);
SwingUtilities.invokeLater(() ->
{
if (button != null)
button.setEnabled(true);
});
}
}
}

View file

@ -2,7 +2,7 @@ package the.bytecode.club.bytecodeviewer.gui.resourceviewer.viewer;
import the.bytecode.club.bytecodeviewer.api.ASMUtil; import the.bytecode.club.bytecodeviewer.api.ASMUtil;
import the.bytecode.club.bytecodeviewer.decompilers.Decompiler; import the.bytecode.club.bytecodeviewer.decompilers.Decompiler;
import the.bytecode.club.bytecodeviewer.gui.resourceviewer.ResourceViewPanel; import the.bytecode.club.bytecodeviewer.gui.resourceviewer.BytecodeViewPanel;
import java.awt.BorderLayout; import java.awt.BorderLayout;
import java.awt.Container; import java.awt.Container;
@ -59,9 +59,9 @@ public class ClassViewer extends ResourceViewer
{ {
public JSplitPane sp; public JSplitPane sp;
public JSplitPane sp2; public JSplitPane sp2;
public ResourceViewPanel resourceViewPanel1 = new ResourceViewPanel(0, this); public BytecodeViewPanel bytecodeViewPanel1 = new BytecodeViewPanel(0, this);
public ResourceViewPanel resourceViewPanel2 = new ResourceViewPanel(1, this); public BytecodeViewPanel bytecodeViewPanel2 = new BytecodeViewPanel(1, this);
public ResourceViewPanel resourceViewPanel3 = new ResourceViewPanel(2, this); public BytecodeViewPanel bytecodeViewPanel3 = new BytecodeViewPanel(2, this);
public List<MethodParser> methods = Arrays.asList(new MethodParser(), new MethodParser(), new MethodParser()); public List<MethodParser> methods = Arrays.asList(new MethodParser(), new MethodParser(), new MethodParser());
public final String workingName; public final String workingName;
@ -76,8 +76,8 @@ public class ClassViewer extends ResourceViewer
this.setName(name); this.setName(name);
this.setLayout(new BorderLayout()); this.setLayout(new BorderLayout());
this.sp = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, resourceViewPanel1.panel, resourceViewPanel2.panel); this.sp = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, bytecodeViewPanel1.panel, bytecodeViewPanel2.panel);
this.sp2 = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, sp, resourceViewPanel3.panel); this.sp2 = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, sp, bytecodeViewPanel3.panel);
this.add(sp2, BorderLayout.CENTER); this.add(sp2, BorderLayout.CENTER);
this.addComponentListener(new ComponentAdapter() { this.addComponentListener(new ComponentAdapter() {
@ -96,9 +96,9 @@ public class ClassViewer extends ResourceViewer
setPanes(); setPanes();
refreshTitle(); refreshTitle();
resourceViewPanel1.createPane(this); bytecodeViewPanel1.createPane(this);
resourceViewPanel2.createPane(this); bytecodeViewPanel2.createPane(this);
resourceViewPanel3.createPane(this); bytecodeViewPanel3.createPane(this);
byte[] classBytes = getResourceBytes(); byte[] classBytes = getResourceBytes();
@ -116,9 +116,9 @@ public class ClassViewer extends ResourceViewer
classBytes = ASMUtil.nodeToBytes(viewerClassNode); classBytes = ASMUtil.nodeToBytes(viewerClassNode);
} }
resourceViewPanel1.updatePane(this, classBytes, button, isPanel1Editable()); bytecodeViewPanel1.updatePane(this, classBytes, button, isPanel1Editable());
resourceViewPanel2.updatePane(this, classBytes, button, isPanel2Editable()); bytecodeViewPanel2.updatePane(this, classBytes, button, isPanel2Editable());
resourceViewPanel3.updatePane(this, classBytes, button, isPanel3Editable()); bytecodeViewPanel3.updatePane(this, classBytes, button, isPanel3Editable());
Thread dumpBuild = new Thread(() -> Thread dumpBuild = new Thread(() ->
{ {
@ -136,12 +136,12 @@ public class ClassViewer extends ResourceViewer
BytecodeViewer.updateBusyStatus(false); BytecodeViewer.updateBusyStatus(false);
if (resourceViewPanel1.decompiler != Decompiler.NONE) if (bytecodeViewPanel1.decompiler != Decompiler.NONE)
resourceViewPanel1.updateThread.startNewThread(); bytecodeViewPanel1.updateThread.startNewThread();
if (resourceViewPanel2.decompiler != Decompiler.NONE) if (bytecodeViewPanel2.decompiler != Decompiler.NONE)
resourceViewPanel2.updateThread.startNewThread(); bytecodeViewPanel2.updateThread.startNewThread();
if (resourceViewPanel3.decompiler != Decompiler.NONE) if (bytecodeViewPanel3.decompiler != Decompiler.NONE)
resourceViewPanel3.updateThread.startNewThread(); bytecodeViewPanel3.updateThread.startNewThread();
}, "ClassViewer Temp Dump"); }, "ClassViewer Temp Dump");
dumpBuild.start(); dumpBuild.start();
@ -164,9 +164,9 @@ public class ClassViewer extends ResourceViewer
} }
public void setPanes() { public void setPanes() {
resourceViewPanel1.decompiler = BytecodeViewer.viewer.viewPane1.getSelectedDecompiler(); bytecodeViewPanel1.decompiler = BytecodeViewer.viewer.viewPane1.getSelectedDecompiler();
resourceViewPanel2.decompiler = BytecodeViewer.viewer.viewPane2.getSelectedDecompiler(); bytecodeViewPanel2.decompiler = BytecodeViewer.viewer.viewPane2.getSelectedDecompiler();
resourceViewPanel3.decompiler = BytecodeViewer.viewer.viewPane3.getSelectedDecompiler(); bytecodeViewPanel3.decompiler = BytecodeViewer.viewer.viewPane3.getSelectedDecompiler();
} }
public boolean isPanel1Editable() { public boolean isPanel1Editable() {
@ -196,13 +196,13 @@ public class ClassViewer extends ResourceViewer
RSyntaxTextArea area = null; RSyntaxTextArea area = null;
switch (paneId) { switch (paneId) {
case 0: case 0:
area = classViewer.resourceViewPanel1.updateThread.updateUpdaterTextArea; area = classViewer.bytecodeViewPanel1.updateThread.updateUpdaterTextArea;
break; break;
case 1: case 1:
area = classViewer.resourceViewPanel2.updateThread.updateUpdaterTextArea; area = classViewer.bytecodeViewPanel2.updateThread.updateUpdaterTextArea;
break; break;
case 2: case 2:
area = classViewer.resourceViewPanel3.updateThread.updateUpdaterTextArea; area = classViewer.bytecodeViewPanel3.updateThread.updateUpdaterTextArea;
break; break;
} }
@ -270,24 +270,24 @@ public class ClassViewer extends ResourceViewer
{ {
sp.setResizeWeight(0.5); sp.setResizeWeight(0.5);
if (resourceViewPanel2.decompiler != Decompiler.NONE && resourceViewPanel1.decompiler != Decompiler.NONE) { if (bytecodeViewPanel2.decompiler != Decompiler.NONE && bytecodeViewPanel1.decompiler != Decompiler.NONE) {
setDividerLocation(sp, 0.5); setDividerLocation(sp, 0.5);
} else if (resourceViewPanel1.decompiler != Decompiler.NONE) { } else if (bytecodeViewPanel1.decompiler != Decompiler.NONE) {
setDividerLocation(sp, 1); setDividerLocation(sp, 1);
} else if (resourceViewPanel2.decompiler != Decompiler.NONE) { } else if (bytecodeViewPanel2.decompiler != Decompiler.NONE) {
sp.setResizeWeight(1); sp.setResizeWeight(1);
setDividerLocation(sp, 0); setDividerLocation(sp, 0);
} else { } else {
setDividerLocation(sp, 0); setDividerLocation(sp, 0);
} }
if (resourceViewPanel3.decompiler != Decompiler.NONE) { if (bytecodeViewPanel3.decompiler != Decompiler.NONE) {
sp2.setResizeWeight(0.7); sp2.setResizeWeight(0.7);
setDividerLocation(sp2, 0.7); setDividerLocation(sp2, 0.7);
if ((resourceViewPanel2.decompiler == Decompiler.NONE && resourceViewPanel1.decompiler != Decompiler.NONE) if ((bytecodeViewPanel2.decompiler == Decompiler.NONE && bytecodeViewPanel1.decompiler != Decompiler.NONE)
|| (resourceViewPanel1.decompiler == Decompiler.NONE && resourceViewPanel2.decompiler != Decompiler.NONE)) { || (bytecodeViewPanel1.decompiler == Decompiler.NONE && bytecodeViewPanel2.decompiler != Decompiler.NONE)) {
setDividerLocation(sp2, 0.5); setDividerLocation(sp2, 0.5);
} else if (resourceViewPanel1.decompiler == Decompiler.NONE) { } else if (bytecodeViewPanel1.decompiler == Decompiler.NONE) {
setDividerLocation(sp2, 0); setDividerLocation(sp2, 0);
} }
} else { } else {

View file

@ -13,13 +13,15 @@ import javax.swing.event.ChangeListener;
import org.fife.ui.rsyntaxtextarea.RSyntaxTextArea; import org.fife.ui.rsyntaxtextarea.RSyntaxTextArea;
import org.fife.ui.rsyntaxtextarea.SyntaxConstants; import org.fife.ui.rsyntaxtextarea.SyntaxConstants;
import org.fife.ui.rtextarea.RTextScrollPane; import org.fife.ui.rtextarea.RTextScrollPane;
import org.objectweb.asm.ClassWriter;
import the.bytecode.club.bytecodeviewer.BytecodeViewer; import the.bytecode.club.bytecodeviewer.BytecodeViewer;
import the.bytecode.club.bytecodeviewer.Configuration; import the.bytecode.club.bytecodeviewer.Configuration;
import the.bytecode.club.bytecodeviewer.compilers.Compiler; import the.bytecode.club.bytecodeviewer.compilers.Compiler;
import the.bytecode.club.bytecodeviewer.decompilers.Decompiler; import the.bytecode.club.bytecodeviewer.decompilers.Decompiler;
import the.bytecode.club.bytecodeviewer.gui.components.MethodsRenderer; import the.bytecode.club.bytecodeviewer.gui.components.MethodsRenderer;
import the.bytecode.club.bytecodeviewer.gui.components.SearchableRSyntaxTextArea; import the.bytecode.club.bytecodeviewer.gui.components.SearchableRSyntaxTextArea;
import the.bytecode.club.bytecodeviewer.gui.resourceviewer.ResourceViewPanel; import the.bytecode.club.bytecodeviewer.gui.hexviewer.JHexEditor;
import the.bytecode.club.bytecodeviewer.gui.resourceviewer.BytecodeViewPanel;
import the.bytecode.club.bytecodeviewer.gui.resourceviewer.viewer.ClassViewer; import the.bytecode.club.bytecodeviewer.gui.resourceviewer.viewer.ClassViewer;
import the.bytecode.club.bytecodeviewer.util.MethodParser; import the.bytecode.club.bytecodeviewer.util.MethodParser;
@ -45,29 +47,103 @@ import static the.bytecode.club.bytecodeviewer.translation.TranslatedStrings.EDI
***************************************************************************/ ***************************************************************************/
/** /**
* Allows us to run a background thread * Updates the Bytecode View Panel in a background thread
* *
* @author Konloch * @author Konloch
* @author WaterWolf * @author WaterWolf
* @author DreamSworK * @author DreamSworK
* @since 09/26/2011 * @since 09/26/2011
*/ */
public abstract class PaneUpdaterThread implements Runnable
public class BytecodeViewPanelUpdater implements Runnable
{ {
public final ClassViewer viewer; public final ClassViewer viewer;
public final ResourceViewPanel resourceViewPanel; public final BytecodeViewPanel bytecodeViewPanel;
private final JButton button;
private final byte[] b;
public SearchableRSyntaxTextArea updateUpdaterTextArea; public SearchableRSyntaxTextArea updateUpdaterTextArea;
public JComboBox<Integer> methodsList; public JComboBox<Integer> methodsList;
public boolean isPanelEditable; public boolean isPanelEditable;
public boolean waitingFor;
private Thread thread; private Thread thread;
public PaneUpdaterThread(ClassViewer viewer, ResourceViewPanel resourceViewPanel) public BytecodeViewPanelUpdater(BytecodeViewPanel bytecodeViewPanel, ClassViewer cv, byte[] b, boolean isPanelEditable, JButton button)
{ {
this.viewer = viewer; this.viewer = cv;
this.resourceViewPanel = resourceViewPanel; this.bytecodeViewPanel = bytecodeViewPanel;
this.b = b;
this.isPanelEditable = isPanelEditable;
this.button = button;
waitingFor = true;
} }
public abstract void processDisplay(); public void processDisplay()
{
try
{
BytecodeViewer.updateBusyStatus(true);
if (bytecodeViewPanel.decompiler != Decompiler.NONE)
{
//hex viewer
if (bytecodeViewPanel.decompiler == Decompiler.HEXCODE_VIEWER)
{
final ClassWriter cw = new ClassWriter(0);
viewer.viewerClassNode.accept(cw);
SwingUtilities.invokeLater(() ->
{
final JHexEditor hex = new JHexEditor(cw.toByteArray());
hex.setFont(new Font(Font.MONOSPACED, Font.PLAIN, (int) BytecodeViewer.viewer.fontSpinner.getValue()));
bytecodeViewPanel.panel.add(hex);
});
}
else
{
final Decompiler decompiler = bytecodeViewPanel.decompiler;
//perform decompiling inside of this thread
final String decompiledSource = decompiler.getDecompiler().decompileClassNode(viewer.viewerClassNode, b);
//set the swing components on the swing thread
SwingUtilities.invokeLater(() ->
{
buildTextArea(decompiler, decompiledSource);
waitingFor = false;
});
//hold this thread until the swing thread has finished attaching the components
while (waitingFor)
{
try {
Thread.sleep(1);
} catch (Exception e) {}
}
}
}
}
catch (IndexOutOfBoundsException | NullPointerException e)
{
//ignore
}
catch (Exception e)
{
BytecodeViewer.handleException(e);
}
finally
{
viewer.resetDivider();
BytecodeViewer.updateBusyStatus(false);
SwingUtilities.invokeLater(() ->
{
if (button != null)
button.setEnabled(true);
});
}
}
public void startNewThread() public void startNewThread()
{ {
@ -78,7 +154,7 @@ public abstract class PaneUpdaterThread implements Runnable
@Override @Override
public void run() public void run()
{ {
if(resourceViewPanel.decompiler == Decompiler.NONE) if(bytecodeViewPanel.decompiler == Decompiler.NONE)
return; return;
processDisplay(); processDisplay();
@ -89,7 +165,7 @@ public abstract class PaneUpdaterThread implements Runnable
{ {
//build an error message //build an error message
SwingUtilities.invokeLater(() -> SwingUtilities.invokeLater(() ->
buildTextArea(resourceViewPanel.decompiler, "Critical BCV Error")); buildTextArea(bytecodeViewPanel.decompiler, "Critical BCV Error"));
return; return;
} }
@ -130,7 +206,7 @@ public abstract class PaneUpdaterThread implements Runnable
@Override @Override
public void caretUpdate(CaretEvent e) public void caretUpdate(CaretEvent e)
{ {
MethodParser methods = viewer.methods.get(resourceViewPanel.panelIndex); MethodParser methods = viewer.methods.get(bytecodeViewPanel.panelIndex);
if (methods != null) if (methods != null)
{ {
int methodLine = methods.findActiveMethod(updateUpdaterTextArea.getCaretLineNumber()); int methodLine = methods.findActiveMethod(updateUpdaterTextArea.getCaretLineNumber());
@ -145,11 +221,11 @@ public abstract class PaneUpdaterThread implements Runnable
} }
if (BytecodeViewer.viewer.synchronizedViewing.isSelected()) { if (BytecodeViewer.viewer.synchronizedViewing.isSelected()) {
int panes = 2; int panes = 2;
if (viewer.resourceViewPanel3.panel != null) if (viewer.bytecodeViewPanel3.panel != null)
panes = 3; panes = 3;
for (int i = 0; i < panes; i++) { for (int i = 0; i < panes; i++) {
if (i != resourceViewPanel.panelIndex) { if (i != bytecodeViewPanel.panelIndex) {
ClassViewer.selectMethod(viewer, i, methods.getMethod(methodLine)); ClassViewer.selectMethod(viewer, i, methods.getMethod(methodLine));
} }
} }
@ -163,7 +239,7 @@ public abstract class PaneUpdaterThread implements Runnable
@Override @Override
public void stateChanged(ChangeEvent e) { public void stateChanged(ChangeEvent e) {
int panes = 2; int panes = 2;
if (viewer.resourceViewPanel3.panel != null) if (viewer.bytecodeViewPanel3.panel != null)
panes = 3; panes = 3;
if (BytecodeViewer.viewer.synchronizedViewing.isSelected()) { if (BytecodeViewer.viewer.synchronizedViewing.isSelected()) {
@ -175,7 +251,7 @@ public abstract class PaneUpdaterThread implements Runnable
activeViewLine; activeViewLine;
int activeLineDelta = -1; int activeLineDelta = -1;
MethodParser.Method activeMethod = null; MethodParser.Method activeMethod = null;
MethodParser activeMethods = viewer.methods.get(resourceViewPanel.panelIndex); MethodParser activeMethods = viewer.methods.get(bytecodeViewPanel.panelIndex);
if (activeMethods != null) { if (activeMethods != null) {
int activeMethodLine = activeMethods.findActiveMethod(activeLine); int activeMethodLine = activeMethods.findActiveMethod(activeLine);
if (activeMethodLine != -1) { if (activeMethodLine != -1) {
@ -185,19 +261,19 @@ public abstract class PaneUpdaterThread implements Runnable
} }
} }
for (int i = 0; i < panes; i++) { for (int i = 0; i < panes; i++) {
if (i != resourceViewPanel.panelIndex) { if (i != bytecodeViewPanel.panelIndex) {
int setLine = -1; int setLine = -1;
RSyntaxTextArea area = null; RSyntaxTextArea area = null;
switch (i) { switch (i) {
case 0: case 0:
area = viewer.resourceViewPanel1.updateThread.updateUpdaterTextArea; area = viewer.bytecodeViewPanel1.updateThread.updateUpdaterTextArea;
break; break;
case 1: case 1:
area = viewer.resourceViewPanel2.updateThread.updateUpdaterTextArea; area = viewer.bytecodeViewPanel2.updateThread.updateUpdaterTextArea;
break; break;
case 2: case 2:
area = viewer.resourceViewPanel3.updateThread.updateUpdaterTextArea; area = viewer.bytecodeViewPanel3.updateThread.updateUpdaterTextArea;
break; break;
} }
@ -229,8 +305,8 @@ public abstract class PaneUpdaterThread implements Runnable
public void synchronizePane() public void synchronizePane()
{ {
if(resourceViewPanel.decompiler == Decompiler.HEXCODE_VIEWER if(bytecodeViewPanel.decompiler == Decompiler.HEXCODE_VIEWER
|| resourceViewPanel.decompiler == Decompiler.NONE) || bytecodeViewPanel.decompiler == Decompiler.NONE)
return; return;
SwingUtilities.invokeLater(()-> SwingUtilities.invokeLater(()->
@ -240,7 +316,7 @@ public abstract class PaneUpdaterThread implements Runnable
updateUpdaterTextArea.addCaretListener(caretListener); updateUpdaterTextArea.addCaretListener(caretListener);
}); });
final MethodParser methods = viewer.methods.get(resourceViewPanel.panelIndex); final MethodParser methods = viewer.methods.get(bytecodeViewPanel.panelIndex);
for (int i = 0; i < updateUpdaterTextArea.getLineCount(); i++) for (int i = 0; i < updateUpdaterTextArea.getLineCount(); i++)
{ {
String lineText = updateUpdaterTextArea.getLineText(i); String lineText = updateUpdaterTextArea.getLineText(i);
@ -269,16 +345,16 @@ public abstract class PaneUpdaterThread implements Runnable
int line = (int) Objects.requireNonNull(methodsList.getSelectedItem()); int line = (int) Objects.requireNonNull(methodsList.getSelectedItem());
RSyntaxTextArea area = null; RSyntaxTextArea area = null;
switch (resourceViewPanel.panelIndex) switch (bytecodeViewPanel.panelIndex)
{ {
case 0: case 0:
area = viewer.resourceViewPanel1.updateThread.updateUpdaterTextArea; area = viewer.bytecodeViewPanel1.updateThread.updateUpdaterTextArea;
break; break;
case 1: case 1:
area = viewer.resourceViewPanel2.updateThread.updateUpdaterTextArea; area = viewer.bytecodeViewPanel2.updateThread.updateUpdaterTextArea;
break; break;
case 2: case 2:
area = viewer.resourceViewPanel3.updateThread.updateUpdaterTextArea; area = viewer.bytecodeViewPanel3.updateThread.updateUpdaterTextArea;
break; break;
} }
@ -305,24 +381,24 @@ public abstract class PaneUpdaterThread implements Runnable
updateUpdaterTextArea = new SearchableRSyntaxTextArea(); updateUpdaterTextArea = new SearchableRSyntaxTextArea();
Configuration.rstaTheme.apply(updateUpdaterTextArea); Configuration.rstaTheme.apply(updateUpdaterTextArea);
resourceViewPanel.panel.add(updateUpdaterTextArea.getScrollPane()); bytecodeViewPanel.panel.add(updateUpdaterTextArea.getScrollPane());
resourceViewPanel.panel.add(updateUpdaterTextArea.getTitleHeader(), BorderLayout.NORTH); bytecodeViewPanel.panel.add(updateUpdaterTextArea.getTitleHeader(), BorderLayout.NORTH);
resourceViewPanel.textArea = updateUpdaterTextArea; bytecodeViewPanel.textArea = updateUpdaterTextArea;
resourceViewPanel.textArea.setSyntaxEditingStyle(SyntaxConstants.SYNTAX_STYLE_JAVA); bytecodeViewPanel.textArea.setSyntaxEditingStyle(SyntaxConstants.SYNTAX_STYLE_JAVA);
resourceViewPanel.textArea.setCodeFoldingEnabled(true); bytecodeViewPanel.textArea.setCodeFoldingEnabled(true);
resourceViewPanel.textArea.setAntiAliasingEnabled(true); bytecodeViewPanel.textArea.setAntiAliasingEnabled(true);
resourceViewPanel.textArea.setText(decompiledSource); bytecodeViewPanel.textArea.setText(decompiledSource);
resourceViewPanel.textArea.setCaretPosition(0); bytecodeViewPanel.textArea.setCaretPosition(0);
resourceViewPanel.textArea.setEditable(isPanelEditable); bytecodeViewPanel.textArea.setEditable(isPanelEditable);
if(isPanelEditable && decompiler == Decompiler.SMALI_DISASSEMBLER) if(isPanelEditable && decompiler == Decompiler.SMALI_DISASSEMBLER)
resourceViewPanel.compileMode = Compiler.SMALI_ASSEMBLER; bytecodeViewPanel.compiler = Compiler.SMALI_ASSEMBLER;
else if(isPanelEditable && decompiler == Decompiler.KRAKATAU_DISASSEMBLER) else if(isPanelEditable && decompiler == Decompiler.KRAKATAU_DISASSEMBLER)
resourceViewPanel.compileMode = Compiler.KRAKATAU_ASSEMBLER; bytecodeViewPanel.compiler = Compiler.KRAKATAU_ASSEMBLER;
String editable = isPanelEditable ? " - " + EDITABLE : ""; String editable = isPanelEditable ? " - " + EDITABLE : "";
resourceViewPanel.textArea.getTitleHeader().setText(decompiler.getDecompilerName() + editable); bytecodeViewPanel.textArea.getTitleHeader().setText(decompiler.getDecompilerName() + editable);
resourceViewPanel.textArea.setFont(new Font(Font.MONOSPACED, Font.PLAIN, (int) BytecodeViewer.viewer.fontSpinner.getValue())); bytecodeViewPanel.textArea.setFont(new Font(Font.MONOSPACED, Font.PLAIN, (int) BytecodeViewer.viewer.fontSpinner.getValue()));
} }
} }

View file

@ -3,6 +3,7 @@ package the.bytecode.club.bytecodeviewer.resources;
import java.io.File; import java.io.File;
import java.util.LinkedHashMap; import java.util.LinkedHashMap;
import org.apache.commons.compress.compressors.FileNameUtil;
import org.apache.commons.io.FilenameUtils; import org.apache.commons.io.FilenameUtils;
import org.objectweb.asm.tree.ClassNode; import org.objectweb.asm.tree.ClassNode;
import the.bytecode.club.bytecodeviewer.api.ASMUtil; import the.bytecode.club.bytecodeviewer.api.ASMUtil;
@ -63,6 +64,7 @@ public class ResourceContainer
if(resourceClassBytes.containsKey(resourceName)) if(resourceClassBytes.containsKey(resourceName))
return resourceClasses.get(FilenameUtils.removeExtension(resourceName)); return resourceClasses.get(FilenameUtils.removeExtension(resourceName));
//TODO check if this is even being called, it's probably not
return resourceClasses.get(resourceName); return resourceClasses.get(resourceName);
} }
@ -90,22 +92,22 @@ public class ResourceContainer
/** /**
* Updates the ClassNode reference on the resourceClass list and resourceClassBytes list * Updates the ClassNode reference on the resourceClass list and resourceClassBytes list
*/ */
public ResourceContainer updateNode(ClassNode oldNode, ClassNode newNode) public ResourceContainer updateNode(String resourceKey, ClassNode newNode)
{ {
String classNodeKey = FilenameUtils.removeExtension(resourceKey);
//update all classnode references for ASM //update all classnode references for ASM
if (resourceClasses.containsKey(oldNode.name)) if (resourceClasses.containsKey(classNodeKey))
{ {
resourceClasses.remove(oldNode.name); resourceClasses.remove(classNodeKey);
resourceClasses.put(newNode.name, newNode); resourceClasses.put(classNodeKey, newNode);
} }
//update the resource bytes //update the resource bytes
String oldResourceKey = oldNode.name + ".class"; if(resourceClassBytes.containsKey(resourceKey))
String newResourceKey = newNode.name + ".class";
if(resourceClassBytes.containsKey(oldResourceKey))
{ {
resourceClassBytes.remove(oldResourceKey); resourceClassBytes.remove(resourceKey);
resourceClassBytes.put(newResourceKey, ASMUtil.nodeToBytes(newNode)); resourceClassBytes.put(resourceKey, ASMUtil.nodeToBytes(newNode));
} }
return this; return this;
} }