Command line parsing refactored, Advanced Settings dialog

This commit is contained in:
Honfika
2013-11-06 23:06:16 +01:00
parent 72a9f59da6
commit 9870157b6b
9 changed files with 710 additions and 498 deletions

View File

@@ -16,16 +16,14 @@
*/
package com.jpexs.decompiler.flash.gui;
import com.jpexs.decompiler.flash.AbortRetryIgnoreHandler;
import com.jpexs.decompiler.flash.Configuration;
import com.jpexs.decompiler.flash.ConsoleAbortRetryIgnoreHandler;
import com.jpexs.decompiler.flash.EventListener;
import com.jpexs.decompiler.flash.SWF;
import com.jpexs.decompiler.flash.Version;
import com.jpexs.decompiler.flash.abc.avm2.AVM2Code;
import com.jpexs.decompiler.flash.console.CommandLineArgumentParser;
import com.jpexs.decompiler.flash.gui.player.FlashPlayerPanel;
import com.jpexs.decompiler.flash.gui.proxy.ProxyFrame;
import com.jpexs.decompiler.graph.ExportMode;
import com.jpexs.helpers.Cache;
import com.jpexs.helpers.Helper;
import com.jpexs.helpers.ProgressListener;
@@ -51,7 +49,6 @@ import java.net.URLDecoder;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Locale;
import java.util.Properties;
@@ -97,7 +94,6 @@ public class Main {
private static boolean working = false;
private static TrayIcon trayIcon;
private static MenuItem stopMenuItem;
private static boolean commandLineMode = false;
public static MainFrame mainFrame;
private static final int UPDATE_SYSTEM_MAJOR = 1;
private static final int UPDATE_SYSTEM_MINOR = 0;
@@ -119,12 +115,6 @@ public class Main {
}
loadFromMemoryFrame.setVisible(true);
}
private static String[] commandlineConfigBoolean = new String[]{
"decompile",
"parallelSpeedUp",
"internalFlashViewer",
"autoDeobfuscate",
"cacheOnDisk"};
private static void loadProperties() {
Properties prop = new Properties();
@@ -140,10 +130,6 @@ public class Main {
}
}
public static boolean isCommandLineMode() {
return commandLineMode;
}
/**
* Get title of the file
*
@@ -209,7 +195,7 @@ public class Main {
loadingDialog.setPercent(percent);
}
}
if (Main.isCommandLineMode()) {
if (CommandLineArgumentParser.isCommandLineMode()) {
System.out.println(name);
}
}
@@ -694,68 +680,6 @@ public class Main {
}
public static void badArguments() {
System.err.println("Error: Bad Commandline Arguments!");
printCmdLineUsage();
System.exit(1);
}
public static void printHeader() {
System.out.println(applicationVerName);
for (int i = 0; i < applicationVerName.length(); i++) {
System.out.print("-");
}
System.out.println();
}
public static void printCmdLineUsage() {
System.out.println("Commandline arguments:");
System.out.println(" 1) -help | --help | /?");
System.out.println(" ...shows commandline arguments (this help)");
System.out.println(" 2) infile");
System.out.println(" ...opens SWF file with the decompiler GUI");
System.out.println(" 3) -proxy (-PXXX)");
System.out.println(" ...auto start proxy in the tray. Optional parameter -P specifies port for proxy. Defaults to 55555. ");
System.out.println(" 4) -export (as|pcode|pcodehex|hex|image|shape|movie|sound|binaryData|text|textplain|all|all_as|all_pcode|all_pcodehex|all_hex) outdirectory infile [-selectas3class class1 class2 ...]");
System.out.println(" ...export infile sources to outdirectory as AsctionScript code (\"as\" argument) or as PCode (\"pcode\" argument), images, shapes, movies, binaryData, text with formatting, plain text or all.");
System.out.println(" When \"as\" or \"pcode\" type specified, optional \"-selectas3class\" parameter can be passed to export only selected classes (ActionScript 3 only)");
System.out.println(" 5) -dumpSWF infile");
System.out.println(" ...dumps list of SWF tags to console");
System.out.println(" 6) -compress infile outfile");
System.out.println(" ...Compress SWF infile and save it to outfile");
System.out.println(" 7) -decompress infile outfile");
System.out.println(" ...Decompress infile and save it to outfile");
System.out.println(" 8) -config key=value[,key2=value2][,key3=value3...] [other parameters]");
System.out.print(" ...Sets configuration values. Available keys[current setting]:");
for (String key : commandlineConfigBoolean) {
System.out.print(" " + key + "[" + Configuration.getConfig(key) + "]");
}
System.out.println("");
System.out.println(" Values are boolean, you can use 0/1, true/false, on/off or yes/no.");
System.out.println(" If no other parameters passed, configuration is saved. Otherwise it is used only once.");
System.out.println(" DO NOT PUT space between comma (,) and next value.");
System.out.println(" 9) -onerror (abort|retryN|ignore)");
System.out.println(" ...error handling mode. \"abort\" stops the exporting, \"retry\" tries the exporting N times, \"ignore\" ignores the current file");
System.out.println(" 10) -timeout N");
System.out.println(" ...decompilation timeout for a single method in AS3 or single action in AS1/2 in seconds");
System.out.println();
System.out.println("Examples:");
System.out.println("java -jar ffdec.jar myfile.swf");
System.out.println("java -jar ffdec.jar -proxy");
System.out.println("java -jar ffdec.jar -proxy -P1234");
System.out.println("java -jar ffdec.jar -export as \"C:\\decompiled\\\" myfile.swf");
System.out.println("java -jar ffdec.jar -export as \"C:\\decompiled\\\" myfile.swf -selectas3class com.example.MyClass com.example.SecondClass");
System.out.println("java -jar ffdec.jar -export pcode \"C:\\decompiled\\\" myfile.swf");
System.out.println("java -jar ffdec.jar -dumpSWF myfile.swf");
System.out.println("java -jar ffdec.jar -compress myfile.swf myfiledec.swf");
System.out.println("java -jar ffdec.jar -decompress myfiledec.swf myfile.swf");
System.out.println("java -jar ffdec.jar -onerror ignore -export as \"C:\\decompiled\\\" myfile.swf");
System.out.println("java -jar ffdec.jar -onerror retry 5 -export as \"C:\\decompiled\\\" myfile.swf");
System.out.println("java -jar ffdec.jar -config autoDeobfuscate=1,parallelSpeedUp=0 -export as \"C:\\decompiled\\\" myfile.swf");
System.out.println("");
System.out.println("Instead of \"java -jar ffdec.jar\" you can use ffdec.bat on Windows, ffdec.sh on Linux/MacOs");
}
private static void offerAssociation() {
boolean offered = Configuration.getConfig("offeredAssociation");
if (!offered) {
@@ -891,13 +815,6 @@ public class Main {
startFreeMemThread();
loadProperties();
Configuration.loadFromFile(getConfigFile(), getReplacementsFile());
int pos = 0;
if (args.length > 0) {
if (args[0].equals("-debug")) {
Configuration.debugMode = true;
pos++;
}
}
initLogging(Configuration.debugMode);
initLang();
@@ -910,424 +827,18 @@ public class Main {
Cache.setStorageType(Cache.STORAGE_MEMORY);
}
int errorMode = AbortRetryIgnoreHandler.UNDEFINED;
int retryCount = 0;
Level traceLevel = Level.WARNING;
if (args.length < pos + 1) {
if (args.length == 0) {
initGui();
showModeFrame();
} else {
boolean parameterProcessed = true;
while (parameterProcessed) {
parameterProcessed = false;
if (args[pos].equals("-config")) {
parameterProcessed = true;
pos++;
if (args.length <= pos) {
System.err.println("Config values expected");
badArguments();
}
setConfigurations(args[pos]);
pos++;
if (args.length <= pos) {
saveConfig();
System.out.println("Configuration saved");
return;
}
} else if (args[pos].equals("-onerror")) {
parameterProcessed = true;
pos++;
if (args.length <= pos) {
System.err.println("onerror parameter expected");
badArguments();
}
String errorModeParameter = args[pos];
switch (errorModeParameter) {
case "abort":
errorMode = AbortRetryIgnoreHandler.ABORT;
break;
case "retry":
errorMode = AbortRetryIgnoreHandler.RETRY;
pos++;
if (args.length <= pos) {
System.err.println("onerror retry count parameter expected");
badArguments();
}
try {
retryCount = Integer.parseInt(args[pos]);
} catch (NumberFormatException nex) {
System.err.println("Bad retry count number");
}
break;
case "ignore":
errorMode = AbortRetryIgnoreHandler.IGNORE;
break;
}
pos++;
} else if (args[pos].equals("-timeout")) {
parameterProcessed = true;
pos++;
if (args.length <= pos) {
System.err.println("timeout parameter expected");
badArguments();
}
try {
int timeout = Integer.parseInt(args[pos]);
Configuration.setConfig("decompilationTimeoutSingleMethod", timeout);
} catch (NumberFormatException nex) {
System.err.println("Bad timeout value");
}
pos++;
} else if (args[pos].equals("-affinity")) {
parameterProcessed = true;
pos++;
if (Platform.isWindows()) {
if (args.length <= pos) {
System.err.println("affinity parameter expected");
badArguments();
}
try {
int affinityMask = Integer.parseInt(args[pos]);
Kernel32.INSTANCE.SetProcessAffinityMask(Kernel32.INSTANCE.GetCurrentProcess(), affinityMask);
} catch (NumberFormatException nex) {
System.err.println("Bad affinityMask value");
}
pos++;
} else {
System.err.println("Process affinity setting is only available on Windows platform.");
}
} else if (args[pos].equals("-priority")) {
parameterProcessed = true;
pos++;
if (Platform.isWindows()) {
if (args.length <= pos) {
System.err.println("priority parameter expected");
badArguments();
}
String priority = args[pos];
int priorityClass = 0;
switch (priority) {
case "low":
priorityClass = Kernel32.IDLE_PRIORITY_CLASS;
break;
case "belownormal":
priorityClass = Kernel32.BELOW_NORMAL_PRIORITY_CLASS;
break;
case "normal":
priorityClass = Kernel32.NORMAL_PRIORITY_CLASS;
break;
case "abovenormal":
priorityClass = Kernel32.ABOVE_NORMAL_PRIORITY_CLASS;
break;
case "high":
priorityClass = Kernel32.HIGH_PRIORITY_CLASS;
break;
case "realtime":
priorityClass = Kernel32.REALTIME_PRIORITY_CLASS;
break;
default:
System.err.println("Bad affinityMask value");
}
if (priorityClass != 0) {
Kernel32.INSTANCE.SetPriorityClass(Kernel32.INSTANCE.GetCurrentProcess(), priorityClass);
}
pos++;
} else {
System.err.println("Process priority setting is only available on Windows platform.");
}
} else if (args[pos].equals("-verbose")) {
parameterProcessed = true;
pos++;
traceLevel = Level.FINE;
}
}
if (args[pos].equals("-removefromcontextmenu")) {
addToContextMenu(false);
System.exit(0);
} else if (args[pos].equals("-addtocontextmenu")) {
addToContextMenu(true);
System.exit(0);
} else if (args[pos].equals("-proxy")) {
int port = 55555;
for (int i = pos; i < args.length; i++) {
if (args[i].startsWith("-P")) {
try {
port = Integer.parseInt(args[pos].substring(2));
} catch (NumberFormatException nex) {
System.err.println("Bad port number");
}
}
}
View.execInEventDispatch(new Runnable() {
@Override
public void run() {
if (proxyFrame == null) {
proxyFrame = new ProxyFrame();
}
}
});
proxyFrame.setPort(port);
addTrayIcon();
switchProxy();
} else if (args[pos].equals("-export")) {
if (args.length < pos + 4) {
badArguments();
}
String[] validExportFormats = new String[]{
"as",
"pcode",
"image",
"shape",
"movie",
"sound",
"binarydata",
"text",
"textplain",
"all",
"fla",
"xfl"
};
AbortRetryIgnoreHandler handler = new ConsoleAbortRetryIgnoreHandler(errorMode, retryCount);
String exportFormat = args[pos + 1].toLowerCase();
if (!Arrays.asList(validExportFormats).contains(exportFormat)) {
System.err.println("Invalid export format:" + exportFormat);
badArguments();
}
File outDir = new File(args[pos + 2]);
File inFile = new File(args[pos + 3]);
if (!inFile.exists()) {
System.err.println("Input SWF file does not exist!");
badArguments();
}
commandLineMode = true;
long startTime = System.currentTimeMillis();
boolean exportOK;
try {
printHeader();
SWF exfile = new SWF(new FileInputStream(inFile), Configuration.getConfig("parallelSpeedUp", true));
final Level level = traceLevel;
exfile.addEventListener(new EventListener() {
@Override
public void handleEvent(String event, Object data) {
if (level.intValue() <= Level.FINE.intValue() && event.equals("exporting")) {
System.out.println((String) data);
}
if (event.equals("exported")) {
System.out.println((String) data);
}
}
});
switch (exportFormat) {
case "all":
case "all_as":
case "all_pcode":
case "all_pcodehex":
case "all_hex":
ExportMode allExportMode = strToExportFormat(exportFormat.substring(3));
System.out.println("Exporting images...");
exfile.exportImages(handler, outDir.getAbsolutePath() + File.separator + "images");
System.out.println("Exporting shapes...");
exfile.exportShapes(handler, outDir.getAbsolutePath() + File.separator + "shapes");
System.out.println("Exporting scripts...");
exfile.exportActionScript(handler, outDir.getAbsolutePath() + File.separator + "scripts", allExportMode, Configuration.getConfig("parallelSpeedUp", true));
System.out.println("Exporting movies...");
exfile.exportMovies(handler, outDir.getAbsolutePath() + File.separator + "movies");
System.out.println("Exporting sounds...");
exfile.exportSounds(handler, outDir.getAbsolutePath() + File.separator + "sounds", true, true);
System.out.println("Exporting binaryData...");
exfile.exportBinaryData(handler, outDir.getAbsolutePath() + File.separator + "binaryData");
System.out.println("Exporting texts...");
exfile.exportTexts(handler, outDir.getAbsolutePath() + File.separator + "texts", true);
exportOK = true;
break;
case "image":
exfile.exportImages(handler, outDir.getAbsolutePath());
exportOK = true;
break;
case "shape":
exfile.exportShapes(handler, outDir.getAbsolutePath());
exportOK = true;
break;
case "as":
case "pcode":
case "pcodehex":
case "hex":
ExportMode exportMode = strToExportFormat(exportFormat);
boolean parallel = Configuration.getConfig("parallelSpeedUp", true);
if ((pos + 5 < args.length) && (args[pos + 4].equals("-selectas3class"))) {
exportOK = true;
for (int i = pos + 5; i < args.length; i++) {
exportOK = exportOK && exfile.exportAS3Class(args[i], outDir.getAbsolutePath(), exportMode, parallel);
}
} else {
exportOK = exfile.exportActionScript(handler, outDir.getAbsolutePath(), exportMode, parallel) != null;
}
break;
case "movie":
exfile.exportMovies(handler, outDir.getAbsolutePath());
exportOK = true;
break;
case "sound":
exfile.exportSounds(handler, outDir.getAbsolutePath(), true, true);
exportOK = true;
break;
case "binarydata":
exfile.exportBinaryData(handler, outDir.getAbsolutePath());
exportOK = true;
break;
case "text":
exfile.exportTexts(handler, outDir.getAbsolutePath(), true);
exportOK = true;
break;
case "textplain":
exfile.exportTexts(handler, outDir.getAbsolutePath(), false);
exportOK = true;
break;
case "fla":
exfile.exportFla(handler, outDir.getAbsolutePath(), inFile.getName(), applicationName, applicationVerName, version, Configuration.getConfig("parallelSpeedUp", true));
exportOK = true;
break;
case "xfl":
exfile.exportXfl(handler, outDir.getAbsolutePath(), inFile.getName(), applicationName, applicationVerName, version, Configuration.getConfig("parallelSpeedUp", true));
exportOK = true;
break;
default:
exportOK = false;
}
} catch (OutOfMemoryError | Exception ex) {
exportOK = false;
System.err.print("FAIL: Exporting Failed on Exception - ");
Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
System.exit(1);
}
long stopTime = System.currentTimeMillis();
long time = stopTime - startTime;
System.out.println("Export finished. Total export time: " + Helper.formatTimeSec(time));
if (exportOK) {
System.out.println("OK");
System.exit(0);
} else {
System.err.println("FAIL");
System.exit(1);
}
} else if (args[pos].equals("-compress")) {
if (args.length < pos + 3) {
badArguments();
}
if (SWF.fws2cws(new FileInputStream(args[pos + 1]), new FileOutputStream(args[pos + 2]))) {
System.out.println("OK");
} else {
System.err.println("FAIL");
}
} else if (args[pos].equals("-decompress")) {
if (args.length < pos + 3) {
badArguments();
}
if (SWF.decompress(new FileInputStream(args[pos + 1]), new FileOutputStream(args[pos + 2]))) {
System.out.println("OK");
System.exit(0);
} else {
System.err.println("FAIL");
System.exit(1);
}
} else if (args[pos].equals("-dumpSWF")) {
if (args.length < pos + 2) {
badArguments();
}
try {
Configuration.dump_tags = true;
Configuration.setConfig("parallelSpeedUp", false);
SWF swf = parseSWF(args[pos + 1]);
} catch (Exception ex) {
Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
System.exit(1);
}
System.exit(0);
} else if (args[pos].equals("-help") || args[pos].equals("--help") || args[pos].equals("/?")) {
printHeader();
printCmdLineUsage();
System.exit(0);
} else if (args.length == pos + 1) {
String fileToOpen = CommandLineArgumentParser.parseArguments(args);
if (fileToOpen != null) {
initGui();
openFile(args[pos]);
} else {
badArguments();
openFile(fileToOpen);
}
}
}
private static ExportMode strToExportFormat(String exportFormatStr) {
if (exportFormatStr.equals("pcode")) {
return ExportMode.PCODE;
} else if (exportFormatStr.equals("pcodehex")) {
return ExportMode.PCODEWITHHEX;
} else if (exportFormatStr.equals("hex")) {
return ExportMode.HEX;
} else {
return ExportMode.SOURCE;
}
}
private static void setConfigurations(String cfgStr) {
String[] cfgs;
if (cfgStr.contains(",")) {
cfgs = cfgStr.split(",");
} else {
cfgs = new String[]{cfgStr};
}
for (String c : cfgs) {
String[] cp;
if (c.contains("=")) {
cp = c.split("=");
} else {
cp = new String[]{c, "1"};
}
String key = cp[0];
String value = cp[1];
if (key.toLowerCase().equals("paralelSpeedUp".toLowerCase())) {
key = "parallelSpeedUp";
}
for (String bk : commandlineConfigBoolean) {
if (key.toLowerCase().equals(bk.toLowerCase())) {
Boolean bValue = parseBooleanConfigValue(value);
if (bValue != null) {
System.out.println("Config " + bk + " set to " + bValue);
Configuration.setConfig(bk, bValue);
}
}
}
}
}
private static Boolean parseBooleanConfigValue(String value) {
if (value == null) {
return null;
}
Boolean bValue = null;
value = value.toLowerCase();
if (value.equals("0") || value.equals("false") || value.equals("no") || value.equals("off")) {
bValue = false;
}
if (value.equals("1") || value.equals("true") || value.equals("yes") || value.equals("on")) {
bValue = true;
}
return bValue;
}
public static String tempFile(String url) throws IOException {
File f = new File(getFFDecHome() + "saved" + File.separator);
if (!f.exists()) {
@@ -1443,6 +954,10 @@ public class Main {
(new AboutDialog()).setVisible(true);
}
public static void advancedSettings() {
(new AdvancedSettingsDialog()).setVisible(true);
}
public static void autoCheckForUpdates() {
Calendar lastUpdatesCheckDate = Configuration.getConfig("lastUpdatesCheckDate", null);
if ((lastUpdatesCheckDate == null) || (lastUpdatesCheckDate.getTime().getTime() < Calendar.getInstance().getTime().getTime() - 1000 * 60 * 60 * 24)) {