diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/BytecodeViewer.java b/src/main/java/the/bytecode/club/bytecodeviewer/BytecodeViewer.java index 04908a5a..18f710aa 100644 --- a/src/main/java/the/bytecode/club/bytecodeviewer/BytecodeViewer.java +++ b/src/main/java/the/bytecode/club/bytecodeviewer/BytecodeViewer.java @@ -12,6 +12,7 @@ import me.konloch.kontainer.io.DiskReader; import org.apache.commons.io.FileUtils; import org.objectweb.asm.tree.ClassNode; import the.bytecode.club.bootloader.Boot; +import the.bytecode.club.bytecodeviewer.api.BCV; import the.bytecode.club.bytecodeviewer.api.ExceptionUI; import the.bytecode.club.bytecodeviewer.gui.components.*; import the.bytecode.club.bytecodeviewer.gui.resourceviewer.TabbedPane; @@ -168,11 +169,6 @@ public class BytecodeViewer //setup look and feel Configuration.lafTheme.setLAF(); - if (PREVIEW_COPY && !CommandLineInput.containsCommand(args)) - showMessage("WARNING: This is a preview/dev copy, you WON'T be alerted when " + VERSION + " is " - + "actually out if you use this." + nl + - "Make sure to watch the repo: https://github.com/Konloch/bytecode-viewer for " + VERSION + "'s release"); - //set swing specific system properties System.setProperty("swing.aatext", "true"); @@ -189,7 +185,6 @@ public class BytecodeViewer //handle CLI int CLI = CommandLineInput.parseCommandLine(args); - if (CLI == CommandLineInput.STOP) return; @@ -200,10 +195,14 @@ public class BytecodeViewer Boot.boot(args, CLI != CommandLineInput.GUI); } else + { installFatJar.start(); + } if (CLI == CommandLineInput.GUI) + { BytecodeViewer.boot(false); + } else { BytecodeViewer.boot(true); @@ -350,15 +349,20 @@ public class BytecodeViewer /** * Returns the ClassNode by the specified name * + * TODO anything relying on this should be rewritten to search using the file container + * * @param name the class name * @return the ClassNode instance */ - public static ClassNode getClassNode(String name) + @Deprecated + public static ClassNode blindlySearchForClassNode(String name) { for (FileContainer container : files) - for (ClassNode c : container.classes) - if (c.name.equals(name)) - return c; + { + ClassNode node = container.getClassNode(name); + if(node != null) + return node; + } return null; } @@ -381,18 +385,6 @@ public class BytecodeViewer public static List getFiles() { return files; } - - /** - * Returns a ClassNode by name specific namefrom a specific File Container - */ - public static ClassNode getClassNode(FileContainer container, String name) - { - for (ClassNode c : container.classes) - if (c.name.equals(name)) - return c; - - return null; - } /** * Grabs the file contents of the loaded resources. @@ -403,8 +395,8 @@ public class BytecodeViewer public static byte[] getFileContents(String name) { for (FileContainer container : files) - if (container.files.containsKey(name)) - return container.files.get(name); + if (container.resourceFiles.containsKey(name)) + return container.resourceFiles.get(name); return null; } @@ -426,8 +418,13 @@ public class BytecodeViewer public static void updateNode(ClassNode oldNode, ClassNode newNode) { for (FileContainer container : files) - if (container.classes.remove(oldNode)) - container.classes.add(newNode); + { + if (container.resourceClasses.containsKey(oldNode.name)) + { + container.resourceClasses.remove(oldNode.name); + container.resourceClasses.put(newNode.name, newNode); + } + } } /** @@ -440,7 +437,7 @@ public class BytecodeViewer ArrayList a = new ArrayList<>(); for (FileContainer container : files) - for (ClassNode c : container.classes) + for (ClassNode c : container.resourceClasses.values()) if (!a.contains(c)) a.add(c); @@ -648,7 +645,20 @@ public class BytecodeViewer return; } - BCVResourceUtils.resetWorkspace(); + resetWorkspace(); + } + + /** + * Resets the workspace + */ + public static void resetWorkspace() + { + BytecodeViewer.files.clear(); + LazyNameUtil.reset(); + BytecodeViewer.viewer.resourcePane.resetWorkspace(); + BytecodeViewer.viewer.workPane.resetWorkspace(); + BytecodeViewer.viewer.searchBoxPane.resetWorkspace(); + BCV.getClassNodeLoader().clear(); } /** diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/CommandLineInput.java b/src/main/java/the/bytecode/club/bytecodeviewer/CommandLineInput.java index 2675c30d..b881ec17 100644 --- a/src/main/java/the/bytecode/club/bytecodeviewer/CommandLineInput.java +++ b/src/main/java/the/bytecode/club/bytecodeviewer/CommandLineInput.java @@ -215,7 +215,7 @@ public class CommandLineInput { Decompiler.PROCYON_DECOMPILER.getDecompiler().decompileToZip(tempZip.getAbsolutePath(), output.getAbsolutePath()); } else { try { - ClassNode cn = BytecodeViewer.getClassNode(target); + ClassNode cn = BytecodeViewer.blindlySearchForClassNode(target); final ClassWriter cw = accept(cn); String contents = Decompiler.PROCYON_DECOMPILER.getDecompiler().decompileClassNode(cn, cw.toByteArray()); DiskWriter.replaceFile(output.getAbsolutePath(), contents, false); @@ -233,7 +233,7 @@ public class CommandLineInput { Decompiler.CFR_DECOMPILER.getDecompiler().decompileToZip(tempZip.getAbsolutePath(), output.getAbsolutePath()); } else { try { - ClassNode cn = BytecodeViewer.getClassNode(target); + ClassNode cn = BytecodeViewer.blindlySearchForClassNode(target); final ClassWriter cw = accept(cn); String contents = Decompiler.CFR_DECOMPILER.getDecompiler().decompileClassNode(cn, cw.toByteArray()); DiskWriter.replaceFile(output.getAbsolutePath(), contents, false); @@ -251,7 +251,7 @@ public class CommandLineInput { Decompiler.FERNFLOWER_DECOMPILER.getDecompiler().decompileToZip(tempZip.getAbsolutePath(), output.getAbsolutePath()); } else { try { - ClassNode cn = BytecodeViewer.getClassNode(target); + ClassNode cn = BytecodeViewer.blindlySearchForClassNode(target); final ClassWriter cw = accept(cn); String contents = Decompiler.FERNFLOWER_DECOMPILER.getDecompiler().decompileClassNode(cn, cw.toByteArray()); DiskWriter.replaceFile(output.getAbsolutePath(), contents, false); @@ -269,7 +269,7 @@ public class CommandLineInput { Decompiler.KRAKATAU_DECOMPILER.getDecompiler().decompileToZip(tempZip.getAbsolutePath(), output.getAbsolutePath()); } else { try { - ClassNode cn = BytecodeViewer.getClassNode(target); + ClassNode cn = BytecodeViewer.blindlySearchForClassNode(target); final ClassWriter cw = accept(cn); String contents = Decompiler.KRAKATAU_DECOMPILER.getDecompiler().decompileClassNode(cn, cw.toByteArray()); DiskWriter.replaceFile(output.getAbsolutePath(), contents, false); @@ -288,7 +288,7 @@ public class CommandLineInput { //Decompiler.krakatauDA.decompileToZip(output.getAbsolutePath()); } else { try { - ClassNode cn = BytecodeViewer.getClassNode(target); + ClassNode cn = BytecodeViewer.blindlySearchForClassNode(target); final ClassWriter cw = accept(cn); String contents = Decompiler.KRAKATAU_DISASSEMBLER.getDecompiler().decompileClassNode(cn, cw.toByteArray()); DiskWriter.replaceFile(output.getAbsolutePath(), contents, false); @@ -307,7 +307,7 @@ public class CommandLineInput { //Decompiler.jdgui.decompileToZip(output.getAbsolutePath()); } else { try { - ClassNode cn = BytecodeViewer.getClassNode(target); + ClassNode cn = BytecodeViewer.blindlySearchForClassNode(target); final ClassWriter cw = accept(cn); String contents = Decompiler.JD_DECOMPILER.getDecompiler().decompileClassNode(cn, cw.toByteArray()); DiskWriter.replaceFile(output.getAbsolutePath(), contents, false); @@ -326,7 +326,7 @@ public class CommandLineInput { //Decompiler.smali.decompileToZip(output.getAbsolutePath()); } else { try { - ClassNode cn = BytecodeViewer.getClassNode(target); + ClassNode cn = BytecodeViewer.blindlySearchForClassNode(target); final ClassWriter cw = accept(cn); String contents = Decompiler.SMALI_DISASSEMBLER.getDecompiler().decompileClassNode(cn, cw.toByteArray()); DiskWriter.replaceFile(output.getAbsolutePath(), contents, false); @@ -345,7 +345,7 @@ public class CommandLineInput { //Decompiler.smali.decompileToZip(output.getAbsolutePath()); } else { try { - ClassNode cn = BytecodeViewer.getClassNode(target); + ClassNode cn = BytecodeViewer.blindlySearchForClassNode(target); final ClassWriter cw = accept(cn); String contents = Decompiler.JADX_DECOMPILER.getDecompiler().decompileClassNode(cn, cw.toByteArray()); DiskWriter.replaceFile(output.getAbsolutePath(), contents, false); diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/Settings.java b/src/main/java/the/bytecode/club/bytecodeviewer/Settings.java index faab9d3b..256741e6 100644 --- a/src/main/java/the/bytecode/club/bytecodeviewer/Settings.java +++ b/src/main/java/the/bytecode/club/bytecodeviewer/Settings.java @@ -11,6 +11,7 @@ import java.util.ArrayList; import java.util.List; import static the.bytecode.club.bytecodeviewer.BytecodeViewer.gson; +import static the.bytecode.club.bytecodeviewer.Configuration.maxRecentFiles; import static the.bytecode.club.bytecodeviewer.Constants.*; /** @@ -38,8 +39,8 @@ public class Settings else recentPlugins = DiskReader.loadArrayList(getBCVDirectory() + fs + "recentplugins.bcv", false); - MiscUtils.deduplicateAndTrim(recentFiles, 25); - MiscUtils.deduplicateAndTrim(recentPlugins, 25); + MiscUtils.deduplicateAndTrim(recentFiles, maxRecentFiles); + MiscUtils.deduplicateAndTrim(recentPlugins, maxRecentFiles); } catch (Exception e) { @@ -56,7 +57,7 @@ public class Settings { recentFiles.remove(f.getAbsolutePath()); // already added on the list recentFiles.add(0, f.getAbsolutePath()); - MiscUtils.deduplicateAndTrim(recentFiles, 25); + MiscUtils.deduplicateAndTrim(recentFiles, maxRecentFiles); DiskWriter.replaceFile(filesName, MiscUtils.listToString(recentFiles), false); resetRecentFilesMenu(); } @@ -87,7 +88,7 @@ public class Settings { recentPlugins.remove(f.getAbsolutePath()); // already added on the list recentPlugins.add(0, f.getAbsolutePath()); - MiscUtils.deduplicateAndTrim(recentPlugins, 25); + MiscUtils.deduplicateAndTrim(recentPlugins, maxRecentFiles); DiskWriter.replaceFile(pluginsName, MiscUtils.listToString(recentPlugins), false); resetRecentFilesMenu(); } diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/api/ASMUtil.java b/src/main/java/the/bytecode/club/bytecodeviewer/api/ASMUtil.java index 53e23ac2..55b4302e 100644 --- a/src/main/java/the/bytecode/club/bytecodeviewer/api/ASMUtil.java +++ b/src/main/java/the/bytecode/club/bytecodeviewer/api/ASMUtil.java @@ -1,6 +1,7 @@ package the.bytecode.club.bytecodeviewer.api; import org.objectweb.asm.ClassReader; +import org.objectweb.asm.ClassWriter; import org.objectweb.asm.tree.ClassNode; import org.objectweb.asm.tree.MethodNode; @@ -12,11 +13,8 @@ public class ASMUtil { /** * Creates a new ClassNode instances from the provided byte[] - * - * @param b the class file's byte[] - * @return the ClassNode instance */ - public static ClassNode getClassNode(final byte[] b) + public static ClassNode bytesToNode(final byte[] b) { ClassReader cr = new ClassReader(b); ClassNode cn = new ClassNode(); @@ -28,6 +26,26 @@ public class ASMUtil return cn; } + /** + * Writes a valid byte[] from the provided classnode + */ + public static byte[] nodeToBytes(ClassNode cn) + { + final ClassWriter cw = new ClassWriter(0); + + try { + cn.accept(cw); + } catch (Exception e) { + e.printStackTrace(); + try { + Thread.sleep(200); + cn.accept(cw); + } catch (InterruptedException ignored) { } + } + + return cw.toByteArray(); + } + public static MethodNode getMethodByName(ClassNode cn, String name) { for(MethodNode m : cn.methods) diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/api/BCV.java b/src/main/java/the/bytecode/club/bytecodeviewer/api/BCV.java index 2025ec8b..f48c5bc8 100644 --- a/src/main/java/the/bytecode/club/bytecodeviewer/api/BCV.java +++ b/src/main/java/the/bytecode/club/bytecodeviewer/api/BCV.java @@ -174,7 +174,7 @@ public class BCV */ public static ClassNode getClassNode(String name) { return the.bytecode.club.bytecodeviewer.BytecodeViewer - .getClassNode(name); + .blindlySearchForClassNode(name); } /** diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/decompilers/bytecode/ClassNodeDecompiler.java b/src/main/java/the/bytecode/club/bytecodeviewer/decompilers/bytecode/ClassNodeDecompiler.java index 3670f38c..187220a6 100644 --- a/src/main/java/the/bytecode/club/bytecodeviewer/decompilers/bytecode/ClassNodeDecompiler.java +++ b/src/main/java/the/bytecode/club/bytecodeviewer/decompilers/bytecode/ClassNodeDecompiler.java @@ -9,7 +9,6 @@ import org.objectweb.asm.tree.FieldNode; import org.objectweb.asm.tree.InnerClassNode; import org.objectweb.asm.tree.MethodNode; import the.bytecode.club.bytecodeviewer.BytecodeViewer; -import the.bytecode.club.bytecodeviewer.decompilers.InternalDecompiler; import static the.bytecode.club.bytecodeviewer.Constants.*; @@ -101,7 +100,7 @@ public class ClassNodeDecompiler if ((innerClassName != null) && !decompiledClasses.contains(innerClassName)) { decompiledClasses.add(innerClassName); - ClassNode cn1 = BytecodeViewer.getClassNode(innerClassName); + ClassNode cn1 = BytecodeViewer.blindlySearchForClassNode(innerClassName); if (cn1 != null) { sb.appendPrefix(" "); sb.append(nl + nl); diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/gui/components/HTMLPane.java b/src/main/java/the/bytecode/club/bytecodeviewer/gui/components/HTMLPane.java index 8b048117..016b76de 100644 --- a/src/main/java/the/bytecode/club/bytecodeviewer/gui/components/HTMLPane.java +++ b/src/main/java/the/bytecode/club/bytecodeviewer/gui/components/HTMLPane.java @@ -30,7 +30,6 @@ public class HTMLPane extends JEditorPane { HTMLPane pane = new HTMLPane(); - text = text.replace("{previewCopy}", String.valueOf(PREVIEW_COPY)); text = text.replace("{fatJar}", String.valueOf(FAT_JAR)); text = text.replace("{java}", Configuration.java); text = text.replace("{javac}", Configuration.javac); diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/gui/resourcelist/ResourceListPane.java b/src/main/java/the/bytecode/club/bytecodeviewer/gui/resourcelist/ResourceListPane.java index ae913651..43fd9008 100644 --- a/src/main/java/the/bytecode/club/bytecodeviewer/gui/resourcelist/ResourceListPane.java +++ b/src/main/java/the/bytecode/club/bytecodeviewer/gui/resourcelist/ResourceListPane.java @@ -29,7 +29,6 @@ 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.components.VisibleComponent; import the.bytecode.club.bytecodeviewer.translation.TranslatedStrings; import the.bytecode.club.bytecodeviewer.translation.Translation; import the.bytecode.club.bytecodeviewer.translation.components.TranslatedJCheckBox; @@ -169,9 +168,9 @@ public class ResourceListPane extends TranslatedVisibleComponent implements File ImageRenderer renderer = new ImageRenderer(); tree.setCellRenderer(renderer); - if (!container.classes.isEmpty()) + if (!container.resourceClasses.isEmpty()) { - for (ClassNode c : container.classes) + for (ClassNode c : container.resourceClasses.values()) { String name = c.name; final String[] spl = name.split("/"); @@ -211,9 +210,9 @@ public class ResourceListPane extends TranslatedVisibleComponent implements File } } - if (!container.files.isEmpty()) + if (!container.resourceFiles.isEmpty()) { - for (final Entry entry : container.files.entrySet()) + for (final Entry entry : container.resourceFiles.entrySet()) { String name = entry.getKey(); final String[] spl = name.split("/"); @@ -311,7 +310,7 @@ public class ResourceListPane extends TranslatedVisibleComponent implements File String name = nameBuffer.toString(); if (name.endsWith(".class")) { - final ClassNode cn = BytecodeViewer.getClassNode(Objects.requireNonNull(container), + final ClassNode cn = Objects.requireNonNull(container).getClassNode( name.substring(0, name.length() - ".class".length())); if (cn != null) diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/gui/resourcesearch/PerformSearch.java b/src/main/java/the/bytecode/club/bytecodeviewer/gui/resourcesearch/PerformSearch.java index f5e65919..5f96cb0f 100644 --- a/src/main/java/the/bytecode/club/bytecodeviewer/gui/resourcesearch/PerformSearch.java +++ b/src/main/java/the/bytecode/club/bytecodeviewer/gui/resourcesearch/PerformSearch.java @@ -43,7 +43,7 @@ class PerformSearch extends BackgroundSearchThread } for (FileContainer container : BytecodeViewer.files) - for (ClassNode c : container.classes) + for (ClassNode c : container.resourceClasses.values()) searchBoxPane.searchType.details.search(container, c, srn, searchBoxPane.exact.isSelected()); Objects.requireNonNull(MainViewerGUI.getComponent(SearchBoxPane.class)).search.setEnabled(true); diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/gui/resourceviewer/viewer/ClassViewer.java b/src/main/java/the/bytecode/club/bytecodeviewer/gui/resourceviewer/viewer/ClassViewer.java index 22d9149f..555e3087 100644 --- a/src/main/java/the/bytecode/club/bytecodeviewer/gui/resourceviewer/viewer/ClassViewer.java +++ b/src/main/java/the/bytecode/club/bytecodeviewer/gui/resourceviewer/viewer/ClassViewer.java @@ -1,5 +1,6 @@ package the.bytecode.club.bytecodeviewer.gui.resourceviewer.viewer; +import the.bytecode.club.bytecodeviewer.api.ASMUtil; import the.bytecode.club.bytecodeviewer.decompilers.Decompiler; import the.bytecode.club.bytecodeviewer.gui.resourceviewer.ResourceViewPanel; import the.bytecode.club.bytecodeviewer.gui.hexviewer.JHexEditor; @@ -66,8 +67,6 @@ public class ClassViewer extends ResourceViewer public ResourceViewPanel resourceViewPanel2 = new ResourceViewPanel(1, this); public ResourceViewPanel resourceViewPanel3 = new ResourceViewPanel(2, this); - public File[] tempFiles; - public ClassViewer THIS = this; public List methods = Arrays.asList(new MethodParser(), new MethodParser(), new MethodParser()); public final String workingName; @@ -93,68 +92,31 @@ public class ClassViewer extends ResourceViewer }); } - public void resetDivider() - { - SwingUtilities.invokeLater(() -> - { - sp.setResizeWeight(0.5); - - if (resourceViewPanel2.decompiler != Decompiler.NONE && resourceViewPanel1.decompiler != Decompiler.NONE) { - setDividerLocation(sp, 0.5); - } else if (resourceViewPanel1.decompiler != Decompiler.NONE) { - setDividerLocation(sp, 1); - } else if (resourceViewPanel2.decompiler != Decompiler.NONE) { - sp.setResizeWeight(1); - setDividerLocation(sp, 0); - } else { - setDividerLocation(sp, 0); - } - - if (resourceViewPanel3.decompiler != Decompiler.NONE) { - sp2.setResizeWeight(0.7); - setDividerLocation(sp2, 0.7); - if ((resourceViewPanel2.decompiler == Decompiler.NONE && resourceViewPanel1.decompiler != Decompiler.NONE) - || (resourceViewPanel1.decompiler == Decompiler.NONE && resourceViewPanel2.decompiler != Decompiler.NONE)) { - setDividerLocation(sp2, 0.5); - } else if (resourceViewPanel1.decompiler == Decompiler.NONE) { - setDividerLocation(sp2, 0); - } - } else { - sp.setResizeWeight(1); - sp2.setResizeWeight(0); - setDividerLocation(sp2, 1); - } - }); - } - public void startPaneUpdater(final JButton button) { - this.cn = BytecodeViewer.getClassNode(container, cn.name); //update the classnode - setPanes(); + this.cn = container.getClassNode(cn.name); //update the classnode + setPanes(); refreshTitle(); resourceViewPanel1.createPane(this); resourceViewPanel2.createPane(this); resourceViewPanel3.createPane(this); - final ClassWriter cw = new ClassWriter(0); - try { - cn.accept(cw); - } catch (Exception e) { - e.printStackTrace(); - try { - Thread.sleep(200); - cn.accept(cw); - } catch (InterruptedException ignored) { } + byte[] classBytes = getBytes(); + + //TODO remove this once all of the importers have been properly updated to use a FileContainerImporter + if(classBytes == null || classBytes.length == 0) + { + System.err.println("WARNING: Imported using the old importer!"); + classBytes = ASMUtil.nodeToBytes(cn); } + + resourceViewPanel1.updatePane(this, classBytes, button, isPanel1Editable()); + resourceViewPanel2.updatePane(this, classBytes, button, isPanel2Editable()); + resourceViewPanel3.updatePane(this, classBytes, button, isPanel3Editable()); - final byte[] b = cw.toByteArray(); - resourceViewPanel1.updatePane(this, b, button, isPanel1Editable()); - resourceViewPanel2.updatePane(this, b, button, isPanel2Editable()); - resourceViewPanel3.updatePane(this, b, button, isPanel3Editable()); - - Thread t = new Thread(() -> + Thread dumpBuild = new Thread(() -> { BytecodeViewer.updateBusyStatus(true); @@ -167,8 +129,6 @@ public class ClassViewer extends ResourceViewer e.printStackTrace(); } } - - tempFiles = BCVResourceUtils.dumpTempFile(container); BytecodeViewer.updateBusyStatus(false); @@ -179,7 +139,7 @@ public class ClassViewer extends ResourceViewer if (resourceViewPanel3.decompiler != Decompiler.NONE) resourceViewPanel3.updateThread.startNewThread(); }, "ClassViewer Temp Dump"); - t.start(); + dumpBuild.start(); if (isPanel1Editable() || isPanel2Editable() || isPanel3Editable()) { @@ -227,42 +187,6 @@ public class ClassViewer extends ResourceViewer return BytecodeViewer.viewer.viewPane3.isPaneEditable(); } - /** - * Whoever wrote this function, THANK YOU! - * - * @param splitter - * @param proportion - * @return - */ - public static JSplitPane setDividerLocation(final JSplitPane splitter, - final double proportion) { - if (splitter.isShowing()) { - if (splitter.getWidth() > 0 && splitter.getHeight() > 0) { - splitter.setDividerLocation(proportion); - } else { - splitter.addComponentListener(new ComponentAdapter() { - @Override - public void componentResized(ComponentEvent ce) { - splitter.removeComponentListener(this); - setDividerLocation(splitter, proportion); - } - }); - } - } else { - splitter.addHierarchyListener(new HierarchyListener() { - @Override - public void hierarchyChanged(HierarchyEvent e) { - if ((e.getChangeFlags() & HierarchyEvent.SHOWING_CHANGED) != 0 - && splitter.isShowing()) { - splitter.removeHierarchyListener(this); - setDividerLocation(splitter, proportion); - } - } - }); - } - return splitter; - } - public static void selectMethod(RSyntaxTextArea area, int methodLine) { if (methodLine != area.getCaretLineNumber()) { @@ -343,5 +267,72 @@ public class ClassViewer extends ResourceViewer } catch (BadLocationException ignored) { } } + public void resetDivider() + { + SwingUtilities.invokeLater(() -> + { + sp.setResizeWeight(0.5); + + if (resourceViewPanel2.decompiler != Decompiler.NONE && resourceViewPanel1.decompiler != Decompiler.NONE) { + setDividerLocation(sp, 0.5); + } else if (resourceViewPanel1.decompiler != Decompiler.NONE) { + setDividerLocation(sp, 1); + } else if (resourceViewPanel2.decompiler != Decompiler.NONE) { + sp.setResizeWeight(1); + setDividerLocation(sp, 0); + } else { + setDividerLocation(sp, 0); + } + + if (resourceViewPanel3.decompiler != Decompiler.NONE) { + sp2.setResizeWeight(0.7); + setDividerLocation(sp2, 0.7); + if ((resourceViewPanel2.decompiler == Decompiler.NONE && resourceViewPanel1.decompiler != Decompiler.NONE) + || (resourceViewPanel1.decompiler == Decompiler.NONE && resourceViewPanel2.decompiler != Decompiler.NONE)) { + setDividerLocation(sp2, 0.5); + } else if (resourceViewPanel1.decompiler == Decompiler.NONE) { + setDividerLocation(sp2, 0); + } + } else { + sp.setResizeWeight(1); + sp2.setResizeWeight(0); + setDividerLocation(sp2, 1); + } + }); + } + + /** + * Whoever wrote this function, THANK YOU! + */ + public static JSplitPane setDividerLocation(final JSplitPane splitter, + final double proportion) + { + if (splitter.isShowing()) { + if (splitter.getWidth() > 0 && splitter.getHeight() > 0) { + splitter.setDividerLocation(proportion); + } else { + splitter.addComponentListener(new ComponentAdapter() { + @Override + public void componentResized(ComponentEvent ce) { + splitter.removeComponentListener(this); + setDividerLocation(splitter, proportion); + } + }); + } + } else { + splitter.addHierarchyListener(new HierarchyListener() { + @Override + public void hierarchyChanged(HierarchyEvent e) { + if ((e.getChangeFlags() & HierarchyEvent.SHOWING_CHANGED) != 0 + && splitter.isShowing()) { + splitter.removeHierarchyListener(this); + setDividerLocation(splitter, proportion); + } + } + }); + } + return splitter; + } + private static final long serialVersionUID = -8650495368920680024L; } diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/gui/resourceviewer/viewer/ResourceViewer.java b/src/main/java/the/bytecode/club/bytecodeviewer/gui/resourceviewer/viewer/ResourceViewer.java index af21baf7..c1e367cc 100644 --- a/src/main/java/the/bytecode/club/bytecodeviewer/gui/resourceviewer/viewer/ResourceViewer.java +++ b/src/main/java/the/bytecode/club/bytecodeviewer/gui/resourceviewer/viewer/ResourceViewer.java @@ -52,6 +52,14 @@ public abstract class ResourceViewer extends JPanel return tabName; } + + public byte[] getBytes() + { + if(container.resourceClassBytes.containsKey(name)) + return container.resourceClassBytes.get(name); + else + return container.resourceFiles.get(name); + } private static final long serialVersionUID = -2965538493489119191L; } \ No newline at end of file diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/plugin/preinstalled/AllatoriStringDecrypter.java b/src/main/java/the/bytecode/club/bytecodeviewer/plugin/preinstalled/AllatoriStringDecrypter.java index b88f4b2b..adf72534 100644 --- a/src/main/java/the/bytecode/club/bytecodeviewer/plugin/preinstalled/AllatoriStringDecrypter.java +++ b/src/main/java/the/bytecode/club/bytecodeviewer/plugin/preinstalled/AllatoriStringDecrypter.java @@ -147,7 +147,7 @@ public class AllatoriStringDecrypter extends Plugin // We have to create new node for editing // Also, one decrypter method could be used for multiple methods in code, what gives us only part of string decrypted - ClassNode decrypterClassNode = ASMUtil.getClassNode(decrypterFileContents); + ClassNode decrypterClassNode = ASMUtil.bytesToNode(decrypterFileContents); MethodNode decryptermethodnode = ASMUtil.getMethodByName(decrypterClassNode, decrypterMethodName); if (decryptermethodnode != null) diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/plugin/strategies/CompiledJavaPluginLaunchStrategy.java b/src/main/java/the/bytecode/club/bytecodeviewer/plugin/strategies/CompiledJavaPluginLaunchStrategy.java index 70ee4edb..9a13ca0a 100644 --- a/src/main/java/the/bytecode/club/bytecodeviewer/plugin/strategies/CompiledJavaPluginLaunchStrategy.java +++ b/src/main/java/the/bytecode/club/bytecodeviewer/plugin/strategies/CompiledJavaPluginLaunchStrategy.java @@ -87,7 +87,7 @@ public class CompiledJavaPluginLaunchStrategy implements PluginLaunchStrategy { String name = entry.getName(); if (name.endsWith(".class")) { - byte[] bytes = JarUtils.getBytes(jis); + byte[] bytes = MiscUtils.getBytes(jis); if (MiscUtils.getFileHeader(bytes).equalsIgnoreCase("cafebabe")) { try { diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/resources/ResourceDecompiling.java b/src/main/java/the/bytecode/club/bytecodeviewer/resources/ResourceDecompiling.java index 5c2724c2..988d56ed 100644 --- a/src/main/java/the/bytecode/club/bytecodeviewer/resources/ResourceDecompiling.java +++ b/src/main/java/the/bytecode/club/bytecodeviewer/resources/ResourceDecompiling.java @@ -191,10 +191,7 @@ public class ResourceDecompiling if (BytecodeViewer.autoCompileSuccessful()) return; - final String s = BytecodeViewer.getCurrentlyOpenedClassNode().name; - - if (s == null) - return; + final ClassNode cn = BytecodeViewer.getCurrentlyOpenedClassNode(); JFileChooser fc = new FileChooser(Configuration.getLastDirectory(), "Select Java Files", @@ -230,7 +227,6 @@ public class ResourceDecompiling if (result == 0) { Thread t1 = new Thread(() -> { try { - ClassNode cn = BytecodeViewer.getClassNode(s); final ClassWriter cw = new ClassWriter(0); try { Objects.requireNonNull(cn).accept(cw); @@ -282,7 +278,6 @@ public class ResourceDecompiling if (result == 1) { Thread t1 = new Thread(() -> { try { - ClassNode cn = BytecodeViewer.getClassNode(s); final ClassWriter cw = new ClassWriter(0); try { Objects.requireNonNull(cn).accept(cw); @@ -308,7 +303,6 @@ public class ResourceDecompiling if (result == 2) { Thread t1 = new Thread(() -> { try { - ClassNode cn = BytecodeViewer.getClassNode(s); final ClassWriter cw = new ClassWriter(0); try { Objects.requireNonNull(cn).accept(cw); @@ -334,7 +328,6 @@ public class ResourceDecompiling if (result == 3) { Thread t1 = new Thread(() -> { try { - ClassNode cn = BytecodeViewer.getClassNode(s); final ClassWriter cw = new ClassWriter(0); try { Objects.requireNonNull(cn).accept(cw); @@ -362,7 +355,6 @@ public class ResourceDecompiling if (result == 4) { Thread t1 = new Thread(() -> { try { - ClassNode cn = BytecodeViewer.getClassNode(s); final ClassWriter cw = new ClassWriter(0); try { Objects.requireNonNull(cn).accept(cw); @@ -371,18 +363,16 @@ public class ResourceDecompiling try { Thread.sleep(200); Objects.requireNonNull(cn).accept(cw); - } catch (InterruptedException ignored) { - } + } catch (InterruptedException ignored) { } } - String contents = Decompiler.KRAKATAU_DECOMPILER.getDecompiler().decompileClassNode(cn, - cw.toByteArray()); + String contents = Decompiler.KRAKATAU_DECOMPILER.getDecompiler(). + decompileClassNode(cn, cw.toByteArray()); DiskWriter.replaceFile(path, contents, false); BytecodeViewer.updateBusyStatus(false); } catch (Exception e) { BytecodeViewer.updateBusyStatus(false); - BytecodeViewer.handleException( - e); + BytecodeViewer.handleException(e); } }); t1.start(); diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/resources/importing/ImportResource.java b/src/main/java/the/bytecode/club/bytecodeviewer/resources/importing/ImportResource.java index 20c5281c..2239f23b 100644 --- a/src/main/java/the/bytecode/club/bytecodeviewer/resources/importing/ImportResource.java +++ b/src/main/java/the/bytecode/club/bytecodeviewer/resources/importing/ImportResource.java @@ -32,7 +32,6 @@ import java.util.Objects; */ public class ImportResource implements Runnable { - private boolean update = true; private final File[] files; public ImportResource(File[] files) {this.files = files;} @@ -46,51 +45,44 @@ public class ImportResource implements Runnable { final String fn = file.getName(); + //check if file exists if (!file.exists()) { - update = false; BytecodeViewer.showMessage("The file " + file.getAbsolutePath() + " could not be found."); Settings.removeRecentFile(file); + continue; } - else + + //check if file is directory + if (file.isDirectory()) { - if (file.isDirectory()) - { - Import.DIRECTORY.getImporter().open(file); - } - else - { - if (fn.endsWith(".jar") || fn.endsWith(".zip") || fn.endsWith(".war") || fn.endsWith(".ear")) - { - if(!Import.ZIP.getImporter().open(file)) - update = false; - } - else if (fn.endsWith(".class")) - { - if(!Import.CLASS.getImporter().open(file)) - update = false; - } - else if (fn.endsWith(".xapk")) - { - Import.XAPK.getImporter().open(file); - return; - } - else if (fn.endsWith(".apk")) - { - Import.APK.getImporter().open(file); - return; - } - else if (fn.endsWith(".dex")) - { - Import.DEX.getImporter().open(file); - return; - } - else - { - Import.FILE.getImporter().open(file); - } - } + Import.DIRECTORY.getImporter().open(file); + continue; } + + //check for zip archives + if (fn.endsWith(".jar") || fn.endsWith(".zip") || fn.endsWith(".war") || fn.endsWith(".ear")) + Import.ZIP.getImporter().open(file); + + //check for classes + else if (fn.endsWith(".class")) + Import.CLASS.getImporter().open(file); + + //check for XAPKs + else if (fn.endsWith(".xapk")) + Import.XAPK.getImporter().open(file); + + //check for APKs + else if (fn.endsWith(".apk")) + Import.APK.getImporter().open(file); + + //check for DEX + else if (fn.endsWith(".dex")) + Import.DEX.getImporter().open(file); + + //everything else import as a resource + else + Import.FILE.getImporter().open(file); } } catch (final Exception e) @@ -100,11 +92,9 @@ public class ImportResource implements Runnable finally { BytecodeViewer.updateBusyStatus(false); - - if (update) - try { - Objects.requireNonNull(MainViewerGUI.getComponent(ResourceListPane.class)).updateTree(); - } catch (NullPointerException ignored) { } + try { + Objects.requireNonNull(MainViewerGUI.getComponent(ResourceListPane.class)).updateTree(); + } catch (NullPointerException ignored) { } } } } diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/resources/importing/Importer.java b/src/main/java/the/bytecode/club/bytecodeviewer/resources/importing/Importer.java index c93c28d4..e6404731 100644 --- a/src/main/java/the/bytecode/club/bytecodeviewer/resources/importing/Importer.java +++ b/src/main/java/the/bytecode/club/bytecodeviewer/resources/importing/Importer.java @@ -26,5 +26,5 @@ import java.io.File; */ public interface Importer { - boolean open(File file) throws Exception; + void open(File file) throws Exception; } diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/resources/importing/impl/APKResourceImporter.java b/src/main/java/the/bytecode/club/bytecodeviewer/resources/importing/impl/APKResourceImporter.java index 0a01e22b..e0ba2772 100644 --- a/src/main/java/the/bytecode/club/bytecodeviewer/resources/importing/impl/APKResourceImporter.java +++ b/src/main/java/the/bytecode/club/bytecodeviewer/resources/importing/impl/APKResourceImporter.java @@ -1,12 +1,13 @@ package the.bytecode.club.bytecodeviewer.resources.importing.impl; 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.resources.importing.Importer; import the.bytecode.club.bytecodeviewer.util.*; import java.io.File; +import java.util.ArrayList; import java.util.Objects; import static the.bytecode.club.bytecodeviewer.Constants.fs; @@ -19,43 +20,40 @@ import static the.bytecode.club.bytecodeviewer.Constants.tempDirectory; public class APKResourceImporter implements Importer { @Override - public boolean open(File file) throws Exception + public void open(File file) throws Exception { - try { - BytecodeViewer.updateBusyStatus(true); - - File tempCopy = new File(tempDirectory + fs + MiscUtils.randomString(32) + ".apk"); - - FileUtils.copyFile(file, tempCopy); - - FileContainer container = new FileContainer(tempCopy, file.getName()); - - if (BytecodeViewer.viewer.decodeAPKResources.isSelected()) { - File decodedResources = - new File(tempDirectory + fs + MiscUtils.randomString(32) + ".apk"); - APKTool.decodeResources(tempCopy, decodedResources, container); - container.files = JarUtils.loadResources(decodedResources); - } - - Objects.requireNonNull(container.files).putAll(JarUtils.loadResources(tempCopy)); //copy and rename - // to prevent unicode filenames - - String name = MiscUtils.getRandomizedName() + ".jar"; - File output = new File(tempDirectory + fs + name); - - if (BytecodeViewer.viewer.apkConversionGroup.isSelected(BytecodeViewer.viewer.apkConversionDex.getModel())) - Dex2Jar.dex2Jar(tempCopy, output); - else if (BytecodeViewer.viewer.apkConversionGroup.isSelected(BytecodeViewer.viewer.apkConversionEnjarify.getModel())) - Enjarify.apk2Jar(tempCopy, output); - - container.classes = JarUtils.loadClasses(output); - - BytecodeViewer.updateBusyStatus(false); - BytecodeViewer.files.add(container); - } catch (final Exception e) { - BytecodeViewer.handleException(e); + BytecodeViewer.updateBusyStatus(true); + + File tempCopy = new File(tempDirectory + fs + MiscUtils.randomString(32) + ".apk"); + + FileUtils.copyFile(file, tempCopy); + + FileContainer container = new FileContainer(tempCopy, file.getName()); + + if (BytecodeViewer.viewer.decodeAPKResources.isSelected()) { + File decodedResources = + new File(tempDirectory + fs + MiscUtils.randomString(32) + ".apk"); + APKTool.decodeResources(tempCopy, decodedResources, container); + container.resourceFiles = JarUtils.loadResources(decodedResources); } - return true; + Objects.requireNonNull(container.resourceFiles).putAll(JarUtils.loadResources(tempCopy)); //copy and rename + // to prevent unicode filenames + + String name = MiscUtils.getRandomizedName() + ".jar"; + File output = new File(tempDirectory + fs + name); + + if (BytecodeViewer.viewer.apkConversionGroup.isSelected(BytecodeViewer.viewer.apkConversionDex.getModel())) + Dex2Jar.dex2Jar(tempCopy, output); + else if (BytecodeViewer.viewer.apkConversionGroup.isSelected(BytecodeViewer.viewer.apkConversionEnjarify.getModel())) + Enjarify.apk2Jar(tempCopy, output); + + //TODO update to FileContainerImporter + ArrayList nodeList = JarUtils.loadClasses(output); + for(ClassNode cn : nodeList) + container.resourceClasses.put(cn.name, cn); + + BytecodeViewer.updateBusyStatus(false); + BytecodeViewer.files.add(container); } } diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/resources/importing/impl/ClassResourceImporter.java b/src/main/java/the/bytecode/club/bytecodeviewer/resources/importing/impl/ClassResourceImporter.java index 41216625..c6d57746 100644 --- a/src/main/java/the/bytecode/club/bytecodeviewer/resources/importing/impl/ClassResourceImporter.java +++ b/src/main/java/the/bytecode/club/bytecodeviewer/resources/importing/impl/ClassResourceImporter.java @@ -1,8 +1,8 @@ package the.bytecode.club.bytecodeviewer.resources.importing.impl; +import org.apache.commons.io.FilenameUtils; import org.objectweb.asm.tree.ClassNode; import the.bytecode.club.bytecodeviewer.BytecodeViewer; -import the.bytecode.club.bytecodeviewer.api.ExceptionUI; import the.bytecode.club.bytecodeviewer.resources.importing.Importer; import the.bytecode.club.bytecodeviewer.util.FileContainer; import the.bytecode.club.bytecodeviewer.util.JarUtils; @@ -18,32 +18,26 @@ import java.io.FileInputStream; public class ClassResourceImporter implements Importer { @Override - public boolean open(File file) throws Exception + public void open(File file) throws Exception { - final String fn = file.getName(); - try - { - byte[] bytes = JarUtils.getBytes(new FileInputStream(file)); - if (MiscUtils.getFileHeader(bytes).equalsIgnoreCase("cafebabe")) - { - final ClassNode cn = JarUtils.getNode(bytes); - - FileContainer container = new FileContainer(file); - container.classes.add(cn); - BytecodeViewer.files.add(container); - } - else - { - BytecodeViewer.showMessage(fn + ": Header does not start with CAFEBABE, ignoring."); - return false; - } - } - catch (final Exception e) - { - BytecodeViewer.handleException(e); - return false; - } + final String name = file.getName(); + byte[] bytes = MiscUtils.getBytes(new FileInputStream(file)); + FileContainer container = new FileContainer(file); - return true; + if (MiscUtils.getFileHeader(bytes).equalsIgnoreCase("cafebabe")) + { + final ClassNode cn = JarUtils.getNode(bytes); + + container.resourceClasses.put(FilenameUtils.removeExtension(name), cn); + container.resourceClassBytes.put(name, bytes); + } + else + { + BytecodeViewer.showMessage(name + "\nHeader does not start with CAFEBABE\nimporting as resource instead."); + + //TODO double check this + container.resourceFiles.put(name, bytes); + } + BytecodeViewer.files.add(container); } } diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/resources/importing/impl/DEXResourceImporter.java b/src/main/java/the/bytecode/club/bytecodeviewer/resources/importing/impl/DEXResourceImporter.java index 09e57f82..2dfbb159 100644 --- a/src/main/java/the/bytecode/club/bytecodeviewer/resources/importing/impl/DEXResourceImporter.java +++ b/src/main/java/the/bytecode/club/bytecodeviewer/resources/importing/impl/DEXResourceImporter.java @@ -1,12 +1,13 @@ package the.bytecode.club.bytecodeviewer.resources.importing.impl; 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.resources.importing.Importer; import the.bytecode.club.bytecodeviewer.util.*; import java.io.File; +import java.util.ArrayList; import static the.bytecode.club.bytecodeviewer.Constants.fs; import static the.bytecode.club.bytecodeviewer.Constants.tempDirectory; @@ -18,33 +19,30 @@ import static the.bytecode.club.bytecodeviewer.Constants.tempDirectory; public class DEXResourceImporter implements Importer { @Override - public boolean open(File file) throws Exception + public void open(File file) throws Exception { - try { - BytecodeViewer.updateBusyStatus(true); - - File tempCopy = new File(tempDirectory + fs + MiscUtils.randomString(32) + ".dex"); - - FileUtils.copyFile(file, tempCopy); //copy and rename to prevent unicode filenames - - FileContainer container = new FileContainer(tempCopy, file.getName()); - - String name = MiscUtils.getRandomizedName() + ".jar"; - File output = new File(tempDirectory + fs + name); - - if (BytecodeViewer.viewer.apkConversionGroup.isSelected(BytecodeViewer.viewer.apkConversionDex.getModel())) - Dex2Jar.dex2Jar(tempCopy, output); - else if (BytecodeViewer.viewer.apkConversionGroup.isSelected(BytecodeViewer.viewer.apkConversionEnjarify.getModel())) - Enjarify.apk2Jar(tempCopy, output); - - container.classes = JarUtils.loadClasses(output); - - BytecodeViewer.updateBusyStatus(false); - BytecodeViewer.files.add(container); - } catch (final Exception e) { - BytecodeViewer.handleException(e); - } + BytecodeViewer.updateBusyStatus(true); - return true; + File tempCopy = new File(tempDirectory + fs + MiscUtils.randomString(32) + ".dex"); + + FileUtils.copyFile(file, tempCopy); //copy and rename to prevent unicode filenames + + FileContainer container = new FileContainer(tempCopy, file.getName()); + + String name = MiscUtils.getRandomizedName() + ".jar"; + File output = new File(tempDirectory + fs + name); + + if (BytecodeViewer.viewer.apkConversionGroup.isSelected(BytecodeViewer.viewer.apkConversionDex.getModel())) + Dex2Jar.dex2Jar(tempCopy, output); + else if (BytecodeViewer.viewer.apkConversionGroup.isSelected(BytecodeViewer.viewer.apkConversionEnjarify.getModel())) + Enjarify.apk2Jar(tempCopy, output); + + //TODO update to FileContainerImporter + ArrayList nodeList = JarUtils.loadClasses(output); + for(ClassNode cn : nodeList) + container.resourceClasses.put(cn.name, cn); + + BytecodeViewer.updateBusyStatus(false); + BytecodeViewer.files.add(container); } } diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/resources/importing/impl/DirectoryResourceImporter.java b/src/main/java/the/bytecode/club/bytecodeviewer/resources/importing/impl/DirectoryResourceImporter.java index 55c05c8f..82776824 100644 --- a/src/main/java/the/bytecode/club/bytecodeviewer/resources/importing/impl/DirectoryResourceImporter.java +++ b/src/main/java/the/bytecode/club/bytecodeviewer/resources/importing/impl/DirectoryResourceImporter.java @@ -1,5 +1,6 @@ package the.bytecode.club.bytecodeviewer.resources.importing.impl; +import org.apache.commons.io.FilenameUtils; import org.objectweb.asm.tree.ClassNode; import the.bytecode.club.bytecodeviewer.BytecodeViewer; import the.bytecode.club.bytecodeviewer.resources.importing.Import; @@ -22,7 +23,7 @@ import java.util.Objects; public class DirectoryResourceImporter implements Importer { @Override - public boolean open(File file) throws Exception + public void open(File file) throws Exception { FileContainer container = new FileContainer(file); HashMap allDirectoryFiles = new HashMap<>(); @@ -61,29 +62,22 @@ public class DirectoryResourceImporter implements Importer //attempt to import archives automatically if (fileName.endsWith(".jar") || fileName.endsWith(".zip") || fileName.endsWith(".war") || fileName.endsWith(".ear")) - { Import.ZIP.getImporter().open(child); - } else if (fileName.endsWith(".apk")) - { Import.APK.getImporter().open(child); - } else if (fileName.endsWith(".dex")) - { Import.DEX.getImporter().open(child); - } else if (fileName.endsWith(".class")) { byte[] bytes = Files.readAllBytes(Paths.get(child.getAbsolutePath())); if (MiscUtils.getFileHeader(bytes).equalsIgnoreCase("cafebabe")) { final ClassNode cn = JarUtils.getNode(bytes); - allDirectoryClasses.put(trimmedPath, cn); + allDirectoryClasses.put(FilenameUtils.removeExtension(trimmedPath), cn); } } - else + else //pack files into a single container { - //pack files into a single container allDirectoryFiles.put(trimmedPath, Files.readAllBytes(Paths.get(child.getAbsolutePath()))); } } @@ -92,9 +86,8 @@ public class DirectoryResourceImporter implements Importer } } - container.classes.addAll(allDirectoryClasses.values()); - container.files = allDirectoryFiles; + container.resourceClasses.putAll(allDirectoryClasses); + container.resourceFiles = allDirectoryFiles; BytecodeViewer.files.add(container); - return true; } } diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/resources/importing/impl/FileResourceImporter.java b/src/main/java/the/bytecode/club/bytecodeviewer/resources/importing/impl/FileResourceImporter.java index 4f32b29a..80f9df36 100644 --- a/src/main/java/the/bytecode/club/bytecodeviewer/resources/importing/impl/FileResourceImporter.java +++ b/src/main/java/the/bytecode/club/bytecodeviewer/resources/importing/impl/FileResourceImporter.java @@ -3,7 +3,9 @@ package the.bytecode.club.bytecodeviewer.resources.importing.impl; import the.bytecode.club.bytecodeviewer.BytecodeViewer; import the.bytecode.club.bytecodeviewer.resources.importing.Importer; import the.bytecode.club.bytecodeviewer.util.FileContainer; +import the.bytecode.club.bytecodeviewer.util.FileContainerImporter; import the.bytecode.club.bytecodeviewer.util.JarUtils; +import the.bytecode.club.bytecodeviewer.util.MiscUtils; import java.io.File; import java.io.FileInputStream; @@ -16,16 +18,15 @@ import java.util.HashMap; public class FileResourceImporter implements Importer { @Override - public boolean open(File file) throws Exception + public void open(File file) throws Exception { - HashMap files1 = new HashMap<>(); - byte[] bytes = JarUtils.getBytes(new FileInputStream(file)); - files1.put(file.getName(), bytes); - - + //create the new file container FileContainer container = new FileContainer(file); - container.files = files1; + //create the new file importer + FileContainerImporter importer = new FileContainerImporter(container); + //import the file into the file container + importer.importAsFile(); + //add the file container to BCV's total loaded files BytecodeViewer.files.add(container); - return true; } } diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/resources/importing/impl/XAPKResourceImporter.java b/src/main/java/the/bytecode/club/bytecodeviewer/resources/importing/impl/XAPKResourceImporter.java index 819ccae2..f1eb2945 100644 --- a/src/main/java/the/bytecode/club/bytecodeviewer/resources/importing/impl/XAPKResourceImporter.java +++ b/src/main/java/the/bytecode/club/bytecodeviewer/resources/importing/impl/XAPKResourceImporter.java @@ -2,7 +2,6 @@ package the.bytecode.club.bytecodeviewer.resources.importing.impl; import me.konloch.kontainer.io.DiskWriter; import org.apache.commons.io.IOUtils; -import org.objectweb.asm.tree.ClassNode; import the.bytecode.club.bytecodeviewer.BytecodeViewer; import the.bytecode.club.bytecodeviewer.Configuration; import the.bytecode.club.bytecodeviewer.resources.importing.Import; @@ -14,6 +13,7 @@ import java.io.*; import java.util.Enumeration; import java.util.HashMap; import java.util.zip.ZipEntry; +import java.util.zip.ZipFile; import static the.bytecode.club.bytecodeviewer.Constants.fs; import static the.bytecode.club.bytecodeviewer.Constants.tempDirectory; @@ -27,14 +27,13 @@ import static the.bytecode.club.bytecodeviewer.Constants.tempDirectory; public class XAPKResourceImporter implements Importer { @Override - public boolean open(File file) throws Exception + public void open(File file) throws Exception { FileContainer container = new FileContainer(file); HashMap allDirectoryFiles = new HashMap<>(); - HashMap allDirectoryClasses = new HashMap<>(); Configuration.silenceExceptionGUI++; //turn exceptions off - try (java.util.zip.ZipFile zipFile = new java.util.zip.ZipFile(file)) + try (ZipFile zipFile = new ZipFile(file)) { Enumeration entries = zipFile.entries(); while (entries.hasMoreElements()) @@ -69,13 +68,11 @@ public class XAPKResourceImporter implements Importer } } } + Configuration.silenceExceptionGUI--; //turn exceptions back on BytecodeViewer.viewer.clearBusyStatus(); //clear errant busy signals from failed APK imports - - container.classes.addAll(allDirectoryClasses.values()); - container.files = allDirectoryFiles; - BytecodeViewer.files.add(container); - return true; + container.resourceFiles = allDirectoryFiles; //store the file resource + BytecodeViewer.files.add(container); //add the file container to BCV's total loaded files } public File exportTo(File original, String extension, byte[] bytes) diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/resources/importing/impl/ZipResourceImporter.java b/src/main/java/the/bytecode/club/bytecodeviewer/resources/importing/impl/ZipResourceImporter.java index 70c99cc8..4826a89f 100644 --- a/src/main/java/the/bytecode/club/bytecodeviewer/resources/importing/impl/ZipResourceImporter.java +++ b/src/main/java/the/bytecode/club/bytecodeviewer/resources/importing/impl/ZipResourceImporter.java @@ -3,6 +3,8 @@ package the.bytecode.club.bytecodeviewer.resources.importing.impl; import the.bytecode.club.bytecodeviewer.BytecodeViewer; import the.bytecode.club.bytecodeviewer.api.ExceptionUI; import the.bytecode.club.bytecodeviewer.resources.importing.Importer; +import the.bytecode.club.bytecodeviewer.util.FileContainer; +import the.bytecode.club.bytecodeviewer.util.FileContainerImporter; import the.bytecode.club.bytecodeviewer.util.JarUtils; import java.io.File; @@ -15,32 +17,15 @@ import java.io.IOException; public class ZipResourceImporter implements Importer { @Override - public boolean open(File file) throws Exception + public void open(File file) throws Exception { - //attempt to load archives using the first method - try - { - JarUtils.importArchiveA(file); - } - catch (IOException z) - { - //attempt to load archives using the fallback method on fail - try - { - JarUtils.importArchiveB(file); - } - catch (final Exception e) - { - BytecodeViewer.handleException(e); - return false; - } - } - catch (final Exception e) - { - BytecodeViewer.handleException(e); - return false; - } - - return true; + //create the new file container + FileContainer container = new FileContainer(file); + //create the new file importer + FileContainerImporter importer = new FileContainerImporter(container); + //import the file as zip into the file container + importer.importAsZip(); + //add the file container to BCV's total loaded files + BytecodeViewer.files.add(container); } } diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/util/BCVResourceUtils.java b/src/main/java/the/bytecode/club/bytecodeviewer/util/BCVResourceUtils.java index d23e528f..ce559e58 100644 --- a/src/main/java/the/bytecode/club/bytecodeviewer/util/BCVResourceUtils.java +++ b/src/main/java/the/bytecode/club/bytecodeviewer/util/BCVResourceUtils.java @@ -33,75 +33,6 @@ import static the.bytecode.club.bytecodeviewer.Constants.RT_JAR_DUMPED; */ public class BCVResourceUtils { - public static void resetWorkspace() - { - BytecodeViewer.files.clear(); - LazyNameUtil.reset(); - BytecodeViewer.viewer.resourcePane.resetWorkspace(); - BytecodeViewer.viewer.workPane.resetWorkspace(); - BytecodeViewer.viewer.searchBoxPane.resetWorkspace(); - BCV.getClassNodeLoader().clear(); - } - - /** - * Dumps the loaded classes as a library to be used for Krakatau - */ - public static File[] dumpTempFile(FileContainer container) - { - File[] files = new File[2]; - - //currently won't optimize if you've got two containers with the same name, will need to add this later - if (!LazyNameUtil.SAME_NAME_JAR_WORKSPACE) - { - if (Configuration.krakatauTempJar != null && !Configuration.krakatauTempJar.exists()) - Configuration.needsReDump = true; - - if (Configuration.needsReDump && Configuration.krakatauTempJar != null) - { - Configuration.krakatauTempDir = null; - Configuration.krakatauTempJar = null; - } - - boolean passes = false; - - if (BytecodeViewer.viewer.viewPane1.getGroup().isSelected(BytecodeViewer.viewer.viewPane1.getKrakatau().getJava().getModel())) - passes = true; - else if (BytecodeViewer.viewer.viewPane1.getGroup().isSelected(BytecodeViewer.viewer.viewPane1.getKrakatau().getBytecode().getModel())) - passes = true; - - else if (BytecodeViewer.viewer.viewPane2.getGroup().isSelected(BytecodeViewer.viewer.viewPane2.getKrakatau().getJava().getModel())) - passes = true; - else if (BytecodeViewer.viewer.viewPane2.getGroup().isSelected(BytecodeViewer.viewer.viewPane2.getKrakatau().getBytecode().getModel())) - passes = true; - - else if (BytecodeViewer.viewer.viewPane3.getGroup().isSelected(BytecodeViewer.viewer.viewPane3.getKrakatau().getJava().getModel())) - passes = true; - else if (BytecodeViewer.viewer.viewPane3.getGroup().isSelected(BytecodeViewer.viewer.viewPane3.getKrakatau().getBytecode().getModel())) - passes = true; - - if (Configuration.krakatauTempJar != null || !passes) - { - files[0] = Configuration.krakatauTempJar; - files[1] = Configuration.krakatauTempDir; - return files; - } - } - - Configuration.currentlyDumping = true; - Configuration.needsReDump = false; - Configuration.krakatauTempDir = new File(tempDirectory + fs + MiscUtils.randomString(32) + fs); - Configuration.krakatauTempDir.mkdir(); - Configuration.krakatauTempJar = new File(tempDirectory + fs + "temp" + MiscUtils.randomString(32) + ".jar"); - //krakatauTempJar = new File(BytecodeViewer.tempDirectory + BytecodeViewer.fs + "temp" + MiscUtils - // .randomString(32) + ".jar."+container.name); - JarUtils.saveAsJarClassesOnly(container.classes, Configuration.krakatauTempJar.getAbsolutePath()); - Configuration.currentlyDumping = false; - - files[0] = Configuration.krakatauTempJar; - files[1] = Configuration.krakatauTempDir; - return files; - } - //rt.jar check public synchronized static void rtCheck() { diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/util/FileContainer.java b/src/main/java/the/bytecode/club/bytecodeviewer/util/FileContainer.java index 6e1297c2..0d96872d 100644 --- a/src/main/java/the/bytecode/club/bytecodeviewer/util/FileContainer.java +++ b/src/main/java/the/bytecode/club/bytecodeviewer/util/FileContainer.java @@ -4,7 +4,6 @@ import java.io.File; import java.util.ArrayList; import java.util.HashMap; import org.objectweb.asm.tree.ClassNode; -import the.bytecode.club.bytecodeviewer.Configuration; /*************************************************************************** * Bytecode Viewer (BCV) - Java & Android Reverse Engineering Suite * @@ -46,16 +45,13 @@ public class FileContainer { public String name; public File APKToolContents = null; - public HashMap files = new HashMap<>(); - public ArrayList classes = new ArrayList<>(); + public HashMap resourceFiles = new HashMap<>(); + public HashMap resourceClassBytes = new HashMap<>(); + public HashMap resourceClasses = new HashMap<>(); public ClassNode getClassNode(String name) { - for (ClassNode c : classes) - if (c.name.equals(name)) - return c; - - return null; + return resourceClasses.get(name); } public String generateWorkName(String name) diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/util/FileContainerImporter.java b/src/main/java/the/bytecode/club/bytecodeviewer/util/FileContainerImporter.java new file mode 100644 index 00000000..5bfb06b9 --- /dev/null +++ b/src/main/java/the/bytecode/club/bytecodeviewer/util/FileContainerImporter.java @@ -0,0 +1,138 @@ +package the.bytecode.club.bytecodeviewer.util; + +import org.apache.commons.compress.archivers.zip.ZipArchiveEntry; +import org.apache.commons.compress.archivers.zip.ZipFile; +import org.apache.commons.io.FilenameUtils; +import org.objectweb.asm.tree.ClassNode; +import the.bytecode.club.bytecodeviewer.api.ASMUtil; + +import java.io.*; +import java.util.Enumeration; +import java.util.zip.ZipEntry; +import java.util.zip.ZipInputStream; + +/** + * @author Konloch + * @since 7/10/2021 + */ +public class FileContainerImporter +{ + private final FileContainer container; + + public FileContainerImporter(FileContainer container) + { + this.container = container; + } + + public void importAsFile() throws IOException + { + addUnknownFile(container.file.getName(), new FileInputStream(container.file), false); + } + + public void importAsZip() throws IOException + { + container.resourceClasses.clear(); + container.resourceClassBytes.clear(); + container.resourceFiles.clear(); + + try + { + //attempt to import using Java ZipInputStream + importZipInputStream(false); + } + catch (IOException e) + { + e.printStackTrace(); + + //fallback to apache commons ZipFile + importApacheZipFile(false); + } + } + + //sorts the file type from classes or resources + public void addUnknownFile(String name, InputStream stream, boolean classesOnly) throws IOException + { + //TODO remove this .class check and just look for cafebabe + if (name.endsWith(".class")) + addClassResource(name, stream); + else if(!classesOnly) + addResource(name, stream); + } + + public void addClassResource(String name, InputStream stream) throws IOException + { + byte[] bytes = MiscUtils.getBytes(stream); + if (MiscUtils.getFileHeader(bytes).equalsIgnoreCase("cafebabe")) + { + try + { + final ClassNode cn = ASMUtil.bytesToNode(bytes); + + //classes are copied into memory twice + ClassNode existingNode = container.resourceClasses.put(FilenameUtils.removeExtension(name), cn); + container.resourceClassBytes.put(name, bytes); + if( existingNode != null) + { + //TODO prompt to ask the user if they would like to overwrite the resource conflict + // or solve it automatically by creating a new file container for each conflict + + System.err.println("WARNING: Resource Conflict: " + name); + System.err.println("Suggested Fix: Contact Konloch to add support for resource conflicts"); + } + } + catch (Exception e) + { + e.printStackTrace(); + } + } else { + System.err.println(container.file + ">" + name + ": Header does not start with CAFEBABE, ignoring."); + } + } + + public void addResource(String name, InputStream stream) throws IOException + { + byte[] bytes = MiscUtils.getBytes(stream); + container.resourceFiles.put(name, bytes); + } + + public void importZipInputStream(boolean classesOnly) throws IOException + { + ZipInputStream jis = new ZipInputStream(new FileInputStream(container.file)); + ZipEntry entry; + while ((entry = jis.getNextEntry()) != null) + { + final String name = entry.getName(); + + //skip directories + if(entry.isDirectory()) + continue; + + addUnknownFile(name, jis, classesOnly); + jis.closeEntry(); + } + jis.close(); + } + + //TODO if this ever fails: import Sun's jarsigner code from JDK 7, re-sign the jar to rebuild the CRC, + // should also rebuild the archive byte offsets + public void importApacheZipFile(boolean classesOnly) throws IOException + { + try (ZipFile zipFile = new ZipFile(container.file)) + { + Enumeration entries = zipFile.getEntries(); + while (entries.hasMoreElements()) + { + ZipArchiveEntry entry = entries.nextElement(); + String name = entry.getName(); + + if(entry.isDirectory()) + continue; + + try (InputStream in = zipFile.getInputStream(entry)) + { + addUnknownFile(name, in, classesOnly); + } + } + } + } +} diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/util/JarUtils.java b/src/main/java/the/bytecode/club/bytecodeviewer/util/JarUtils.java index 5b66570f..1be9dccc 100644 --- a/src/main/java/the/bytecode/club/bytecodeviewer/util/JarUtils.java +++ b/src/main/java/the/bytecode/club/bytecodeviewer/util/JarUtils.java @@ -7,6 +7,7 @@ import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.util.ArrayList; +import java.util.Collection; import java.util.Enumeration; import java.util.HashMap; import java.util.Map.Entry; @@ -17,6 +18,7 @@ import java.util.zip.ZipInputStream; import me.konloch.kontainer.io.DiskWriter; import org.apache.commons.compress.archivers.zip.ZipArchiveEntry; import org.apache.commons.compress.archivers.zip.ZipFile; +import org.apache.commons.io.FilenameUtils; import org.objectweb.asm.ClassWriter; import org.objectweb.asm.tree.ClassNode; import the.bytecode.club.bytecodeviewer.BytecodeViewer; @@ -45,11 +47,14 @@ import static the.bytecode.club.bytecodeviewer.Constants.*; /** * Loading and saving jars * + * NOTE: This is in the process of being replaced with the Import & Export API + * * @author Konloch * @author WaterWolf * @since 09/26/2011 */ +@Deprecated public class JarUtils { public static Object LOCK = new Object(); @@ -70,7 +75,7 @@ public class JarUtils while ((entry = jis.getNextEntry()) != null) { try { final String name = entry.getName(); - final byte[] bytes = getBytes(jis); + final byte[] bytes = MiscUtils.getBytes(jis); if (!name.endsWith(".class")) { if (!entry.isDirectory()) files.put(name, bytes); @@ -79,7 +84,7 @@ public class JarUtils { try { final ClassNode cn = getNode(bytes); - container.classes.add(cn); + container.resourceClasses.put(FilenameUtils.removeExtension(name), cn); } catch (Exception e) { System.err.println("Skipping: " + name); e.printStackTrace(); @@ -100,7 +105,7 @@ public class JarUtils } } jis.close(); - container.files = files; + container.resourceFiles = files; BytecodeViewer.files.add(container); } @@ -126,7 +131,7 @@ public class JarUtils String name = entry.getName(); if (!entry.isDirectory()) { try (InputStream in = zipFile.getInputStream(entry)) { - final byte[] bytes = getBytes(in); + final byte[] bytes = MiscUtils.getBytes(in); if (!name.endsWith(".class")) { files.put(name, bytes); @@ -135,7 +140,7 @@ public class JarUtils { try { final ClassNode cn = getNode(bytes); - container.classes.add(cn); + container.resourceClasses.put(FilenameUtils.removeExtension(name), cn); } catch (Exception e) { e.printStackTrace(); } @@ -149,7 +154,7 @@ public class JarUtils } } - container.files = files; + container.resourceFiles = files; BytecodeViewer.files.add(container); } @@ -162,7 +167,7 @@ public class JarUtils try { final String name = entry.getName(); if (name.endsWith(".class")) { - byte[] bytes = getBytes(jis); + byte[] bytes = MiscUtils.getBytes(jis); if (MiscUtils.getFileHeader(bytes).equalsIgnoreCase("cafebabe")) { try { @@ -205,7 +210,7 @@ public class JarUtils final String name = entry.getName(); if (!name.endsWith(".class") && !name.endsWith(".dex")) { if (!entry.isDirectory()) - files.put(name, getBytes(jis)); + files.put(name, MiscUtils.getBytes(jis)); jis.closeEntry(); } @@ -218,25 +223,6 @@ public class JarUtils jis.close(); return files; - - } - - /** - * Reads an InputStream and returns the read byte[] - * - * @param is InputStream - * @return the read byte[] - * @throws IOException - */ - public static byte[] getBytes(final InputStream is) throws IOException { - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - byte[] buffer = new byte[1024]; - int a; - while ((a = is.read(buffer)) != -1) { - baos.write(buffer, 0, a); - } - baos.close(); - return baos.toByteArray(); } /** @@ -248,7 +234,7 @@ public class JarUtils public static ClassNode getNode(final byte[] bytez) { synchronized (LOCK) { - return ASMUtil.getClassNode(bytez); + return ASMUtil.bytesToNode(bytez); } } @@ -278,7 +264,7 @@ public class JarUtils out.closeEntry(); for (FileContainer container : BytecodeViewer.files) - for (Entry entry : container.files.entrySet()) { + for (Entry entry : container.resourceFiles.entrySet()) { String filename = entry.getKey(); if (!filename.startsWith("META-INF")) { out.putNextEntry(new ZipEntry(filename)); @@ -299,7 +285,8 @@ public class JarUtils * @param nodeList The loaded ClassNodes * @param path the exact jar output path */ - public static void saveAsJarClassesOnly(ArrayList nodeList, String path) { + public static void saveAsJarClassesOnly(Collection nodeList, String path) + { synchronized (LOCK) { try @@ -380,7 +367,7 @@ public class JarUtils } for (FileContainer container : BytecodeViewer.files) - for (Entry entry : container.files.entrySet()) { + for (Entry entry : container.resourceFiles.entrySet()) { String filename = entry.getKey(); if (!filename.startsWith("META-INF")) { if (!noDupe.contains(filename)) { diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/util/MiscUtils.java b/src/main/java/the/bytecode/club/bytecodeviewer/util/MiscUtils.java index 05f350a5..575fdf90 100644 --- a/src/main/java/the/bytecode/club/bytecodeviewer/util/MiscUtils.java +++ b/src/main/java/the/bytecode/club/bytecodeviewer/util/MiscUtils.java @@ -8,7 +8,6 @@ import the.bytecode.club.bytecodeviewer.translation.Language; import javax.imageio.ImageIO; import javax.swing.*; -import java.awt.*; import java.awt.image.BufferedImage; import java.io.*; import java.lang.reflect.Field; @@ -181,7 +180,7 @@ public class MiscUtils StringBuilder block = new StringBuilder(); for (FileContainer container : fileContainers) { block.append(container.name); - for (ClassNode node : container.classes) { + for (ClassNode node : container.resourceClasses.values()) { block.append(node.name); } } @@ -273,4 +272,26 @@ public class MiscUtils return path; } + + + + /** + * Reads an InputStream and returns the read byte[] + * + * @param is InputStream + * @return the read byte[] + * @throws IOException + */ + public static byte[] getBytes(final InputStream is) throws IOException + { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + + byte[] buffer = new byte[1024]; + int a; + while ((a = is.read(buffer)) != -1) + baos.write(buffer, 0, a); + + baos.close(); + return baos.toByteArray(); + } } diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/util/SecurityMan.java b/src/main/java/the/bytecode/club/bytecodeviewer/util/SecurityMan.java index 99d53321..7aa85883 100644 --- a/src/main/java/the/bytecode/club/bytecodeviewer/util/SecurityMan.java +++ b/src/main/java/the/bytecode/club/bytecodeviewer/util/SecurityMan.java @@ -89,7 +89,8 @@ public class SecurityMan extends SecurityManager } if (allow && !blocking) { - System.out.println("Allowing exec:" + cmd); + System.out.println("Allowing exec: " + cmd); + } else throw new SecurityException("BCV is awesome, blocking(" + blocking + ") exec " + cmd); }