mirror of
https://git.huckle.dev/Huckles-Minecraft-Archive/jpexs-decompiler.git
synced 2026-07-18 07:28:09 +00:00
AS2 detection of uninitialized class fields is parallel
This commit is contained in:
@@ -16,6 +16,7 @@
|
||||
*/
|
||||
package com.jpexs.decompiler.flash.action.as2;
|
||||
|
||||
import com.jpexs.decompiler.flash.IdentifiersDeobfuscation;
|
||||
import com.jpexs.decompiler.flash.SWF;
|
||||
import com.jpexs.decompiler.flash.action.model.CallMethodActionItem;
|
||||
import com.jpexs.decompiler.flash.action.model.DeleteActionItem;
|
||||
@@ -33,7 +34,9 @@ import com.jpexs.decompiler.flash.helpers.collections.MyEntry;
|
||||
import com.jpexs.decompiler.flash.tags.DoInitActionTag;
|
||||
import com.jpexs.decompiler.flash.tags.base.ASMSource;
|
||||
import com.jpexs.decompiler.graph.AbstractGraphTargetVisitor;
|
||||
import com.jpexs.decompiler.graph.DottedChain;
|
||||
import com.jpexs.decompiler.graph.GraphTargetItem;
|
||||
import com.jpexs.helpers.Cache;
|
||||
import com.jpexs.helpers.CancellableWorker;
|
||||
import com.jpexs.helpers.ProgressListener;
|
||||
import java.util.ArrayList;
|
||||
@@ -59,9 +62,16 @@ public class UninitializedClassFieldsDetector {
|
||||
progressListeners.remove(listener);
|
||||
}
|
||||
|
||||
private void fireProgress(String status) {
|
||||
private void fireProgress(ASMSource asm, String asmPath) {
|
||||
if (asm instanceof DoInitActionTag) {
|
||||
DoInitActionTag doi = (DoInitActionTag) asm;
|
||||
String exportName = doi.getSwf().getExportName(doi.spriteId);
|
||||
if (exportName != null) {
|
||||
asmPath = DottedChain.parseNoSuffix(exportName).toPrintableString(false);
|
||||
}
|
||||
}
|
||||
for (ProgressListener listener : progressListeners) {
|
||||
listener.status(status);
|
||||
listener.status(asmPath);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -211,83 +221,158 @@ public class UninitializedClassFieldsDetector {
|
||||
}
|
||||
final Map<String, Map<String, Trait>> result = new LinkedHashMap<>();
|
||||
Map<String, ASMSource> asms = swf.getASMs(false);
|
||||
|
||||
CancellableWorker worker = CancellableWorker.getCurrent();
|
||||
|
||||
/*Map<String, List<GraphTargetItem>> trees = new HashMap<>();
|
||||
asms.entrySet().parallelStream()
|
||||
.forEach(item -> {
|
||||
CancellableWorker.assignThreadToWorker(Thread.currentThread(), worker);
|
||||
if (worker.isCancelled()) {
|
||||
return;
|
||||
}
|
||||
fireProgress(item.getValue(), item.getKey());
|
||||
try {
|
||||
trees.put(item.getKey(), item.getValue().getActionsToTree());
|
||||
} catch (Throwable t) {
|
||||
trees.put(item.getKey(), new ArrayList<>());
|
||||
//ignore
|
||||
}
|
||||
}); */
|
||||
|
||||
List<ASMSource> classesAsms = new ArrayList<>();
|
||||
|
||||
|
||||
final Map<String, Map<String, Trait>> classTraits = new LinkedHashMap<>(ActionScript2Classes.getClassToTraits());
|
||||
final Map<String, List<String>> classInheritance = new HashMap<>(ActionScript2Classes.getClassInheritance());
|
||||
|
||||
//get all assigned traits and inheritance tree
|
||||
for (String key : asms.keySet()) {
|
||||
if (CancellableWorker.isInterrupted()) {
|
||||
throw new InterruptedException();
|
||||
}
|
||||
ASMSource asm = asms.get(key);
|
||||
if (asm instanceof DoInitActionTag) {
|
||||
DoInitActionTag doi = (DoInitActionTag) asm;
|
||||
String exportName = doi.getSwf().getCharacter(doi.getCharacterId()).getExportName();
|
||||
if (exportName != null && exportName.startsWith("__Packages.")) {
|
||||
fireProgress(key);
|
||||
List<GraphTargetItem> tree = asm.getActionsToTree();
|
||||
for (GraphTargetItem item : tree) {
|
||||
if (item instanceof InterfaceActionItem) {
|
||||
InterfaceActionItem iai = (InterfaceActionItem) item;
|
||||
String className = String.join(".", getMembersPath(iai.name));
|
||||
classInheritance.put(className, new ArrayList<>());
|
||||
if (iai.superInterfaces != null) {
|
||||
for (GraphTargetItem imp : iai.superInterfaces) {
|
||||
String imtName = String.join(".", getMembersPath(imp));
|
||||
classInheritance.get(className).add(imtName);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (item instanceof ClassActionItem) {
|
||||
ClassActionItem cai = (ClassActionItem) item;
|
||||
final String className = String.join(".", getMembersPath(cai.className));
|
||||
classInheritance.put(className, new ArrayList<>());
|
||||
if (!classTraits.containsKey(className)) {
|
||||
classTraits.put(className, new LinkedHashMap<>());
|
||||
}
|
||||
for (int i = 0; i < cai.traits.size(); i++) {
|
||||
MyEntry<GraphTargetItem, GraphTargetItem> en = cai.traits.get(i);
|
||||
if (!(en.getKey() instanceof DirectValueActionItem)) {
|
||||
continue;
|
||||
}
|
||||
DirectValueActionItem dv = (DirectValueActionItem) en.getKey();
|
||||
String name = dv.getAsString();
|
||||
GraphTargetItem value = en.getValue();
|
||||
boolean isStatic = cai.traitsStatic.get(i);
|
||||
if (value instanceof FunctionActionItem) {
|
||||
if (name.startsWith("__get__") || name.startsWith("__set__")) {
|
||||
String vname = name.substring(7);
|
||||
Variable v = new Variable(isStatic, vname, vname, className);
|
||||
classTraits.get(className).put(vname, v);
|
||||
|
||||
Map<String, List<GraphTargetItem>> cachedTrees = new HashMap<>();
|
||||
|
||||
asms.entrySet().parallelStream()
|
||||
.filter(item -> item.getValue() instanceof DoInitActionTag)
|
||||
.forEach(entry -> {
|
||||
CancellableWorker.assignThreadToWorker(Thread.currentThread(), worker);
|
||||
if (worker.isCancelled()) {
|
||||
return;
|
||||
}
|
||||
Method m = new Method(isStatic, name, "Unknown" /*FIXME?*/, className);
|
||||
classTraits.get(className).put(name, m);
|
||||
} else {
|
||||
Variable v = new Variable(isStatic, name, name, className);
|
||||
classTraits.get(className).put(name, v);
|
||||
}
|
||||
}
|
||||
if (cai.extendsOp != null) {
|
||||
String parentClassName = String.join(".", getMembersPath(cai.extendsOp));
|
||||
classInheritance.get(className).add(parentClassName);
|
||||
} else {
|
||||
classInheritance.get(className).add("Object");
|
||||
}
|
||||
if (cai.implementsOp != null) {
|
||||
for (GraphTargetItem imp : cai.implementsOp) {
|
||||
String imtName = String.join(".", getMembersPath(imp));
|
||||
classInheritance.get(className).add(imtName);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
classesAsms.add(doi);
|
||||
}
|
||||
}
|
||||
}
|
||||
fireProgress(entry.getValue(), entry.getKey());
|
||||
|
||||
String key = entry.getKey();
|
||||
ASMSource asm = asms.get(key);
|
||||
if (asm instanceof DoInitActionTag) {
|
||||
DoInitActionTag doi = (DoInitActionTag) asm;
|
||||
String exportName = doi.getSwf().getCharacter(doi.getCharacterId()).getExportName();
|
||||
if (exportName != null && exportName.startsWith("__Packages.")) {
|
||||
//fireProgress(doi, key);
|
||||
List<GraphTargetItem> tree = new ArrayList<>();
|
||||
try {
|
||||
tree = asm.getActionsToTree();
|
||||
} catch (Throwable t) {
|
||||
//ignore
|
||||
}
|
||||
cachedTrees.put(key, tree);
|
||||
//get all assigned traits and inheritance tree
|
||||
for (GraphTargetItem item : tree) {
|
||||
if (item instanceof InterfaceActionItem) {
|
||||
InterfaceActionItem iai = (InterfaceActionItem) item;
|
||||
String className = String.join(".", getMembersPath(iai.name));
|
||||
classInheritance.put(className, new ArrayList<>());
|
||||
if (iai.superInterfaces != null) {
|
||||
for (GraphTargetItem imp : iai.superInterfaces) {
|
||||
String imtName = String.join(".", getMembersPath(imp));
|
||||
classInheritance.get(className).add(imtName);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (item instanceof ClassActionItem) {
|
||||
ClassActionItem cai = (ClassActionItem) item;
|
||||
final String className = String.join(".", getMembersPath(cai.className));
|
||||
classInheritance.put(className, new ArrayList<>());
|
||||
if (!classTraits.containsKey(className)) {
|
||||
classTraits.put(className, new LinkedHashMap<>());
|
||||
}
|
||||
for (int i = 0; i < cai.traits.size(); i++) {
|
||||
MyEntry<GraphTargetItem, GraphTargetItem> en = cai.traits.get(i);
|
||||
if (!(en.getKey() instanceof DirectValueActionItem)) {
|
||||
continue;
|
||||
}
|
||||
DirectValueActionItem dv = (DirectValueActionItem) en.getKey();
|
||||
String name = dv.getAsString();
|
||||
GraphTargetItem value = en.getValue();
|
||||
boolean isStatic = cai.traitsStatic.get(i);
|
||||
if (value instanceof FunctionActionItem) {
|
||||
if (name.startsWith("__get__") || name.startsWith("__set__")) {
|
||||
String vname = name.substring(7);
|
||||
Variable v = new Variable(isStatic, vname, vname, className);
|
||||
classTraits.get(className).put(vname, v);
|
||||
}
|
||||
Method m = new Method(isStatic, name, "Unknown" /*FIXME?*/, className);
|
||||
classTraits.get(className).put(name, m);
|
||||
} else {
|
||||
Variable v = new Variable(isStatic, name, name, className);
|
||||
classTraits.get(className).put(name, v);
|
||||
}
|
||||
}
|
||||
if (cai.extendsOp != null) {
|
||||
String parentClassName = String.join(".", getMembersPath(cai.extendsOp));
|
||||
classInheritance.get(className).add(parentClassName);
|
||||
} else {
|
||||
classInheritance.get(className).add("Object");
|
||||
}
|
||||
if (cai.implementsOp != null) {
|
||||
for (GraphTargetItem imp : cai.implementsOp) {
|
||||
String imtName = String.join(".", getMembersPath(imp));
|
||||
classInheritance.get(className).add(imtName);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//Detect this.x assigns
|
||||
for (GraphTargetItem item : tree) {
|
||||
if (item instanceof ClassActionItem) {
|
||||
ClassActionItem cai = (ClassActionItem) item;
|
||||
final String className = String.join(".", getMembersPath(cai.className));
|
||||
for (int i = 0; i < cai.traits.size(); i++) {
|
||||
MyEntry<GraphTargetItem, GraphTargetItem> en = cai.traits.get(i);
|
||||
if (!(en.getKey() instanceof DirectValueActionItem)) {
|
||||
continue;
|
||||
}
|
||||
GraphTargetItem value = en.getValue();
|
||||
if (value instanceof GraphTargetItem) {
|
||||
AbstractGraphTargetVisitor visitor = new AbstractGraphTargetVisitor() {
|
||||
@Override
|
||||
public boolean visit(GraphTargetItem item) {
|
||||
List<String> path = getFullPath(item);
|
||||
if (path != null) {
|
||||
List<String> parent = new ArrayList<>(path);
|
||||
parent.remove(parent.size() - 1);
|
||||
if (parent.size() == 1) {
|
||||
if (parent.get(0).equals("this")) {
|
||||
String name = path.get(path.size() - 1);
|
||||
if (!containsTrait(classTraits, classInheritance, className, name) && (!result.containsKey(className) || !result.get(className).containsKey(name))) {
|
||||
Variable v = new Variable(false, name, null, className);
|
||||
if (!result.containsKey(className)) {
|
||||
result.put(className, new LinkedHashMap<>());
|
||||
}
|
||||
result.get(className).put(name, v);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
};
|
||||
visitor.visit(value);
|
||||
value.visitRecursively(visitor);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
});
|
||||
|
||||
//Complete inheritance tree
|
||||
for (String className : classInheritance.keySet()) {
|
||||
@@ -301,73 +386,28 @@ public class UninitializedClassFieldsDetector {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//Detect this.x assigns
|
||||
for (String key : asms.keySet()) {
|
||||
if (CancellableWorker.isInterrupted()) {
|
||||
throw new InterruptedException();
|
||||
}
|
||||
ASMSource asm = asms.get(key);
|
||||
if (asm instanceof DoInitActionTag) {
|
||||
DoInitActionTag doi = (DoInitActionTag) asm;
|
||||
String exportName = doi.getSwf().getCharacter(doi.getCharacterId()).getExportName();
|
||||
if (exportName != null && exportName.startsWith("__Packages.")) {
|
||||
fireProgress(key);
|
||||
List<GraphTargetItem> tree = asm.getActionsToTree();
|
||||
for (GraphTargetItem item : tree) {
|
||||
if (item instanceof ClassActionItem) {
|
||||
ClassActionItem cai = (ClassActionItem) item;
|
||||
final String className = String.join(".", getMembersPath(cai.className));
|
||||
for (int i = 0; i < cai.traits.size(); i++) {
|
||||
MyEntry<GraphTargetItem, GraphTargetItem> en = cai.traits.get(i);
|
||||
if (!(en.getKey() instanceof DirectValueActionItem)) {
|
||||
continue;
|
||||
}
|
||||
GraphTargetItem value = en.getValue();
|
||||
if (value instanceof GraphTargetItem) {
|
||||
AbstractGraphTargetVisitor visitor = new AbstractGraphTargetVisitor() {
|
||||
@Override
|
||||
public boolean visit(GraphTargetItem item) {
|
||||
List<String> path = getFullPath(item);
|
||||
if (path != null) {
|
||||
List<String> parent = new ArrayList<>(path);
|
||||
parent.remove(parent.size() - 1);
|
||||
if (parent.size() == 1) {
|
||||
if (parent.get(0).equals("this")) {
|
||||
String name = path.get(path.size() - 1);
|
||||
if (!containsTrait(classTraits, classInheritance, className, name) && (!result.containsKey(className) || !result.get(className).containsKey(name))) {
|
||||
Variable v = new Variable(false, name, null, className);
|
||||
if (!result.containsKey(className)) {
|
||||
result.put(className, new LinkedHashMap<>());
|
||||
}
|
||||
result.get(className).put(name, v);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
};
|
||||
visitor.visit(value);
|
||||
value.visitRecursively(visitor);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
classesAsms.add(doi);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//getting static classname.x assigns
|
||||
for (String key : asms.keySet()) {
|
||||
if (CancellableWorker.isInterrupted()) {
|
||||
throw new InterruptedException();
|
||||
asms.entrySet().parallelStream().forEach(entry -> {
|
||||
CancellableWorker.assignThreadToWorker(Thread.currentThread(), worker);
|
||||
if (worker.isCancelled()) {
|
||||
return;
|
||||
}
|
||||
fireProgress(entry.getValue(), entry.getKey());
|
||||
String key = entry.getKey();
|
||||
ASMSource asm = asms.get(key);
|
||||
fireProgress(key);
|
||||
List<GraphTargetItem> tree = asm.getActionsToTree();
|
||||
//fireProgress(asm, key);
|
||||
List<GraphTargetItem> tree = new ArrayList<>();
|
||||
if (cachedTrees.containsKey(key)) {
|
||||
tree = cachedTrees.get(key);
|
||||
} else {
|
||||
try {
|
||||
tree = asm.getActionsToTree();
|
||||
} catch(Throwable t) {
|
||||
//ignore
|
||||
}
|
||||
}
|
||||
for (GraphTargetItem item : tree) {
|
||||
AbstractGraphTargetVisitor visitor = new AbstractGraphTargetVisitor() {
|
||||
@Override
|
||||
@@ -402,7 +442,7 @@ public class UninitializedClassFieldsDetector {
|
||||
visitor.visit(item);
|
||||
item.visitRecursively(visitor);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
//Removed cached version of classes - allow reparsing using detected uninitialized fields
|
||||
|
||||
@@ -24,12 +24,15 @@ import com.jpexs.decompiler.flash.exporters.settings.ScriptExportSettings;
|
||||
import com.jpexs.decompiler.flash.tags.base.ASMSource;
|
||||
import com.jpexs.helpers.CancellableWorker;
|
||||
import com.jpexs.helpers.Helper;
|
||||
import com.jpexs.helpers.ProgressListener;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
@@ -93,87 +96,127 @@ public class AS2ScriptExporter {
|
||||
List<ExportScriptTask> tasks = new ArrayList<>();
|
||||
String[] keys = asms.keySet().toArray(new String[asms.size()]);
|
||||
|
||||
Set<SWF> swfsThatNeedUninitializedClassTraitsDetection = new HashSet<>();
|
||||
|
||||
for (String key : keys) {
|
||||
ASMSource asm = asms.get(key);
|
||||
String currentOutDir = outdir + key + File.separator;
|
||||
currentOutDir = new File(currentOutDir).getParentFile().toString() + File.separator;
|
||||
|
||||
List<String> existingNames = existingNamesMap.get(currentOutDir);
|
||||
if (existingNames == null) {
|
||||
existingNames = new ArrayList<>();
|
||||
existingNamesMap.put(currentOutDir, existingNames);
|
||||
if (asm.getSwf().needsCalculatingAS2UninitializeClassTraits(asm)) {
|
||||
swfsThatNeedUninitializedClassTraitsDetection.add(asm.getSwf());
|
||||
}
|
||||
|
||||
String name = Helper.makeFileName(asm.getExportFileName());
|
||||
int i = 1;
|
||||
String baseName = name;
|
||||
while (existingNames.contains(name)) {
|
||||
i++;
|
||||
name = baseName + "_" + i;
|
||||
}
|
||||
existingNames.add(name);
|
||||
|
||||
tasks.add(new ExportScriptTask(handler, cnt++, asms.size(), name, asm, currentOutDir, exportSettings, evl));
|
||||
}
|
||||
|
||||
if (!parallel || tasks.size() < 2) {
|
||||
try {
|
||||
CancellableWorker.call("as2scriptexport", new Callable<Void>() {
|
||||
@Override
|
||||
public Void call() throws Exception {
|
||||
for (ExportScriptTask task : tasks) {
|
||||
if (CancellableWorker.isInterrupted()) {
|
||||
throw new InterruptedException();
|
||||
}
|
||||
|
||||
ret.add(task.call());
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}, Configuration.exportTimeout.get(), TimeUnit.SECONDS);
|
||||
} catch (TimeoutException ex) {
|
||||
logger.log(Level.SEVERE, Helper.formatTimeToText(Configuration.exportTimeout.get()) + " ActionScript export limit reached", ex);
|
||||
} catch (ExecutionException | InterruptedException ex) {
|
||||
logger.log(Level.SEVERE, "Error during AS2 export", ex);
|
||||
|
||||
ProgressListener progressListener = new ProgressListener() {
|
||||
@Override
|
||||
public void progress(int p) {
|
||||
}
|
||||
} else {
|
||||
ExecutorService executor = Executors.newFixedThreadPool(Configuration.getParallelThreadCount());
|
||||
List<Future<File>> futureResults = new ArrayList<>();
|
||||
for (ExportScriptTask task : tasks) {
|
||||
Future<File> future = executor.submit(task);
|
||||
futureResults.add(future);
|
||||
}
|
||||
|
||||
try {
|
||||
executor.shutdown();
|
||||
if (!executor.awaitTermination(Configuration.exportTimeout.get(), TimeUnit.SECONDS)) {
|
||||
logger.log(Level.SEVERE, "{0} ActionScript export limit reached", Helper.formatTimeToText(Configuration.exportTimeout.get()));
|
||||
|
||||
for (ExportScriptTask task : tasks) {
|
||||
CancellableWorker.cancelThread(task.thread);
|
||||
}
|
||||
@Override
|
||||
public void status(String status) {
|
||||
if (evl != null) {
|
||||
evl.handleEvent("unitializedClassFields", status);
|
||||
}
|
||||
} catch (InterruptedException ex) {
|
||||
//ignored
|
||||
} finally {
|
||||
executor.shutdownNow();
|
||||
}
|
||||
};
|
||||
|
||||
for (SWF swf : swfsThatNeedUninitializedClassTraitsDetection) {
|
||||
swf.getUninitializedClassFieldsDetector().addProgressListener(progressListener);
|
||||
}
|
||||
|
||||
try {
|
||||
for (SWF swf : swfsThatNeedUninitializedClassTraitsDetection) {
|
||||
swf.calculateAs2UninitializedClassTraits();
|
||||
}
|
||||
} catch (InterruptedException ie) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
try {
|
||||
for (String key : keys) {
|
||||
ASMSource asm = asms.get(key);
|
||||
String currentOutDir = outdir + key + File.separator;
|
||||
currentOutDir = new File(currentOutDir).getParentFile().toString() + File.separator;
|
||||
|
||||
List<String> existingNames = existingNamesMap.get(currentOutDir);
|
||||
if (existingNames == null) {
|
||||
existingNames = new ArrayList<>();
|
||||
existingNamesMap.put(currentOutDir, existingNames);
|
||||
}
|
||||
|
||||
String name = Helper.makeFileName(asm.getExportFileName());
|
||||
int i = 1;
|
||||
String baseName = name;
|
||||
while (existingNames.contains(name)) {
|
||||
i++;
|
||||
name = baseName + "_" + i;
|
||||
}
|
||||
existingNames.add(name);
|
||||
|
||||
tasks.add(new ExportScriptTask(handler, cnt++, asms.size(), name, asm, currentOutDir, exportSettings, evl));
|
||||
}
|
||||
|
||||
for (int f = 0; f < futureResults.size(); f++) {
|
||||
if (!parallel || tasks.size() < 2) {
|
||||
try {
|
||||
if (futureResults.get(f).isDone()) {
|
||||
ret.add(futureResults.get(f).get());
|
||||
CancellableWorker.call("as2scriptexport", new Callable<Void>() {
|
||||
@Override
|
||||
public Void call() throws Exception {
|
||||
for (ExportScriptTask task : tasks) {
|
||||
if (CancellableWorker.isInterrupted()) {
|
||||
throw new InterruptedException();
|
||||
}
|
||||
|
||||
ret.add(task.call());
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}, Configuration.exportTimeout.get(), TimeUnit.SECONDS);
|
||||
} catch (TimeoutException ex) {
|
||||
logger.log(Level.SEVERE, Helper.formatTimeToText(Configuration.exportTimeout.get()) + " ActionScript export limit reached", ex);
|
||||
} catch (ExecutionException | InterruptedException ex) {
|
||||
logger.log(Level.SEVERE, "Error during AS2 export", ex);
|
||||
}
|
||||
} else {
|
||||
ExecutorService executor = Executors.newFixedThreadPool(Configuration.getParallelThreadCount());
|
||||
List<Future<File>> futureResults = new ArrayList<>();
|
||||
for (ExportScriptTask task : tasks) {
|
||||
Future<File> future = executor.submit(task);
|
||||
futureResults.add(future);
|
||||
}
|
||||
|
||||
try {
|
||||
executor.shutdown();
|
||||
if (!executor.awaitTermination(Configuration.exportTimeout.get(), TimeUnit.SECONDS)) {
|
||||
logger.log(Level.SEVERE, "{0} ActionScript export limit reached", Helper.formatTimeToText(Configuration.exportTimeout.get()));
|
||||
|
||||
for (ExportScriptTask task : tasks) {
|
||||
CancellableWorker.cancelThread(task.thread);
|
||||
}
|
||||
}
|
||||
} catch (InterruptedException ex) {
|
||||
//ignored
|
||||
} catch (ExecutionException ex) {
|
||||
if (!(ex.getCause() instanceof InterruptedException)) {
|
||||
logger.log(Level.SEVERE, "Error during ActionScript export", ex);
|
||||
}
|
||||
} finally {
|
||||
executor.shutdownNow();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
for (int f = 0; f < futureResults.size(); f++) {
|
||||
try {
|
||||
if (futureResults.get(f).isDone()) {
|
||||
ret.add(futureResults.get(f).get());
|
||||
}
|
||||
} catch (InterruptedException ex) {
|
||||
//ignored
|
||||
} catch (ExecutionException ex) {
|
||||
if (!(ex.getCause() instanceof InterruptedException)) {
|
||||
logger.log(Level.SEVERE, "Error during ActionScript export", ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
} finally {
|
||||
for (SWF swf : swfsThatNeedUninitializedClassTraitsDetection) {
|
||||
swf.getUninitializedClassFieldsDetector().removeProgressListener(progressListener);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user