Resource Exporting Cleanup
This commit is contained in:
parent
51ce387345
commit
b0f5e938db
12 changed files with 425 additions and 317 deletions
|
@ -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));
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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<FileContainer> containers = BytecodeViewer.getFiles();
|
||||
List<FileContainer> validContainers = new ArrayList<>();
|
||||
List<String> 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();
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
package the.bytecode.club.bytecodeviewer.resources.exporting;
|
||||
|
||||
/**
|
||||
* @author Konloch
|
||||
* @since 6/27/2021
|
||||
*/
|
||||
public interface Exporter
|
||||
{
|
||||
void promptForExport();
|
||||
}
|
|
@ -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<FileContainer> containers = BytecodeViewer.getFiles();
|
||||
List<FileContainer> validContainers = new ArrayList<>();
|
||||
List<String> 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();
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
}
|
|
@ -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()
|
||||
{
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
{
|
||||
|
|
Loading…
Reference in a new issue