From b0f5e938db2cc7e3be024e5680a3fdd76ca1a94c Mon Sep 17 00:00:00 2001 From: Konloch Date: Sun, 27 Jun 2021 13:41:38 -0700 Subject: [PATCH] Resource Exporting Cleanup --- .../bytecodeviewer/gui/MainViewerGUI.java | 10 +- .../gui/components/ExportJar.java | 14 +- .../resources/ResourceExporting.java | 294 ------------------ .../resources/exporting/Export.java | 28 ++ .../resources/exporting/Exporter.java | 10 + .../resources/exporting/impl/APKExport.java | 133 ++++++++ .../resources/exporting/impl/DexExport.java | 88 ++++++ .../exporting/impl/RunnableJarExporter.java | 67 ++++ .../resources/exporting/impl/ZipExport.java | 74 +++++ .../{ImportType.java => Import.java} | 4 +- .../resources/importing/ImportResource.java | 12 +- .../impl/DirectoryResourceImporter.java | 8 +- 12 files changed, 425 insertions(+), 317 deletions(-) delete mode 100644 src/main/java/the/bytecode/club/bytecodeviewer/resources/ResourceExporting.java create mode 100644 src/main/java/the/bytecode/club/bytecodeviewer/resources/exporting/Export.java create mode 100644 src/main/java/the/bytecode/club/bytecodeviewer/resources/exporting/Exporter.java create mode 100644 src/main/java/the/bytecode/club/bytecodeviewer/resources/exporting/impl/APKExport.java create mode 100644 src/main/java/the/bytecode/club/bytecodeviewer/resources/exporting/impl/DexExport.java create mode 100644 src/main/java/the/bytecode/club/bytecodeviewer/resources/exporting/impl/RunnableJarExporter.java create mode 100644 src/main/java/the/bytecode/club/bytecodeviewer/resources/exporting/impl/ZipExport.java rename src/main/java/the/bytecode/club/bytecodeviewer/resources/importing/{ImportType.java => Import.java} (85%) diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/gui/MainViewerGUI.java b/src/main/java/the/bytecode/club/bytecodeviewer/gui/MainViewerGUI.java index ade18005..37e8dbcb 100644 --- a/src/main/java/the/bytecode/club/bytecodeviewer/gui/MainViewerGUI.java +++ b/src/main/java/the/bytecode/club/bytecodeviewer/gui/MainViewerGUI.java @@ -31,9 +31,9 @@ import the.bytecode.club.bytecodeviewer.plugin.preinstalled.ShowMainMethods; import the.bytecode.club.bytecodeviewer.plugin.preinstalled.StackFramesRemover; import the.bytecode.club.bytecodeviewer.plugin.preinstalled.ZKMStringDecrypter; import the.bytecode.club.bytecodeviewer.plugin.preinstalled.ZStringArrayDecrypter; +import the.bytecode.club.bytecodeviewer.resources.exporting.Export; import the.bytecode.club.bytecodeviewer.util.*; import the.bytecode.club.bytecodeviewer.resources.ResourceDecompiling; -import the.bytecode.club.bytecodeviewer.resources.ResourceExporting; import static the.bytecode.club.bytecodeviewer.Constants.*; @@ -341,10 +341,10 @@ public class MainViewerGUI extends JFrame reloadResources.addActionListener(arg0 -> reloadResources()); runButton.addActionListener(e -> runResources()); compileButton.addActionListener(arg0 -> compileOnNewThread()); - saveAsRunnableJar.addActionListener(e -> ResourceExporting.saveAsRunnableJar()); - saveAsAPK.addActionListener(arg0 -> ResourceExporting.saveAsAPK()); - saveAsDex.addActionListener(arg0 -> ResourceExporting.saveAsDex()); - saveAsZip.addActionListener(arg0 -> ResourceExporting.saveAsZip()); + saveAsRunnableJar.addActionListener(e -> Export.RUNNABLE_JAR.getExporter().promptForExport()); + saveAsAPK.addActionListener(arg0 -> Export.APK.getExporter().promptForExport()); + saveAsDex.addActionListener(arg0 -> Export.DEX.getExporter().promptForExport()); + saveAsZip.addActionListener(arg0 -> Export.ZIP.getExporter().promptForExport()); decompileSaveAll.addActionListener(arg0 -> ResourceDecompiling.decompileSaveAll()); decompileSaveOpened.addActionListener(arg0 -> ResourceDecompiling.decompileSaveOpenedOnly()); about.addActionListener(arg0 -> aboutWindow.setVisible(true)); diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/gui/components/ExportJar.java b/src/main/java/the/bytecode/club/bytecodeviewer/gui/components/ExportJar.java index 38004163..fd715118 100644 --- a/src/main/java/the/bytecode/club/bytecodeviewer/gui/components/ExportJar.java +++ b/src/main/java/the/bytecode/club/bytecodeviewer/gui/components/ExportJar.java @@ -53,15 +53,17 @@ public class ExportJar extends JFrame scrollPane.setColumnHeaderView(new JLabel("META-INF/MANIFEST.MF:")); - final JTextArea mani = new JTextArea(); - mani.setText("Manifest-Version: 1.0\r\nClass-Path: .\r\nMain-Class: "); - scrollPane.setViewportView(mani); + final JTextArea manifest = new JTextArea(); + manifest.setText("Manifest-Version: 1.0\r\nClass-Path: .\r\nMain-Class: "); + scrollPane.setViewportView(manifest); getContentPane().add(btnNewButton); - btnNewButton.addActionListener(arg0 -> { + btnNewButton.addActionListener(arg0 -> + { BytecodeViewer.viewer.updateBusyStatus(true); - Thread t = new Thread(() -> { - JarUtils.saveAsJar(BytecodeViewer.getLoadedClasses(), jarPath, mani.getText()); + Thread t = new Thread(() -> + { + JarUtils.saveAsJar(BytecodeViewer.getLoadedClasses(), jarPath, manifest.getText()); BytecodeViewer.viewer.updateBusyStatus(false); }); t.start(); diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/resources/ResourceExporting.java b/src/main/java/the/bytecode/club/bytecodeviewer/resources/ResourceExporting.java deleted file mode 100644 index ce01b2f7..00000000 --- a/src/main/java/the/bytecode/club/bytecodeviewer/resources/ResourceExporting.java +++ /dev/null @@ -1,294 +0,0 @@ -package the.bytecode.club.bytecodeviewer.resources; - -import the.bytecode.club.bytecodeviewer.BytecodeViewer; -import the.bytecode.club.bytecodeviewer.Configuration; -import the.bytecode.club.bytecodeviewer.gui.components.ExportJar; -import the.bytecode.club.bytecodeviewer.gui.components.FileChooser; -import the.bytecode.club.bytecodeviewer.gui.components.MultipleChoiceDialogue; -import the.bytecode.club.bytecodeviewer.util.*; - -import javax.swing.*; -import javax.swing.filechooser.FileFilter; -import java.io.File; -import java.util.ArrayList; -import java.util.List; - -import static the.bytecode.club.bytecodeviewer.Constants.fs; -import static the.bytecode.club.bytecodeviewer.Constants.tempDirectory; - -/** - * @author Konloch - * @since 6/21/2021 - */ -public class ResourceExporting -{ - public static void saveAsRunnableJar() - { - if (BytecodeViewer.getLoadedClasses().isEmpty()) - { - BytecodeViewer.showMessage("First open a class, jar, zip, apk or dex file."); - return; - } - - Thread exportThread = new Thread(() -> - { - if (BytecodeViewer.viewer.compileOnSave.isSelected() && !BytecodeViewer.compile(false)) - return; - - JFileChooser fc = new FileChooser(new File(Configuration.lastDirectory), - "Select Jar Export", - "Jar Archives", - "jar"); - - int returnVal = fc.showSaveDialog(BytecodeViewer.viewer); - if (returnVal == JFileChooser.APPROVE_OPTION) - { - Configuration.lastDirectory = fc.getSelectedFile().getAbsolutePath(); - File file = fc.getSelectedFile(); - String path = file.getAbsolutePath(); - - //auto append .jar - if (!path.endsWith(".jar")) - path = path + ".jar"; - - if (new File(path).exists()) - { - MultipleChoiceDialogue dialogue = new MultipleChoiceDialogue("Bytecode Viewer - Overwrite File", - "Are you sure you wish to overwrite this existing file?", - new String[]{"Yes", "No"}); - - if (dialogue.promptChoice() == 0) { - file.delete(); - } else { - return; - } - } - - new ExportJar(path).setVisible(true); - } - }); - exportThread.start(); - } - - public static void saveAsZip() - { - if (BytecodeViewer.getLoadedClasses().isEmpty()) - { - BytecodeViewer.showMessage("First open a class, jar, zip, apk or dex file."); - return; - } - - Thread exportThread = new Thread(() -> - { - if (BytecodeViewer.viewer.compileOnSave.isSelected() && !BytecodeViewer.compile(false)) - return; - - JFileChooser fc = new FileChooser(new File(Configuration.lastDirectory), - "Select Zip Export", - "Zip Archives", - "zip"); - - int returnVal = fc.showSaveDialog(BytecodeViewer.viewer); - if (returnVal == JFileChooser.APPROVE_OPTION) - { - Configuration.lastDirectory = fc.getSelectedFile().getAbsolutePath(); - File file = fc.getSelectedFile(); - - //auto append .zip - if (!file.getAbsolutePath().endsWith(".zip")) - file = new File(file.getAbsolutePath() + ".zip"); - - if (file.exists()) - { - MultipleChoiceDialogue dialogue = new MultipleChoiceDialogue("Bytecode Viewer - Overwrite File", - "Are you sure you wish to overwrite this existing file?", - new String[]{"Yes", "No"}); - - if (dialogue.promptChoice() == 0) { - file.delete(); - } else { - return; - } - } - - final File file2 = file; - - BytecodeViewer.viewer.updateBusyStatus(true); - Thread saveThread = new Thread(() -> - { - JarUtils.saveAsJar(BytecodeViewer.getLoadedClasses(), file2.getAbsolutePath()); - BytecodeViewer.viewer.updateBusyStatus(false); - }); - saveThread.start(); - } - }); - exportThread.start(); - } - - public static void saveAsDex() - { - if (BytecodeViewer.getLoadedClasses().isEmpty()) - { - BytecodeViewer.showMessage("First open a class, jar, zip, apk or dex file."); - return; - } - - Thread t = new Thread(() -> - { - if (BytecodeViewer.viewer.compileOnSave.isSelected() && !BytecodeViewer.compile(false)) - return; - - JFileChooser fc = new FileChooser(new File(Configuration.lastDirectory), - "Select DEX Export", - "Android DEX Files", - "dex"); - - int returnVal = fc.showSaveDialog(BytecodeViewer.viewer); - if (returnVal == JFileChooser.APPROVE_OPTION) - { - Configuration.lastDirectory = fc.getSelectedFile().getAbsolutePath(); - final File file = fc.getSelectedFile(); - String output = file.getAbsolutePath(); - - //auto append .dex - if (!output.endsWith(".dex")) - output = output + ".dex"; - - final File file2 = new File(output); - if (file2.exists()) - { - MultipleChoiceDialogue dialogue = new MultipleChoiceDialogue("Bytecode Viewer - Overwrite File", - "Are you sure you wish to overwrite this existing file?", - new String[]{"Yes", "No"}); - - if (dialogue.promptChoice() == 0) { - file.delete(); - } else { - return; - } - } - - Thread t16 = new Thread(() -> { - BytecodeViewer.viewer.updateBusyStatus(true); - final String input = tempDirectory + fs + MiscUtils.getRandomizedName() + ".jar"; - JarUtils.saveAsJar(BytecodeViewer.getLoadedClasses(), input); - - Thread t15 = new Thread(() -> { - Dex2Jar.saveAsDex(new File(input), file2); - - BytecodeViewer.viewer.updateBusyStatus(false); - }); - t15.start(); - }); - t16.start(); - } - }); - t.start(); - } - - public static void saveAsAPK() - { - if (BytecodeViewer.getLoadedClasses().isEmpty()) - { - BytecodeViewer.showMessage("First open a class, jar, zip, apk or dex file."); - return; - } - - //if theres only one file in the container don't bother asking - List containers = BytecodeViewer.getFiles(); - List validContainers = new ArrayList<>(); - List validContainersNames = new ArrayList<>(); - FileContainer container; - - for (FileContainer fileContainer : containers) - { - if (fileContainer.APKToolContents != null && fileContainer.APKToolContents.exists()) - { - validContainersNames.add(fileContainer.name); - validContainers.add(fileContainer); - } - } - - if (!validContainers.isEmpty()) - { - container = validContainers.get(0); - - if (validContainers.size() >= 2) - { - JOptionPane pane = new JOptionPane("Which file would you like to export as an APK?"); - Object[] options = validContainersNames.toArray(new String[0]); - - pane.setOptions(options); - JDialog dialog = pane.createDialog(BytecodeViewer.viewer, "Bytecode Viewer - Select APK"); - dialog.setVisible(true); - Object obj = pane.getValue(); - int result = -1; - for (int k = 0; k < options.length; k++) - if (options[k].equals(obj)) - result = k; - - container = containers.get(result); - } - } else { - BytecodeViewer.showMessage("You can only export as APK from a valid APK file. Make sure " - + "Settings>Decode Resources is ticked on.\n\nTip: Try exporting as DEX, it doesn't rely on " - + "decoded APK resources"); - return; - } - - final FileContainer finalContainer = container; - - Thread exportThread = new Thread(() -> - { - if (BytecodeViewer.viewer.compileOnSave.isSelected() && !BytecodeViewer.compile(false)) - return; - - JFileChooser fc = new FileChooser(new File(Configuration.lastDirectory), - "Select APK Export", - "Android APK", - "apk"); - - int returnVal = fc.showSaveDialog(BytecodeViewer.viewer); - if (returnVal == JFileChooser.APPROVE_OPTION) - { - Configuration.lastDirectory = fc.getSelectedFile().getAbsolutePath(); - final File file = fc.getSelectedFile(); - String output = file.getAbsolutePath(); - - //auto appened .apk - if (!output.endsWith(".apk")) - output = output + ".apk"; - - final File file2 = new File(output); - if (file2.exists()) - { - MultipleChoiceDialogue dialogue = new MultipleChoiceDialogue("Bytecode Viewer - Overwrite File", - "Are you sure you wish to overwrite this existing file?", - new String[]{"Yes", "No"}); - - if (dialogue.promptChoice() == 0) { - file.delete(); - } else { - return; - } - } - - Thread saveThread = new Thread(() -> - { - BytecodeViewer.viewer.updateBusyStatus(true); - final String input = tempDirectory + fs + MiscUtils.getRandomizedName() + ".jar"; - JarUtils.saveAsJar(BytecodeViewer.getLoadedClasses(), input); - - Thread buildAPKThread = new Thread(() -> - { - APKTool.buildAPK(new File(input), file2, finalContainer); - BytecodeViewer.viewer.updateBusyStatus(false); - }); - buildAPKThread.start(); - }); - saveThread.start(); - } - }); - exportThread.start(); - } -} diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/resources/exporting/Export.java b/src/main/java/the/bytecode/club/bytecodeviewer/resources/exporting/Export.java new file mode 100644 index 00000000..8d00491f --- /dev/null +++ b/src/main/java/the/bytecode/club/bytecodeviewer/resources/exporting/Export.java @@ -0,0 +1,28 @@ +package the.bytecode.club.bytecodeviewer.resources.exporting; + +import the.bytecode.club.bytecodeviewer.resources.exporting.impl.APKExport; +import the.bytecode.club.bytecodeviewer.resources.exporting.impl.DexExport; +import the.bytecode.club.bytecodeviewer.resources.exporting.impl.RunnableJarExporter; +import the.bytecode.club.bytecodeviewer.resources.exporting.impl.ZipExport; + +/** + * @author Konloch + * @since 6/27/2021 + */ +public enum Export +{ + RUNNABLE_JAR(new RunnableJarExporter()), + ZIP(new ZipExport()), + DEX(new DexExport()), + APK(new APKExport()) + ; + + private final Exporter exporter; + + Export(Exporter exporter) {this.exporter = exporter;} + + public Exporter getExporter() + { + return exporter; + } +} diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/resources/exporting/Exporter.java b/src/main/java/the/bytecode/club/bytecodeviewer/resources/exporting/Exporter.java new file mode 100644 index 00000000..0a359a84 --- /dev/null +++ b/src/main/java/the/bytecode/club/bytecodeviewer/resources/exporting/Exporter.java @@ -0,0 +1,10 @@ +package the.bytecode.club.bytecodeviewer.resources.exporting; + +/** + * @author Konloch + * @since 6/27/2021 + */ +public interface Exporter +{ + void promptForExport(); +} diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/resources/exporting/impl/APKExport.java b/src/main/java/the/bytecode/club/bytecodeviewer/resources/exporting/impl/APKExport.java new file mode 100644 index 00000000..203c7b77 --- /dev/null +++ b/src/main/java/the/bytecode/club/bytecodeviewer/resources/exporting/impl/APKExport.java @@ -0,0 +1,133 @@ +package the.bytecode.club.bytecodeviewer.resources.exporting.impl; + +import the.bytecode.club.bytecodeviewer.BytecodeViewer; +import the.bytecode.club.bytecodeviewer.Configuration; +import the.bytecode.club.bytecodeviewer.gui.components.FileChooser; +import the.bytecode.club.bytecodeviewer.gui.components.MultipleChoiceDialogue; +import the.bytecode.club.bytecodeviewer.resources.exporting.Exporter; +import the.bytecode.club.bytecodeviewer.util.APKTool; +import the.bytecode.club.bytecodeviewer.util.FileContainer; +import the.bytecode.club.bytecodeviewer.util.JarUtils; +import the.bytecode.club.bytecodeviewer.util.MiscUtils; + +import javax.swing.*; +import java.io.File; +import java.util.ArrayList; +import java.util.List; + +import static the.bytecode.club.bytecodeviewer.Constants.fs; +import static the.bytecode.club.bytecodeviewer.Constants.tempDirectory; + +/** + * @author Konloch + * @since 6/27/2021 + */ +public class APKExport implements Exporter +{ + @Override + public void promptForExport() + { + if (BytecodeViewer.getLoadedClasses().isEmpty()) + { + BytecodeViewer.showMessage("First open a class, jar, zip, apk or dex file."); + return; + } + + //if theres only one file in the container don't bother asking + List containers = BytecodeViewer.getFiles(); + List validContainers = new ArrayList<>(); + List validContainersNames = new ArrayList<>(); + FileContainer container; + + for (FileContainer fileContainer : containers) + { + if (fileContainer.APKToolContents != null && fileContainer.APKToolContents.exists()) + { + validContainersNames.add(fileContainer.name); + validContainers.add(fileContainer); + } + } + + if (!validContainers.isEmpty()) + { + container = validContainers.get(0); + + if (validContainers.size() >= 2) + { + JOptionPane pane = new JOptionPane("Which file would you like to export as an APK?"); + Object[] options = validContainersNames.toArray(new String[0]); + + pane.setOptions(options); + JDialog dialog = pane.createDialog(BytecodeViewer.viewer, "Bytecode Viewer - Select APK"); + dialog.setVisible(true); + Object obj = pane.getValue(); + int result = -1; + for (int k = 0; k < options.length; k++) + if (options[k].equals(obj)) + result = k; + + container = containers.get(result); + } + } else { + BytecodeViewer.showMessage("You can only export as APK from a valid APK file. Make sure " + + "Settings>Decode Resources is ticked on.\n\nTip: Try exporting as DEX, it doesn't rely on " + + "decoded APK resources"); + return; + } + + final FileContainer finalContainer = container; + + Thread exportThread = new Thread(() -> + { + if (BytecodeViewer.viewer.compileOnSave.isSelected() && !BytecodeViewer.compile(false)) + return; + + JFileChooser fc = new FileChooser(new File(Configuration.lastDirectory), + "Select APK Export", + "Android APK", + "apk"); + + int returnVal = fc.showSaveDialog(BytecodeViewer.viewer); + if (returnVal == JFileChooser.APPROVE_OPTION) + { + Configuration.lastDirectory = fc.getSelectedFile().getAbsolutePath(); + final File file = fc.getSelectedFile(); + String output = file.getAbsolutePath(); + + //auto appened .apk + if (!output.endsWith(".apk")) + output = output + ".apk"; + + final File file2 = new File(output); + if (file2.exists()) + { + MultipleChoiceDialogue dialogue = new MultipleChoiceDialogue("Bytecode Viewer - Overwrite File", + "Are you sure you wish to overwrite this existing file?", + new String[]{"Yes", "No"}); + + if (dialogue.promptChoice() == 0) { + file.delete(); + } else { + return; + } + } + + Thread saveThread = new Thread(() -> + { + BytecodeViewer.viewer.updateBusyStatus(true); + final String input = tempDirectory + fs + MiscUtils.getRandomizedName() + ".jar"; + JarUtils.saveAsJar(BytecodeViewer.getLoadedClasses(), input); + + Thread buildAPKThread = new Thread(() -> + { + APKTool.buildAPK(new File(input), file2, finalContainer); + BytecodeViewer.viewer.updateBusyStatus(false); + }); + buildAPKThread.start(); + }); + saveThread.start(); + } + }); + exportThread.start(); + } +} diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/resources/exporting/impl/DexExport.java b/src/main/java/the/bytecode/club/bytecodeviewer/resources/exporting/impl/DexExport.java new file mode 100644 index 00000000..9cc6fb66 --- /dev/null +++ b/src/main/java/the/bytecode/club/bytecodeviewer/resources/exporting/impl/DexExport.java @@ -0,0 +1,88 @@ +package the.bytecode.club.bytecodeviewer.resources.exporting.impl; + +import the.bytecode.club.bytecodeviewer.BytecodeViewer; +import the.bytecode.club.bytecodeviewer.Configuration; +import the.bytecode.club.bytecodeviewer.gui.components.FileChooser; +import the.bytecode.club.bytecodeviewer.gui.components.MultipleChoiceDialogue; +import the.bytecode.club.bytecodeviewer.resources.exporting.Exporter; +import the.bytecode.club.bytecodeviewer.util.Dex2Jar; +import the.bytecode.club.bytecodeviewer.util.JarUtils; +import the.bytecode.club.bytecodeviewer.util.MiscUtils; + +import javax.swing.*; +import java.io.File; + +import static the.bytecode.club.bytecodeviewer.Constants.fs; +import static the.bytecode.club.bytecodeviewer.Constants.tempDirectory; + +/** + * @author Konloch + * @since 6/27/2021 + */ +public class DexExport implements Exporter +{ + + @Override + public void promptForExport() + { + if (BytecodeViewer.getLoadedClasses().isEmpty()) + { + BytecodeViewer.showMessage("First open a class, jar, zip, apk or dex file."); + return; + } + + Thread exportThread = new Thread(() -> + { + if (BytecodeViewer.viewer.compileOnSave.isSelected() && !BytecodeViewer.compile(false)) + return; + + JFileChooser fc = new FileChooser(new File(Configuration.lastDirectory), + "Select DEX Export", + "Android DEX Files", + "dex"); + + int returnVal = fc.showSaveDialog(BytecodeViewer.viewer); + if (returnVal == JFileChooser.APPROVE_OPTION) + { + Configuration.lastDirectory = fc.getSelectedFile().getAbsolutePath(); + final File file = fc.getSelectedFile(); + String output = file.getAbsolutePath(); + + //auto append .dex + if (!output.endsWith(".dex")) + output = output + ".dex"; + + File outputPath = new File(output); + if (outputPath.exists()) + { + MultipleChoiceDialogue dialogue = new MultipleChoiceDialogue("Bytecode Viewer - Overwrite File", + "Are you sure you wish to overwrite this existing file?", + new String[]{"Yes", "No"}); + + if (dialogue.promptChoice() == 0) { + file.delete(); + } else { + return; + } + } + + Thread saveAsJar = new Thread(() -> + { + BytecodeViewer.viewer.updateBusyStatus(true); + final String input = tempDirectory + fs + MiscUtils.getRandomizedName() + ".jar"; + JarUtils.saveAsJar(BytecodeViewer.getLoadedClasses(), input); + + Thread saveAsDex = new Thread(() -> + { + Dex2Jar.saveAsDex(new File(input), outputPath); + + BytecodeViewer.viewer.updateBusyStatus(false); + }); + saveAsDex.start(); + }); + saveAsJar.start(); + } + }); + exportThread.start(); + } +} diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/resources/exporting/impl/RunnableJarExporter.java b/src/main/java/the/bytecode/club/bytecodeviewer/resources/exporting/impl/RunnableJarExporter.java new file mode 100644 index 00000000..2adeabef --- /dev/null +++ b/src/main/java/the/bytecode/club/bytecodeviewer/resources/exporting/impl/RunnableJarExporter.java @@ -0,0 +1,67 @@ +package the.bytecode.club.bytecodeviewer.resources.exporting.impl; + +import the.bytecode.club.bytecodeviewer.BytecodeViewer; +import the.bytecode.club.bytecodeviewer.Configuration; +import the.bytecode.club.bytecodeviewer.gui.components.ExportJar; +import the.bytecode.club.bytecodeviewer.gui.components.FileChooser; +import the.bytecode.club.bytecodeviewer.gui.components.MultipleChoiceDialogue; +import the.bytecode.club.bytecodeviewer.resources.exporting.Exporter; + +import javax.swing.*; +import java.io.File; + +/** + * @author Konloch + * @since 6/27/2021 + */ +public class RunnableJarExporter implements Exporter +{ + @Override + public void promptForExport() + { + if (BytecodeViewer.getLoadedClasses().isEmpty()) + { + BytecodeViewer.showMessage("First open a class, jar, zip, apk or dex file."); + return; + } + + Thread exportThread = new Thread(() -> + { + if (BytecodeViewer.viewer.compileOnSave.isSelected() && !BytecodeViewer.compile(false)) + return; + + JFileChooser fc = new FileChooser(new File(Configuration.lastDirectory), + "Select Jar Export", + "Jar Archives", + "jar"); + + int returnVal = fc.showSaveDialog(BytecodeViewer.viewer); + if (returnVal == JFileChooser.APPROVE_OPTION) + { + Configuration.lastDirectory = fc.getSelectedFile().getAbsolutePath(); + File file = fc.getSelectedFile(); + String path = file.getAbsolutePath(); + + //auto append .jar + if (!path.endsWith(".jar")) + path = path + ".jar"; + + if (new File(path).exists()) + { + MultipleChoiceDialogue dialogue = new MultipleChoiceDialogue("Bytecode Viewer - Overwrite File", + "Are you sure you wish to overwrite this existing file?", + new String[]{"Yes", "No"}); + + if (dialogue.promptChoice() == 0) { + file.delete(); + } else { + return; + } + } + + new ExportJar(path).setVisible(true); + } + }); + exportThread.start(); + } +} diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/resources/exporting/impl/ZipExport.java b/src/main/java/the/bytecode/club/bytecodeviewer/resources/exporting/impl/ZipExport.java new file mode 100644 index 00000000..21e7f486 --- /dev/null +++ b/src/main/java/the/bytecode/club/bytecodeviewer/resources/exporting/impl/ZipExport.java @@ -0,0 +1,74 @@ +package the.bytecode.club.bytecodeviewer.resources.exporting.impl; + +import the.bytecode.club.bytecodeviewer.BytecodeViewer; +import the.bytecode.club.bytecodeviewer.Configuration; +import the.bytecode.club.bytecodeviewer.gui.components.FileChooser; +import the.bytecode.club.bytecodeviewer.gui.components.MultipleChoiceDialogue; +import the.bytecode.club.bytecodeviewer.resources.exporting.Exporter; +import the.bytecode.club.bytecodeviewer.util.JarUtils; + +import javax.swing.*; +import java.io.File; + +/** + * @author Konloch + * @since 6/27/2021 + */ +public class ZipExport implements Exporter +{ + @Override + public void promptForExport() + { + if (BytecodeViewer.getLoadedClasses().isEmpty()) + { + BytecodeViewer.showMessage("First open a class, jar, zip, apk or dex file."); + return; + } + + Thread exportThread = new Thread(() -> + { + if (BytecodeViewer.viewer.compileOnSave.isSelected() && !BytecodeViewer.compile(false)) + return; + + JFileChooser fc = new FileChooser(new File(Configuration.lastDirectory), + "Select Zip Export", + "Zip Archives", + "zip"); + + int returnVal = fc.showSaveDialog(BytecodeViewer.viewer); + if (returnVal == JFileChooser.APPROVE_OPTION) + { + Configuration.lastDirectory = fc.getSelectedFile().getAbsolutePath(); + File file = fc.getSelectedFile(); + + //auto append .zip + if (!file.getAbsolutePath().endsWith(".zip")) + file = new File(file.getAbsolutePath() + ".zip"); + + if (file.exists()) + { + MultipleChoiceDialogue dialogue = new MultipleChoiceDialogue("Bytecode Viewer - Overwrite File", + "Are you sure you wish to overwrite this existing file?", + new String[]{"Yes", "No"}); + + if (dialogue.promptChoice() == 0) { + file.delete(); + } else { + return; + } + } + + final File file2 = file; + + BytecodeViewer.viewer.updateBusyStatus(true); + Thread saveThread = new Thread(() -> + { + JarUtils.saveAsJar(BytecodeViewer.getLoadedClasses(), file2.getAbsolutePath()); + BytecodeViewer.viewer.updateBusyStatus(false); + }); + saveThread.start(); + } + }); + exportThread.start(); + } +} diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/resources/importing/ImportType.java b/src/main/java/the/bytecode/club/bytecodeviewer/resources/importing/Import.java similarity index 85% rename from src/main/java/the/bytecode/club/bytecodeviewer/resources/importing/ImportType.java rename to src/main/java/the/bytecode/club/bytecodeviewer/resources/importing/Import.java index 26281e2f..2e7f3995 100644 --- a/src/main/java/the/bytecode/club/bytecodeviewer/resources/importing/ImportType.java +++ b/src/main/java/the/bytecode/club/bytecodeviewer/resources/importing/Import.java @@ -6,7 +6,7 @@ import the.bytecode.club.bytecodeviewer.resources.importing.impl.*; * @author Konloch * @since 6/26/2021 */ -public enum ImportType +public enum Import { DIRECTORY(new DirectoryResourceImporter()), FILE(new FileResourceImporter()), @@ -18,7 +18,7 @@ public enum ImportType private final Importer importer; - ImportType(Importer importer) {this.importer = importer;} + Import(Importer importer) {this.importer = importer;} public Importer getImporter() { 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 0de6562a..6f441473 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 @@ -54,33 +54,33 @@ public class ImportResource implements Runnable { if (file.isDirectory()) { - ImportType.DIRECTORY.getImporter().open(file); + Import.DIRECTORY.getImporter().open(file); } else { if (fn.endsWith(".jar") || fn.endsWith(".zip") || fn.endsWith(".war")) { - if(!ImportType.ZIP.getImporter().open(file)) + if(!Import.ZIP.getImporter().open(file)) update = false; } else if (fn.endsWith(".class")) { - if(!ImportType.CLASS.getImporter().open(file)) + if(!Import.CLASS.getImporter().open(file)) update = false; } else if (fn.endsWith(".apk")) { - ImportType.APK.getImporter().open(file); + Import.APK.getImporter().open(file); return; } else if (fn.endsWith(".dex")) { - ImportType.DEX.getImporter().open(file); + Import.DEX.getImporter().open(file); return; } else { - ImportType.FILE.getImporter().open(file); + Import.FILE.getImporter().open(file); } } } 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 656cce8b..72249011 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,7 +1,7 @@ package the.bytecode.club.bytecodeviewer.resources.importing.impl; import the.bytecode.club.bytecodeviewer.BytecodeViewer; -import the.bytecode.club.bytecodeviewer.resources.importing.ImportType; +import the.bytecode.club.bytecodeviewer.resources.importing.Import; import the.bytecode.club.bytecodeviewer.resources.importing.Importer; import the.bytecode.club.bytecodeviewer.util.FileContainer; @@ -58,15 +58,15 @@ public class DirectoryResourceImporter implements Importer //attempt to import archives automatically if (fileName.endsWith(".jar") || fileName.endsWith(".zip") || fileName.endsWith(".war")) { - ImportType.ZIP.getImporter().open(child); + Import.ZIP.getImporter().open(child); } else if (fileName.endsWith(".apk")) { - ImportType.APK.getImporter().open(child); + Import.APK.getImporter().open(child); } else if (fileName.endsWith(".dex")) { - ImportType.DEX.getImporter().open(child); + Import.DEX.getImporter().open(child); } else {