Issue #431: Canceling background threads (after timeout, or after user action, e.g new treeitem selected) fixed + small fixes

This commit is contained in:
Honfika
2013-12-03 00:26:21 +01:00
parent 3aa09fdf2b
commit 06b95ac6e1
42 changed files with 1083 additions and 773 deletions

View File

@@ -22,6 +22,7 @@ import com.jpexs.decompiler.flash.abc.ClassPath;
import com.jpexs.decompiler.flash.abc.RenameType;
import com.jpexs.decompiler.flash.abc.ScriptPack;
import com.jpexs.decompiler.flash.action.Action;
import com.jpexs.decompiler.flash.action.ActionDeobfuscation;
import com.jpexs.decompiler.flash.action.ActionGraphSource;
import com.jpexs.decompiler.flash.action.model.ConstantPool;
import com.jpexs.decompiler.flash.action.model.DirectValueActionItem;
@@ -101,6 +102,7 @@ import com.jpexs.decompiler.graph.GraphSourceItemContainer;
import com.jpexs.decompiler.graph.GraphTargetItem;
import com.jpexs.decompiler.graph.model.LocalData;
import com.jpexs.helpers.Cache;
import com.jpexs.helpers.CancellableWorker;
import com.jpexs.helpers.Helper;
import com.jpexs.helpers.ProgressListener;
import com.jpexs.helpers.utf8.Utf8Helper;
@@ -129,7 +131,6 @@ import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Random;
import java.util.Set;
import java.util.Stack;
import java.util.concurrent.Callable;
@@ -142,7 +143,6 @@ import java.util.concurrent.TimeoutException;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.regex.Pattern;
import java.util.zip.DeflaterOutputStream;
import java.util.zip.InflaterInputStream;
import javax.imageio.ImageIO;
@@ -298,7 +298,7 @@ public final class SWF {
}
}
public SWF(InputStream is, boolean parallelRead) throws IOException {
public SWF(InputStream is, boolean parallelRead) throws IOException, InterruptedException {
this(is, null, parallelRead);
}
@@ -310,7 +310,7 @@ public final class SWF {
* @param parallelRead Use parallel threads?
* @throws IOException
*/
public SWF(InputStream is, ProgressListener listener, boolean parallelRead) throws IOException {
public SWF(InputStream is, ProgressListener listener, boolean parallelRead) throws IOException, InterruptedException {
this(is, listener, parallelRead, false);
}
@@ -323,7 +323,7 @@ public final class SWF {
* @param checkOnly Check only file validity
* @throws IOException
*/
public SWF(InputStream is, ProgressListener listener, boolean parallelRead, boolean checkOnly) throws IOException {
public SWF(InputStream is, ProgressListener listener, boolean parallelRead, boolean checkOnly) throws IOException, InterruptedException {
byte[] hdr = new byte[3];
is.read(hdr);
String shdr = new String(hdr, Utf8Helper.charset);
@@ -663,7 +663,7 @@ public final class SWF {
long time = stopTime - startTime;
informListeners("exported", "Exported script " + currentIndex + "/" + count + " " + path + ", " + Helper.formatTimeSec(time));
}
return null;
return rio.result;
}
}
@@ -696,7 +696,7 @@ public final class SWF {
if (!parallel || packs.size() < 2) {
try {
Helper.timedCall(new Callable<Void>() {
CancellableWorker.call(new Callable<Void>() {
@Override
public Void call() throws Exception {
for (MyEntry<ClassPath, ScriptPack> item : packs) {
@@ -712,26 +712,32 @@ public final class SWF {
Logger.getLogger(ABC.class.getName()).log(Level.SEVERE, "Error during ABC export", ex);
}
} else {
ExecutorService executor = Executors.newFixedThreadPool(20);
ExecutorService executor = Executors.newFixedThreadPool(Configuration.parallelThreadCount.get());
List<Future<File>> futureResults = new ArrayList<>();
for (MyEntry<ClassPath, ScriptPack> item : packs) {
Future<File> future = executor.submit(new ExportPackTask(handler, cnt, packs.size(), item.key, item.value, outdir, abcTags, exportMode, parallel));
futureResults.add(future);
}
for (int f = 0; f < futureResults.size(); f++) {
try {
ret.add(futureResults.get(f).get());
} catch (InterruptedException | ExecutionException ex) {
Logger.getLogger(SWF.class.getName()).log(Level.SEVERE, "Error during ABC export", ex);
try {
executor.shutdown();
if (!executor.awaitTermination(Configuration.exportTimeout.get(), TimeUnit.SECONDS)) {
Logger.getLogger(ABC.class.getName()).log(Level.SEVERE, Helper.formatTimeToText(Configuration.exportTimeout.get()) + " ActionScript export limit reached");
}
} catch (InterruptedException ex) {
} finally {
executor.shutdownNow();
}
try {
executor.awaitTermination(Configuration.exportTimeout.get(), TimeUnit.SECONDS);
executor.shutdownNow();
} catch (InterruptedException ex) {
Logger.getLogger(ABC.class.getName()).log(Level.SEVERE, Helper.formatTimeToText(Configuration.exportTimeout.get()) + " ActionScript export limit reached", ex);
for (int f = 0; f < futureResults.size(); f++) {
try {
if (futureResults.get(f).isDone()) {
ret.add(futureResults.get(f).get());
}
} catch (InterruptedException ex) {
} catch (ExecutionException ex) {
Logger.getLogger(SWF.class.getName()).log(Level.SEVERE, "Error during ABC export", ex);
}
}
}
@@ -1482,133 +1488,12 @@ public final class SWF {
public void exportBinaryData(AbortRetryIgnoreHandler handler, String outdir) throws IOException {
exportBinaryData(handler, outdir, tags);
}
public static final String[] reservedWords = {
"as", "break", "case", "catch", "class", "const", "continue", "default", "delete", "do", "each", "else",
"extends", "false", "finally", "for", "function", "get", "if", "implements", "import", "in", "instanceof",
"interface", "internal", "is", "native", "new", "null", "override", "package", "private", "protected", "public",
"return", "set", "super", "switch", "this", "throw", "true", "try", "typeof", "use", "var", /*"void",*/ "while",
"with", "dynamic", "default", "final", "in"};
private boolean isReserved(String s) {
for (String rw : reservedWords) {
if (rw.equals(s.trim())) {
return true;
}
}
return false;
}
private HashMap<String, String> deobfuscated = new HashMap<>();
private Random rnd = new Random();
private final int DEFAULT_FOO_SIZE = 10;
public static final String validFirstCharacters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_";
public static final String validNextCharacters = validFirstCharacters + "0123456789";
public static final String fooCharacters = "bcdfghjklmnpqrstvwz";
public static final String fooJoinCharacters = "aeiouy";
private List<MyEntry<DirectValueActionItem, ConstantPool>> allVariableNames = new ArrayList<>();
private HashSet<String> allVariableNamesStr = new HashSet<>();
private List<GraphSourceItem> allFunctions = new ArrayList<>();
private HashMap<DirectValueActionItem, ConstantPool> allStrings = new HashMap<>();
private HashMap<DirectValueActionItem, String> usageTypes = new HashMap<>();
private String fooString(String orig, boolean firstUppercase, int rndSize) {
boolean exists;
String ret;
loopfoo:
do {
exists = false;
int len = 3 + rnd.nextInt(rndSize - 3);
ret = "";
for (int i = 0; i < len; i++) {
String c = "";
if ((i % 2) == 0) {
c = "" + fooCharacters.charAt(rnd.nextInt(fooCharacters.length()));
} else {
c = "" + fooJoinCharacters.charAt(rnd.nextInt(fooJoinCharacters.length()));
}
if (i == 0 && firstUppercase) {
c = c.toUpperCase(Locale.ENGLISH);
}
ret += c;
}
if (allVariableNamesStr.contains(ret)) {
exists = true;
rndSize += 1;
continue loopfoo;
}
if (isReserved(ret)) {
exists = true;
rndSize += 1;
continue;
}
if (deobfuscated.containsValue(ret)) {
exists = true;
rndSize += 1;
continue;
}
} while (exists);
return ret;
}
public String deobfuscateName(String s, boolean firstUppercase, String usageType, RenameType renameType, Map<String, String> selected) {
boolean isValid = true;
if (usageType == null) {
usageType = "name";
}
if (selected != null) {
if (selected.containsKey(s)) {
return selected.get(s);
}
}
if (isReserved(s)) {
isValid = false;
}
if (isValid) {
for (int i = 0; i < s.length(); i++) {
if (s.charAt(i) > 127) {
isValid = false;
break;
}
}
}
if (isValid) {
Pattern pat = Pattern.compile("^[" + Pattern.quote(validFirstCharacters) + "]" + "[" + Pattern.quote(validFirstCharacters + validNextCharacters) + "]*$");
if (!pat.matcher(s).matches()) {
isValid = false;
}
}
if (!isValid) {
if (deobfuscated.containsKey(s)) {
return deobfuscated.get(s);
} else {
Integer cnt = typeCounts.get(usageType);
if (cnt == null) {
cnt = 0;
}
String ret = null;
if (renameType == RenameType.TYPENUMBER) {
boolean found;
do {
found = false;
cnt++;
ret = usageType + "_" + cnt;
found = allVariableNamesStr.contains(ret);
} while (found);
typeCounts.put(usageType, cnt);
} else if (renameType == RenameType.RANDOMWORD) {
ret = fooString(s, firstUppercase, DEFAULT_FOO_SIZE);
}
deobfuscated.put(s, ret);
return ret;
}
}
return null;
}
private ActionDeobfuscation deobfuscation = new ActionDeobfuscation();
private static void getVariables(ConstantPool constantPool, List<Object> localData, Stack<GraphTargetItem> stack, List<GraphTargetItem> output, ActionGraphSource code, int ip, List<MyEntry<DirectValueActionItem, ConstantPool>> variables, List<GraphSourceItem> functions, HashMap<DirectValueActionItem, ConstantPool> strings, List<Integer> visited, HashMap<DirectValueActionItem, String> usageTypes, String path) throws InterruptedException {
boolean debugMode = false;
@@ -1638,6 +1523,9 @@ public final class SWF {
|| (ins instanceof ActionNewObject)
|| (ins instanceof ActionCallMethod)
|| (ins instanceof ActionCallFunction)) {
if (stack.isEmpty()) {
break;
}
name = stack.peek();
}
@@ -1681,12 +1569,18 @@ public final class SWF {
r.add(new ArrayList<GraphTargetItem>());
r.add(new ArrayList<GraphTargetItem>());
r.add(new ArrayList<GraphTargetItem>());
((GraphSourceItemContainer) ins).translateContainer(r, stack, output, new HashMap<Integer, String>(), new HashMap<String, GraphTargetItem>(), new HashMap<String, GraphTargetItem>());
try {
((GraphSourceItemContainer) ins).translateContainer(r, stack, output, new HashMap<Integer, String>(), new HashMap<String, GraphTargetItem>(), new HashMap<String, GraphTargetItem>());
} catch (EmptyStackException ex) {
}
//ip++;
continue;
}
if ((ins instanceof ActionSetVariable) || (ins instanceof ActionSetMember) || (ins instanceof ActionDefineLocal)) {
if (stack.size() < 2) {
break;
}
name = stack.get(stack.size() - 2);
}
@@ -1718,8 +1612,6 @@ public final class SWF {
} catch (EmptyStackException ex) {
// probably obfucated code, never executed branch
break;
} catch (InterruptedException ex) {
Logger.getLogger(SWF.class.getName()).log(Level.SEVERE, "Error during getting variables", ex);
}
if (ins.isExit()) {
break;
@@ -1742,6 +1634,9 @@ public final class SWF {
if (ins.isBranch() || ins.isJump()) {
if (ins instanceof ActionIf) {
if (stack.isEmpty()) {
break;
}
stack.pop();
}
visited.add(ip);
@@ -1799,96 +1694,6 @@ public final class SWF {
}
}
public void deobfuscateInstanceNames(RenameType renameType, List<Tag> tags, Map<String, String> selected) {
for (Tag t : tags) {
if (t instanceof DefineSpriteTag) {
deobfuscateInstanceNames(renameType, ((DefineSpriteTag) t).subTags, selected);
}
if (t instanceof PlaceObjectTypeTag) {
PlaceObjectTypeTag po = (PlaceObjectTypeTag) t;
String name = po.getInstanceName();
if (name != null) {
String changedName = deobfuscateName(name, false, "instance", renameType, selected);
if (changedName != null) {
po.setInstanceName(changedName);
}
}
String className = po.getClassName();
if (className != null) {
String changedClassName = deobfuscateNameWithPackage(className, renameType, selected);
if (changedClassName != null) {
po.setClassName(changedClassName);
}
}
}
}
}
public String deobfuscatePackage(String pkg, RenameType renameType, Map<String, String> selected) {
if (deobfuscated.containsKey(pkg)) {
return deobfuscated.get(pkg);
}
String[] parts = null;
if (pkg.contains(".")) {
parts = pkg.split("\\.");
} else {
parts = new String[]{pkg};
}
String ret = "";
boolean isChanged = false;
for (int p = 0; p < parts.length; p++) {
if (p > 0) {
ret += ".";
}
String partChanged = deobfuscateName(parts[p], false, "package", renameType, selected);
if (partChanged != null) {
ret += partChanged;
isChanged = true;
} else {
ret += parts[p];
}
}
if (isChanged) {
deobfuscated.put(pkg, ret);
return ret;
}
return null;
}
public String deobfuscateNameWithPackage(String n, RenameType renameType, Map<String, String> selected) {
String pkg = null;
String name = "";
if (n.contains(".")) {
pkg = n.substring(0, n.lastIndexOf('.'));
name = n.substring(n.lastIndexOf('.') + 1);
} else {
name = n;
}
boolean changed = false;
if ((pkg != null) && (!pkg.isEmpty())) {
String changedPkg = deobfuscatePackage(pkg, renameType, selected);
if (changedPkg != null) {
changed = true;
pkg = changedPkg;
}
}
String changedName = deobfuscateName(name, true, "class", renameType, selected);
if (changedName != null) {
changed = true;
name = changedName;
}
if (changed) {
String newClassName = "";
if (pkg == null) {
newClassName = name;
} else {
newClassName = pkg + "." + name;
}
return newClassName;
}
return null;
}
public int deobfuscateAS3Identifiers(RenameType renameType) {
for (Tag tag : tags) {
if (tag instanceof ABCContainerTag) {
@@ -1904,17 +1709,16 @@ public final class SWF {
if (tag instanceof SymbolClassTag) {
SymbolClassTag sc = (SymbolClassTag) tag;
for (int i = 0; i < sc.classNames.length; i++) {
String newname = deobfuscateNameWithPackage(sc.classNames[i], renameType, deobfuscated);
String newname = deobfuscation.deobfuscateNameWithPackage(sc.classNames[i], deobfuscated, renameType, deobfuscated);
if (newname != null) {
sc.classNames[i] = newname;
}
}
}
}
deobfuscateInstanceNames(renameType, tags, new HashMap<String, String>());
deobfuscation.deobfuscateInstanceNames(deobfuscated, renameType, tags, new HashMap<String, String>());
return deobfuscated.size();
}
HashMap<String, Integer> typeCounts = new HashMap<>();
public int deobfuscateIdentifiers(RenameType renameType) throws InterruptedException {
findFileAttributes();
@@ -1956,7 +1760,7 @@ public final class SWF {
int fc = 0;
for (MyEntry<DirectValueActionItem, ConstantPool> it : allVariableNames) {
String name = it.key.toStringNoH(it.value);
allVariableNamesStr.add(name);
deobfuscation.allVariableNamesStr.add(name);
}
informListeners("rename", "classes");
@@ -1984,7 +1788,12 @@ public final class SWF {
}
}
int staticOperation = Graph.SOP_USE_STATIC; //(Boolean) Configuration.getConfig("autoDeobfuscate", true) ? Graph.SOP_SKIP_STATIC : Graph.SOP_USE_STATIC;
List<GraphTargetItem> dec = Action.actionsToTree(dia.getActions(version), version, staticOperation, ""/*FIXME*/);
List<GraphTargetItem> dec;
try {
dec = Action.actionsToTree(dia.getActions(version), version, staticOperation, ""/*FIXME*/);
} catch (EmptyStackException ex) {
continue;
}
GraphTargetItem name = null;
for (GraphTargetItem it : dec) {
if (it instanceof ClassActionItem) {
@@ -1999,7 +1808,7 @@ public final class SWF {
if (fun.calculatedFunctionName instanceof DirectValueActionItem) {
DirectValueActionItem dvf = (DirectValueActionItem) fun.calculatedFunctionName;
String fname = dvf.toStringNoH(null);
String changed = deobfuscateName(fname, false, "method", renameType, selected);
String changed = deobfuscation.deobfuscateName(fname, false, "method", deobfuscated, renameType, selected);
if (changed != null) {
deobfuscated.put(fname, changed);
}
@@ -2019,7 +1828,7 @@ public final class SWF {
if (gti instanceof DirectValueActionItem) {
DirectValueActionItem dvf = (DirectValueActionItem) gti;
String vname = dvf.toStringNoH(null);
String changed = deobfuscateName(vname, false, "attribute", renameType, selected);
String changed = deobfuscation.deobfuscateName(vname, false, "attribute", deobfuscated, renameType, selected);
if (changed != null) {
deobfuscated.put(vname, changed);
}
@@ -2053,7 +1862,7 @@ public final class SWF {
if (classNameParts != null) {
changedNameStr = classNameParts[classNameParts.length - 1 - pos];
}
String changedNameStr2 = deobfuscateName(changedNameStr, pos == 0, pos == 0 ? "class" : "package", renameType, selected);
String changedNameStr2 = deobfuscation.deobfuscateName(changedNameStr, pos == 0, pos == 0 ? "class" : "package", deobfuscated, renameType, selected);
if (changedNameStr2 != null) {
changedNameStr = changedNameStr2;
}
@@ -2077,7 +1886,7 @@ public final class SWF {
if (classNameParts != null) {
changedNameStr = classNameParts[classNameParts.length - 1 - pos];
}
String changedNameStr2 = deobfuscateName(changedNameStr, pos == 0, pos == 0 ? "class" : "package", renameType, selected);
String changedNameStr2 = deobfuscation.deobfuscateName(changedNameStr, pos == 0, pos == 0 ? "class" : "package", deobfuscated, renameType, selected);
if (changedNameStr2 != null) {
changedNameStr = changedNameStr2;
}
@@ -2098,7 +1907,7 @@ public final class SWF {
if (f.functionName.isEmpty()) { //anonymous function, leave as is
continue;
}
String changed = deobfuscateName(f.functionName, false, "function", renameType, selected);
String changed = deobfuscation.deobfuscateName(f.functionName, false, "function", deobfuscated, renameType, selected);
if (changed != null) {
f.replacedFunctionName = changed;
ret++;
@@ -2109,7 +1918,7 @@ public final class SWF {
if (f.functionName.isEmpty()) { //anonymous function, leave as is
continue;
}
String changed = deobfuscateName(f.functionName, false, "function", renameType, selected);
String changed = deobfuscation.deobfuscateName(f.functionName, false, "function", deobfuscated, renameType, selected);
if (changed != null) {
f.replacedFunctionName = changed;
ret++;
@@ -2132,7 +1941,7 @@ public final class SWF {
for (MyEntry<DirectValueActionItem, ConstantPool> it : allVariableNames) {
vc++;
String name = it.key.toStringNoH(it.value);
String changed = deobfuscateName(name, false, usageTypes.get(it.key), renameType, selected);
String changed = deobfuscation.deobfuscateName(name, false, usageTypes.get(it.key), deobfuscated, renameType, selected);
if (changed != null) {
boolean addNew = false;
String h = System.identityHashCode(it.key) + "_" + name;
@@ -2169,7 +1978,7 @@ public final class SWF {
actionsMap.put(src, Action.removeNops(0, actionsMap.get(src), version, 0, ""/*FIXME path*/));
src.setActions(actionsMap.get(src), version);
}
deobfuscateInstanceNames(renameType, tags, selected);
deobfuscation.deobfuscateInstanceNames(deobfuscated, renameType, tags, selected);
return ret;
}

View File

@@ -604,7 +604,7 @@ public class SWFInputStream extends InputStream {
* @return List of tags
* @throws IOException
*/
public List<Tag> readTagList(SWF swf, int level, boolean parallel) throws IOException {
public List<Tag> readTagList(SWF swf, int level, boolean parallel) throws IOException, InterruptedException {
return readTagList(swf, level, parallel, false);
}
@@ -619,7 +619,7 @@ public class SWFInputStream extends InputStream {
* @return List of tags
* @throws IOException
*/
public List<Tag> readTagList(SWF swf, int level, boolean parallel, boolean skipUnusualTags) throws IOException {
public List<Tag> readTagList(SWF swf, int level, boolean parallel, boolean skipUnusualTags) throws IOException, InterruptedException {
return readTagList(swf, level, parallel, skipUnusualTags, true);
}
@@ -635,11 +635,11 @@ public class SWFInputStream extends InputStream {
* @return List of tags
* @throws IOException
*/
public List<Tag> readTagList(SWF swf, int level, boolean parallel, boolean skipUnusualTags, boolean parseTags) throws IOException {
public List<Tag> readTagList(SWF swf, int level, boolean parallel, boolean skipUnusualTags, boolean parseTags) throws IOException, InterruptedException {
ExecutorService executor = null;
List<Future<Tag>> futureResults = new ArrayList<>();
if (parallel) {
executor = Executors.newFixedThreadPool(20);
executor = Executors.newFixedThreadPool(Configuration.parallelThreadCount.get());
futureResults = new ArrayList<>();
}
List<Tag> tags = new ArrayList<>();
@@ -723,7 +723,9 @@ public class SWFInputStream extends InputStream {
for (Future<Tag> future : futureResults) {
try {
tags.add(future.get());
} catch (InterruptedException | ExecutionException e) {
} catch (InterruptedException ex) {
future.cancel(true);
} catch (ExecutionException e) {
Logger.getLogger(SWFInputStream.class.getName()).log(Level.SEVERE, "Error during tag reading", e);
}
}
@@ -733,7 +735,7 @@ public class SWFInputStream extends InputStream {
return tags;
}
public static Tag resolveTag(SWF swf, Tag tag, int version, int level, boolean parallel, boolean skipUnusualTags) {
public static Tag resolveTag(SWF swf, Tag tag, int version, int level, boolean parallel, boolean skipUnusualTags) throws InterruptedException {
Tag ret;
byte[] data = tag.getData(version);
@@ -1023,7 +1025,7 @@ public class SWFInputStream extends InputStream {
* @return Tag or null when End tag
* @throws IOException
*/
public Tag readTag(SWF swf, int level, long pos, boolean resolve, boolean parallel, boolean skipUnusualTags) throws IOException {
public Tag readTag(SWF swf, int level, long pos, boolean resolve, boolean parallel, boolean skipUnusualTags) throws IOException, InterruptedException {
int tagIDTagLength = readUI16();
int tagID = (tagIDTagLength) >> 6;
if (tagID == 0) {

View File

@@ -50,6 +50,7 @@ import com.jpexs.decompiler.flash.tags.base.ContainerItem;
import com.jpexs.decompiler.flash.tags.base.Exportable;
import com.jpexs.decompiler.graph.ExportMode;
import com.jpexs.decompiler.graph.TranslateException;
import com.jpexs.helpers.CancellableWorker;
import com.jpexs.helpers.Helper;
import java.io.File;
import java.io.FileOutputStream;
@@ -260,7 +261,7 @@ public class TagNode {
public static List<File> exportNodeAS(final List<Tag> allTags, final AbortRetryIgnoreHandler handler, final List<TagNode> nodeList, final String outdir, final ExportMode exportMode, final EventListener ev) throws IOException {
try {
List<File> result = Helper.timedCall(new Callable<List<File>>() {
List<File> result = CancellableWorker.call(new Callable<List<File>>() {
@Override
public List<File> call() throws Exception {

View File

@@ -18,6 +18,7 @@ package com.jpexs.decompiler.flash.abc;
import com.jpexs.decompiler.flash.EventListener;
import com.jpexs.decompiler.flash.abc.avm2.AVM2Code;
import com.jpexs.decompiler.flash.abc.avm2.AVM2Deobfuscation;
import com.jpexs.decompiler.flash.abc.avm2.ConstantPool;
import com.jpexs.decompiler.flash.abc.avm2.UnknownInstructionCode;
import com.jpexs.decompiler.flash.abc.avm2.instructions.AVM2Instruction;
@@ -43,13 +44,10 @@ import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Random;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.regex.Pattern;
public class ABC {
@@ -67,6 +65,7 @@ public class ABC {
public static final int MINORwithDECIMAL = 17;
protected HashSet<EventListener> listeners = new HashSet<>();
private static final Logger logger = Logger.getLogger(ABC.class.getName());
private AVM2Deobfuscation deobfuscation;
public int addMethodBody(MethodBody body) {
bodies = Arrays.copyOf(bodies, bodies.length + 1);
@@ -111,7 +110,7 @@ public class ABC {
return rem;
}
public int removeDeadCode() {
public int removeDeadCode() throws InterruptedException {
int rem = 0;
for (MethodBody body : bodies) {
rem += body.removeDeadCode(constants, null/*FIXME*/, method_info[body.method_info]);
@@ -119,7 +118,7 @@ public class ABC {
return rem;
}
public void restoreControlFlow() {
public void restoreControlFlow() throws InterruptedException {
for (MethodBody body : bodies) {
body.restoreControlFlow(constants, null/*FIXME*/, method_info[body.method_info]);
}
@@ -238,14 +237,14 @@ public class ABC {
for (int i = 0; i < instance_info.length; i++) {
informListeners("deobfuscate", "class " + i + "/" + instance_info.length);
if (instance_info[i].name_index != 0) {
constants.getMultiname(instance_info[i].name_index).name_index = deobfuscateName(stringUsageTypes, stringUsages, namespaceUsages, namesMap, constants.getMultiname(instance_info[i].name_index).name_index, true, renameType);
constants.getMultiname(instance_info[i].name_index).name_index = deobfuscation.deobfuscateName(stringUsageTypes, stringUsages, namespaceUsages, namesMap, constants.getMultiname(instance_info[i].name_index).name_index, true, renameType);
if (constants.getMultiname(instance_info[i].name_index).namespace_index != 0) {
constants.getNamespace(constants.getMultiname(instance_info[i].name_index).namespace_index).name_index =
deobfuscatePackageName(stringUsageTypes, stringUsages, namesMap, constants.getNamespace(constants.getMultiname(instance_info[i].name_index).namespace_index).name_index, renameType);
deobfuscation.deobfuscatePackageName(stringUsageTypes, stringUsages, namesMap, constants.getNamespace(constants.getMultiname(instance_info[i].name_index).namespace_index).name_index, renameType);
}
}
if (instance_info[i].super_index != 0) {
constants.getMultiname(instance_info[i].super_index).name_index = deobfuscateName(stringUsageTypes, stringUsages, namespaceUsages, namesMap, constants.getMultiname(instance_info[i].super_index).name_index, true, renameType);
constants.getMultiname(instance_info[i].super_index).name_index = deobfuscation.deobfuscateName(stringUsageTypes, stringUsages, namespaceUsages, namesMap, constants.getMultiname(instance_info[i].super_index).name_index, true, renameType);
}
}
if (classesOnly) {
@@ -253,14 +252,14 @@ public class ABC {
}
for (int i = 1; i < constants.getMultinameCount(); i++) {
informListeners("deobfuscate", "name " + i + "/" + constants.getMultinameCount());
constants.getMultiname(i).name_index = deobfuscateName(stringUsageTypes, stringUsages, namespaceUsages, namesMap, constants.getMultiname(i).name_index, false, renameType);
constants.getMultiname(i).name_index = deobfuscation.deobfuscateName(stringUsageTypes, stringUsages, namespaceUsages, namesMap, constants.getMultiname(i).name_index, false, renameType);
}
for (int i = 1; i < constants.getNamespaceCount(); i++) {
informListeners("deobfuscate", "namespace " + i + "/" + constants.getNamespaceCount());
if (constants.getNamespace(i).kind != Namespace.KIND_PACKAGE) { //only packages
continue;
}
constants.getNamespace(i).name_index = deobfuscatePackageName(stringUsageTypes, stringUsages, namesMap, constants.getNamespace(i).name_index, renameType);
constants.getNamespace(i).name_index = deobfuscation.deobfuscatePackageName(stringUsageTypes, stringUsages, namesMap, constants.getNamespace(i).name_index, renameType);
}
//process reflection using getDefinitionByName too
@@ -283,11 +282,11 @@ public class ABC {
}
if (!pkg.isEmpty()) {
int pkgStrIndex = constants.getStringId(pkg, true);
pkgStrIndex = deobfuscatePackageName(stringUsageTypes, stringUsages, namesMap, pkgStrIndex, renameType);
pkgStrIndex = deobfuscation.deobfuscatePackageName(stringUsageTypes, stringUsages, namesMap, pkgStrIndex, renameType);
pkg = constants.getString(pkgStrIndex);
}
int nameStrIndex = constants.getStringId(name, true);
nameStrIndex = deobfuscateName(stringUsageTypes, stringUsages, namespaceUsages, namesMap, nameStrIndex, true, renameType);
nameStrIndex = deobfuscation.deobfuscateName(stringUsageTypes, stringUsages, namespaceUsages, namesMap, nameStrIndex, true, renameType);
name = constants.getString(nameStrIndex);
String fullChanged = "";
if (!pkg.isEmpty()) {
@@ -311,6 +310,7 @@ public class ABC {
major_version = ais.readU16();
logger.log(Level.FINE, "ABC minor_version: {0}, major_version: {1}", new Object[]{minor_version, major_version});
constants = new ConstantPool();
deobfuscation = new AVM2Deobfuscation(constants);
//constant integers
int constant_int_pool_count = ais.readU30();
constants.constant_int = new ArrayList<>(constant_int_pool_count);
@@ -738,21 +738,11 @@ public class ABC {
}
}
public String builtInNs(String ns) {
if (ns.equals("http://www.adobe.com/2006/actionscript/flash/proxy")) {
return "flash.utils.flash_proxy";
}
if (ns.equals("http://adobe.com/AS3/2006/builtin")) {
return "-";
}
return null;
}
public String nsValueToName(String value) {
if (namespaceMap.containsKey(value)) {
return namespaceMap.get(value);
} else {
String ns = builtInNs(value);
String ns = deobfuscation.builtInNs(value);
if (ns == null) {
return "";
} else {
@@ -792,198 +782,6 @@ public class ABC {
output.println("MethodBody[" + i + "]:"); //+ bodies[i].toString(this, constants, method_info));
}
}
public static final String[] reservedWords = {
"as", "break", "case", "catch", "class", "const", "continue", "default", "delete", "do", "each", "else",
"extends", "false", "finally", "for", "function", "get", "if", "implements", "import", "in", "instanceof",
"interface", "internal", "is", "native", "new", "null", "override", "package", "private", "protected", "public",
"return", "set", "super", "switch", "this", "throw", "true", "try", "typeof", "use", "var", /*"void",*/ "while",
"with", "dynamic", "default", "final", "in", "static"};
public static final String validFirstCharacters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_";
public static final String validNextCharacters = validFirstCharacters + "0123456789";
public static final String validNsCharacters = ".:$";
public static final String fooCharacters = "bcdfghjklmnpqrstvwz";
public static final String fooJoinCharacters = "aeiouy";
private Random rnd = new Random();
private final int DEFAULT_FOO_SIZE = 10;
private Map<String, Integer> usageTypesCount = new HashMap<>();
private String fooString(HashMap<String, String> deobfuscated, String orig, boolean firstUppercase, int rndSize, String usageType, RenameType renameType) {
boolean exists;
String ret;
int pos = 0;
if (usageType == null) {
usageType = "name";
}
if (usageTypesCount.containsKey(usageType)) {
pos = usageTypesCount.get(usageType);
}
loopfoo:
do {
exists = false;
ret = "";
if (renameType == RenameType.TYPENUMBER) {
pos++;
ret = usageType + "_" + pos;
} else if (renameType == RenameType.RANDOMWORD) {
int len = 3 + rnd.nextInt(rndSize - 3);
for (int i = 0; i < len; i++) {
String c = "";
if ((i % 2) == 0) {
c = "" + fooCharacters.charAt(rnd.nextInt(fooCharacters.length()));
} else {
c = "" + fooJoinCharacters.charAt(rnd.nextInt(fooJoinCharacters.length()));
}
if (i == 0 && firstUppercase) {
c = c.toUpperCase(Locale.ENGLISH);
}
ret += c;
}
}
for (int i = 1; i < constants.getStringCount(); i++) {
if (constants.getString(i).equals(ret)) {
exists = true;
rndSize += 1;
continue loopfoo;
}
}
if (isReserved(ret)) {
exists = true;
rndSize += 1;
continue;
}
if (deobfuscated.containsValue(ret)) {
exists = true;
rndSize += 1;
continue;
}
} while (exists);
usageTypesCount.put(usageType, pos);
deobfuscated.put(orig, ret);
return ret;
}
private boolean isReserved(String s) {
for (String rw : reservedWords) {
if (rw.equals(s.trim())) {
return true;
}
}
return false;
}
private boolean isValidNSPart(String s) {
boolean isValid = true;
if (isReserved(s)) {
isValid = false;
}
if (isValid) {
for (int i = 0; i < s.length(); i++) {
if (s.charAt(i) > 127) {
isValid = false;
break;
}
}
}
if (isValid) {
Pattern pat = Pattern.compile("^([" + Pattern.quote(validFirstCharacters) + "]" + "[" + Pattern.quote(validFirstCharacters + validNextCharacters + validNsCharacters) + "]*)*$");
if (!pat.matcher(s).matches()) {
isValid = false;
}
}
return isValid;
}
public int deobfuscatePackageName(Map<Integer, String> stringUsageTypes, Set<Integer> stringUsages, HashMap<String, String> namesMap, int strIndex, RenameType renameType) {
if (strIndex <= 0) {
return strIndex;
}
String s = constants.getString(strIndex);
if (builtInNs(s) != null) {
return strIndex;
}
boolean isValid = isValidNSPart(s);
if (!isValid) {
String newName;
if (namesMap.containsKey(s)) {
newName = constants.setString(strIndex, namesMap.get(s));
} else {
String[] parts = null;
if (s.contains(".")) {
parts = s.split("\\.");
} else {
parts = new String[]{s};
}
String ret = "";
for (int p = 0; p < parts.length; p++) {
if (p > 0) {
ret += ".";
}
if (!isValidNSPart(parts[p])) {
ret += fooString(namesMap, parts[p], false, DEFAULT_FOO_SIZE, "package", renameType);
} else {
ret += parts[p];
}
}
newName = ret;
namesMap.put(s, newName);
}
if (stringUsages.contains(strIndex)) {
strIndex = constants.addString(newName);
} else {
constants.setString(strIndex, newName);
}
}
return strIndex;
}
public int deobfuscateName(Map<Integer, String> stringUsageTypes, Set<Integer> stringUsages, Set<Integer> namespaceUsages, HashMap<String, String> namesMap, int strIndex, boolean firstUppercase, RenameType renameType) {
if (strIndex <= 0) {
return strIndex;
}
String s = constants.getString(strIndex);
boolean isValid = true;
if (isReserved(s)) {
isValid = false;
}
if (isValid) {
for (int i = 0; i < s.length(); i++) {
if (s.charAt(i) > 127) {
isValid = false;
break;
}
}
}
if (isValid) {
Pattern pat = Pattern.compile("^[" + Pattern.quote(validFirstCharacters) + "]" + "[" + Pattern.quote(validFirstCharacters + validNextCharacters) + "]*$");
if (!pat.matcher(s).matches()) {
isValid = false;
}
}
if (!isValid) {
String newname;
if (namesMap.containsKey(s)) {
newname = namesMap.get(s);
} else {
newname = fooString(namesMap, constants.getString(strIndex), firstUppercase, DEFAULT_FOO_SIZE, stringUsageTypes.get(strIndex), renameType);
}
if (stringUsages.contains(strIndex) || namespaceUsages.contains(strIndex)) { //this name is already referenced as String
strIndex = constants.addString(s); //add new index
}
constants.setString(strIndex, newname);
if (!namesMap.containsKey(s)) {
namesMap.put(s, constants.getString(strIndex));
}
}
return strIndex;
}
private void checkMultinameUsedInMethod(int multinameIndex, int methodInfo, List<MultinameUsage> ret, int classIndex, int traitIndex, boolean isStatic, boolean isInitializer, Traits traits, int parentTraitIndex) {
for (int p = 0; p < method_info[methodInfo].param_types.length; p++) {

View File

@@ -26,6 +26,7 @@ import com.jpexs.decompiler.flash.helpers.GraphTextWriter;
import com.jpexs.decompiler.flash.helpers.NulWriter;
import com.jpexs.decompiler.flash.tags.ABCContainerTag;
import com.jpexs.decompiler.graph.ExportMode;
import com.jpexs.helpers.CancellableWorker;
import com.jpexs.helpers.Helper;
import java.io.File;
import java.io.FileOutputStream;
@@ -143,7 +144,7 @@ public class ScriptPack {
public void toSource(GraphTextWriter writer, final List<ABCContainerTag> abcList, final Trait[] traits, final ExportMode exportMode, final boolean parallel) throws InterruptedException {
writer.suspendMeasure();
try {
Helper.timedCall(new Callable<Void>() {
CancellableWorker.call(new Callable<Void>() {
@Override
public Void call() throws Exception {
convert(new NulWriter(), abcList, traits, exportMode, parallel);
@@ -159,7 +160,7 @@ public class ScriptPack {
writer.appendNoHilight(" */").newLine();
writer.appendNoHilight("throw new IllegalOperationError(\"Not decompiled due to timeout\");").newLine();
return;
} catch (InterruptedException | ExecutionException ex) {
} catch (ExecutionException ex) {
writer.continueMeasure();
Logger.getLogger(MethodBody.class.getName()).log(Level.SEVERE, "Decompilation error", ex);
writer.appendNoHilight("/*").newLine();

View File

@@ -1796,7 +1796,10 @@ public class AVM2Code implements Serializable {
return stats;
}
private void visitCode(int ip, int lastIp, HashMap<Integer, List<Integer>> refs) {
private void visitCode(int ip, int lastIp, HashMap<Integer, List<Integer>> refs) throws InterruptedException {
if (Thread.currentThread().isInterrupted()) {
throw new InterruptedException();
}
while (ip < code.size()) {
if (!refs.containsKey(ip)) {
refs.put(ip, new ArrayList<Integer>());
@@ -1844,7 +1847,7 @@ public class AVM2Code implements Serializable {
};
}
public HashMap<Integer, List<Integer>> visitCode(MethodBody body) {
public HashMap<Integer, List<Integer>> visitCode(MethodBody body) throws InterruptedException {
HashMap<Integer, List<Integer>> refs = new HashMap<>();
for (int i = 0; i < code.size(); i++) {
refs.put(i, new ArrayList<Integer>());
@@ -2078,7 +2081,7 @@ public class AVM2Code implements Serializable {
}
private void restoreControlFlowPass(ConstantPool constants, Trait trait, MethodInfo info, MethodBody body, boolean secondpass) {
private void restoreControlFlowPass(ConstantPool constants, Trait trait, MethodInfo info, MethodBody body, boolean secondpass) throws InterruptedException {
try {
HashMap<Integer, List<Integer>> refs;
int[] visited2 = new int[code.size()];
@@ -2134,7 +2137,7 @@ public class AVM2Code implements Serializable {
removeDeadCode(constants, trait, info, body);
}
public void restoreControlFlow(ConstantPool constants, Trait trait, MethodInfo info, MethodBody body) {
public void restoreControlFlow(ConstantPool constants, Trait trait, MethodInfo info, MethodBody body) throws InterruptedException {
restoreControlFlowPass(constants, trait, info, body, false);
//restoreControlFlowPass(constants, body, true);
}
@@ -2146,7 +2149,7 @@ public class AVM2Code implements Serializable {
}
}
}*/
public void removeIgnored(ConstantPool constants, Trait trait, MethodInfo info, MethodBody body) {
public void removeIgnored(ConstantPool constants, Trait trait, MethodInfo info, MethodBody body) throws InterruptedException {
try {
List<Integer> outputMap = new ArrayList<>();
HilightedTextWriter writer = new HilightedTextWriter(false);
@@ -2170,7 +2173,7 @@ public class AVM2Code implements Serializable {
invalidateCache();
}
public int removeDeadCode(ConstantPool constants, Trait trait, MethodInfo info, MethodBody body) {
public int removeDeadCode(ConstantPool constants, Trait trait, MethodInfo info, MethodBody body) throws InterruptedException {
HashMap<Integer, List<Integer>> refs = visitCode(body);
int cnt = 0;
@@ -2377,7 +2380,7 @@ public class AVM2Code implements Serializable {
@SuppressWarnings("unchecked")
private static int removeTraps(HashMap<Integer, List<Integer>> refs, boolean secondPass, boolean indeterminate, List<Object> localData, Stack<GraphTargetItem> stack, List<GraphTargetItem> output, AVM2GraphSource code, int ip, HashMap<Integer, Integer> visited, HashMap<Integer, HashMap<Integer, GraphTargetItem>> visitedStates, HashMap<AVM2Instruction, Decision> decisions, String path, int recursionLevel) throws InterruptedException {
if (Thread.interrupted()) {
if (Thread.currentThread().isInterrupted()) {
throw new InterruptedException();
}
if (recursionLevel > code.size() + 1) {

View File

@@ -0,0 +1,243 @@
/*
* Copyright (C) 2010-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 <http://www.gnu.org/licenses/>.
*/
package com.jpexs.decompiler.flash.abc.avm2;
import com.jpexs.decompiler.flash.abc.RenameType;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
import java.util.Random;
import java.util.Set;
import java.util.regex.Pattern;
/**
*
* @author JPEXS
*/
public class AVM2Deobfuscation {
private static Random rnd = new Random();
private static final int DEFAULT_FOO_SIZE = 10;
public static final String[] reservedWords = {
"as", "break", "case", "catch", "class", "const", "continue", "default", "delete", "do", "each", "else",
"extends", "false", "finally", "for", "function", "get", "if", "implements", "import", "in", "instanceof",
"interface", "internal", "is", "native", "new", "null", "override", "package", "private", "protected", "public",
"return", "set", "super", "switch", "this", "throw", "true", "try", "typeof", "use", "var", /*"void",*/ "while",
"with", "dynamic", "default", "final", "in", "static"};
public static final String validFirstCharacters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_";
public static final String validNextCharacters = validFirstCharacters + "0123456789";
public static final String validNsCharacters = ".:$";
public static final String fooCharacters = "bcdfghjklmnpqrstvwz";
public static final String fooJoinCharacters = "aeiouy";
private ConstantPool constants;
private Map<String, Integer> usageTypesCount = new HashMap<>();
public AVM2Deobfuscation(ConstantPool constants) {
this.constants = constants;
}
private static boolean isReserved(String s) {
for (String rw : reservedWords) {
if (rw.equals(s.trim())) {
return true;
}
}
return false;
}
private boolean isValidNSPart(String s) {
boolean isValid = true;
if (isReserved(s)) {
isValid = false;
}
if (isValid) {
for (int i = 0; i < s.length(); i++) {
if (s.charAt(i) > 127) {
isValid = false;
break;
}
}
}
if (isValid) {
Pattern pat = Pattern.compile("^([" + Pattern.quote(validFirstCharacters) + "]" + "[" + Pattern.quote(validFirstCharacters + validNextCharacters + validNsCharacters) + "]*)*$");
if (!pat.matcher(s).matches()) {
isValid = false;
}
}
return isValid;
}
public String builtInNs(String ns) {
if (ns.equals("http://www.adobe.com/2006/actionscript/flash/proxy")) {
return "flash.utils.flash_proxy";
}
if (ns.equals("http://adobe.com/AS3/2006/builtin")) {
return "-";
}
return null;
}
private String fooString(HashMap<String, String> deobfuscated, String orig, boolean firstUppercase, int rndSize, String usageType, RenameType renameType) {
boolean exists;
String ret;
int pos = 0;
if (usageType == null) {
usageType = "name";
}
if (usageTypesCount.containsKey(usageType)) {
pos = usageTypesCount.get(usageType);
}
loopfoo:
do {
exists = false;
ret = "";
if (renameType == RenameType.TYPENUMBER) {
pos++;
ret = usageType + "_" + pos;
} else if (renameType == RenameType.RANDOMWORD) {
int len = 3 + rnd.nextInt(rndSize - 3);
for (int i = 0; i < len; i++) {
String c = "";
if ((i % 2) == 0) {
c = "" + fooCharacters.charAt(rnd.nextInt(fooCharacters.length()));
} else {
c = "" + fooJoinCharacters.charAt(rnd.nextInt(fooJoinCharacters.length()));
}
if (i == 0 && firstUppercase) {
c = c.toUpperCase(Locale.ENGLISH);
}
ret += c;
}
}
for (int i = 1; i < constants.getStringCount(); i++) {
if (constants.getString(i).equals(ret)) {
exists = true;
rndSize += 1;
continue loopfoo;
}
}
if (isReserved(ret)) {
exists = true;
rndSize += 1;
continue;
}
if (deobfuscated.containsValue(ret)) {
exists = true;
rndSize += 1;
continue;
}
} while (exists);
usageTypesCount.put(usageType, pos);
deobfuscated.put(orig, ret);
return ret;
}
public int deobfuscatePackageName(Map<Integer, String> stringUsageTypes, Set<Integer> stringUsages, HashMap<String, String> namesMap, int strIndex, RenameType renameType) {
if (strIndex <= 0) {
return strIndex;
}
String s = constants.getString(strIndex);
if (builtInNs(s) != null) {
return strIndex;
}
boolean isValid = isValidNSPart(s);
if (!isValid) {
String newName;
if (namesMap.containsKey(s)) {
newName = constants.setString(strIndex, namesMap.get(s));
} else {
String[] parts = null;
if (s.contains(".")) {
parts = s.split("\\.");
} else {
parts = new String[]{s};
}
String ret = "";
for (int p = 0; p < parts.length; p++) {
if (p > 0) {
ret += ".";
}
if (!isValidNSPart(parts[p])) {
ret += fooString(namesMap, parts[p], false, DEFAULT_FOO_SIZE, "package", renameType);
} else {
ret += parts[p];
}
}
newName = ret;
namesMap.put(s, newName);
}
if (stringUsages.contains(strIndex)) {
strIndex = constants.addString(newName);
} else {
constants.setString(strIndex, newName);
}
}
return strIndex;
}
public int deobfuscateName(Map<Integer, String> stringUsageTypes, Set<Integer> stringUsages, Set<Integer> namespaceUsages, HashMap<String, String> namesMap, int strIndex, boolean firstUppercase, RenameType renameType) {
if (strIndex <= 0) {
return strIndex;
}
String s = constants.getString(strIndex);
boolean isValid = true;
if (isReserved(s)) {
isValid = false;
}
if (isValid) {
for (int i = 0; i < s.length(); i++) {
if (s.charAt(i) > 127) {
isValid = false;
break;
}
}
}
if (isValid) {
Pattern pat = Pattern.compile("^[" + Pattern.quote(validFirstCharacters) + "]" + "[" + Pattern.quote(validFirstCharacters + validNextCharacters) + "]*$");
if (!pat.matcher(s).matches()) {
isValid = false;
}
}
if (!isValid) {
String newname;
if (namesMap.containsKey(s)) {
newname = namesMap.get(s);
} else {
newname = fooString(namesMap, constants.getString(strIndex), firstUppercase, DEFAULT_FOO_SIZE, stringUsageTypes.get(strIndex), renameType);
}
if (stringUsages.contains(strIndex) || namespaceUsages.contains(strIndex)) { //this name is already referenced as String
strIndex = constants.addString(s); //add new index
}
constants.setString(strIndex, newname);
if (!namesMap.containsKey(s)) {
namesMap.put(s, constants.getString(strIndex));
}
}
return strIndex;
}
}

View File

@@ -7,7 +7,6 @@ import com.jpexs.decompiler.flash.abc.avm2.instructions.AVM2Instruction;
import com.jpexs.decompiler.flash.abc.types.MethodBody;
import com.jpexs.decompiler.graph.GraphPart;
import com.jpexs.decompiler.graph.GraphSource;
import com.jpexs.decompiler.graph.GraphSourceItem;
import com.jpexs.decompiler.graph.GraphTargetItem;
import java.util.ArrayList;
import java.util.HashMap;

View File

@@ -73,7 +73,7 @@ public class ASM3Parser {
}
}
public static AVM2Code parse(Reader reader, ConstantPool constants, Trait trait, MethodBody body, MethodInfo info) throws IOException, ParseException {
public static AVM2Code parse(Reader reader, ConstantPool constants, Trait trait, MethodBody body, MethodInfo info) throws IOException, ParseException, InterruptedException {
return parse(reader, constants, trait, null, body, info);
}
@@ -473,7 +473,7 @@ public class ASM3Parser {
return new ValueKind(value_index, value_kind);
}
public static AVM2Code parse(Reader reader, ConstantPool constants, Trait trait, MissingSymbolHandler missingHandler, MethodBody body, MethodInfo info) throws IOException, ParseException {
public static AVM2Code parse(Reader reader, ConstantPool constants, Trait trait, MissingSymbolHandler missingHandler, MethodBody body, MethodInfo info) throws IOException, ParseException, InterruptedException {
AVM2Code code = new AVM2Code();
List<OffsetItem> offsetItems = new ArrayList<>();
@@ -909,6 +909,9 @@ public class ASM3Parser {
for (OffsetItem oi : offsetItems) {
for (LabelItem li : labelItems) {
if (Thread.currentThread().isInterrupted()) {
throw new InterruptedException();
}
if (oi.label.equals(li.label)) {
AVM2Instruction ins = code.code.get((int) oi.insPosition);
int relOffset;

View File

@@ -30,6 +30,7 @@ import com.jpexs.decompiler.graph.ExportMode;
import com.jpexs.decompiler.graph.Graph;
import com.jpexs.decompiler.graph.GraphTargetItem;
import com.jpexs.decompiler.graph.model.LocalData;
import com.jpexs.helpers.CancellableWorker;
import com.jpexs.helpers.Helper;
import java.io.Serializable;
import java.util.ArrayList;
@@ -76,11 +77,11 @@ public class MethodBody implements Cloneable, Serializable {
return s;
}
public int removeDeadCode(ConstantPool constants, Trait trait, MethodInfo info) {
public int removeDeadCode(ConstantPool constants, Trait trait, MethodInfo info) throws InterruptedException {
return code.removeDeadCode(constants, trait, info, this);
}
public void restoreControlFlow(ConstantPool constants, Trait trait, MethodInfo info) {
public void restoreControlFlow(ConstantPool constants, Trait trait, MethodInfo info) throws InterruptedException {
code.restoreControlFlow(constants, trait, info, this);
}
@@ -139,7 +140,7 @@ public class MethodBody implements Cloneable, Serializable {
}
};
if (firstLevel) {
Helper.timedCall(callable, timeout, TimeUnit.SECONDS);
CancellableWorker.call(callable, timeout, TimeUnit.SECONDS);
} else {
callable.call();
}

View File

@@ -437,12 +437,12 @@ public class TraitClass extends Trait implements TraitWithSlot {
int bodyIndex = abc.findBodyIndex(abc.class_info[class_info].cinit_index);
if (bodyIndex != -1) {
if (!classInitializerIsEmpty) {
writer.newLine();
writer.startTrait(abc.class_info[class_info].static_traits.traits.length + abc.instance_info[class_info].instance_traits.traits.length + 1);
writer.appendNoHilight("{").newLine();
abc.bodies[bodyIndex].toString(path +/*packageName +*/ "/" + abc.instance_info[class_info].getName(abc.constants).getName(abc.constants, fullyQualifiedNames) + ".staticinitializer", exportMode, true, scriptIndex, class_info, abc, this, abc.constants, abc.method_info, new Stack<GraphTargetItem>(), true, writer, fullyQualifiedNames, abc.class_info[class_info].static_traits);
writer.appendNoHilight("}").newLine();
writer.endTrait();
writer.newLine();
}
} else {
//"/*classInitializer*/";
@@ -465,6 +465,7 @@ public class TraitClass extends Trait implements TraitWithSlot {
}
}
writer.newLine();
writer.startTrait(abc.class_info[class_info].static_traits.traits.length + abc.instance_info[class_info].instance_traits.traits.length);
writer.appendNoHilight(modifier);
writer.appendNoHilight("function ");
@@ -482,7 +483,6 @@ public class TraitClass extends Trait implements TraitWithSlot {
}
writer.appendNoHilight("}").newLine();
writer.endTrait();
writer.newLine();
}
//static variables,constants & methods

View File

@@ -17,6 +17,7 @@
package com.jpexs.decompiler.flash.abc.types.traits;
import com.jpexs.decompiler.flash.abc.ABC;
import com.jpexs.decompiler.flash.configuration.Configuration;
import com.jpexs.decompiler.flash.helpers.GraphTextWriter;
import com.jpexs.decompiler.flash.helpers.NulWriter;
import com.jpexs.decompiler.flash.tags.ABCContainerTag;
@@ -121,9 +122,7 @@ public class Traits implements Serializable {
public GraphTextWriter toString(Trait parent, String path, List<ABCContainerTag> abcTags, ABC abc, boolean isStatic, ExportMode exportMode, boolean makePackages, int scriptIndex, int classIndex, GraphTextWriter writer, List<String> fullyQualifiedNames, boolean parallel) throws InterruptedException {
for (int t = 0; t < traits.length; t++) {
if (t > 0) {
writer.newLine();
}
writer.newLine();
Trait trait = traits[t];
int h = t;
if (classIndex != -1) {
@@ -157,7 +156,7 @@ public class Traits implements Serializable {
task.call();
}
} else {
ExecutorService executor = Executors.newFixedThreadPool(20);
ExecutorService executor = Executors.newFixedThreadPool(Configuration.parallelThreadCount.get());
List<Future<Void>> futureResults = null;
futureResults = new ArrayList<>();
@@ -170,7 +169,10 @@ public class Traits implements Serializable {
for (int f = 0; f < futureResults.size(); f++) {
try {
futureResults.get(f).get();
} catch (InterruptedException | ExecutionException ex) {
} catch (InterruptedException ex) {
executor.shutdownNow();
throw ex;
} catch (ExecutionException ex) {
Logger.getLogger(Traits.class.getName()).log(Level.SEVERE, "Error during traits converting", ex);
}
}

View File

@@ -64,6 +64,7 @@ import com.jpexs.decompiler.graph.model.IfItem;
import com.jpexs.decompiler.graph.model.LocalData;
import com.jpexs.decompiler.graph.model.NotItem;
import com.jpexs.decompiler.graph.model.ScriptEndItem;
import com.jpexs.helpers.CancellableWorker;
import com.jpexs.helpers.Helper;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
@@ -705,7 +706,7 @@ public class Action implements GraphSourceItem {
Throwable convertException = null;
int timeout = Configuration.decompilationTimeoutSingleMethod.get();
try {
tree = Helper.timedCall(new Callable<List<GraphTargetItem>>() {
tree = CancellableWorker.call(new Callable<List<GraphTargetItem>>() {
@Override
public List<GraphTargetItem> call() throws Exception {
int staticOperation = Graph.SOP_USE_STATIC; //(Boolean) Configuration.getConfig("autoDeobfuscate", true) ? Graph.SOP_SKIP_STATIC : Graph.SOP_USE_STATIC;
@@ -714,7 +715,7 @@ public class Action implements GraphSourceItem {
return tree;
}
}, timeout, TimeUnit.SECONDS);
} catch (InterruptedException | TimeoutException | ExecutionException | OutOfMemoryError | TranslateException | StackOverflowError ex) {
} catch (TimeoutException | ExecutionException | OutOfMemoryError | TranslateException | StackOverflowError ex) {
Logger.getLogger(Action.class.getName()).log(Level.SEVERE, "Decompilation error", ex);
convertException = ex;
if (ex instanceof ExecutionException && ex.getCause() instanceof Exception) {

View File

@@ -0,0 +1,252 @@
/*
* Copyright (C) 2010-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 <http://www.gnu.org/licenses/>.
*/
package com.jpexs.decompiler.flash.action;
import com.jpexs.decompiler.flash.abc.RenameType;
import com.jpexs.decompiler.flash.tags.DefineSpriteTag;
import com.jpexs.decompiler.flash.tags.Tag;
import com.jpexs.decompiler.flash.tags.base.PlaceObjectTypeTag;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Random;
import java.util.regex.Pattern;
/**
*
* @author JPEXS
*/
public class ActionDeobfuscation {
private Random rnd = new Random();
private final int DEFAULT_FOO_SIZE = 10;
public HashSet<String> allVariableNamesStr = new HashSet<>();
private HashMap<String, Integer> typeCounts = new HashMap<>();
public static final String[] reservedWords = {
"as", "break", "case", "catch", "class", "const", "continue", "default", "delete", "do", "each", "else",
"extends", "false", "finally", "for", "function", "get", "if", "implements", "import", "in", "instanceof",
"interface", "internal", "is", "native", "new", "null", "override", "package", "private", "protected", "public",
"return", "set", "super", "switch", "this", "throw", "true", "try", "typeof", "use", "var", /*"void",*/ "while",
"with", "dynamic", "default", "final", "in"};
public static final String validFirstCharacters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_";
public static final String validNextCharacters = validFirstCharacters + "0123456789";
public static final String fooCharacters = "bcdfghjklmnpqrstvwz";
public static final String fooJoinCharacters = "aeiouy";
private boolean isReserved(String s) {
for (String rw : reservedWords) {
if (rw.equals(s.trim())) {
return true;
}
}
return false;
}
private String fooString(HashMap<String, String> deobfuscated, String orig, boolean firstUppercase, int rndSize) {
boolean exists;
String ret;
loopfoo:
do {
exists = false;
int len = 3 + rnd.nextInt(rndSize - 3);
ret = "";
for (int i = 0; i < len; i++) {
String c = "";
if ((i % 2) == 0) {
c = "" + fooCharacters.charAt(rnd.nextInt(fooCharacters.length()));
} else {
c = "" + fooJoinCharacters.charAt(rnd.nextInt(fooJoinCharacters.length()));
}
if (i == 0 && firstUppercase) {
c = c.toUpperCase(Locale.ENGLISH);
}
ret += c;
}
if (allVariableNamesStr.contains(ret)) {
exists = true;
rndSize += 1;
continue loopfoo;
}
if (isReserved(ret)) {
exists = true;
rndSize += 1;
continue;
}
if (deobfuscated.containsValue(ret)) {
exists = true;
rndSize += 1;
continue;
}
} while (exists);
return ret;
}
public void deobfuscateInstanceNames(HashMap<String, String> namesMap, RenameType renameType, List<Tag> tags, Map<String, String> selected) {
for (Tag t : tags) {
if (t instanceof DefineSpriteTag) {
deobfuscateInstanceNames(namesMap, renameType, ((DefineSpriteTag) t).subTags, selected);
}
if (t instanceof PlaceObjectTypeTag) {
PlaceObjectTypeTag po = (PlaceObjectTypeTag) t;
String name = po.getInstanceName();
if (name != null) {
String changedName = deobfuscateName(name, false, "instance", namesMap, renameType, selected);
if (changedName != null) {
po.setInstanceName(changedName);
}
}
String className = po.getClassName();
if (className != null) {
String changedClassName = deobfuscateNameWithPackage(className, namesMap, renameType, selected);
if (changedClassName != null) {
po.setClassName(changedClassName);
}
}
}
}
}
public String deobfuscatePackage(String pkg, HashMap<String, String> namesMap, RenameType renameType, Map<String, String> selected) {
if (namesMap.containsKey(pkg)) {
return namesMap.get(pkg);
}
String[] parts = null;
if (pkg.contains(".")) {
parts = pkg.split("\\.");
} else {
parts = new String[]{pkg};
}
String ret = "";
boolean isChanged = false;
for (int p = 0; p < parts.length; p++) {
if (p > 0) {
ret += ".";
}
String partChanged = deobfuscateName(parts[p], false, "package", namesMap, renameType, selected);
if (partChanged != null) {
ret += partChanged;
isChanged = true;
} else {
ret += parts[p];
}
}
if (isChanged) {
namesMap.put(pkg, ret);
return ret;
}
return null;
}
public String deobfuscateNameWithPackage(String n, HashMap<String, String> namesMap, RenameType renameType, Map<String, String> selected) {
String pkg = null;
String name = "";
if (n.contains(".")) {
pkg = n.substring(0, n.lastIndexOf('.'));
name = n.substring(n.lastIndexOf('.') + 1);
} else {
name = n;
}
boolean changed = false;
if ((pkg != null) && (!pkg.isEmpty())) {
String changedPkg = deobfuscatePackage(pkg, namesMap, renameType, selected);
if (changedPkg != null) {
changed = true;
pkg = changedPkg;
}
}
String changedName = deobfuscateName(name, true, "class", namesMap, renameType, selected);
if (changedName != null) {
changed = true;
name = changedName;
}
if (changed) {
String newClassName = "";
if (pkg == null) {
newClassName = name;
} else {
newClassName = pkg + "." + name;
}
return newClassName;
}
return null;
}
public String deobfuscateName(String s, boolean firstUppercase, String usageType, HashMap<String, String> namesMap, RenameType renameType, Map<String, String> selected) {
boolean isValid = true;
if (usageType == null) {
usageType = "name";
}
if (selected != null) {
if (selected.containsKey(s)) {
return selected.get(s);
}
}
if (isReserved(s)) {
isValid = false;
}
if (isValid) {
for (int i = 0; i < s.length(); i++) {
if (s.charAt(i) > 127) {
isValid = false;
break;
}
}
}
if (isValid) {
Pattern pat = Pattern.compile("^[" + Pattern.quote(validFirstCharacters) + "]" + "[" + Pattern.quote(validFirstCharacters + validNextCharacters) + "]*$");
if (!pat.matcher(s).matches()) {
isValid = false;
}
}
if (!isValid) {
if (namesMap.containsKey(s)) {
return namesMap.get(s);
} else {
Integer cnt = typeCounts.get(usageType);
if (cnt == null) {
cnt = 0;
}
String ret = null;
if (renameType == RenameType.TYPENUMBER) {
boolean found;
do {
found = false;
cnt++;
ret = usageType + "_" + cnt;
found = allVariableNamesStr.contains(ret);
} while (found);
typeCounts.put(usageType, cnt);
} else if (renameType == RenameType.RANDOMWORD) {
ret = fooString(namesMap, s, firstUppercase, DEFAULT_FOO_SIZE);
}
namesMap.put(s, ret);
return ret;
}
}
return null;
}
}

View File

@@ -43,6 +43,7 @@ import com.jpexs.decompiler.graph.GraphTargetItem;
import com.jpexs.decompiler.graph.NotCompileTimeItem;
import com.jpexs.decompiler.graph.TranslateException;
import com.jpexs.decompiler.graph.model.LocalData;
import com.jpexs.helpers.CancellableWorker;
import com.jpexs.helpers.Helper;
import com.jpexs.helpers.MemoryInputStream;
import java.io.IOException;
@@ -54,6 +55,10 @@ import java.util.Map;
import java.util.Queue;
import java.util.Scanner;
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;
@@ -80,7 +85,41 @@ public class ActionListReader {
* @return List of actions
* @throws IOException
*/
public static List<Action> readActionList(List<DisassemblyListener> listeners, long containerSWFOffset, MemoryInputStream mis, int version, int ip, int endIp, String path) throws IOException {
public static List<Action> readActionListTimeout(final List<DisassemblyListener> listeners, final long containerSWFOffset, final MemoryInputStream mis, final int version, final int ip, final int endIp, final String path) throws IOException, InterruptedException, TimeoutException {
try {
return CancellableWorker.call(new Callable<List<Action>>() {
@Override
public List<Action> call() throws IOException, InterruptedException {
return readActionList(listeners, containerSWFOffset, mis, version, ip, endIp, path);
}
}, Configuration.decompilationTimeoutSingleMethod.get(), TimeUnit.SECONDS);
} catch (ExecutionException ex) {
Throwable cause = ex.getCause();
if (cause instanceof InterruptedException) {
throw (InterruptedException) cause;
} else if (cause instanceof InterruptedException) {
throw (IOException) cause;
} else {
Logger.getLogger(ActionListReader.class.getName()).log(Level.SEVERE, null, ex);
}
}
return null;
}
/**
* Reads list of actions from the stream. Reading ends with
* ActionEndFlag(=0) or end of the stream.
* @param listeners
* @param containerSWFOffset
* @param mis
* @param version
* @param ip
* @param endIp
* @param path
* @return List of actions
* @throws IOException
*/
public static List<Action> readActionList(List<DisassemblyListener> listeners, long containerSWFOffset, MemoryInputStream mis, int version, int ip, int endIp, String path) throws IOException, InterruptedException {
boolean deobfuscate = Configuration.autoDeobfuscate.get();
ConstantPool cpool = new ConstantPool();
@@ -151,11 +190,7 @@ public class ActionListReader {
if (deobfuscate) {
try {
try {
actions = deobfuscateActionList(listeners, containerSWFOffset, actions, version, ip, path);
} catch (InterruptedException ex) {
Logger.getLogger(ActionListReader.class.getName()).log(Level.SEVERE, null, ex);
}
actions = deobfuscateActionList(listeners, containerSWFOffset, actions, version, ip, path);
updateActionLengths(actions, version);
removeZeroJumps(actions, version);
} catch (TranslateException ex) {
@@ -680,6 +715,10 @@ public class ActionListReader {
Scanner sc = new Scanner(System.in);
loopip:
while (((endip == -1) || (endip > ip)) && (a = actions.get(pos)) != null) {
if (Thread.currentThread().isInterrupted()) {
throw new InterruptedException();
}
int actionLen = getTotalActionLength(a);
pos += actionLen;
if (!visited.containsKey(ip)) {

View File

@@ -53,6 +53,8 @@ public class Configuration {
public static final ConfigurationItem<Boolean> decompile = null;
@ConfigurationDefaultBoolean(true)
public static final ConfigurationItem<Boolean> parallelSpeedUp = null;
@ConfigurationDefaultInt(20)
public static final ConfigurationItem<Integer> parallelThreadCount = null;
@ConfigurationDefaultBoolean(true)
public static final ConfigurationItem<Boolean> autoDeobfuscate = null;
@ConfigurationDefaultBoolean(true)

View File

@@ -94,6 +94,10 @@ public class CommandLineArgumentParser {
System.out.println(" ...error handling mode. \"abort\" stops the exporting, \"retry\" tries the exporting N times, \"ignore\" ignores the current file");
System.out.println(" 11) -timeout N");
System.out.println(" ...decompilation timeout for a single method in AS3 or single action in AS1/2 in seconds");
System.out.println(" 12) -exportTimeout N");
System.out.println(" ...total export timeout in seconds");
System.out.println(" 13) -exportFileTimeout N");
System.out.println(" ...export timeout for a single AS3 class in seconds");
System.out.println();
System.out.println("Examples:");
System.out.println("java -jar ffdec.jar myfile.swf");
@@ -125,6 +129,9 @@ public class CommandLineArgumentParser {
OUTER:
while (true) {
nextParam = args.remove();
if (nextParam != null) {
nextParam = nextParam.toLowerCase();
}
switch (nextParam) {
case "-config":
parseConfig(args);
@@ -140,6 +147,12 @@ public class CommandLineArgumentParser {
case "-timeout":
parseTimeout(args);
break;
case "-exporttimeout":
parseExportTimeout(args);
break;
case "-exportfiletimeout":
parseExportFileTimeout(args);
break;
case "-affinity":
parseAffinity(args);
break;
@@ -320,6 +333,32 @@ public class CommandLineArgumentParser {
}
}
private static void parseExportTimeout(Queue<String> args) {
if (args.isEmpty()) {
System.err.println("timeout parameter expected");
badArguments();
}
try {
int timeout = Integer.parseInt(args.remove());
Configuration.exportTimeout.set(timeout);
} catch (NumberFormatException nex) {
System.err.println("Bad timeout value");
}
}
private static void parseExportFileTimeout(Queue<String> args) {
if (args.isEmpty()) {
System.err.println("timeout parameter expected");
badArguments();
}
try {
int timeout = Integer.parseInt(args.remove());
Configuration.decompilationTimeoutFile.set(timeout);
} catch (NumberFormatException nex) {
System.err.println("Bad timeout value");
}
}
private static void parseAffinity(Queue<String> args) {
if (Platform.isWindows()) {
if (args.isEmpty()) {

View File

@@ -27,6 +27,7 @@ import com.jpexs.decompiler.flash.console.ContextMenuTools;
import com.jpexs.decompiler.flash.gui.player.FlashPlayerPanel;
import com.jpexs.decompiler.flash.gui.proxy.ProxyFrame;
import com.jpexs.helpers.Cache;
import com.jpexs.helpers.CancellableWorker;
import com.jpexs.helpers.Helper;
import com.jpexs.helpers.ProgressListener;
import com.jpexs.helpers.streams.SeekableInputStream;
@@ -151,17 +152,17 @@ public class Main {
startWork(name, percent, null);
}
public static void startWork(String name, Runnable cancelCallback) {
startWork(name, -1, cancelCallback);
public static void startWork(String name, CancellableWorker worker) {
startWork(name, -1, worker);
}
public static void startWork(final String name, final int percent, final Runnable cancelCallback) {
public static void startWork(final String name, final int percent, final CancellableWorker worker) {
working = true;
View.execInEventDispatchLater(new Runnable() {
@Override
public void run() {
if (mainFrame != null) {
mainFrame.setWorkStatus(name, cancelCallback);
mainFrame.setWorkStatus(name, worker);
if (percent == -1) {
mainFrame.hidePercent();
} else {
@@ -186,12 +187,17 @@ public class Main {
public static void stopWork() {
working = false;
if (mainFrame != null) {
mainFrame.setWorkStatus("", null);
}
if (loadingDialog != null) {
loadingDialog.setDetail("");
}
View.execInEventDispatchLater(new Runnable() {
@Override
public void run() {
if (mainFrame != null) {
mainFrame.setWorkStatus("", null);
}
if (loadingDialog != null) {
loadingDialog.setDetail("");
}
}
});
}
public static SWF parseSWF(String file) throws Exception {
@@ -302,6 +308,7 @@ public class Main {
}
public static boolean reloadSWF() {
CancellableWorker.cancelBackgroundThreads();
if (Main.inputStream == null) {
mainFrame.setVisible(false);
Helper.emptyObject(mainFrame);

View File

@@ -101,9 +101,8 @@ import com.jpexs.decompiler.flash.types.RECT;
import com.jpexs.decompiler.flash.types.RGB;
import com.jpexs.decompiler.flash.types.TEXTRECORD;
import com.jpexs.decompiler.graph.ExportMode;
import com.jpexs.helpers.AsyncResult;
import com.jpexs.helpers.Cache;
import com.jpexs.helpers.Callback;
import com.jpexs.helpers.CancellableWorker;
import com.jpexs.helpers.Helper;
import com.jpexs.process.ProcessTools;
import java.awt.BorderLayout;
@@ -167,8 +166,7 @@ import java.util.Stack;
import java.util.Timer;
import java.util.TimerTask;
import java.util.TreeSet;
import java.util.concurrent.Callable;
import java.util.concurrent.FutureTask;
import java.util.concurrent.CancellationException;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.Box;
@@ -198,7 +196,6 @@ import javax.swing.JTextField;
import javax.swing.JTree;
import javax.swing.SwingConstants;
import javax.swing.SwingUtilities;
import javax.swing.SwingWorker;
import javax.swing.UIManager;
import javax.swing.border.BevelBorder;
import javax.swing.event.DocumentEvent;
@@ -247,7 +244,7 @@ public final class MainFrame extends AppRibbonFrame implements ActionListener, T
public JLabel statusLabel = new JLabel("");
public JPanel statusPanel = new JPanel();
public JButton cancelButton = new JButton();
public Runnable cancelButtonPressed;
public CancellableWorker currentWorker;
public JProgressBar progressBar = new JProgressBar(0, 100);
private DeobfuscationDialog deobfuscationDialog;
public JTree tagTree;
@@ -310,7 +307,7 @@ public final class MainFrame extends AppRibbonFrame implements ActionListener, T
public static final String INTERNAL_VIEWER_CARD = "INTERNALVIEWER";
private Map<Integer, String> sourceFontsMap = new HashMap<>();
private AbortRetryIgnoreHandler errorHandler = new GuiAbortRetryIgnoreHandler();
private FutureTask<Void> setSourceTask;
private CancellableWorker setSourceWorker;
public void setPercent(int percent) {
progressBar.setValue(percent);
@@ -346,15 +343,15 @@ public final class MainFrame extends AppRibbonFrame implements ActionListener, T
statusLabel.setText(s);
}
public void setWorkStatus(String s, Runnable cancelCallback) {
public void setWorkStatus(String s, CancellableWorker worker) {
if (s.isEmpty()) {
loadingPanel.setVisible(false);
} else {
loadingPanel.setVisible(true);
}
statusLabel.setText(s);
cancelButtonPressed = cancelCallback;
cancelButton.setVisible(cancelCallback != null);
currentWorker = worker;
cancelButton.setVisible(worker != null);
}
private String fixCommandTitle(String title) {
@@ -564,7 +561,7 @@ public final class MainFrame extends AppRibbonFrame implements ActionListener, T
RibbonApplicationMenu mainMenu = new RibbonApplicationMenu();
RibbonApplicationMenuEntryPrimary exportFlaMenu = new RibbonApplicationMenuEntryPrimary(View.getResizableIcon("exportfla32"), translate("menu.file.export.fla"), new ActionRedirector(this, "EXPORTFLA"), CommandButtonKind.ACTION_ONLY);
RibbonApplicationMenuEntryPrimary exportAllMenu = new RibbonApplicationMenuEntryPrimary(View.getResizableIcon("export32"), translate("menu.file.export.all"), new ActionRedirector(this, "EXPORTSEL"), CommandButtonKind.ACTION_ONLY);
RibbonApplicationMenuEntryPrimary exportAllMenu = new RibbonApplicationMenuEntryPrimary(View.getResizableIcon("export32"), translate("menu.file.export.all"), new ActionRedirector(this, "EXPORT"), CommandButtonKind.ACTION_ONLY);
RibbonApplicationMenuEntryPrimary exportSelMenu = new RibbonApplicationMenuEntryPrimary(View.getResizableIcon("exportsel32"), translate("menu.file.export.selection"), new ActionRedirector(this, "EXPORTSEL"), CommandButtonKind.ACTION_ONLY);
RibbonApplicationMenuEntryPrimary checkUpdatesMenu = new RibbonApplicationMenuEntryPrimary(View.getResizableIcon("update32"), translate("menu.help.checkupdates"), new ActionRedirector(this, "CHECKUPDATES"), CommandButtonKind.ACTION_ONLY);
RibbonApplicationMenuEntryPrimary aboutMenu = new RibbonApplicationMenuEntryPrimary(View.getResizableIcon("about32"), translate("menu.help.about"), new ActionRedirector(this, "ABOUT"), CommandButtonKind.ACTION_ONLY);
@@ -1111,8 +1108,8 @@ public final class MainFrame extends AppRibbonFrame implements ActionListener, T
@Override
public void actionPerformed(ActionEvent e) {
if (cancelButtonPressed != null) {
cancelButtonPressed.run();
if (currentWorker != null) {
currentWorker.cancel(true);
}
}
});
@@ -2463,9 +2460,9 @@ public final class MainFrame extends AppRibbonFrame implements ActionListener, T
final String txt = searchDialog.searchField.getText();
if (!txt.isEmpty()) {
if (abcPanel != null) {
(new Thread() {
new CancellableWorker() {
@Override
public void run() {
protected Void doInBackground() throws Exception {
if (abcPanel.search(txt, searchDialog.ignoreCaseCheckBox.isSelected(), searchDialog.regexpCheckBox.isSelected())) {
View.execInEventDispatch(new Runnable() {
@Override
@@ -2477,12 +2474,13 @@ public final class MainFrame extends AppRibbonFrame implements ActionListener, T
} else {
View.showMessageDialog(null, translate("message.search.notfound").replace("%searchtext%", txt), translate("message.search.notfound.title"), JOptionPane.INFORMATION_MESSAGE);
}
return null;
}
}).start();
}.execute();
} else {
(new Thread() {
new CancellableWorker() {
@Override
public void run() {
protected Void doInBackground() {
if (actionPanel.search(txt, searchDialog.ignoreCaseCheckBox.isSelected(), searchDialog.regexpCheckBox.isSelected())) {
View.execInEventDispatch(new Runnable() {
@Override
@@ -2493,8 +2491,9 @@ public final class MainFrame extends AppRibbonFrame implements ActionListener, T
} else {
View.showMessageDialog(null, translate("message.search.notfound").replace("%searchtext%", txt), translate("message.search.notfound.title"), JOptionPane.INFORMATION_MESSAGE);
}
return null;
}
}).start();
}.execute();
}
}
}
@@ -2646,14 +2645,19 @@ public final class MainFrame extends AppRibbonFrame implements ActionListener, T
if (swf.fileAttributes.actionScript3) {
final int multiName = abcPanel.decompiledTextArea.getMultinameUnderCursor();
if (multiName > 0) {
(new Thread() {
new CancellableWorker() {
@Override
public void run() {
public Void doInBackground() throws Exception {
Main.startWork(translate("work.renaming") + "...");
renameMultiname(multiName);
return null;
}
@Override
protected void done() {
Main.stopWork();
}
}).start();
}.execute();
} else {
View.showMessageDialog(null, translate("message.rename.notfound.multiname"), translate("message.rename.notfound.title"), JOptionPane.INFORMATION_MESSAGE);
@@ -2661,18 +2665,23 @@ public final class MainFrame extends AppRibbonFrame implements ActionListener, T
} else {
final String identifier = actionPanel.getStringUnderCursor();
if (identifier != null) {
(new Thread() {
new CancellableWorker() {
@Override
public void run() {
public Void doInBackground() throws Exception {
Main.startWork(translate("work.renaming") + "...");
try {
renameIdentifier(identifier);
} catch (InterruptedException ex) {
Logger.getLogger(MainFrame.class.getName()).log(Level.SEVERE, null, ex);
}
return null;
}
@Override
protected void done() {
Main.stopWork();
}
}).start();
}.execute();
} else {
View.showMessageDialog(null, translate("message.rename.notfound.identifier"), translate("message.rename.notfound.title"), JOptionPane.INFORMATION_MESSAGE);
}
@@ -2760,9 +2769,9 @@ public final class MainFrame extends AppRibbonFrame implements ActionListener, T
}
}
final File selfile = sf;
(new Thread() {
new CancellableWorker() {
@Override
public void run() {
protected Void doInBackground() throws Exception {
Helper.freeMem();
try {
if (compressed) {
@@ -2774,9 +2783,14 @@ public final class MainFrame extends AppRibbonFrame implements ActionListener, T
View.showMessageDialog(null, translate("error.export") + ": " + ex.getClass().getName() + " " + ex.getLocalizedMessage(), translate("error"), JOptionPane.ERROR_MESSAGE);
}
Helper.freeMem();
return null;
}
@Override
protected void done() {
Main.stopWork();
}
}).start();
}.execute();
}
break;
case "EXPORTSEL":
@@ -2798,9 +2812,9 @@ public final class MainFrame extends AppRibbonFrame implements ActionListener, T
final boolean isMp3OrWav = export.getOption(ExportDialog.OPTION_SOUNDS) == 0;
final boolean isFormatted = export.getOption(ExportDialog.OPTION_TEXTS) == 1;
final boolean onlySel = e.getActionCommand().endsWith("SEL");
(new Thread() {
new CancellableWorker() {
@Override
public void run() {
public Void doInBackground() throws Exception {
try {
if (onlySel) {
exportSelection(errorHandler, selFile, export);
@@ -2817,13 +2831,24 @@ public final class MainFrame extends AppRibbonFrame implements ActionListener, T
Logger.getLogger(MainFrame.class.getName()).log(Level.SEVERE, "Error during export", ex);
View.showMessageDialog(null, translate("error.export") + ": " + ex.getClass().getName() + " " + ex.getLocalizedMessage());
}
return null;
}
@Override
protected void done() {
Main.stopWork();
long timeAfter = System.currentTimeMillis();
long timeMs = timeAfter - timeBefore;
final long timeMs = timeAfter - timeBefore;
setStatus(translate("export.finishedin").replace("%time%", Helper.formatTimeSec(timeMs)));
View.execInEventDispatchLater(new Runnable() {
@Override
public void run() {
setStatus(translate("export.finishedin").replace("%time%", Helper.formatTimeSec(timeMs)));
}
});
}
}).start();
}.execute();
}
}
@@ -2868,7 +2893,7 @@ public final class MainFrame extends AppRibbonFrame implements ActionListener, T
Main.startWork(translate("work.restoringControlFlow"));
final boolean all = e.getActionCommand().endsWith("ALL");
if ((!all) || confirmExperimental()) {
new SwingWorker() {
new CancellableWorker() {
@Override
protected Object doInBackground() throws Exception {
int cnt = 0;
@@ -2883,12 +2908,23 @@ public final class MainFrame extends AppRibbonFrame implements ActionListener, T
}
abcPanel.detailPanel.methodTraitPanel.methodCodePanel.setBodyIndex(bi, abcPanel.abc, abcPanel.decompiledTextArea.getCurrentTrait());
}
Main.stopWork();
View.showMessageDialog(null, "Control flow restored");
abcPanel.reload();
doFilter();
return true;
}
@Override
protected void done() {
Main.stopWork();
View.showMessageDialog(null, translate("work.restoringControlFlow.complete"));
View.execInEventDispatch(new Runnable() {
@Override
public void run() {
abcPanel.reload();
doFilter();
}
});
}
}.execute();
}
break;
@@ -2897,29 +2933,39 @@ public final class MainFrame extends AppRibbonFrame implements ActionListener, T
final RenameType renameType = new RenameDialog().display();
if (renameType != null) {
Main.startWork(translate("work.renaming.identifiers") + "...");
new SwingWorker() {
new CancellableWorker<Integer>() {
@Override
protected Object doInBackground() throws Exception {
try {
int cnt = swf.deobfuscateIdentifiers(renameType);
Main.stopWork();
View.showMessageDialog(null, translate("message.rename.renamed").replace("%count%", "" + cnt));
swf.assignClassesToSymbols();
clearCache();
if (abcPanel != null) {
abcPanel.reload();
protected Integer doInBackground() throws Exception {
int cnt = swf.deobfuscateIdentifiers(renameType);
return cnt;
}
@Override
protected void done() {
View.execInEventDispatch(new Runnable() {
@Override
public void run() {
try {
int cnt = get();
Main.stopWork();
View.showMessageDialog(null, translate("message.rename.renamed").replace("%count%", "" + cnt));
swf.assignClassesToSymbols();
clearCache();
if (abcPanel != null) {
abcPanel.reload();
}
doFilter();
reload(true);
} catch (Exception ex) {
Logger.getLogger(MainFrame.class.getName()).log(Level.SEVERE, "Error during renaming identifiers", ex);
Main.stopWork();
View.showMessageDialog(null, translate("error.occured").replace("%error%", ex.getClass().getSimpleName()));
}
}
doFilter();
reload(true);
} catch (Exception ex) {
Logger.getLogger(MainFrame.class.getName()).log(Level.SEVERE, "Error during renaming identifiers", ex);
Main.stopWork();
View.showMessageDialog(null, translate("error.occured").replace("%error%", ex.getClass().getSimpleName()));
}
return true;
});
}
}.execute();
}
}
break;
@@ -2931,7 +2977,7 @@ public final class MainFrame extends AppRibbonFrame implements ActionListener, T
deobfuscationDialog.setVisible(true);
if (deobfuscationDialog.ok) {
Main.startWork(translate("work.deobfuscating") + "...");
new SwingWorker() {
new CancellableWorker() {
@Override
protected Object doInBackground() throws Exception {
try {
@@ -2964,12 +3010,23 @@ public final class MainFrame extends AppRibbonFrame implements ActionListener, T
} catch (Exception ex) {
Logger.getLogger(MainFrame.class.getName()).log(Level.SEVERE, "Deobfuscation error", ex);
}
return true;
}
@Override
protected void done() {
Main.stopWork();
View.showMessageDialog(null, translate("work.deobfuscating.complete"));
clearCache();
abcPanel.reload();
doFilter();
return true;
View.execInEventDispatch(new Runnable() {
@Override
public void run() {
clearCache();
abcPanel.reload();
doFilter();
}
});
}
}.execute();
}
@@ -3076,22 +3133,14 @@ public final class MainFrame extends AppRibbonFrame implements ActionListener, T
oldValue = tagObj;
if (tagObj instanceof ScriptPack) {
final ScriptPack scriptLeaf = (ScriptPack) tagObj;
if (setSourceWorker != null) {
setSourceWorker.cancel(true);
}
if (!Main.isWorking()) {
Main.startWork(translate("work.decompiling") + "...", new Runnable() {
CancellableWorker worker = new CancellableWorker() {
@Override
public void run() {
if (setSourceTask != null) {
setSourceTask.cancel(true);
}
abcPanel.decompiledTextArea.setText("//" + AppStrings.translate("work.canceled"));
}
});
FutureTask<Void> task = Helper.callAsync(new Callable<Void>() {
@Override
public Void call() throws Exception {
protected Void doInBackground() throws Exception {
int classIndex = -1;
for (Trait t : scriptLeaf.abc.script_info[scriptLeaf.scriptIndex].traits.traits) {
if (t instanceof TraitClass) {
@@ -3108,18 +3157,29 @@ public final class MainFrame extends AppRibbonFrame implements ActionListener, T
abcPanel.decompiledTextArea.setNoTrait();
return null;
}
}, new Callback<AsyncResult<Void>>() {
@Override
public void call(AsyncResult<Void> result) {
setSourceTask = null;
if (result.error != null) {
abcPanel.decompiledTextArea.setText("//Decompilation error: " + result.error);
}
protected void done() {
Main.stopWork();
View.execInEventDispatch(new Runnable() {
@Override
public void run() {
try {
get();
} catch (CancellationException ex) {
abcPanel.decompiledTextArea.setText("//" + AppStrings.translate("work.canceled"));
} catch (Exception ex) {
abcPanel.decompiledTextArea.setText("//Decompilation error: " + ex);
}
}
});
}
});
setSourceTask = task;
};
worker.execute();
setSourceWorker = worker;
Main.startWork(translate("work.decompiling") + "...", worker);
}
showDetail(DETAILCARDAS3NAVIGATOR);

View File

@@ -220,7 +220,8 @@ public class View {
} else {
try {
SwingUtilities.invokeAndWait(r);
} catch (InterruptedException | InvocationTargetException ex) {
} catch (InterruptedException ex) {
} catch (InvocationTargetException ex) {
Logger.getLogger(View.class.getName()).log(Level.SEVERE, null, ex);
}
}

View File

@@ -53,6 +53,7 @@ import com.jpexs.decompiler.flash.gui.abc.tablemodels.UIntTableModel;
import com.jpexs.decompiler.flash.helpers.Freed;
import com.jpexs.decompiler.flash.helpers.collections.MyEntry;
import com.jpexs.decompiler.flash.tags.ABCContainerTag;
import com.jpexs.helpers.CancellableWorker;
import com.jpexs.helpers.Helper;
import java.awt.BorderLayout;
import java.awt.Component;
@@ -64,10 +65,7 @@ import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;
import java.util.concurrent.atomic.AtomicReference;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.regex.Pattern;
@@ -131,21 +129,11 @@ public class ABCPanel extends JPanel implements ItemListener, ActionListener, Fr
decAdd = ", " + AppStrings.translate("work.decompiling");
}
final AtomicReference<FutureTask<Void>> taskRef = new AtomicReference<>();
Main.startWork(workText + " \"" + txt + "\"" + decAdd + " - (" + pos + "/" + allpacks.size() + ") " + item.key.toString() + "... ", new Runnable() {
@Override
public void run() {
FutureTask task = taskRef.get();
if (task != null) {
task.cancel(true);
}
}
});
try {
Helper.cancellableCall(new Callable<Void>() {
CancellableWorker worker = new CancellableWorker() {
@Override
public Void call() throws Exception {
public Void doInBackground() throws Exception {
decompiledTextArea.cacheScriptPack(item.value, list);
if (pat.matcher(decompiledTextArea.getCachedText(item.value)).find()) {
found.add(item.value);
@@ -153,7 +141,10 @@ public class ABCPanel extends JPanel implements ItemListener, ActionListener, Fr
}
return null;
}
}, taskRef);
};
worker.execute();
Main.startWork(workText + " \"" + txt + "\"" + decAdd + " - (" + pos + "/" + allpacks.size() + ") " + item.key.toString() + "... ", worker);
worker.get();
} catch (InterruptedException ex) {
break;
} catch (ExecutionException ex) {

View File

@@ -223,6 +223,7 @@ public class ASMSourceEditorPane extends LineMarkedEditorPane implements CaretLi
abc.bodies[bodyIndex].code = acode;
}
} catch (IOException ex) {
} catch (InterruptedException ex) {
} catch (ParseException ex) {
View.showMessageDialog(this, (ex.text + " on line " + ex.line));
selectLine((int) ex.line);

View File

@@ -26,6 +26,7 @@ import com.jpexs.decompiler.flash.gui.Main;
import com.jpexs.decompiler.flash.gui.View;
import com.jpexs.decompiler.flash.helpers.collections.MyEntry;
import com.jpexs.decompiler.flash.tags.ABCContainerTag;
import com.jpexs.helpers.CancellableWorker;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JTree;
@@ -127,9 +128,9 @@ public final class ClassesListTree extends JTree implements TreeSelectionListene
final ScriptPack scriptLeaf = (ScriptPack) item;
if (!Main.isWorking()) {
Main.startWork(AppStrings.translate("work.decompiling") + "...");
(new Thread() {
new CancellableWorker() {
@Override
public void run() {
public Void doInBackground() throws Exception {
int classIndex = -1;
for (Trait t : scriptLeaf.abc.script_info[scriptLeaf.scriptIndex].traits.traits) {
if (t instanceof TraitClass) {
@@ -144,9 +145,14 @@ public final class ClassesListTree extends JTree implements TreeSelectionListene
abcPanel.decompiledTextArea.setClassIndex(classIndex);
abcPanel.decompiledTextArea.setNoTrait();
abcPanel.detailPanel.methodTraitPanel.methodCodePanel.clear();
return null;
}
@Override
protected void done() {
Main.stopWork();
}
}).start();
}.execute();
}
}

View File

@@ -38,8 +38,6 @@ import java.util.ArrayList;
import java.util.List;
import java.util.Timer;
import java.util.TimerTask;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.SwingUtilities;
import javax.swing.event.CaretEvent;
import javax.swing.event.CaretListener;
@@ -488,7 +486,6 @@ public class DecompiledEditorPane extends LineMarkedEditorPane implements CaretL
cacheScriptPack(scriptLeaf, abcList);
cd = getCached(scriptLeaf);
} catch (InterruptedException ex) {
Logger.getLogger(DecompiledEditorPane.class.getName()).log(Level.SEVERE, null, ex);
}
if (cd != null) {
final String hilightedCode = cd.text;

View File

@@ -41,9 +41,8 @@ import com.jpexs.decompiler.flash.tags.Tag;
import com.jpexs.decompiler.flash.tags.base.ASMSource;
import com.jpexs.decompiler.graph.ExportMode;
import com.jpexs.decompiler.graph.GraphTargetItem;
import com.jpexs.helpers.AsyncResult;
import com.jpexs.helpers.Cache;
import com.jpexs.helpers.Callback;
import com.jpexs.helpers.CancellableWorker;
import com.jpexs.helpers.Helper;
import java.awt.BorderLayout;
import java.awt.FlowLayout;
@@ -59,8 +58,7 @@ import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.concurrent.Callable;
import java.util.concurrent.FutureTask;
import java.util.concurrent.CancellationException;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.regex.Pattern;
@@ -119,7 +117,7 @@ public class ActionPanel extends JPanel implements ActionListener {
private boolean searchIgnoreCase;
private boolean searchRegexp;
private Cache cache = Cache.getInstance(true);
private FutureTask<Void> setSourceTask;
private CancellableWorker setSourceWorker;
public void clearCache() {
cache.clear();
@@ -287,7 +285,11 @@ public class ActionPanel extends JPanel implements ActionListener {
DisassemblyListener listener = getDisassemblyListener();
asm.addDisassemblyListener(listener);
HilightedTextWriter writer = new HilightedTextWriter(true);
asm.getASMSource(SWF.DEFAULT_VERSION, exportMode, writer, lastCode);
try {
asm.getASMSource(SWF.DEFAULT_VERSION, exportMode, writer, lastCode);
} catch (InterruptedException ex) {
Logger.getLogger(ActionPanel.class.getName()).log(Level.SEVERE, null, ex);
}
asm.removeDisassemblyListener(listener);
return new HilightedText(writer);
}
@@ -339,27 +341,17 @@ public class ActionPanel extends JPanel implements ActionListener {
}
public void setSource(final ASMSource src, final boolean useCache) {
if (setSourceTask != null) {
setSourceTask.cancel(true);
if (setSourceWorker != null) {
setSourceWorker.cancel(true);
}
this.src = src;
Main.startWork(AppStrings.translate("work.decompiling") + "...", new Runnable() {
@Override
public void run() {
if (setSourceTask != null) {
setSourceTask.cancel(true);
}
editor.setText("; " + AppStrings.translate("work.canceled"));
}
});
final ASMSource asm = (ASMSource) src;
FutureTask<Void> task = Helper.callAsync(new Callable<Void>() {
CancellableWorker worker = new CancellableWorker() {
@Override
public Void call() throws Exception {
protected Void doInBackground() throws Exception {
editor.setText("; " + AppStrings.translate("work.disassembling") + "...");
if (Configuration.decompile.get()) {
decompiledEditor.setText("//" + AppStrings.translate("work.waitingfordissasembly") + "...");
@@ -389,20 +381,30 @@ public class ActionPanel extends JPanel implements ActionListener {
setDecompiledEditMode(false);
return null;
}
}, new Callback<AsyncResult<Void>>() {
@Override
public void call(AsyncResult<Void> result) {
setSourceTask = null;
if (result.error != null) {
decompiledEditor.setText("//Decompilation error: " + result.error);
}
protected void done() {
setSourceWorker = null;
Main.stopWork();
View.execInEventDispatch(new Runnable() {
@Override
public void run() {
try {
get();
} catch (CancellationException ex) {
editor.setText("; " + AppStrings.translate("work.canceled"));
} catch (Exception ex) {
decompiledEditor.setText("//Decompilation error: " + ex);
}
}
});
}
});
setSourceTask = task;
};
worker.execute();
setSourceWorker = worker;
Main.startWork(AppStrings.translate("work.decompiling") + "...", worker);
}
public void hilightOffset(long offset) {

View File

@@ -377,4 +377,5 @@ menu.advancedsettings.advancedsettings = Advanced Settings
menu.recentFiles = Recent files
#after version 1.7.4
work.restoringControlFlow.complete = Control flow restored

View File

@@ -375,3 +375,6 @@ work.canceled = Megszak\u00edtva
work.restoringControlFlow = Vez\u00e9rl\u00e9si-folyam helyre\u00e1ll\u00edt\u00e1s
menu.advancedsettings.advancedsettings = Halad\u00f3 be\u00e1ll\u00edt\u00e1sok
menu.recentFiles = El\u0151zm\u00e9nyek
#after version 1.7.4
work.restoringControlFlow.complete = Vez\u00e9rl\u00e9si-folyam helyre\u00e1ll\u00edt\u00e1s befejez\u0151d\u00f6tt

View File

@@ -139,7 +139,7 @@ public class DefineButtonTag extends CharacterTag implements ASMSource, BoundedT
* @return ASM source
*/
@Override
public GraphTextWriter getASMSource(int version, ExportMode exportMode, GraphTextWriter writer, List<Action> actions) {
public GraphTextWriter getASMSource(int version, ExportMode exportMode, GraphTextWriter writer, List<Action> actions) throws InterruptedException {
if (actions == null) {
actions = getActions(version);
}
@@ -163,7 +163,7 @@ public class DefineButtonTag extends CharacterTag implements ASMSource, BoundedT
* @return List of actions
*/
@Override
public List<Action> getActions(int version) {
public List<Action> getActions(int version) throws InterruptedException {
try {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
int prevLength = 0;
@@ -176,8 +176,10 @@ public class DefineButtonTag extends CharacterTag implements ASMSource, BoundedT
MemoryInputStream rri = new MemoryInputStream(baos.toByteArray());
rri.seek(prevLength);
List<Action> list = ActionListReader.readActionList(listeners, getPos() + hdrSize - prevLength, rri, version, prevLength, -1, toString()/*FIXME?*/);
List<Action> list = ActionListReader.readActionListTimeout(listeners, getPos() + hdrSize - prevLength, rri, version, prevLength, -1, toString()/*FIXME?*/);
return list;
} catch (InterruptedException ex) {
throw ex;
} catch (Exception ex) {
Logger.getLogger(DoActionTag.class.getName()).log(Level.SEVERE, null, ex);
return new ArrayList<>();

View File

@@ -192,7 +192,7 @@ public class DefineSpriteTag extends CharacterTag implements Container, BoundedT
* @param skipUnusualTags
* @throws IOException
*/
public DefineSpriteTag(SWF swf, byte[] data, int version, int level, long pos, boolean parallel, boolean skipUnusualTags) throws IOException {
public DefineSpriteTag(SWF swf, byte[] data, int version, int level, long pos, boolean parallel, boolean skipUnusualTags) throws IOException, InterruptedException {
super(swf, ID, "DefineSprite", data, pos);
SWFInputStream sis = new SWFInputStream(new ByteArrayInputStream(data), version, pos);
spriteId = sis.readUI16();

View File

@@ -76,7 +76,7 @@ public class DoActionTag extends Tag implements ASMSource {
* @return ASM source
*/
@Override
public GraphTextWriter getASMSource(int version, ExportMode exportMode, GraphTextWriter writer, List<Action> actions) {
public GraphTextWriter getASMSource(int version, ExportMode exportMode, GraphTextWriter writer, List<Action> actions) throws InterruptedException {
if (actions == null) {
actions = getActions(version);
}
@@ -104,7 +104,7 @@ public class DoActionTag extends Tag implements ASMSource {
}
@Override
public List<Action> getActions(int version) {
public List<Action> getActions(int version) throws InterruptedException {
try {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
int prevLength = 0;
@@ -119,8 +119,10 @@ public class DoActionTag extends Tag implements ASMSource {
baos.write(actionBytes);
MemoryInputStream rri = new MemoryInputStream(baos.toByteArray());
rri.seek(prevLength);
List<Action> list = ActionListReader.readActionList(listeners, getPos() - prevLength, rri, version, prevLength, -1, toString()/*FIXME?*/);
List<Action> list = ActionListReader.readActionListTimeout(listeners, getPos() - prevLength, rri, version, prevLength, -1, toString()/*FIXME?*/);
return list;
} catch (InterruptedException ex) {
throw ex;
} catch (Exception ex) {
Logger.getLogger(DoActionTag.class.getName()).log(Level.SEVERE, null, ex);
return new ArrayList<>();

View File

@@ -103,7 +103,7 @@ public class DoInitActionTag extends CharacterIdTag implements ASMSource {
* @return ASM source
*/
@Override
public GraphTextWriter getASMSource(int version, ExportMode exportMode, GraphTextWriter writer, List<Action> actions) {
public GraphTextWriter getASMSource(int version, ExportMode exportMode, GraphTextWriter writer, List<Action> actions) throws InterruptedException {
if (actions == null) {
actions = getActions(version);
}
@@ -111,7 +111,7 @@ public class DoInitActionTag extends CharacterIdTag implements ASMSource {
}
@Override
public List<Action> getActions(int version) {
public List<Action> getActions(int version) throws InterruptedException {
try {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
int prevLength = 0;
@@ -129,8 +129,10 @@ public class DoInitActionTag extends CharacterIdTag implements ASMSource {
baos.write(actionBytes);
MemoryInputStream rri = new MemoryInputStream(baos.toByteArray());
rri.seek(prevLength);
List<Action> list = ActionListReader.readActionList(listeners, getPos() + 2 - prevLength, rri, version, prevLength, -1, toString()/*FIXME?*/);
List<Action> list = ActionListReader.readActionListTimeout(listeners, getPos() + 2 - prevLength, rri, version, prevLength, -1, toString()/*FIXME?*/);
return list;
} catch (InterruptedException ex) {
throw ex;
} catch (Exception ex) {
Logger.getLogger(DoActionTag.class.getName()).log(Level.SEVERE, null, ex);
return new ArrayList<>();

View File

@@ -36,7 +36,7 @@ public interface ASMSource {
* @param exportMode PCode or hex?
* @return ASM source
*/
public GraphTextWriter getASMSource(int version, ExportMode exportMode, GraphTextWriter writer, List<Action> actions);
public GraphTextWriter getASMSource(int version, ExportMode exportMode, GraphTextWriter writer, List<Action> actions) throws InterruptedException;
/**
* Whether or not this object contains ASM source
@@ -51,7 +51,7 @@ public interface ASMSource {
* @param version Version
* @return List of actions
*/
public List<Action> getActions(int version);
public List<Action> getActions(int version) throws InterruptedException;
/**
* Sets actions associated with this object

View File

@@ -148,7 +148,7 @@ public class BUTTONCONDACTION implements ASMSource, Exportable, ContainerItem {
* @return ASM source
*/
@Override
public GraphTextWriter getASMSource(int version, ExportMode exportMode, GraphTextWriter writer, List<Action> actions) {
public GraphTextWriter getASMSource(int version, ExportMode exportMode, GraphTextWriter writer, List<Action> actions) throws InterruptedException {
if (actions == null) {
actions = getActions(version);
}
@@ -172,11 +172,13 @@ public class BUTTONCONDACTION implements ASMSource, Exportable, ContainerItem {
* @return List of actions
*/
@Override
public List<Action> getActions(int version) {
public List<Action> getActions(int version) throws InterruptedException {
try {
List<Action> list = ActionListReader.readActionList(listeners, getPos() + 4, new MemoryInputStream(actionBytes), version, 0, -1, toString()/*FIXME?*/);
List<Action> list = ActionListReader.readActionListTimeout(listeners, getPos() + 4, new MemoryInputStream(actionBytes), version, 0, -1, toString()/*FIXME?*/);
return list;
} catch (InterruptedException ex) {
throw ex;
} catch (Exception ex) {
Logger.getLogger(BUTTONCONDACTION.class.getName()).log(Level.SEVERE, null, ex);
return new ArrayList<>();

View File

@@ -153,7 +153,7 @@ public class CLIPACTIONRECORD implements ASMSource, Exportable, ContainerItem {
* @return ASM source
*/
@Override
public GraphTextWriter getASMSource(int version, ExportMode exportMode, GraphTextWriter writer, List<Action> actions) {
public GraphTextWriter getASMSource(int version, ExportMode exportMode, GraphTextWriter writer, List<Action> actions) throws InterruptedException {
if (actions == null) {
actions = getActions(version);
}
@@ -171,10 +171,12 @@ public class CLIPACTIONRECORD implements ASMSource, Exportable, ContainerItem {
}
@Override
public List<Action> getActions(int version) {
public List<Action> getActions(int version) throws InterruptedException {
try {
List<Action> list = ActionListReader.readActionList(listeners, getPos() + hdrPos, new MemoryInputStream(actionBytes), version, 0, -1, toString()/*FIXME?*/);
List<Action> list = ActionListReader.readActionListTimeout(listeners, getPos() + hdrPos, new MemoryInputStream(actionBytes), version, 0, -1, toString()/*FIXME?*/);
return list;
} catch (InterruptedException ex) {
throw ex;
} catch (Exception ex) {
Logger.getLogger(BUTTONCONDACTION.class.getName()).log(Level.SEVERE, null, ex);
return new ArrayList<>();

View File

@@ -103,6 +103,10 @@ public class Graph {
}
private boolean fixGraphOnce(List<Object> localData, GraphPart part, List<GraphPart> visited, boolean doChildren) throws InterruptedException {
if (Thread.currentThread().isInterrupted()) {
throw new InterruptedException();
}
if (visited.contains(part)) {
return false;
}
@@ -1358,7 +1362,7 @@ public class Graph {
}
protected List<GraphTargetItem> printGraph(List<GraphPart> visited, List<Object> localData, Stack<GraphTargetItem> stack, List<GraphPart> allParts, GraphPart parent, GraphPart part, List<GraphPart> stopPart, List<Loop> loops, List<GraphTargetItem> ret, int staticOperation, String path, int recursionLevel) throws InterruptedException {
if (Thread.interrupted()) {
if (Thread.currentThread().isInterrupted()) {
throw new InterruptedException();
}
if (stopPart == null) {
@@ -2034,7 +2038,7 @@ public class Graph {
protected void checkGraph(List<GraphPart> allBlocks) {
}
private List<GraphPart> makeGraph(GraphSource code, List<GraphPart> allBlocks, List<Integer> alternateEntries) {
private List<GraphPart> makeGraph(GraphSource code, List<GraphPart> allBlocks, List<Integer> alternateEntries) throws InterruptedException {
HashMap<Integer, List<Integer>> refs = code.visitCode(alternateEntries);
List<GraphPart> ret = new ArrayList<>();
boolean[] visited = new boolean[code.size()];
@@ -2052,7 +2056,10 @@ public class Graph {
return ip;
}
private GraphPart makeGraph(GraphPart parent, GraphPath path, GraphSource code, int startip, int lastIp, List<GraphPart> allBlocks, HashMap<Integer, List<Integer>> refs, boolean[] visited2) {
private GraphPart makeGraph(GraphPart parent, GraphPath path, GraphSource code, int startip, int lastIp, List<GraphPart> allBlocks, HashMap<Integer, List<Integer>> refs, boolean[] visited2) throws InterruptedException {
if (Thread.currentThread().isInterrupted()) {
throw new InterruptedException();
}
int ip = startip;
for (GraphPart p : allBlocks) {

View File

@@ -61,7 +61,7 @@ public class GraphPart implements Serializable {
}
private boolean leadsTo(List<Object> localData, Graph gr, GraphSource code, GraphPart part, List<GraphPart> visited, List<Loop> loops) throws InterruptedException {
if (Thread.interrupted()) {
if (Thread.currentThread().isInterrupted()) {
throw new InterruptedException();
}

View File

@@ -37,7 +37,10 @@ public abstract class GraphSource implements Serializable {
public abstract List<GraphTargetItem> translatePart(GraphPart part, List<Object> localData, Stack<GraphTargetItem> stack, int start, int end, int staticOperation, String path) throws InterruptedException;
private void visitCode(int ip, int lastIp, HashMap<Integer, List<Integer>> refs, int endIp) {
private void visitCode(int ip, int lastIp, HashMap<Integer, List<Integer>> refs, int endIp) throws InterruptedException {
if (Thread.currentThread().isInterrupted()) {
throw new InterruptedException();
}
boolean debugMode = false;
while (((endIp == -1) || (ip < endIp)) && (ip < size())) {
refs.get(ip).add(lastIp);
@@ -87,7 +90,7 @@ public abstract class GraphSource implements Serializable {
};
}
public HashMap<Integer, List<Integer>> visitCode(List<Integer> alternateEntries) {
public HashMap<Integer, List<Integer>> visitCode(List<Integer> alternateEntries) throws InterruptedException {
HashMap<Integer, List<Integer>> refs = new HashMap<>();
int siz = size();
for (int i = 0; i < siz; i++) {

View File

@@ -18,7 +18,6 @@ package com.jpexs.decompiler.graph.model;
import com.jpexs.decompiler.flash.helpers.GraphTextWriter;
import com.jpexs.decompiler.graph.GraphTargetItem;
import static com.jpexs.decompiler.graph.GraphTargetItem.NOPRECEDENCE;
/**
*

View File

@@ -1,34 +0,0 @@
/*
* Copyright (C) 2010-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 <http://www.gnu.org/licenses/>.
*/
package com.jpexs.helpers;
/**
* Class with helper method
*
* @author JPEXS
*/
public class AsyncResult<T> {
public T result;
public Throwable error;
public AsyncResult(T result, Throwable error) {
this.result = result;
this.error = error;
}
}

View File

@@ -162,8 +162,7 @@ public class Cache {
cacheFiles.put(key, temp);
} catch (Exception ex) {
} catch (IOException ex) {
//ignore
}
} else if (storageType == STORAGE_MEMORY) {

View File

@@ -0,0 +1,128 @@
/*
* Copyright (C) 2010-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 <http://www.gnu.org/licenses/>.
*/
package com.jpexs.helpers;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
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.RunnableFuture;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
/**
*
* @author JPEXS
*/
public abstract class CancellableWorker<T> implements RunnableFuture<T> {
private static final ExecutorService THREAD_POOL = Executors.newCachedThreadPool();
private static List<CancellableWorker> workers = Collections.synchronizedList(new ArrayList<CancellableWorker>());
private final FutureTask<T> future;
public CancellableWorker() {
super();
Callable<T> callable =
new Callable<T>() {
@Override
public T call() throws Exception {
return doInBackground();
}
};
future = new FutureTask<T>(callable) {
@Override
protected void done() {
workerDone();
}
};
}
protected abstract T doInBackground() throws Exception;
@Override
public final void run() {
workers.add(this);
future.run();
}
protected void done() {
}
public final void execute() {
THREAD_POOL.execute(this);
}
@Override
public final boolean cancel(boolean mayInterruptIfRunning) {
return future.cancel(mayInterruptIfRunning);
}
@Override
public final boolean isCancelled() {
return future.isCancelled();
}
@Override
public final boolean isDone() {
return future.isDone();
}
@Override
public final T get() throws InterruptedException, ExecutionException {
return future.get();
}
@Override
public final T get(long timeout, TimeUnit unit) throws InterruptedException,
ExecutionException, TimeoutException {
return future.get(timeout, unit);
}
private void workerDone() {
workers.remove(this);
done();
}
public static <T> T call(final Callable<T> c, long timeout, TimeUnit timeUnit) throws InterruptedException, ExecutionException, TimeoutException {
CancellableWorker<T> worker = new CancellableWorker<T>() {
@Override
protected T doInBackground() throws Exception {
return c.call();
}
};
try {
worker.execute();
return worker.get(timeout, timeUnit);
} finally {
worker.cancel(true);
}
}
public static void cancelBackgroundThreads() {
List<CancellableWorker> oldWorkers = workers;
workers = new ArrayList<>();
for (CancellableWorker worker : oldWorkers) {
worker.cancel(true);
}
}
}

View File

@@ -41,15 +41,6 @@ import java.util.Collection;
import java.util.List;
import java.util.Scanner;
import java.util.Stack;
import java.util.concurrent.Callable;
import java.util.concurrent.CancellationException;
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.concurrent.atomic.AtomicReference;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.regex.Matcher;
@@ -62,8 +53,6 @@ import java.util.regex.Pattern;
*/
public class Helper {
private static final ExecutorService THREAD_POOL = Executors.newCachedThreadPool();
/**
* Converts array of int values to string
*
@@ -625,61 +614,6 @@ public class Helper {
return data;
}
public static <T> T timedCall(Callable<T> c, long timeout, TimeUnit timeUnit) throws InterruptedException, ExecutionException, TimeoutException {
FutureTask<T> task = new FutureTask<>(c);
THREAD_POOL.execute(task);
try {
return task.get(timeout, timeUnit);
} finally {
task.cancel(true);
}
}
public static <T> FutureTask<T> callAsync(final Callable<T> c) {
return callAsync(c, null);
}
public static <T> FutureTask<T> callAsync(final Callable<T> c, final Callback<AsyncResult<T>> callback) {
FutureTask<T> task = new FutureTask<>(new Callable<T>() {
@Override
public T call() throws Exception {
try {
T t = c.call();
if (callback != null) {
callback.call(new AsyncResult<>(t, null));
}
return t;
} catch (Throwable ex) {
if (callback != null) {
callback.call(new AsyncResult<T>(null, ex));
}
throw ex;
}
}
});
THREAD_POOL.execute(task);
return task;
}
public static <T> T cancellableCall(final Callable<T> c, final AtomicReference<FutureTask<T>> cancellation) throws InterruptedException, ExecutionException {
FutureTask<T> task = new FutureTask<>(new Callable<T>() {
@Override
public T call() throws Exception {
T t = c.call();
return t;
}
});
cancellation.set(task);
THREAD_POOL.execute(task);
try {
return task.get();
} catch (CancellationException ex) {
throw new InterruptedException();
}
}
public static boolean contains(int[] array, int value) {
for (int i : array) {
if (i == value) {