diff --git a/trunk/build.xml b/trunk/build.xml
index c0d8d6007..8c09f4605 100644
--- a/trunk/build.xml
+++ b/trunk/build.xml
@@ -46,7 +46,6 @@
-
-
+
diff --git a/trunk/build_common.xml b/trunk/build_common.xml
index 2576f9480..199c4db70 100644
--- a/trunk/build_common.xml
+++ b/trunk/build_common.xml
@@ -273,6 +273,8 @@ Please follow instructions on http://www.free-decompiler.com/flash/translations.
+
+
diff --git a/trunk/src/com/jpexs/decompiler/flash/AbortRetryIgnoreHandler.java b/trunk/src/com/jpexs/decompiler/flash/AbortRetryIgnoreHandler.java
index 2526b1f27..4d73742c7 100644
--- a/trunk/src/com/jpexs/decompiler/flash/AbortRetryIgnoreHandler.java
+++ b/trunk/src/com/jpexs/decompiler/flash/AbortRetryIgnoreHandler.java
@@ -22,9 +22,12 @@ package com.jpexs.decompiler.flash;
*/
public interface AbortRetryIgnoreHandler {
+ public static int UNDEFINED = -1;
public static int ABORT = 0;
public static int RETRY = 1;
public static int IGNORE = 2;
public int handle(Throwable thrown);
+
+ public AbortRetryIgnoreHandler getNewInstance();
}
diff --git a/trunk/src/com/jpexs/decompiler/flash/Configuration.java b/trunk/src/com/jpexs/decompiler/flash/Configuration.java
index 767ea9e8a..443a128b5 100644
--- a/trunk/src/com/jpexs/decompiler/flash/Configuration.java
+++ b/trunk/src/com/jpexs/decompiler/flash/Configuration.java
@@ -53,7 +53,15 @@ public class Configuration {
* Limit of code subs (for obfuscated code)
*/
public static final int SUBLIMITER = 500;
- //using parameter names in decompiling may cause problems because oficial programs like Flash CS 5.5 inserts wrong parameter names indices
+ /**
+ * Decompilation timeout in seconds
+ */
+ public static final int DECOMPILATION_TIMEOUT = 30 * 60;
+ /**
+ * Decompilation timeout for a single method in AS3 or single action in AS1/2 in seconds
+ */
+ public static final int DECOMPILATION_TIMEOUT_SINGLE_METHOD = 5;
+ //using parameter names in decompiling may cause problems because official programs like Flash CS 5.5 inserts wrong parameter names indices
public static final boolean PARAM_NAMES_ENABLE = false;
private static HashMap config = new HashMap<>();
/**
diff --git a/trunk/src/com/jpexs/decompiler/flash/ConsoleAbortRetryIgnoreHandler.java b/trunk/src/com/jpexs/decompiler/flash/ConsoleAbortRetryIgnoreHandler.java
new file mode 100644
index 000000000..f95dd8c91
--- /dev/null
+++ b/trunk/src/com/jpexs/decompiler/flash/ConsoleAbortRetryIgnoreHandler.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2013 JPEXS
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package com.jpexs.decompiler.flash;
+
+import java.util.Scanner;
+
+/**
+ *
+ * @author JPEXS
+ */
+public class ConsoleAbortRetryIgnoreHandler implements AbortRetryIgnoreHandler {
+ int errorCount = 0;
+ int errorMode;
+ int retryCount;
+
+ public ConsoleAbortRetryIgnoreHandler(int errorMode, int retryCount) {
+ this.errorMode = errorMode;
+ this.retryCount = retryCount;
+ }
+
+ @Override
+ public int handle(Throwable thrown) {
+ if (errorMode != AbortRetryIgnoreHandler.UNDEFINED){
+ int result = errorMode;
+
+ if (errorMode == AbortRetryIgnoreHandler.RETRY && errorCount < retryCount) {
+ errorCount++;
+ }
+ else {
+ result = AbortRetryIgnoreHandler.IGNORE;
+ }
+
+ return result;
+ }
+ Scanner sc = new Scanner(System.in);
+ System.out.println("Error occured: " + thrown.getLocalizedMessage());
+ String n = null;
+ do {
+ System.out.print("Select action: (A)bort, (R)Retry, (I)Ignore:");
+ n = sc.nextLine();
+ switch (n.toLowerCase()) {
+ case "a":
+ return AbortRetryIgnoreHandler.ABORT;
+ case "r":
+ return AbortRetryIgnoreHandler.RETRY;
+ case "i":
+ return AbortRetryIgnoreHandler.IGNORE;
+ }
+ } while (true);
+ }
+
+ @Override
+ public AbortRetryIgnoreHandler getNewInstance() {
+ return new ConsoleAbortRetryIgnoreHandler(errorMode, retryCount);
+ }
+}
diff --git a/trunk/src/com/jpexs/decompiler/flash/SWF.java b/trunk/src/com/jpexs/decompiler/flash/SWF.java
index 94ceb8d73..f05d115e3 100644
--- a/trunk/src/com/jpexs/decompiler/flash/SWF.java
+++ b/trunk/src/com/jpexs/decompiler/flash/SWF.java
@@ -591,12 +591,14 @@ public class SWF {
outdir += File.separator;
}
outdir += "scripts" + File.separator;
- ret.addAll(TagNode.exportNodeAS(tags, handler, list, outdir, isPcode, evl));
+ AtomicInteger cnt = new AtomicInteger(1);
+ int totalCount = TagNode.getTagCountRecursive(list);
+ ret.addAll(TagNode.exportNodeAS(tags, handler, list, outdir, isPcode, cnt, totalCount, evl));
return ret;
}
public List exportActionScript3(AbortRetryIgnoreHandler handler, String outdir, boolean isPcode, boolean parallel) {
- ExecutorService executor = Executors.newFixedThreadPool(20);
+ ExecutorService executor = Executors.newFixedThreadPool(parallel ? 20 : 1);
List> futureResults = new ArrayList<>();
AtomicInteger cnt = new AtomicInteger(1);
List abcTags = new ArrayList<>();
@@ -622,9 +624,9 @@ public class SWF {
try {
executor.shutdown();
- executor.awaitTermination(30, TimeUnit.MINUTES);
+ executor.awaitTermination(Configuration.DECOMPILATION_TIMEOUT, TimeUnit.SECONDS);
} catch (InterruptedException ex) {
- Logger.getLogger(ABC.class.getName()).log(Level.SEVERE, "30 minutes ActionScript export limit reached", ex);
+ Logger.getLogger(ABC.class.getName()).log(Level.SEVERE, Helper.formatTimeToText(Configuration.DECOMPILATION_TIMEOUT) + " ActionScript export limit reached", ex);
}
return ret;
}
diff --git a/trunk/src/com/jpexs/decompiler/flash/TagNode.java b/trunk/src/com/jpexs/decompiler/flash/TagNode.java
index 003e98134..b59e97c22 100644
--- a/trunk/src/com/jpexs/decompiler/flash/TagNode.java
+++ b/trunk/src/com/jpexs/decompiler/flash/TagNode.java
@@ -53,6 +53,9 @@ import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.logging.Level;
+import java.util.logging.Logger;
public class TagNode {
@@ -231,11 +234,30 @@ public class TagNode {
}
}
+ public static int getTagCountRecursive(List nodeList) {
+ int count = 0;
+
+ for (TagNode node : nodeList) {
+ if (node.subItems.isEmpty()) {
+ if ((node.tag instanceof ASMSource) && (node.export)) {
+ count += 1;
+ }
+ } else {
+ count += getTagCountRecursive(node.subItems);
+ }
+
+ }
+
+ return count;
+ }
+
public static List exportNodeAS(List allTags, AbortRetryIgnoreHandler handler, List nodeList, String outdir, boolean isPcode) throws IOException {
- return exportNodeAS(allTags, handler, nodeList, outdir, isPcode, null);
+ AtomicInteger cnt = new AtomicInteger(1);
+ int totalCount = TagNode.getTagCountRecursive(nodeList);
+ return exportNodeAS(allTags, handler, nodeList, outdir, isPcode, cnt, totalCount, null);
}
- public static List exportNodeAS(List allTags, AbortRetryIgnoreHandler handler, List nodeList, String outdir, boolean isPcode, EventListener ev) throws IOException {
+ public static List exportNodeAS(List allTags, AbortRetryIgnoreHandler handler, List nodeList, String outdir, boolean isPcode, AtomicInteger index, int count, EventListener ev) throws IOException {
File dir = new File(outdir);
List ret = new ArrayList<>();
if (!outdir.endsWith(File.separator)) {
@@ -269,11 +291,10 @@ public class TagNode {
do {
retry = false;
try {
+ long startTime = System.currentTimeMillis();
+
String f = outdir + name + ".as";
File file = new File(f);
- if (ev != null) {
- ev.handleEvent("export", "Exporting " + f + " ...");
- }
String res;
ASMSource asm = ((ASMSource) node.tag);
if (isPcode) {
@@ -286,10 +307,19 @@ public class TagNode {
try (FileOutputStream fos = new FileOutputStream(f)) {
fos.write(res.getBytes("utf-8"));
}
+
+ long stopTime = System.currentTimeMillis();
+
+ if (ev != null) {
+ long time = stopTime - startTime;
+ ev.handleEvent("export", "Exported " + index.getAndIncrement() + "/" + count + " " + f + ", " + Helper.formatTimeSec(time));
+ }
+
ret.add(file);
- } catch (Exception ex) {
+ } catch (Exception | OutOfMemoryError | StackOverflowError ex) {
+ Logger.getLogger(TagNode.class.getName()).log(Level.SEVERE, "Decompilation error", ex);
if (handler != null) {
- int action = handler.handle(ex);
+ int action = handler.getNewInstance().handle(ex);
switch (action) {
case AbortRetryIgnoreHandler.ABORT:
throw ex;
@@ -305,7 +335,7 @@ public class TagNode {
} while (retry);
}
} else {
- ret.addAll(exportNodeAS(allTags, handler, node.subItems, outdir + name, isPcode, ev));
+ ret.addAll(exportNodeAS(allTags, handler, node.subItems, outdir + name, isPcode, index, count, ev));
}
}
diff --git a/trunk/src/com/jpexs/decompiler/flash/abc/avm2/model/operations/TypeOfAVM2Item.java b/trunk/src/com/jpexs/decompiler/flash/abc/avm2/model/operations/TypeOfAVM2Item.java
index 07687c50b..bff5b8fb7 100644
--- a/trunk/src/com/jpexs/decompiler/flash/abc/avm2/model/operations/TypeOfAVM2Item.java
+++ b/trunk/src/com/jpexs/decompiler/flash/abc/avm2/model/operations/TypeOfAVM2Item.java
@@ -19,12 +19,6 @@ package com.jpexs.decompiler.flash.abc.avm2.model.operations;
import com.jpexs.decompiler.flash.abc.avm2.instructions.AVM2Instruction;
import com.jpexs.decompiler.flash.ecma.EcmaScript;
import com.jpexs.decompiler.flash.ecma.EcmaType;
-import static com.jpexs.decompiler.flash.ecma.EcmaType.BOOLEAN;
-import static com.jpexs.decompiler.flash.ecma.EcmaType.NULL;
-import static com.jpexs.decompiler.flash.ecma.EcmaType.NUMBER;
-import static com.jpexs.decompiler.flash.ecma.EcmaType.OBJECT;
-import static com.jpexs.decompiler.flash.ecma.EcmaType.STRING;
-import static com.jpexs.decompiler.flash.ecma.EcmaType.UNDEFINED;
import com.jpexs.decompiler.graph.GraphTargetItem;
import com.jpexs.decompiler.graph.model.UnaryOpItem;
diff --git a/trunk/src/com/jpexs/decompiler/flash/abc/types/MethodBody.java b/trunk/src/com/jpexs/decompiler/flash/abc/types/MethodBody.java
index 45bcdd748..698e165b6 100644
--- a/trunk/src/com/jpexs/decompiler/flash/abc/types/MethodBody.java
+++ b/trunk/src/com/jpexs/decompiler/flash/abc/types/MethodBody.java
@@ -22,6 +22,7 @@ import com.jpexs.decompiler.flash.abc.avm2.AVM2Code;
import com.jpexs.decompiler.flash.abc.avm2.CodeStats;
import com.jpexs.decompiler.flash.abc.avm2.ConstantPool;
import com.jpexs.decompiler.flash.abc.types.traits.Traits;
+import com.jpexs.decompiler.flash.action.Action;
import com.jpexs.decompiler.flash.helpers.Helper;
import com.jpexs.decompiler.flash.helpers.Highlighting;
import com.jpexs.decompiler.graph.Graph;
@@ -31,6 +32,10 @@ import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Stack;
+import java.util.concurrent.Callable;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
import java.util.logging.Level;
import java.util.logging.Logger;
@@ -103,7 +108,7 @@ public class MethodBody implements Cloneable, Serializable {
return ret;
}
- public String toString(String path, boolean pcode, boolean isStatic, int scriptIndex, int classIndex, ABC abc, ConstantPool constants, MethodInfo method_info[], Stack scopeStack, boolean isStaticInitializer, boolean hilight, List fullyQualifiedNames, Traits initTraits) {
+ public String toString(final String path, boolean pcode, final boolean isStatic, final int scriptIndex, final int classIndex, final ABC abc, final ConstantPool constants, final MethodInfo method_info[], final Stack scopeStack, final boolean isStaticInitializer, final boolean hilight, final List fullyQualifiedNames, final Traits initTraits) {
if (debugMode) {
System.err.println("Decompiling " + path);
}
@@ -118,30 +123,46 @@ public class MethodBody implements Cloneable, Serializable {
if (pcode) {
s += code.toASMSource(constants, this, false);
} else {
- AVM2Code deobfuscated = null;
- MethodBody b = (MethodBody) Helper.deepCopy(this);
- deobfuscated = b.code;
- deobfuscated.markMappedOffsets();
- if ((Boolean) Configuration.getConfig("autoDeobfuscate", true)) {
- try {
- deobfuscated.removeTraps(constants, b, abc, scriptIndex, classIndex, isStatic, path);
- } catch (Exception | StackOverflowError ex) {
- Logger.getLogger(MethodBody.class.getName()).log(Level.SEVERE, "Error during remove traps in " + path, ex);
- }
- }
- //deobfuscated.restoreControlFlow(constants, b);
- //try {
- s += deobfuscated.toSource(path, isStatic, scriptIndex, classIndex, abc, constants, method_info, b, hilight, getLocalRegNames(abc), scopeStack, isStaticInitializer, fullyQualifiedNames, initTraits, Graph.SOP_USE_STATIC, new HashMap(), deobfuscated.visitCode(b));
- s = s.trim();
- if (s.equals("")) {
- s = " ";
- }
- if (hilight) {
- s = Highlighting.hilighMethod(s, this.method_info);
+ try {
+ s += Helper.timedCall(new Callable() {
+ @Override
+ public String call() throws Exception {
+ return toSource(path, isStatic, scriptIndex, classIndex, abc, constants, method_info, scopeStack, isStaticInitializer, hilight, fullyQualifiedNames, initTraits);
+ }
+ }, Configuration.DECOMPILATION_TIMEOUT_SINGLE_METHOD, TimeUnit.SECONDS);
+ } catch (InterruptedException | ExecutionException | TimeoutException ex) {
+ Logger.getLogger(Action.class.getName()).log(Level.SEVERE, "Decompilation error", ex);
+ s += "/*\r\n * Decompilation error\r\n * Timeout (" + Helper.formatTimeToText(Configuration.DECOMPILATION_TIMEOUT_SINGLE_METHOD) + ") was reached\r\n */";
}
}
return s;
}
+
+ public String toSource(String path, boolean isStatic, int scriptIndex, int classIndex, ABC abc, ConstantPool constants, MethodInfo method_info[], Stack scopeStack, boolean isStaticInitializer, boolean hilight, List fullyQualifiedNames, Traits initTraits) {
+ AVM2Code deobfuscated = null;
+ MethodBody b = (MethodBody) Helper.deepCopy(this);
+ deobfuscated = b.code;
+ deobfuscated.markMappedOffsets();
+ if ((Boolean) Configuration.getConfig("autoDeobfuscate", true)) {
+ try {
+ deobfuscated.removeTraps(constants, b, abc, scriptIndex, classIndex, isStatic, path);
+ } catch (Exception | StackOverflowError ex) {
+ Logger.getLogger(MethodBody.class.getName()).log(Level.SEVERE, "Error during remove traps in " + path, ex);
+ }
+ }
+ //deobfuscated.restoreControlFlow(constants, b);
+ //try {
+ String s = deobfuscated.toSource(path, isStatic, scriptIndex, classIndex, abc, constants, method_info, b, hilight, getLocalRegNames(abc), scopeStack, isStaticInitializer, fullyQualifiedNames, initTraits, Graph.SOP_USE_STATIC, new HashMap(), deobfuscated.visitCode(b));
+ s = s.trim();
+ if (s.equals("")) {
+ s = " ";
+ }
+ if (hilight) {
+ s = Highlighting.hilighMethod(s, this.method_info);
+ }
+
+ return s;
+ }
@Override
public Object clone() throws CloneNotSupportedException {
diff --git a/trunk/src/com/jpexs/decompiler/flash/action/Action.java b/trunk/src/com/jpexs/decompiler/flash/action/Action.java
index a823ec23b..97f1d4661 100644
--- a/trunk/src/com/jpexs/decompiler/flash/action/Action.java
+++ b/trunk/src/com/jpexs/decompiler/flash/action/Action.java
@@ -16,6 +16,7 @@
*/
package com.jpexs.decompiler.flash.action;
+import com.jpexs.decompiler.flash.Configuration;
import com.jpexs.decompiler.flash.DisassemblyListener;
import com.jpexs.decompiler.flash.SWF;
import com.jpexs.decompiler.flash.SWFInputStream;
@@ -49,6 +50,7 @@ import com.jpexs.decompiler.flash.ecma.Null;
import com.jpexs.decompiler.flash.helpers.Helper;
import com.jpexs.decompiler.flash.helpers.Highlighting;
import com.jpexs.decompiler.flash.helpers.collections.MyEntry;
+import com.jpexs.decompiler.flash.tags.base.ASMSource;
import com.jpexs.decompiler.graph.Graph;
import com.jpexs.decompiler.graph.GraphSource;
import com.jpexs.decompiler.graph.GraphSourceItem;
@@ -62,6 +64,9 @@ import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.StringReader;
import java.util.*;
+import java.util.concurrent.Callable;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
import java.util.logging.Level;
import java.util.logging.Logger;
@@ -408,7 +413,7 @@ public class Action implements GraphSourceItem {
* @param path
* @return ASM source as String
*/
- public static String actionsToString(List listeners, long address, List list, List importantOffsets, List constantPool, int version, boolean hex, long swfPos, String path) {
+ private static String actionsToString(List listeners, long address, List list, List importantOffsets, List constantPool, int version, boolean hex, long swfPos, String path) {
long offset;
if (importantOffsets == null) {
//setActionsAddresses(list, 0, version);
@@ -434,6 +439,10 @@ public class Action implements GraphSourceItem {
}
pos++;
if (hex) {
+ if (lastPush) {
+ ret.append("\r\n");
+ lastPush = false;
+ }
ret.append("");/* +"0x"+Helper.formatAddress(a.getFileAddress())+": "+*/;
ret.append(Helper.bytesToHexString(a.getBytes(version)));
ret.append("\r\n");
@@ -707,15 +716,22 @@ public class Action implements GraphSourceItem {
* @param path
* @return String with Source code
*/
- public static String actionsToSource(List actions, int version, String path) {
+ public static String actionsToSource(final List actions, final int version, final String path) {
try {
- //List tree = actionsToTree(new HashMap(), actions, version);
- int staticOperation = Graph.SOP_USE_STATIC; //(Boolean) Configuration.getConfig("autoDeobfuscate", true) ? Graph.SOP_SKIP_STATIC : Graph.SOP_USE_STATIC;
+ return Helper.timedCall(new Callable() {
+ @Override
+ public String call() throws Exception {
+ //List tree = actionsToTree(new HashMap(), actions, version);
+ int staticOperation = Graph.SOP_USE_STATIC; //(Boolean) Configuration.getConfig("autoDeobfuscate", true) ? Graph.SOP_SKIP_STATIC : Graph.SOP_USE_STATIC;
- List tree = actionsToTree(new HashMap(), new HashMap(), new HashMap(), actions, version, staticOperation, path);
+ List tree = actionsToTree(new HashMap(), new HashMap(), new HashMap(), actions, version, staticOperation, path);
-
- return Graph.graphToString(tree);
+ return Graph.graphToString(tree);
+ }
+ }, Configuration.DECOMPILATION_TIMEOUT_SINGLE_METHOD, TimeUnit.SECONDS);
+ } catch (TimeoutException ex) {
+ Logger.getLogger(Action.class.getName()).log(Level.SEVERE, "Decompilation error", ex);
+ return "/*\r\n * Decompilation error\r\n * Timeout (" + Helper.formatTimeToText(Configuration.DECOMPILATION_TIMEOUT_SINGLE_METHOD) + ") was reached\r\n */";
} catch (Exception | OutOfMemoryError | StackOverflowError ex2) {
Logger.getLogger(Action.class.getName()).log(Level.SEVERE, "Decompilation error", ex2);
if (ex2 instanceof OutOfMemoryError) {
diff --git a/trunk/src/com/jpexs/decompiler/flash/action/model/PrintAsBitmapActionItem.java b/trunk/src/com/jpexs/decompiler/flash/action/model/PrintAsBitmapActionItem.java
index e4212c6f5..15ea46c19 100644
--- a/trunk/src/com/jpexs/decompiler/flash/action/model/PrintAsBitmapActionItem.java
+++ b/trunk/src/com/jpexs/decompiler/flash/action/model/PrintAsBitmapActionItem.java
@@ -21,7 +21,6 @@ import com.jpexs.decompiler.flash.action.parser.script.ActionSourceGenerator;
import com.jpexs.decompiler.flash.action.swf4.ActionGetURL2;
import com.jpexs.decompiler.graph.GraphSourceItem;
import com.jpexs.decompiler.graph.GraphTargetItem;
-import static com.jpexs.decompiler.graph.GraphTargetItem.PRECEDENCE_PRIMARY;
import com.jpexs.decompiler.graph.SourceGenerator;
import java.util.ArrayList;
import java.util.List;
diff --git a/trunk/src/com/jpexs/decompiler/flash/gui/Main.java b/trunk/src/com/jpexs/decompiler/flash/gui/Main.java
index 6472c9e84..1350044da 100644
--- a/trunk/src/com/jpexs/decompiler/flash/gui/Main.java
+++ b/trunk/src/com/jpexs/decompiler/flash/gui/Main.java
@@ -18,6 +18,7 @@ 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.PercentListener;
import com.jpexs.decompiler.flash.SWF;
@@ -529,6 +530,8 @@ public class Main {
System.out.println(" Values are boolean, you can use 0/1, true/false 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();
System.out.println("Examples:");
System.out.println("java -jar ffdec.jar myfile.swf");
@@ -540,6 +543,8 @@ public class Main {
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");
@@ -690,61 +695,100 @@ public class Main {
} else {
Cache.setStorageType(Cache.STORAGE_MEMORY);
}
+
+ int errorMode = AbortRetryIgnoreHandler.UNDEFINED;
+ int retryCount = 0;
if (args.length < pos + 1) {
autoCheckForUpdates();
offerAssociation();
showModeFrame();
} else {
- if (args[pos].equals("-config")) {
- pos++;
- if (args.length <= pos) {
- System.err.println("Config values expected");
- badArguments();
- }
- String cfgStr = args[pos];
- 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("=");
+ 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();
+ }
+ String cfgStr = args[pos];
+ String cfgs[];
+ if (cfgStr.contains(",")) {
+ cfgs = cfgStr.split(",");
} else {
- cp = new String[]{c, "1"};
+ cfgs = new String[]{cfgStr};
}
- 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 = null;
- if (value.equals("0") || value.toLowerCase().equals("false") || value.toLowerCase().equals("no") || value.toLowerCase().equals("off")) {
- bValue = false;
- }
- if (value.equals("1") || value.toLowerCase().equals("true") || value.toLowerCase().equals("yes") || value.toLowerCase().equals("on")) {
- bValue = true;
- }
- if (bValue != null) {
- System.out.println("Config " + bk + " set to " + bValue);
- Configuration.setConfig(bk, bValue);
+
+ 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 = null;
+ if (value.equals("0") || value.toLowerCase().equals("false") || value.toLowerCase().equals("no") || value.toLowerCase().equals("off")) {
+ bValue = false;
+ }
+ if (value.equals("1") || value.toLowerCase().equals("true") || value.toLowerCase().equals("yes") || value.toLowerCase().equals("on")) {
+ bValue = true;
+ }
+ if (bValue != null) {
+ System.out.println("Config " + bk + " set to " + bValue);
+ Configuration.setConfig(bk, bValue);
+ }
}
}
}
+ pos++;
+ if (args.length <= pos) {
+ saveConfig();
+ System.out.println("Configuration saved");
+ return;
+ }
}
- pos++;
- if (args.length <= pos) {
- saveConfig();
- System.out.println("Configuration saved");
- return;
+ 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++;
}
}
if (args[pos].equals("-removefromcontextmenu")) {
@@ -793,26 +837,7 @@ public class Main {
"xfl"
};
- AbortRetryIgnoreHandler handler = new AbortRetryIgnoreHandler() {
- @Override
- public int handle(Throwable thrown) {
- Scanner sc = new Scanner(System.in);
- System.out.println("Error occured: " + thrown.getLocalizedMessage());
- String n = null;
- do {
- System.out.print("Select action: (A)bort, (R)Retry, (I)Ignore:");
- n = sc.nextLine();
- switch (n.toLowerCase()) {
- case "a":
- return AbortRetryIgnoreHandler.ABORT;
- case "r":
- return AbortRetryIgnoreHandler.RETRY;
- case "i":
- return AbortRetryIgnoreHandler.IGNORE;
- }
- } while (true);
- }
- };
+ 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);
diff --git a/trunk/src/com/jpexs/decompiler/flash/gui/MainFrame.java b/trunk/src/com/jpexs/decompiler/flash/gui/MainFrame.java
index 4f0fdf7e6..7c126d3c8 100644
--- a/trunk/src/com/jpexs/decompiler/flash/gui/MainFrame.java
+++ b/trunk/src/com/jpexs/decompiler/flash/gui/MainFrame.java
@@ -18,6 +18,7 @@ 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.FrameNode;
import com.jpexs.decompiler.flash.PackageNode;
import com.jpexs.decompiler.flash.SWF;
@@ -288,6 +289,12 @@ public class MainFrame extends AppRibbonFrame implements ActionListener, TreeSel
return View.showOptionDialog(null, translate("error.occured").replace("%error%", thrown.getLocalizedMessage()), translate("error"), JOptionPane.YES_NO_OPTION, JOptionPane.ERROR_MESSAGE, null, options, "");
}
}
+
+ @Override
+ public AbortRetryIgnoreHandler getNewInstance() {
+ // there are no non-static field in this class, so return the original instance
+ return this;
+ }
};
public void setPercent(int percent) {
@@ -1404,6 +1411,12 @@ public class MainFrame extends AppRibbonFrame implements ActionListener, TreeSel
@Override
public void run() {
if (record.getLevel() == Level.SEVERE) {
+ if (errorNotificationButton == null) {
+ // todo: honfika
+ // why null?
+ return;
+ }
+
errorNotificationButton.setIcon(View.getIcon("error16"));
errorNotificationButton.setToolTipText(translate("errors.present"));
if (timer != null) {
diff --git a/trunk/src/com/jpexs/decompiler/flash/gui/action/ActionPanel.java b/trunk/src/com/jpexs/decompiler/flash/gui/action/ActionPanel.java
index a313c381e..c59f3ead4 100644
--- a/trunk/src/com/jpexs/decompiler/flash/gui/action/ActionPanel.java
+++ b/trunk/src/com/jpexs/decompiler/flash/gui/action/ActionPanel.java
@@ -168,7 +168,7 @@ public class ActionPanel extends JPanel implements ActionListener {
private void cacheScript(ASMSource src) {
if (!cache.contains(src)) {
List as = src.getActions(SWF.DEFAULT_VERSION);
- String s = com.jpexs.decompiler.flash.action.Action.actionsToSource(as, SWF.DEFAULT_VERSION, src.toString()/*FIXME?*/);
+ String s = Action.actionsToSource(as, SWF.DEFAULT_VERSION, src.toString()/*FIXME?*/);
List hilights = Highlighting.getInstrHighlights(s);
String srcNoHex = Highlighting.stripHilights(s);
cache.put(src, new CachedScript(srcNoHex, hilights));
@@ -567,6 +567,10 @@ public class ActionPanel extends JPanel implements ActionListener {
}
public void setDecompiledEditMode(boolean val) {
+ if (lastASM == null) {
+ return;
+ }
+
String pref = lastASM.getActionSourcePrefix();
int lastPos = decompiledEditor.getCaretPosition();
int lastLine = decompiledEditor.getLine();
diff --git a/trunk/src/com/jpexs/decompiler/flash/helpers/Helper.java b/trunk/src/com/jpexs/decompiler/flash/helpers/Helper.java
index 5913e9028..c22a30469 100644
--- a/trunk/src/com/jpexs/decompiler/flash/helpers/Helper.java
+++ b/trunk/src/com/jpexs/decompiler/flash/helpers/Helper.java
@@ -34,6 +34,13 @@ import java.util.BitSet;
import java.util.Collection;
import java.util.List;
import java.util.Stack;
+import java.util.concurrent.Callable;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.FutureTask;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.regex.Matcher;
@@ -46,6 +53,8 @@ import java.util.regex.Pattern;
*/
public class Helper {
+ private static final ExecutorService THREAD_POOL = Executors.newCachedThreadPool();
+
/**
* Converts array of int values to string
*
@@ -504,8 +513,41 @@ public class Helper {
timeStr += Helper.padZeros(timeS, 2) + "." + Helper.padZeros(timeMs, 3);
return timeStr;
}
+
public static void freeMem(){
Cache.clearAll();
System.gc();
}
+ public static String formatTimeToText(int timeS) {
+ long timeM = timeS / 60;
+ timeS = timeS % 60;
+ long timeH = timeM / 60;
+ timeM = timeM % 60;
+
+ String timeStr = "";
+ if (timeH > 0) {
+ timeStr += timeH + (timeH > 1 ? " hours" : " hour");
+ }
+ if (timeM > 0) {
+ if (timeStr.length() > 0) {
+ timeStr += " and ";
+ }
+ timeStr += timeM + (timeM > 1 ? " minutes" : " minute");
+ }
+ if (timeS > 0) {
+ if (timeStr.length() > 0) {
+ timeStr += " and ";
+ }
+ timeStr += timeS + (timeS > 1 ? " seconds" : " second");
+ }
+
+ // (currently) used only in log, so no localization is required
+ return timeStr;
+ }
+
+ public static T timedCall(Callable c, long timeout, TimeUnit timeUnit) throws InterruptedException, ExecutionException, TimeoutException {
+ FutureTask task = new FutureTask(c);
+ THREAD_POOL.execute(task);
+ return task.get(timeout, timeUnit);
+ }
}