diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/RetryTask.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/RetryTask.java index 5d5ee5e80..2cef5ec61 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/RetryTask.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/RetryTask.java @@ -28,8 +28,6 @@ public class RetryTask { private final AbortRetryIgnoreHandler handler; - public Object result; - public RetryTask(RunnableIOEx r, AbortRetryIgnoreHandler handler) { this.r = r; this.handler = handler; diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/SWF.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/SWF.java index 0e5c4cb7a..879366100 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/SWF.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/SWF.java @@ -1346,7 +1346,7 @@ public final class SWF implements SWFContainerItem, Timelined { if (isAS3()) { ret.addAll(new AS3ScriptExporter().exportActionScript3(this, handler, outdir, exportSettings, parallel, evl)); } else { - ret.addAll(new AS2ScriptExporter().exportAS2ScriptsTimeout(handler, outdir, getASMs(true), exportSettings, evl)); + ret.addAll(new AS2ScriptExporter().exportAS2Scripts(handler, outdir, getASMs(true), exportSettings, parallel, evl)); } return ret; } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/script/AS2ScriptExporter.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/script/AS2ScriptExporter.java index fefc02662..8a566b278 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/script/AS2ScriptExporter.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/script/AS2ScriptExporter.java @@ -19,18 +19,12 @@ package com.jpexs.decompiler.flash.exporters.script; import com.jpexs.decompiler.flash.AbortRetryIgnoreHandler; import com.jpexs.decompiler.flash.EventListener; import com.jpexs.decompiler.flash.SWF; -import com.jpexs.decompiler.flash.action.Action; import com.jpexs.decompiler.flash.configuration.Configuration; -import com.jpexs.decompiler.flash.exporters.modes.ScriptExportMode; import com.jpexs.decompiler.flash.exporters.settings.ScriptExportSettings; -import com.jpexs.decompiler.flash.helpers.FileTextWriter; import com.jpexs.decompiler.flash.tags.base.ASMSource; -import com.jpexs.decompiler.graph.TranslateException; import com.jpexs.helpers.CancellableWorker; import com.jpexs.helpers.Helper; -import com.jpexs.helpers.Path; import java.io.File; -import java.io.FileOutputStream; import java.io.IOException; import java.util.ArrayList; import java.util.HashMap; @@ -38,9 +32,11 @@ import java.util.List; import java.util.Map; import java.util.concurrent.Callable; import java.util.concurrent.ExecutionException; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.Future; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; -import java.util.concurrent.atomic.AtomicInteger; import java.util.logging.Level; import java.util.logging.Logger; @@ -53,35 +49,18 @@ public class AS2ScriptExporter { private static final Logger logger = Logger.getLogger(AS2ScriptExporter.class.getName()); public List exportActionScript2(SWF swf, AbortRetryIgnoreHandler handler, String outdir, ScriptExportSettings exportSettings, boolean parallel, EventListener evl) throws IOException { - return exportAS2ScriptsTimeout(handler, outdir, swf.getASMs(true), exportSettings, evl); + return exportAS2Scripts(handler, outdir, swf.getASMs(true), exportSettings, parallel, evl); } - public List exportAS2ScriptsTimeout(final AbortRetryIgnoreHandler handler, final String outdir, final Map asms, final ScriptExportSettings exportSettings, final EventListener evl) throws IOException { - try { - List result = CancellableWorker.call(new Callable>() { - - @Override - public List call() throws Exception { - return exportAS2Scripts(handler, outdir, asms, exportSettings, evl); - } - }, Configuration.exportTimeout.get(), TimeUnit.SECONDS); - return result; - } 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); - } - return new ArrayList<>(); - } - - private List exportAS2Scripts(AbortRetryIgnoreHandler handler, String outdir, Map asms, ScriptExportSettings exportSettings, EventListener evl) throws IOException, InterruptedException { + public List exportAS2Scripts(AbortRetryIgnoreHandler handler, String outdir, Map asms, ScriptExportSettings exportSettings, boolean parallel, EventListener evl) throws IOException { List ret = new ArrayList<>(); if (!outdir.endsWith(File.separator)) { outdir += File.separator; } Map> existingNamesMap = new HashMap<>(); - AtomicInteger cnt = new AtomicInteger(1); + int cnt = 1; + List tasks = new ArrayList<>(); for (String key : asms.keySet()) { ASMSource asm = asms.get(key); String currentOutDir = outdir + key + File.separator; @@ -102,80 +81,59 @@ public class AS2ScriptExporter { } existingNames.add(name); - File f = exportAS2Script(handler, currentOutDir, asm, exportSettings, evl, cnt, asms.size(), name); - if (f != null) { - ret.add(f); + tasks.add(new ExportScriptTask(handler, cnt++, asms.size(), name, asm, currentOutDir, exportSettings, evl)); + } + + if (!parallel || tasks.size() < 2) { + try { + CancellableWorker.call(new Callable() { + @Override + public Void call() throws Exception { + for (ExportScriptTask task : tasks) { + if (Thread.currentThread().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> futureResults = new ArrayList<>(); + for (ExportScriptTask task : tasks) { + Future future = executor.submit(task); + futureResults.add(future); + } + + try { + executor.shutdown(); + if (!executor.awaitTermination(Configuration.exportTimeout.get(), TimeUnit.SECONDS)) { + logger.log(Level.SEVERE, Helper.formatTimeToText(Configuration.exportTimeout.get()) + " ActionScript export limit reached"); + } + } catch (InterruptedException ex) { + } finally { + executor.shutdownNow(); + } + + 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.log(Level.SEVERE, "Error during ABC export", ex); + } } } return ret; } - - private File exportAS2Script(AbortRetryIgnoreHandler handler, String outdir, ASMSource asm, ScriptExportSettings exportSettings, EventListener evl, AtomicInteger index, int count, String name) throws IOException, InterruptedException { - boolean retry; - do { - retry = false; - try { - int currentIndex = index.getAndIncrement(); - - if (!exportSettings.singleFile) { - Path.createDirectorySafe(new File(outdir)); - } - - String f = Path.combine(outdir, name) + exportSettings.getFileExtension(); - if (evl != null) { - evl.handleExportingEvent("script", currentIndex, count, f); - } - - long startTime = System.currentTimeMillis(); - - File file = new File(f); - try (FileTextWriter writer = exportSettings.singleFile ? null : new FileTextWriter(Configuration.getCodeFormatting(), new FileOutputStream(f))) { - FileTextWriter writer2 = exportSettings.singleFile ? exportSettings.singleFileWriter : writer; - ScriptExportMode exportMode = exportSettings.mode; - if (exportMode == ScriptExportMode.HEX) { - asm.getActionSourcePrefix(writer2); - asm.getActionBytesAsHex(writer2); - asm.getActionSourceSuffix(writer2); - } else if (exportMode != ScriptExportMode.AS) { - asm.getActionSourcePrefix(writer2); - asm.getASMSource(exportMode, writer2, null); - asm.getActionSourceSuffix(writer2); - } else { - List as = asm.getActions(); - Action.setActionsAddresses(as, 0); - Action.actionsToSource(asm, as, asm.toString()/*FIXME?*/, writer2); - } - } - - long stopTime = System.currentTimeMillis(); - - if (evl != null) { - long time = stopTime - startTime; - evl.handleExportedEvent("script", currentIndex, count, f + ", " + Helper.formatTimeSec(time)); - } - - return file; - } catch (InterruptedException ex) { - throw ex; - } catch (IOException | OutOfMemoryError | TranslateException | StackOverflowError ex) { - logger.log(Level.SEVERE, "Decompilation error in script: " + name, ex); - if (handler != null) { - int action = handler.getNewInstance().handle(ex); - switch (action) { - case AbortRetryIgnoreHandler.ABORT: - throw ex; - case AbortRetryIgnoreHandler.RETRY: - retry = true; - break; - case AbortRetryIgnoreHandler.IGNORE: - retry = false; - break; - } - } - } - } while (retry); - - return null; - } } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/script/AS3ScriptExporter.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/script/AS3ScriptExporter.java index 02e863571..e10c8b643 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/script/AS3ScriptExporter.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/script/AS3ScriptExporter.java @@ -34,7 +34,6 @@ import java.util.concurrent.Executors; import java.util.concurrent.Future; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; -import java.util.concurrent.atomic.AtomicInteger; import java.util.logging.Level; import java.util.logging.Logger; @@ -46,27 +45,30 @@ public class AS3ScriptExporter { private static final Logger logger = Logger.getLogger(AS3ScriptExporter.class.getName()); - public List exportActionScript3(SWF swf, final AbortRetryIgnoreHandler handler, final String outdir, final ScriptExportSettings exportSettings, final boolean parallel, final EventListener evl) { - final AtomicInteger cnt = new AtomicInteger(1); - + public List exportActionScript3(SWF swf, AbortRetryIgnoreHandler handler, String outdir, ScriptExportSettings exportSettings, boolean parallel, EventListener evl) { final List ret = new ArrayList<>(); final List packs = swf.getAS3Packs(); - if (!parallel || packs.size() < 2) { + int cnt = 1; + List tasks = new ArrayList<>(); + for (ScriptPack item : packs) { + if (!item.isSimple && Configuration.ignoreCLikePackages.get()) { + continue; + } + + tasks.add(new ExportPackTask(handler, cnt++, packs.size(), item.getClassPath(), item, outdir, exportSettings, parallel, evl)); + } + + if (!parallel || tasks.size() < 2) { try { CancellableWorker.call(new Callable() { @Override public Void call() throws Exception { - for (ScriptPack item : packs) { + for (ExportPackTask task : tasks) { if (Thread.currentThread().isInterrupted()) { throw new InterruptedException(); } - if (!item.isSimple && Configuration.ignoreCLikePackages.get()) { - continue; - } - - ExportPackTask task = new ExportPackTask(handler, cnt, packs.size(), item.getClassPath(), item, outdir, exportSettings, parallel, evl); ret.add(task.call()); } return null; @@ -74,17 +76,14 @@ public class AS3ScriptExporter { }, Configuration.exportTimeout.get(), TimeUnit.SECONDS); } catch (TimeoutException ex) { logger.log(Level.SEVERE, Helper.formatTimeToText(Configuration.exportTimeout.get()) + " ActionScript export limit reached", ex); - } catch (Exception ex) { + } catch (ExecutionException | InterruptedException ex) { logger.log(Level.SEVERE, "Error during ABC export", ex); } } else { ExecutorService executor = Executors.newFixedThreadPool(Configuration.getParallelThreadCount()); List> futureResults = new ArrayList<>(); - for (ScriptPack item : packs) { - if (!item.isSimple && Configuration.ignoreCLikePackages.get()) { - continue; - } - Future future = executor.submit(new ExportPackTask(handler, cnt, packs.size(), item.getClassPath(), item, outdir, exportSettings, parallel, evl)); + for (ExportPackTask task : tasks) { + Future future = executor.submit(task); futureResults.add(future); } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/script/ExportPackTask.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/script/ExportPackTask.java index e79a64df0..483d0a21d 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/script/ExportPackTask.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/script/ExportPackTask.java @@ -20,7 +20,6 @@ import com.jpexs.decompiler.flash.AbortRetryIgnoreHandler; import com.jpexs.decompiler.flash.EventListener; import com.jpexs.decompiler.flash.RetryTask; import com.jpexs.decompiler.flash.RunnableIOExResult; -import com.jpexs.decompiler.flash.abc.ABC; import com.jpexs.decompiler.flash.abc.ClassPath; import com.jpexs.decompiler.flash.abc.ScriptPack; import com.jpexs.decompiler.flash.exporters.settings.ScriptExportSettings; @@ -28,7 +27,6 @@ import com.jpexs.helpers.Helper; import java.io.File; import java.io.IOException; import java.util.concurrent.Callable; -import java.util.concurrent.atomic.AtomicInteger; /** * @@ -44,7 +42,7 @@ public class ExportPackTask implements Callable { ClassPath path; - AtomicInteger index; + int index; int count; @@ -58,7 +56,7 @@ public class ExportPackTask implements Callable { EventListener eventListener; - public ExportPackTask(AbortRetryIgnoreHandler handler, AtomicInteger index, int count, ClassPath path, ScriptPack pack, String directory, ScriptExportSettings exportSettings, boolean parallel, EventListener evl) { + public ExportPackTask(AbortRetryIgnoreHandler handler, int index, int count, ClassPath path, ScriptPack pack, String directory, ScriptExportSettings exportSettings, boolean parallel, EventListener evl) { this.pack = pack; this.directory = directory; this.exportSettings = exportSettings; @@ -71,7 +69,7 @@ public class ExportPackTask implements Callable { } @Override - public File call() throws Exception { + public File call() throws IOException, InterruptedException { RunnableIOExResult rio = new RunnableIOExResult() { @Override public void run() throws IOException, InterruptedException { @@ -80,19 +78,18 @@ public class ExportPackTask implements Callable { stopTime = System.currentTimeMillis(); } }; - int currentIndex = index.getAndIncrement(); + if (eventListener != null) { - synchronized (ABC.class) { - eventListener.handleExportingEvent("script", currentIndex, count, path); - } + eventListener.handleExportingEvent("script", index, count, path); } + new RetryTask(rio, handler).run(); + if (eventListener != null) { - synchronized (ABC.class) { - long time = stopTime - startTime; - eventListener.handleExportedEvent("script", currentIndex, count, path + ", " + Helper.formatTimeSec(time)); - } + long time = stopTime - startTime; + eventListener.handleExportedEvent("script", index, count, path + ", " + Helper.formatTimeSec(time)); } + return rio.result; } } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/script/ExportScriptTask.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/script/ExportScriptTask.java new file mode 100644 index 000000000..be3d76f44 --- /dev/null +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/script/ExportScriptTask.java @@ -0,0 +1,124 @@ +/* + * Copyright (C) 2010-2015 JPEXS, All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3.0 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. + */ +package com.jpexs.decompiler.flash.exporters.script; + +import com.jpexs.decompiler.flash.AbortRetryIgnoreHandler; +import com.jpexs.decompiler.flash.EventListener; +import com.jpexs.decompiler.flash.RunnableIOExResult; +import com.jpexs.decompiler.flash.action.Action; +import com.jpexs.decompiler.flash.configuration.Configuration; +import com.jpexs.decompiler.flash.exporters.modes.ScriptExportMode; +import com.jpexs.decompiler.flash.exporters.settings.ScriptExportSettings; +import com.jpexs.decompiler.flash.helpers.FileTextWriter; +import com.jpexs.decompiler.flash.tags.base.ASMSource; +import com.jpexs.helpers.Helper; +import com.jpexs.helpers.Path; +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.util.List; +import java.util.concurrent.Callable; +import java.util.logging.Logger; + +/** + * + * @author JPEXS + */ +public class ExportScriptTask implements Callable { + + private static final Logger logger = Logger.getLogger(ExportScriptTask.class.getName()); + + ASMSource asm; + + String directory; + + ScriptExportSettings exportSettings; + + String name; + + int index; + + int count; + + AbortRetryIgnoreHandler handler; + + long startTime; + + long stopTime; + + EventListener eventListener; + + public ExportScriptTask(AbortRetryIgnoreHandler handler, int index, int count, String name, ASMSource asm, String directory, ScriptExportSettings exportSettings, EventListener evl) { + this.asm = asm; + this.directory = directory; + this.exportSettings = exportSettings; + this.name = name; + this.index = index; + this.count = count; + this.handler = handler; + this.eventListener = evl; + } + + @Override + public File call() throws IOException, InterruptedException { + String f = Path.combine(directory, name) + exportSettings.getFileExtension(); + RunnableIOExResult rio = new RunnableIOExResult() { + @Override + public void run() throws IOException, InterruptedException { + startTime = System.currentTimeMillis(); + + if (!exportSettings.singleFile) { + Path.createDirectorySafe(new File(directory)); + } + + File file = new File(f); + try (FileTextWriter writer = exportSettings.singleFile ? null : new FileTextWriter(Configuration.getCodeFormatting(), new FileOutputStream(f))) { + FileTextWriter writer2 = exportSettings.singleFile ? exportSettings.singleFileWriter : writer; + ScriptExportMode exportMode = exportSettings.mode; + if (exportMode == ScriptExportMode.HEX) { + asm.getActionSourcePrefix(writer2); + asm.getActionBytesAsHex(writer2); + asm.getActionSourceSuffix(writer2); + } else if (exportMode != ScriptExportMode.AS) { + asm.getActionSourcePrefix(writer2); + asm.getASMSource(exportMode, writer2, null); + asm.getActionSourceSuffix(writer2); + } else { + List as = asm.getActions(); + Action.setActionsAddresses(as, 0); + Action.actionsToSource(asm, as, asm.toString()/*FIXME?*/, writer2); + } + } + + this.result = file; + + stopTime = System.currentTimeMillis(); + } + }; + + if (eventListener != null) { + eventListener.handleExportingEvent("script", index, count, f); + } + + if (eventListener != null) { + long time = stopTime - startTime; + eventListener.handleExportedEvent("script", index, count, f + ", " + Helper.formatTimeSec(time)); + } + + return rio.result; + } +} diff --git a/src/com/jpexs/decompiler/flash/gui/MainPanel.java b/src/com/jpexs/decompiler/flash/gui/MainPanel.java index d07ec135b..0f392f8d2 100644 --- a/src/com/jpexs/decompiler/flash/gui/MainPanel.java +++ b/src/com/jpexs/decompiler/flash/gui/MainPanel.java @@ -1251,7 +1251,7 @@ public final class MainPanel extends JPanel implements TreeSelectionListener, Se Map asmsToExport = swf.getASMs(true, as12scripts, false); try (FileTextWriter writer = scriptExportSettings.singleFile ? new FileTextWriter(Configuration.getCodeFormatting(), new FileOutputStream(singleFileName)) : null) { scriptExportSettings.singleFileWriter = writer; - ret.addAll(new AS2ScriptExporter().exportAS2ScriptsTimeout(handler, scriptsFolder, asmsToExport, scriptExportSettings, evl)); + ret.addAll(new AS2ScriptExporter().exportAS2Scripts(handler, scriptsFolder, asmsToExport, scriptExportSettings, parallel, evl)); } } }