From 5f2ffd0089944312ed3443a55e9d0cfc0b6cd847 Mon Sep 17 00:00:00 2001 From: "honfika@gmail.com" Date: Sat, 24 Dec 2016 18:52:09 +0100 Subject: [PATCH] Multi thread AS search --- .../decompiler/flash/DecompilerPool.java | 154 ++++ .../com/jpexs/decompiler/flash/RetryTask.java | 4 + .../src/com/jpexs/decompiler/flash/SWF.java | 158 ++-- .../decompiler/flash/cache/AS2Cache.java | 69 ++ .../decompiler/flash/cache/AS3Cache.java | 52 ++ .../flash/cache/ScriptDecompiledListener.java | 27 + .../flash/configuration/Configuration.java | 6 +- .../jpexs/decompiler/flash/iggy/IggyFile.java | 487 +++++++------ .../flash/iggy/IggyFlashHeader32.java | 30 + .../flash/iggy/IggyFlashHeader64.java | 56 +- .../flash/iggy/IggyFontBinInfo.java | 13 +- .../jpexs/decompiler/flash/iggy/IggySwf.java | 685 +++++++++--------- .../flash/iggy/conversion/IggySwfBundle.java | 229 +++--- .../flash/locales/AppResources_ca.properties | 2 + .../src/com/jpexs/decompiler/graph/Graph.java | 4 +- .../jpexs/decompiler/flash/gui/MainPanel.java | 26 + .../decompiler/flash/gui/abc/ABCPanel.java | 61 +- .../flash/gui/player/FlashPlayerPanel.java | 3 +- 18 files changed, 1277 insertions(+), 789 deletions(-) create mode 100644 libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/DecompilerPool.java create mode 100644 libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/cache/AS2Cache.java create mode 100644 libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/cache/AS3Cache.java create mode 100644 libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/cache/ScriptDecompiledListener.java diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/DecompilerPool.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/DecompilerPool.java new file mode 100644 index 000000000..4d9968cf4 --- /dev/null +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/DecompilerPool.java @@ -0,0 +1,154 @@ +/* + * Copyright (C) 2010-2016 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; + +import com.jpexs.decompiler.flash.abc.ScriptPack; +import com.jpexs.decompiler.flash.abc.types.ConvertData; +import com.jpexs.decompiler.flash.abc.types.ScriptInfo; +import com.jpexs.decompiler.flash.action.ActionList; +import com.jpexs.decompiler.flash.cache.ScriptDecompiledListener; +import com.jpexs.decompiler.flash.configuration.Configuration; +import com.jpexs.decompiler.flash.exporters.modes.ScriptExportMode; +import com.jpexs.decompiler.flash.helpers.HighlightedText; +import com.jpexs.decompiler.flash.helpers.HighlightedTextWriter; +import com.jpexs.decompiler.flash.tags.base.ASMSource; +import java.util.concurrent.Callable; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.Future; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.TimeUnit; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * + * @author JPEXS + */ +public class DecompilerPool { + + private final ThreadPoolExecutor executor; + + public DecompilerPool() { + int threadCount = Configuration.getParallelThreadCount(); + executor = new ThreadPoolExecutor(threadCount, threadCount, + 0L, TimeUnit.MILLISECONDS, + new LinkedBlockingQueue<>()); + } + + public Future submitTask(ASMSource src, ActionList actions, ScriptDecompiledListener listener) { + Future f = executor.submit(new Callable() { + @Override + public HighlightedText call() throws Exception { + Thread.sleep(10000); + HighlightedTextWriter writer = new HighlightedTextWriter(Configuration.getCodeFormatting(), true); + writer.startFunction("!script"); + src.getActionScriptSource(writer, actions); + writer.endFunction(); + + HighlightedText result = new HighlightedText(writer); + SWF swf = src.getSwf(); + if (swf != null) { + swf.as2Cache.put(src, result); + } + + if (listener != null) { + listener.onComplete(result); + } + + return result; + } + }); + + return f; + } + + public Future submitTask(ScriptPack pack, ScriptDecompiledListener listener) { + Future f = executor.submit(new Callable() { + @Override + public HighlightedText call() throws Exception { + int scriptIndex = pack.scriptIndex; + ScriptInfo script = null; + if (scriptIndex > -1) { + script = pack.abc.script_info.get(scriptIndex); + } + boolean parallel = Configuration.parallelSpeedUp.get(); + Thread.sleep(10000); + HighlightedTextWriter writer = new HighlightedTextWriter(Configuration.getCodeFormatting(), true); + pack.toSource(writer, script == null ? null : script.traits.traits, new ConvertData(), ScriptExportMode.AS, parallel); + + HighlightedText result = new HighlightedText(writer); + SWF swf = pack.getSwf(); + if (swf != null) { + swf.as3Cache.put(pack, result); + } + + if (listener != null) { + listener.onComplete(result); + } + + return result; + } + }); + + return f; + } + + public String getStat() { + return "core: " + executor.getCorePoolSize() + + " size: " + executor.getPoolSize() + + " largest: " + executor.getLargestPoolSize() + + " max: " + executor.getMaximumPoolSize() + + " active: " + executor.getActiveCount() + + " count: " + executor.getTaskCount() + + " completed: " + executor.getCompletedTaskCount(); + } + + public HighlightedText decompile(ASMSource src, ActionList actions) throws InterruptedException { + Future future = submitTask(src, actions, null); + try { + return future.get(); + } catch (InterruptedException ex) { + future.cancel(true); + throw ex; + } catch (ExecutionException ex) { + Logger.getLogger(DecompilerPool.class.getName()).log(Level.SEVERE, null, ex); + } + + return null; + } + + public HighlightedText decompile(ScriptPack pack) throws InterruptedException { + Future future = submitTask(pack, null); + try { + return future.get(); + } catch (InterruptedException ex) { + future.cancel(true); + throw ex; + } catch (ExecutionException ex) { + Logger.getLogger(DecompilerPool.class.getName()).log(Level.SEVERE, null, ex); + } + + return null; + } + + public void shutdown() throws InterruptedException { + executor.shutdown(); + if (!executor.awaitTermination(100, TimeUnit.SECONDS)) { + } + } +} 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 71830400f..09716f2c6 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/RetryTask.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/RetryTask.java @@ -42,6 +42,10 @@ public class RetryTask { } catch (InterruptedException ex) { throw ex; } catch (Exception ex) { + if (handler == null) { + throw ex; + } + switch (handler.handle(ex)) { case AbortRetryIgnoreHandler.ABORT: throw ex; 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 6ec2550ed..b53ab0c6a 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/SWF.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/SWF.java @@ -36,7 +36,6 @@ import com.jpexs.decompiler.flash.abc.avm2.model.StringAVM2Item; import com.jpexs.decompiler.flash.abc.types.ConvertData; import com.jpexs.decompiler.flash.abc.types.MethodBody; import com.jpexs.decompiler.flash.abc.types.Multiname; -import com.jpexs.decompiler.flash.abc.types.ScriptInfo; import com.jpexs.decompiler.flash.abc.types.traits.Trait; import com.jpexs.decompiler.flash.abc.types.traits.TraitClass; import com.jpexs.decompiler.flash.abc.types.traits.TraitMethodGetterSetter; @@ -70,6 +69,9 @@ import com.jpexs.decompiler.flash.action.swf5.ActionNewMethod; import com.jpexs.decompiler.flash.action.swf5.ActionNewObject; import com.jpexs.decompiler.flash.action.swf5.ActionSetMember; import com.jpexs.decompiler.flash.action.swf7.ActionDefineFunction2; +import com.jpexs.decompiler.flash.cache.AS2Cache; +import com.jpexs.decompiler.flash.cache.AS3Cache; +import com.jpexs.decompiler.flash.cache.ScriptDecompiledListener; import com.jpexs.decompiler.flash.configuration.Configuration; import com.jpexs.decompiler.flash.dumpview.DumpInfo; import com.jpexs.decompiler.flash.dumpview.DumpInfoSwfNode; @@ -156,6 +158,7 @@ import com.jpexs.decompiler.graph.model.LocalData; import com.jpexs.helpers.ByteArrayRange; import com.jpexs.helpers.Cache; import com.jpexs.helpers.Helper; +import com.jpexs.helpers.ImmediateFuture; import com.jpexs.helpers.NulStream; import com.jpexs.helpers.ProgressListener; import com.jpexs.helpers.SerializableImage; @@ -187,6 +190,7 @@ import java.util.Map; import java.util.Random; import java.util.Set; import java.util.TreeMap; +import java.util.concurrent.Future; import java.util.logging.Level; import java.util.logging.Logger; import java.util.zip.DeflaterOutputStream; @@ -338,13 +342,12 @@ public final class SWF implements SWFContainerItem, Timelined { private final Cache soundCache = Cache.getInstance(false, false, "sound"); @Internal - private final Cache as2PcodeCache = Cache.getInstance(true, true, "as2pcode"); + public final AS2Cache as2Cache = new AS2Cache(); @Internal - private final Cache as2Cache = Cache.getInstance(true, false, "as2"); + public final AS3Cache as3Cache = new AS3Cache(); - @Internal - private final Cache as3Cache = Cache.getInstance(true, false, "as3"); + private static final DecompilerPool decompilerPool = new DecompilerPool(); public static List swfSignatures = Arrays.asList( "FWS", // Uncompressed Flash @@ -395,7 +398,6 @@ public final class SWF implements SWFContainerItem, Timelined { swfList.swfs.clear(); } - as2PcodeCache.clear(); as2Cache.clear(); as3Cache.clear(); frameCache.clear(); @@ -2543,7 +2545,6 @@ public final class SWF implements SWFContainerItem, Timelined { } public void clearScriptCache() { - as2PcodeCache.clear(); as2Cache.clear(); as3Cache.clear(); IdentifiersDeobfuscation.clearCache(); @@ -2582,31 +2583,71 @@ public final class SWF implements SWFContainerItem, Timelined { public static void uncache(ASMSource src) { if (src != null) { SWF swf = src.getSwf(); - swf.as2Cache.remove(src); - swf.as2PcodeCache.remove(src); + if (swf != null) { + swf.as2Cache.remove(src); + } } } public static void uncache(ScriptPack pack) { if (pack != null) { - pack.getSwf().as3Cache.remove(pack); + SWF swf = pack.getSwf(); + if (swf != null) { + swf.as3Cache.remove(pack); + } } } public static boolean isCached(ASMSource src) { - return src.getSwf().as2Cache.contains(src); + if (src != null) { + SWF swf = src.getSwf(); + if (swf != null) { + return swf.as2Cache.isCached(src); + } + } + + return false; } public static boolean isCached(ScriptPack pack) { - return pack.getSwf().as3Cache.contains(pack); + if (pack != null) { + SWF swf = pack.getSwf(); + if (swf != null) { + return swf.as3Cache.isCached(pack); + } + } + + return false; + } + + public static HighlightedText getFromCache(ASMSource src) { + if (src != null) { + SWF swf = src.getSwf(); + if (swf != null) { + return swf.as2Cache.get(src); + } + } + + return null; + } + + public static HighlightedText getFromCache(ScriptPack pack) { + if (pack != null) { + SWF swf = pack.getSwf(); + if (swf != null) { + return swf.as3Cache.get(pack); + } + } + + return null; } public static ActionList getCachedActionList(ASMSource src, final List listeners) throws InterruptedException { synchronized (src) { SWF swf = src.getSwf(); int deobfuscationMode = Configuration.autoDeobfuscate.get() ? 1 : 0; - if (swf != null && swf.as2PcodeCache.contains(src)) { - ActionList result = swf.as2PcodeCache.get(src); + if (swf != null && swf.as2Cache.isPcodeCached(src)) { + ActionList result = swf.as2Cache.getPcode(src); if (result.deobfuscationMode == deobfuscationMode) { return result; } @@ -2625,7 +2666,7 @@ public final class SWF implements SWFContainerItem, Timelined { list.fileData = actionBytes.getArray(); list.deobfuscationMode = deobfuscationMode; if (swf != null) { - swf.as2PcodeCache.put(src, list); + swf.as2Cache.put(src, list); } return list; @@ -2638,49 +2679,68 @@ public final class SWF implements SWFContainerItem, Timelined { } } - public static HighlightedText getFromCache(ASMSource src) { - SWF swf = src.getSwf(); - if (swf.as2Cache.contains(src)) { - return swf.as2Cache.get(src); - } - - return null; - } - public static HighlightedText getCached(ASMSource src, ActionList actions) throws InterruptedException { SWF swf = src.getSwf(); - if (swf.as2Cache.contains(src)) { - return swf.as2Cache.get(src); + HighlightedText res; + if (swf != null) { + res = swf.as2Cache.get(src); + if (res != null) { + return res; + } } - HighlightedTextWriter writer = new HighlightedTextWriter(Configuration.getCodeFormatting(), true); - writer.startFunction("!script"); - src.getActionScriptSource(writer, actions); - writer.endFunction(); - - HighlightedText res = new HighlightedText(writer); - swf.as2Cache.put(src, res); - return res; + return decompilerPool.decompile(src, actions); } public static HighlightedText getCached(ScriptPack pack) throws InterruptedException { SWF swf = pack.getSwf(); - if (swf.as3Cache.contains(pack)) { - return swf.as3Cache.get(pack); + HighlightedText res; + if (swf != null) { + res = swf.as3Cache.get(pack); + if (res != null) { + return res; + } } - int scriptIndex = pack.scriptIndex; - ScriptInfo script = null; - if (scriptIndex > -1) { - script = pack.abc.script_info.get(scriptIndex); - } - boolean parallel = Configuration.parallelSpeedUp.get(); - HighlightedTextWriter writer = new HighlightedTextWriter(Configuration.getCodeFormatting(), true); - pack.toSource(writer, script == null ? null : script.traits.traits, new ConvertData(), ScriptExportMode.AS, parallel); - HighlightedText res = new HighlightedText(writer); - swf.as3Cache.put(pack, res); + return decompilerPool.decompile(pack); + } - return res; + public static Future getCachedFuture(ASMSource src, ActionList actions, ScriptDecompiledListener listener) throws InterruptedException { + SWF swf = src.getSwf(); + HighlightedText res; + if (swf != null) { + res = swf.as2Cache.get(src); + if (res != null) { + if (listener != null) { + listener.onComplete(res); + } + + return new ImmediateFuture<>(res); + } + } + + return decompilerPool.submitTask(src, actions, listener); + } + + public static Future getCachedFuture(ScriptPack pack, ScriptDecompiledListener listener) throws InterruptedException { + SWF swf = pack.getSwf(); + HighlightedText res; + if (swf != null) { + res = swf.as3Cache.get(pack); + if (res != null) { + if (listener != null) { + listener.onComplete(res); + } + + return new ImmediateFuture<>(res); + } + } + + return decompilerPool.submitTask(pack, listener); + } + + public DecompilerPool getDecompilerPool() { + return decompilerPool; } public Cache getRectCache() { @@ -2898,7 +2958,8 @@ public final class SWF implements SWFContainerItem, Timelined { timelined.setModified(true); timelined.resetTimeline(); } else // timeline should be always the swf here - if (removeDependencies) { + { + if (removeDependencies) { removeTagWithDependenciesFromTimeline(tag, timelined.getTimeline()); timelined.setModified(true); } else { @@ -2907,6 +2968,7 @@ public final class SWF implements SWFContainerItem, Timelined { timelined.setModified(true); } } + } } @Override diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/cache/AS2Cache.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/cache/AS2Cache.java new file mode 100644 index 000000000..a5f90b90d --- /dev/null +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/cache/AS2Cache.java @@ -0,0 +1,69 @@ +/* + * Copyright (C) 2010-2016 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.cache; + +import com.jpexs.decompiler.flash.action.ActionList; +import com.jpexs.decompiler.flash.helpers.HighlightedText; +import com.jpexs.decompiler.flash.tags.base.ASMSource; +import com.jpexs.helpers.Cache; + +/** + * + * @author JPEXS + */ +public class AS2Cache { + + private final Cache cache = Cache.getInstance(true, false, "as2"); + + private final Cache pcodeCache = Cache.getInstance(true, true, "as2pcode"); + + public void clear() { + pcodeCache.clear(); + cache.clear(); + } + + public boolean isCached(ASMSource src) { + return cache.contains(src); + } + + public boolean isPcodeCached(ASMSource src) { + return pcodeCache.contains(src); + } + + public HighlightedText get(ASMSource src) { + return cache.get(src); + } + + public ActionList getPcode(ASMSource src) { + return pcodeCache.get(src); + } + + public void put(ASMSource src, HighlightedText text) { + cache.put(src, text); + } + + public void put(ASMSource src, ActionList actionList) { + pcodeCache.put(src, actionList); + } + + public void remove(ASMSource src) { + if (src != null) { + cache.remove(src); + pcodeCache.remove(src); + } + } +} diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/cache/AS3Cache.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/cache/AS3Cache.java new file mode 100644 index 000000000..0b8a998a7 --- /dev/null +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/cache/AS3Cache.java @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2010-2016 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.cache; + +import com.jpexs.decompiler.flash.abc.ScriptPack; +import com.jpexs.decompiler.flash.helpers.HighlightedText; +import com.jpexs.helpers.Cache; + +/** + * + * @author JPEXS + */ +public class AS3Cache { + + private final Cache cache = Cache.getInstance(true, false, "as3"); + + public void clear() { + cache.clear(); + } + + public boolean isCached(ScriptPack pack) { + return cache.contains(pack); + } + + public HighlightedText get(ScriptPack pack) { + return cache.get(pack); + } + + public void put(ScriptPack pack, HighlightedText text) { + cache.put(pack, text); + } + + public void remove(ScriptPack pack) { + if (pack != null) { + cache.remove(pack); + } + } +} diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/cache/ScriptDecompiledListener.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/cache/ScriptDecompiledListener.java new file mode 100644 index 000000000..b97c2ab0e --- /dev/null +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/cache/ScriptDecompiledListener.java @@ -0,0 +1,27 @@ +/* + * Copyright (C) 2010-2016 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.cache; + +/** + * + * @author JPEXS + */ +@FunctionalInterface +public interface ScriptDecompiledListener { + + public void onComplete(T result); +} diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/configuration/Configuration.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/configuration/Configuration.java index 3d23ec52f..dd6edc47c 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/configuration/Configuration.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/configuration/Configuration.java @@ -57,7 +57,7 @@ import javax.swing.JOptionPane; * * @author JPEXS */ -public class Configuration { +public final class Configuration { private static final String CONFIG_NAME = "config.bin"; @@ -83,7 +83,7 @@ public class Configuration { @ConfigurationDefaultInt(10) @ConfigurationCategory("decompilation") - public static final ConfigurationItem parallelSpeedUpThreadCount = null; + private static final ConfigurationItem parallelSpeedUpThreadCount = null; @ConfigurationDefaultBoolean(false) @ConfigurationCategory("script") @@ -926,7 +926,7 @@ public class Configuration { } public static Map getConfigurationFields() { - Field[] fields = Configuration.class.getFields(); + Field[] fields = Configuration.class.getDeclaredFields(); Map result = new HashMap<>(); for (Field field : fields) { if (ConfigurationItem.class.isAssignableFrom(field.getType())) { diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/iggy/IggyFile.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/iggy/IggyFile.java index 80f1c1d89..6c84f4eca 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/iggy/IggyFile.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/iggy/IggyFile.java @@ -1,244 +1,243 @@ -package com.jpexs.decompiler.flash.iggy; - -import com.jpexs.decompiler.flash.iggy.streams.DataStreamInterface; -import com.jpexs.decompiler.flash.iggy.streams.IggyIndexBuilder; -import com.jpexs.decompiler.flash.iggy.streams.RandomAccessFileDataStream; -import com.jpexs.decompiler.flash.iggy.streams.ReadDataStreamInterface; -import com.jpexs.decompiler.flash.iggy.streams.SeekMode; -import com.jpexs.decompiler.flash.iggy.streams.StructureInterface; -import com.jpexs.decompiler.flash.iggy.streams.TemporaryDataStream; -import com.jpexs.decompiler.flash.iggy.streams.WriteDataStreamInterface; -import java.io.File; -import java.io.FileOutputStream; -import java.io.FilenameFilter; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.util.ArrayList; -import java.util.List; -import java.util.logging.Level; -import java.util.logging.Logger; - -/** - * - * @author JPEXS - * - * Based of works of somebody called eternity. - * - */ -public class IggyFile implements StructureInterface { - - final static Logger LOGGER = Logger.getLogger(IggyFile.class.getName()); - - private File originalFile; - private IggyHeader header; - private List subFileEntries = new ArrayList<>(); - private List subFileEntriesData = new ArrayList<>(); - - private IggySwf iggySwf; - - public static final int FIRST_TAG_POSITION = 3; - - public IggySwf getSwf() { - return iggySwf; - } - - public IggyFile(String filePath) throws IOException { - this(new File(filePath)); - } - - public IggyFile(File file) throws IOException { - this.originalFile = file; - try (ReadDataStreamInterface stream = new RandomAccessFileDataStream(file)) { - readFromDataStream(stream); - } - } - - public File getOriginalFile() { - return originalFile; - } - - public IggyHeader getHeader() { - return header; - } - - public IggySubFileEntry getSubFileEntry(int entryIndex) { - if (entryIndex < 0 || entryIndex >= subFileEntries.size()) { - throw new ArrayIndexOutOfBoundsException("No entry with index " + entryIndex + " exists"); - } - return subFileEntries.get(entryIndex); - } - - public int getNumEntries() { - return subFileEntries.size(); - } - - public byte[] getEntryData(int entryIndex) { - if (entryIndex < 0 || entryIndex >= subFileEntries.size()) { - throw new ArrayIndexOutOfBoundsException("No entry with index " + entryIndex + " exists"); - } - return subFileEntriesData.get(entryIndex); - } - - @Override - public String toString() { - StringBuilder sb = new StringBuilder(); - sb.append("[IggyFile:").append("\r\n"); - sb.append(header).append("\r\n"); - sb.append("Entries:").append("\r\n"); - for (IggySubFileEntry entry : subFileEntries) { - sb.append(entry).append("\r\n"); - } - sb.append("]"); - return sb.toString(); - } - - public static void extractIggyFile(File iggyFile, File extractDir) throws IOException { - final String FILENAME_FORMAT = "index%d_type%d.bin"; - IggyFile ir = new IggyFile(iggyFile); - for (int i = 0; i < ir.getNumEntries(); i++) { - IggySubFileEntry entry = ir.getSubFileEntry(i); - try (FileOutputStream fos = new FileOutputStream(new File(extractDir, String.format(FILENAME_FORMAT, i, entry.type)))) { - fos.write(ir.getEntryData(i)); - } - } - } - - public String getSwfName() { - return iggySwf.getName(); - } - - public long getSwfXMin() { - return iggySwf.getHdr().getXMin(); - } - - public long getSwfYMin() { - return iggySwf.getHdr().getYMin(); - } - - public long getSwfXMax() { - return iggySwf.getHdr().getXMax(); - } - - public long getSwfYMax() { - return iggySwf.getHdr().getYMax(); - } - - public float getSwfFrameRate() { - return iggySwf.getHdr().getFrameRate(); - } - - /** - * Removes entries of type INDEX.There can be more than one INDEX, - * continuous. This removes all ot them. - */ - public void removeIndexEntries() { - long offsetsChange = 0; - final int ENTRY_SIZE = 16; - for (int i = 0; i < subFileEntries.size(); i++) { - IggySubFileEntry entry = subFileEntries.get(i); - entry.offset += offsetsChange; - if (entry.type == IggySubFileEntry.TYPE_INDEX) { - offsetsChange = offsetsChange - entry.size - ENTRY_SIZE; - subFileEntriesData.remove(i); - subFileEntries.remove(i); - i--; - } - } - } - - public boolean updateFlashEntry() throws IOException { - - byte replacementData[]; - byte replacementIndexData[]; - IggyIndexBuilder ib = new IggyIndexBuilder(); - try (DataStreamInterface stream = new TemporaryDataStream()) { - stream.setIndexing(ib); - iggySwf.writeToDataStream(stream); - replacementData = stream.getAllBytes(); - replacementIndexData = ib.getIndexBytes(); - } catch (IOException ex) { - Logger.getLogger(IggyFile.class.getName()).log(Level.SEVERE, "Error during updating SWF", ex); - return false; - } - - long offsetsChange = 0; - for (int i = 0; i < subFileEntries.size(); i++) { - IggySubFileEntry entry = subFileEntries.get(i); - entry.offset += offsetsChange; - if (entry.type == IggySubFileEntry.TYPE_FLASH) { - long oldSize = entry.size; - long newSize = replacementData.length; - entry.size = newSize; - entry.size2 = newSize; - offsetsChange = offsetsChange + (newSize - oldSize); //entries after this one will have modified offsets - subFileEntriesData.set(i, replacementData); - } - } - - removeIndexEntries(); - IggySubFileEntry indexEntry = new IggySubFileEntry(IggySubFileEntry.TYPE_INDEX, replacementIndexData.length, replacementIndexData.length, 0 /*offset will be set automatically*/); - subFileEntries.add(indexEntry); - subFileEntriesData.add(replacementIndexData); - return true; - } - - private void parseEntries() throws IOException { - for (int i = 0; i < subFileEntries.size(); i++) { - IggySubFileEntry entry = subFileEntries.get(i); - if (entry.type == IggySubFileEntry.TYPE_FLASH) { - iggySwf = new IggySwf(new TemporaryDataStream(getEntryData(i))); - break; - } - /*if (entry.type == IggySubFileEntry.TYPE_INDEX) { - IggyIndexParser.parseIndex(true, new TemporaryDataStream(getEntryData(i)), new ArrayList<>(), new ArrayList<>()); - }*/ - } - } - - @Override - public void readFromDataStream(ReadDataStreamInterface stream) throws IOException { - header = new IggyHeader(stream); - if (!header.is64()) { - throw new IOException("32 bit iggy files are not (yet) supported, sorry"); - } - for (int i = 0; i < header.getNumSubfiles(); i++) { - subFileEntries.add(new IggySubFileEntry(stream)); - } - for (IggySubFileEntry entry : subFileEntries) { - stream.seek(entry.offset, SeekMode.SET); - byte[] entryData = stream.readBytes((int) entry.size); - subFileEntriesData.add(entryData); - } - parseEntries(); - } - - public void saveChanges() throws IOException { - updateFlashEntry(); - try (RandomAccessFileDataStream raf = new RandomAccessFileDataStream(originalFile)) { - writeToDataStream(raf); - } - } - - @Override - public void writeToDataStream(WriteDataStreamInterface stream) throws IOException { - header.writeToDataStream(stream); - - long startOffset = IggyHeader.STRUCT_SIZE + IggySubFileEntry.STRUCTURE_SIZE * subFileEntries.size(); - long currentOffset = startOffset; - - for (int i = 0; i < subFileEntries.size(); i++) { - IggySubFileEntry entry = subFileEntries.get(i); - entry.offset = currentOffset; - currentOffset += entry.size; - entry.writeToDataStream(stream); - } - - for (int i = 0; i < subFileEntries.size(); i++) { - byte[] entryData = subFileEntriesData.get(i); - stream.writeBytes(entryData); - } - - } - -} +package com.jpexs.decompiler.flash.iggy; + +import com.jpexs.decompiler.flash.iggy.streams.DataStreamInterface; +import com.jpexs.decompiler.flash.iggy.streams.IggyIndexBuilder; +import com.jpexs.decompiler.flash.iggy.streams.RandomAccessFileDataStream; +import com.jpexs.decompiler.flash.iggy.streams.ReadDataStreamInterface; +import com.jpexs.decompiler.flash.iggy.streams.SeekMode; +import com.jpexs.decompiler.flash.iggy.streams.StructureInterface; +import com.jpexs.decompiler.flash.iggy.streams.TemporaryDataStream; +import com.jpexs.decompiler.flash.iggy.streams.WriteDataStreamInterface; +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * + * @author JPEXS + * + * Based of works of somebody called eternity. + * + */ +public class IggyFile implements StructureInterface { + + final static Logger LOGGER = Logger.getLogger(IggyFile.class.getName()); + + private File originalFile; + + private IggyHeader header; + + private List subFileEntries = new ArrayList<>(); + + private List subFileEntriesData = new ArrayList<>(); + + private IggySwf iggySwf; + + public static final int FIRST_TAG_POSITION = 3; + + public IggySwf getSwf() { + return iggySwf; + } + + public IggyFile(String filePath) throws IOException { + this(new File(filePath)); + } + + public IggyFile(File file) throws IOException { + this.originalFile = file; + try (ReadDataStreamInterface stream = new RandomAccessFileDataStream(file)) { + readFromDataStream(stream); + } + } + + public File getOriginalFile() { + return originalFile; + } + + public IggyHeader getHeader() { + return header; + } + + public IggySubFileEntry getSubFileEntry(int entryIndex) { + if (entryIndex < 0 || entryIndex >= subFileEntries.size()) { + throw new ArrayIndexOutOfBoundsException("No entry with index " + entryIndex + " exists"); + } + return subFileEntries.get(entryIndex); + } + + public int getNumEntries() { + return subFileEntries.size(); + } + + public byte[] getEntryData(int entryIndex) { + if (entryIndex < 0 || entryIndex >= subFileEntries.size()) { + throw new ArrayIndexOutOfBoundsException("No entry with index " + entryIndex + " exists"); + } + return subFileEntriesData.get(entryIndex); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("[IggyFile:").append("\r\n"); + sb.append(header).append("\r\n"); + sb.append("Entries:").append("\r\n"); + for (IggySubFileEntry entry : subFileEntries) { + sb.append(entry).append("\r\n"); + } + sb.append("]"); + return sb.toString(); + } + + public static void extractIggyFile(File iggyFile, File extractDir) throws IOException { + final String FILENAME_FORMAT = "index%d_type%d.bin"; + IggyFile ir = new IggyFile(iggyFile); + for (int i = 0; i < ir.getNumEntries(); i++) { + IggySubFileEntry entry = ir.getSubFileEntry(i); + try (FileOutputStream fos = new FileOutputStream(new File(extractDir, String.format(FILENAME_FORMAT, i, entry.type)))) { + fos.write(ir.getEntryData(i)); + } + } + } + + public String getSwfName() { + return iggySwf.getName(); + } + + public long getSwfXMin() { + return iggySwf.getHdr().getXMin(); + } + + public long getSwfYMin() { + return iggySwf.getHdr().getYMin(); + } + + public long getSwfXMax() { + return iggySwf.getHdr().getXMax(); + } + + public long getSwfYMax() { + return iggySwf.getHdr().getYMax(); + } + + public float getSwfFrameRate() { + return iggySwf.getHdr().getFrameRate(); + } + + /** + * Removes entries of type INDEX.There can be more than one INDEX, + * continuous. This removes all ot them. + */ + public void removeIndexEntries() { + long offsetsChange = 0; + final int ENTRY_SIZE = 16; + for (int i = 0; i < subFileEntries.size(); i++) { + IggySubFileEntry entry = subFileEntries.get(i); + entry.offset += offsetsChange; + if (entry.type == IggySubFileEntry.TYPE_INDEX) { + offsetsChange = offsetsChange - entry.size - ENTRY_SIZE; + subFileEntriesData.remove(i); + subFileEntries.remove(i); + i--; + } + } + } + + public boolean updateFlashEntry() throws IOException { + + byte replacementData[]; + byte replacementIndexData[]; + IggyIndexBuilder ib = new IggyIndexBuilder(); + try (DataStreamInterface stream = new TemporaryDataStream()) { + stream.setIndexing(ib); + iggySwf.writeToDataStream(stream); + replacementData = stream.getAllBytes(); + replacementIndexData = ib.getIndexBytes(); + } catch (IOException ex) { + Logger.getLogger(IggyFile.class.getName()).log(Level.SEVERE, "Error during updating SWF", ex); + return false; + } + + long offsetsChange = 0; + for (int i = 0; i < subFileEntries.size(); i++) { + IggySubFileEntry entry = subFileEntries.get(i); + entry.offset += offsetsChange; + if (entry.type == IggySubFileEntry.TYPE_FLASH) { + long oldSize = entry.size; + long newSize = replacementData.length; + entry.size = newSize; + entry.size2 = newSize; + offsetsChange = offsetsChange + (newSize - oldSize); //entries after this one will have modified offsets + subFileEntriesData.set(i, replacementData); + } + } + + removeIndexEntries(); + IggySubFileEntry indexEntry = new IggySubFileEntry(IggySubFileEntry.TYPE_INDEX, replacementIndexData.length, replacementIndexData.length, 0 /*offset will be set automatically*/); + subFileEntries.add(indexEntry); + subFileEntriesData.add(replacementIndexData); + return true; + } + + private void parseEntries() throws IOException { + for (int i = 0; i < subFileEntries.size(); i++) { + IggySubFileEntry entry = subFileEntries.get(i); + if (entry.type == IggySubFileEntry.TYPE_FLASH) { + iggySwf = new IggySwf(new TemporaryDataStream(getEntryData(i))); + break; + } + /*if (entry.type == IggySubFileEntry.TYPE_INDEX) { + IggyIndexParser.parseIndex(true, new TemporaryDataStream(getEntryData(i)), new ArrayList<>(), new ArrayList<>()); + }*/ + } + } + + @Override + public void readFromDataStream(ReadDataStreamInterface stream) throws IOException { + header = new IggyHeader(stream); + if (!header.is64()) { + throw new IOException("32 bit iggy files are not (yet) supported, sorry"); + } + for (int i = 0; i < header.getNumSubfiles(); i++) { + subFileEntries.add(new IggySubFileEntry(stream)); + } + for (IggySubFileEntry entry : subFileEntries) { + stream.seek(entry.offset, SeekMode.SET); + byte[] entryData = stream.readBytes((int) entry.size); + subFileEntriesData.add(entryData); + } + parseEntries(); + } + + public void saveChanges() throws IOException { + updateFlashEntry(); + try (RandomAccessFileDataStream raf = new RandomAccessFileDataStream(originalFile)) { + writeToDataStream(raf); + } + } + + @Override + public void writeToDataStream(WriteDataStreamInterface stream) throws IOException { + header.writeToDataStream(stream); + + long startOffset = IggyHeader.STRUCT_SIZE + IggySubFileEntry.STRUCTURE_SIZE * subFileEntries.size(); + long currentOffset = startOffset; + + for (int i = 0; i < subFileEntries.size(); i++) { + IggySubFileEntry entry = subFileEntries.get(i); + entry.offset = currentOffset; + currentOffset += entry.size; + entry.writeToDataStream(stream); + } + + for (int i = 0; i < subFileEntries.size(); i++) { + byte[] entryData = subFileEntriesData.get(i); + stream.writeBytes(entryData); + } + + } +} diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/iggy/IggyFlashHeader32.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/iggy/IggyFlashHeader32.java index 6006b1c6a..113bb1898 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/iggy/IggyFlashHeader32.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/iggy/IggyFlashHeader32.java @@ -18,64 +18,94 @@ public class IggyFlashHeader32 implements IggyFlashHeaderInterface { @IggyFieldType(DataType.uint32_t) long main_offset; // 0 Relative offset to first section (matches sizeof header) + @IggyFieldType(DataType.uint32_t) long as3_section_offset; // 4 Relative offset to as3 file names table... + @IggyFieldType(DataType.uint32_t) long unk_offset; // 8 relative offset to something + @IggyFieldType(DataType.uint32_t) long unk_offset2; // 0xC relative offset to something + @IggyFieldType(DataType.uint32_t) long unk_offset3; // 0x10 relative offset to something + @IggyFieldType(DataType.uint32_t) long unk_offset4; // 0x14 relative offset to something + @IggyFieldType(DataType.uint32_t) long xmin; //0x18 in pixels + @IggyFieldType(DataType.uint32_t) long ymin; //0x0C in pixels + @IggyFieldType(DataType.uint32_t) long xmax; // 0x20 in pixels + @IggyFieldType(DataType.uint32_t) long ymax; // 0x24 in pixels + @IggyFieldType(DataType.uint32_t) long unk_28; // probably number of blocks/objects after header + @IggyFieldType(DataType.uint32_t) long unk_2C; + @IggyFieldType(DataType.uint32_t) long unk_30; + @IggyFieldType(DataType.uint32_t) long unk_34; + @IggyFieldType(DataType.uint32_t) long unk_38; + @IggyFieldType(DataType.uint32_t) long unk_3C; + @IggyFieldType(DataType.float_t) float frameRate; + @IggyFieldType(DataType.uint32_t) long unk_44; + @IggyFieldType(DataType.uint32_t) long unk_48; + @IggyFieldType(DataType.uint32_t) long unk_4C; + @IggyFieldType(DataType.uint32_t) long names_offset; // 0x50 relative offset to the names/import section of the file + @IggyFieldType(DataType.uint32_t) long unk_offset5; // 0x54 relative offset to something + @IggyFieldType(DataType.uint64_t) long unk_58; // Maybe number of imports/names pointed by names_offset + @IggyFieldType(DataType.uint32_t) long last_section_offset; // 0x60 relative offset, points to the small last section of the file + @IggyFieldType(DataType.uint32_t) long unk_offset6; // 0x64 relative offset to something + @IggyFieldType(DataType.uint32_t) long as3_code_offset; // 0x68 relative offset to as3 code (8 bytes header + abc blob) + @IggyFieldType(DataType.uint32_t) long as3_names_offset; // 0x6C relative offset to as3 file names table (or classes names or whatever) + @IggyFieldType(DataType.uint32_t) long unk_70; + @IggyFieldType(DataType.uint32_t) long unk_74; + @IggyFieldType(DataType.uint32_t) long unk_78; // Maybe number of classes / as3 names + @IggyFieldType(DataType.uint32_t) long unk_7C; diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/iggy/IggyFlashHeader64.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/iggy/IggyFlashHeader64.java index 6f627bb76..5c9a6f6ad 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/iggy/IggyFlashHeader64.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/iggy/IggyFlashHeader64.java @@ -9,7 +9,7 @@ import java.lang.reflect.Field; /** * - * @author Jindra + * @author JPEXS * * Based of works of somebody called eternity. */ @@ -17,62 +17,91 @@ public class IggyFlashHeader64 implements IggyFlashHeaderInterface { @IggyFieldType(DataType.uint64_t) long off_base; // 0 Relative offset to first section (matches sizeof header); + @IggyFieldType(DataType.uint64_t) long off_sequence_end; // 8 Relative offset to as3 file names table... + @IggyFieldType(DataType.uint64_t) long off_font_end; // 0x10 relative offset to something + @IggyFieldType(DataType.uint64_t) long off_sequence_start1; // 0x18 relative offset to something + @IggyFieldType(DataType.uint64_t) long off_sequence_start2; // 0x20 relative offset to something + @IggyFieldType(DataType.uint64_t) long off_sequence_start3; // 0x28 names_offset; 0x50 relative pointer to the names/import section of the file + @IggyFieldType(DataType.uint32_t) long xmin; // 0x30 in pixels + @IggyFieldType(DataType.uint32_t) long ymin; // 0x34 in pixels + @IggyFieldType(DataType.uint32_t) long xmax; // 0x38 in pixels + @IggyFieldType(DataType.uint32_t) long ymax; // 0x3C in pixels + @IggyFieldType(DataType.uint32_t) - long unk_40; // probably numer of blocks/objects after header + long unk_40; // probably number of blocks/objects after header + @IggyFieldType(DataType.uint32_t) long unk_44; + @IggyFieldType(DataType.uint32_t) long unk_48; + @IggyFieldType(DataType.uint32_t) long unk_4C; + @IggyFieldType(DataType.uint32_t) long unk_50; + @IggyFieldType(DataType.uint32_t) long unk_54; + @IggyFieldType(DataType.float_t) float frame_rate; + @IggyFieldType(DataType.uint32_t) long unk_5C; + @IggyFieldType(DataType.uint64_t) long imported_guid; + @IggyFieldType(DataType.uint64_t) long my_guid; // same for some fonts (eng + chinese) + @IggyFieldType(DataType.uint64_t) long off_names; // 0x70 relative offset to the names/import section of the file - end of fonts + @IggyFieldType(DataType.uint64_t) long off_unk78; // 0x78 relative offset to something + @IggyFieldType(DataType.uint64_t) long unk80; + @IggyFieldType(DataType.uint64_t) long off_last_section; + @IggyFieldType(DataType.uint64_t) long off_flash_filename; + @IggyFieldType(DataType.uint64_t) long off_decl_strings; + @IggyFieldType(DataType.uint64_t) long off_type_of_fonts; + @IggyFieldType(DataType.uint64_t) long flags; + @IggyFieldType(DataType.uint32_t) long font_count; + @IggyFieldType(DataType.uint32_t) long zero2; @@ -87,29 +116,51 @@ public class IggyFlashHeader64 implements IggyFlashHeaderInterface { } private long base_address; + private long sequence_end_address; + private long font_end_address; + private long sequence_start_address1; + private long sequence_start_address2; + private long sequence_start_address3; + private long names_address; + private long unk78_address; + private long last_section_address; + private long flash_filename_address; + private long decl_strings_address; + private long type_fonts_address; private long base_ofs_pos; + private long sequence_end_ofs_pos; + private long font_end_ofs_pos; + private long sequence_start1_ofs_pos; + private long sequence_start2_ofs_pos; + private long sequence_start3_ofs_pos; + private long names_ofs_pos; + private long unk78_ofs_pos; + private long last_section_ofs_pos; + private long flash_filename_ofs_pos; + private long decl_strings_ofs_pos; + private long type_fonts_ofs_pos; public long getBase_ofs_pos() { @@ -389,5 +440,4 @@ public class IggyFlashHeader64 implements IggyFlashHeaderInterface { public float getFrameRate() { return frame_rate; } - } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/iggy/IggyFontBinInfo.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/iggy/IggyFontBinInfo.java index 97d01c1dc..d44a8066e 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/iggy/IggyFontBinInfo.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/iggy/IggyFontBinInfo.java @@ -16,24 +16,34 @@ public class IggyFontBinInfo implements StructureInterface { @IggyFieldType(DataType.uint64_t) long size_of_this_info = STRUCT_SIZE; + @IggyFieldType(value = DataType.uint16_t, count = 4) int font_specific[]; + @IggyFieldType(DataType.float_t) float normX; + @IggyFieldType(DataType.float_t) float zero; + @IggyFieldType(DataType.float_t) float zero2; + @IggyFieldType(DataType.float_t) float normY; + @IggyFieldType(DataType.float_t) float minSize; + @IggyFieldType(DataType.float_t) float maxSize; + @IggyFieldType(DataType.uint64_t) long order_in_iggy_file; + @IggyFieldType(DataType.int64_t) long address_back; //relative + @IggyFieldType(value = DataType.uint8_t, count = 40) byte pad[]; @@ -59,7 +69,7 @@ public class IggyFontBinInfo implements StructureInterface { maxSize = s.readFloat(); order_in_iggy_file = s.readUI64(); address_back = s.readSI64(); -//if(address_back + s.position() - 8 != text_offsets[i]) Printf("Wrong iggy font format (bininfo-offsetback) (%u)!\n",i); +//if(address_back + s.position() - 8 != text_offsets[i]) Printf("Wrong iggy font format (bininfo-offsetback) (%u)!\n",i); pad = s.readBytes(40); } @@ -79,5 +89,4 @@ public class IggyFontBinInfo implements StructureInterface { s.writeSI64(address_back); s.writeBytes(pad); } - } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/iggy/IggySwf.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/iggy/IggySwf.java index e5907428c..290e51513 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/iggy/IggySwf.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/iggy/IggySwf.java @@ -1,339 +1,346 @@ -package com.jpexs.decompiler.flash.iggy; - -import com.jpexs.decompiler.flash.iggy.annotations.IggyFieldType; -import com.jpexs.decompiler.flash.iggy.streams.IggyIndexBuilder; -import com.jpexs.decompiler.flash.iggy.streams.ReadDataStreamInterface; -import com.jpexs.decompiler.flash.iggy.streams.SeekMode; -import com.jpexs.decompiler.flash.iggy.streams.StructureInterface; -import com.jpexs.decompiler.flash.iggy.streams.WriteDataStreamInterface; -import java.io.IOException; -import java.util.ArrayList; -import java.util.List; - -/** - * - * @author JPEXS - */ -public class IggySwf implements StructureInterface { - - final static int NO_OFFSET = 1; - - @IggyFieldType(value = DataType.wchar_t, count = 48) - String name; - - private List fonts = new ArrayList<>(); - // private List font_data_addresses = new ArrayList<>(); - private List add_fonts = new ArrayList<>(); -// private List add_font_data_addresses = new ArrayList<>(); - - private IggyFlashHeader64 hdr; - - public IggySwf(ReadDataStreamInterface stream) throws IOException { - readFromDataStream(stream); - } - private List texts = new ArrayList<>(); - //private List text_data_addresses = new ArrayList<>(); - private List add_texts = new ArrayList<>(); - //private List add_text_data_addresses = new ArrayList<>(); - - //private byte font_add_data[]; - //private List font_additional_size = new ArrayList<>(); - private IggyFontBinInfo font_bin_info[]; - private List sequenceNames = new ArrayList<>(); - //private List sequenceValues = new ArrayList<>(); - - private IggyFontTypeInfo type_info[]; - private String type_info_name[]; - private IggyDeclStrings decl_strings; - private long ofs_additional; - private long additional_address; - - public IggyFlashHeader64 getHdr() { - return hdr; - } - - public List getFonts() { - return fonts; - } - - public List getAddFonts() { - return add_fonts; - } - - public List getTexts() { - return texts; - } - - public List getAddTexts() { - return add_texts; - } - - @Override - public void readFromDataStream(ReadDataStreamInterface s) throws IOException { - this.hdr = new IggyFlashHeader64(s); - //Save all font bytes to buffer for later easy modification - //here is offset[0] - 184 - name = s.readWChar(); - //here is offset[1] - 230 - int pad8 = 8 - (int) (s.position() % 8); - if (pad8 > 8) { - s.seek(pad8, SeekMode.CUR); - } - //here is offset [2] - 232 - s.seek(hdr.getBaseAddress(), SeekMode.SET); - s.readUI64(); //pad 1 - - List itemsAddresses = new ArrayList<>(); - - while (true) { - long offset = s.readUI64(); - if (offset == 1) { - break; - } - itemsAddresses.add(offset + s.position() - 8); - } - if (hdr.getImported_guid() != 0) { - ofs_additional = s.readUI64(); - additional_address = ofs_additional == 1 ? 0 : ofs_additional + s.position() - 8; - } - for (Long addr : itemsAddresses) { - s.seek(addr, SeekMode.SET); - int kind = s.readUI8(); - s.seek(-1, SeekMode.CUR); - switch (kind) { - case 22 /*FONT*/: - IggyFont font = new IggyFont(s); - //font_data_addresses.add(addr); - fonts.add(font); - break; - case 6 /*TEXT*/: - IggyText text = new IggyText(s); - //text_data_addresses.add(addr); - texts.add(text); - break; - default: - throw new RuntimeException("Unknown item kind: " + kind); - } - } - - if (additional_address != 0) { - s.seek(additional_address, SeekMode.SET); - List additionalItemsAddresses = new ArrayList<>(); - while (true) { - long offset = s.readUI64(); - if (offset == 1) { - break; - } - additionalItemsAddresses.add(offset + s.position() - 8); - } - for (Long addr : additionalItemsAddresses) { - s.seek(addr, SeekMode.SET); - int kind = s.readUI8(); - s.seek(-1, SeekMode.CUR); - switch (kind) { - case 22 /*FONT*/: - IggyFont font = new IggyFont(s); - //add_font_data_addresses.add(addr); - add_fonts.add(font); - break; - case 6 /*TEXT*/: - IggyText text = new IggyText(s); - //add_text_data_addresses.add(addr); - add_texts.add(text); - break; - default: - throw new RuntimeException("Unknown imported item kind: " + kind); - } - } - } - s.seek(hdr.getFontEndAddress(), SeekMode.SET); - //here is offset [4] - 856 ? - font_bin_info = new IggyFontBinInfo[(int) hdr.font_count]; - for (int i = 0; i < hdr.font_count; i++) { - font_bin_info[i] = new IggyFontBinInfo(s); - } - - sequenceNames = new ArrayList<>(); - - long seq_addresses[] = new long[]{hdr.getSequenceStartAddress1(), hdr.getSequenceStartAddress2(), hdr.getSequenceStartAddress3()}; - long seq_name_addresses[] = new long[3]; - for (int i = 0; i < 3; i++) { - if (seq_addresses[i] == 0) { - seq_name_addresses[i] = 0; - //0 - } else { - s.seek(seq_addresses[i], SeekMode.SET); - long ofs_seq_name = s.readUI64(); - seq_name_addresses[i] = ofs_seq_name == 1 ? 0 : ofs_seq_name + s.position() - 8; - s.readUI64(); //is this crucial? - } - } - - for (int i = 0; i < 3; i++) { - if (seq_name_addresses[i] > 0) { - s.seek(seq_name_addresses[i], SeekMode.SET); - sequenceNames.add(s.readWChar()); - } else { - sequenceNames.add(null); - } - } - s.pad8bytes(); - - //sequence = new IggySequence(s); - s.seek(hdr.getTypeFontsAddress(), SeekMode.SET); - type_info = new IggyFontTypeInfo[(int) hdr.font_count]; - type_info_name = new String[(int) hdr.font_count]; - for (int i = 0; i < hdr.font_count; i++) { - type_info[i] = new IggyFontTypeInfo(s); - } - for (int i = 0; i < hdr.font_count; i++) { - s.seek(type_info[i].getLocal_name_ofs_pos() + type_info[i].ofs_local_name, SeekMode.SET); - type_info_name[i] = s.readWChar(); - } - - s.seek(hdr.getDeclStringsAddress(), SeekMode.SET); - decl_strings = new IggyDeclStrings(s); - /*WriteDataStreamInterface outs = new TemporaryDataStream(); - writeToDataStream(outs); - Helper.writeFile("d:\\Dropbox\\jpexs-laptop\\iggi\\parts\\swf_out.bin", outs.getAllBytes());*/ - } - - public String getName() { - return name; - } - - @Override - public void writeToDataStream(WriteDataStreamInterface s) throws IOException { - IggyIndexBuilder ib = s.getIndexing(); - hdr.writeToDataStream(s); - s.writeWChar(name); - s.pad8bytes(); - s.writeUI64(1); - ib.write16bitArray(name.length() + 1); - ib.writeTwoPaddingBytes(); - ib.write64bitPointerArray(64); - long posBeforeOffsets = s.position(); - - final int FILL_LATER = 1; - - List fontPosFillLater = new ArrayList<>(); - - for (int i = 0; i < fonts.size(); i++) { - fontPosFillLater.add(s.position()); - s.writeUI64(FILL_LATER); - } - List textPosFillLater = new ArrayList<>(); - for (int i = 0; i < texts.size(); i++) { - textPosFillLater.add(s.position()); - s.writeUI64(FILL_LATER); - } - s.writeUI64(1); - - long addPosFillLater = s.position(); - s.writeUI64(FILL_LATER); - long posAfter = posBeforeOffsets + 64 * 8; - long curPos = s.position(); - long numLeft = posAfter - curPos; - long ofsLeft = numLeft / 8; - for (int i = 0; i < ofsLeft - 1; i++) { - s.writeUI64(FILL_LATER); - } - - for (int i = 0; i < fonts.size(); i++) { - s.setOlderOffsetToThisPos(fontPosFillLater.get(i)); - fonts.get(i).writeToDataStream(s); - } - for (int i = 0; i < texts.size(); i++) { - s.setOlderOffsetToThisPos(textPosFillLater.get(i)); - texts.get(i).writeToDataStream(s); - } - - if (!add_fonts.isEmpty() || !add_texts.isEmpty()) { - s.setOlderOffsetToThisPos(addPosFillLater); - - List addFontPosFillLater = new ArrayList<>(); - - for (int i = 0; i < add_fonts.size(); i++) { - addFontPosFillLater.add(s.position()); - s.writeUI64(FILL_LATER); - } - List addTextPosFillLater = new ArrayList<>(); - for (int i = 0; i < add_texts.size(); i++) { - addTextPosFillLater.add(s.position()); - s.writeUI64(FILL_LATER); - } - s.writeUI64(FILL_LATER); - for (int i = 0; i < add_fonts.size(); i++) { - s.setOlderOffsetToThisPos(addFontPosFillLater.get(i)); - add_fonts.get(i).writeToDataStream(s); - } - for (int i = 0; i < add_texts.size(); i++) { - s.setOlderOffsetToThisPos(addTextPosFillLater.get(i)); - add_texts.get(i).writeToDataStream(s); - } - } - s.setOlderOffsetToThisPos(hdr.getFont_end_ofs_pos()); - ib.writeConstLengthArray(IggyIndexBuilder.CONST_BIN_INFO_SIZE, hdr.font_count); - for (int i = 0; i < hdr.font_count; i++) { - font_bin_info[i].writeToDataStream(s); - } - - long seq_ofs_pos[] = new long[]{hdr.getSequence_start1_ofs_pos(), hdr.getSequence_start2_ofs_pos(), hdr.getSequence_start3_ofs_pos()}; - long off_seq_expected[] = new long[]{hdr.off_sequence_start1, hdr.off_sequence_start2, hdr.off_sequence_start3}; - - long seq_name_fill_later[] = new long[3]; - - s.setOlderOffsetToThisPos(seq_ofs_pos[0]); - s.writeUI64(1); - s.writeUI64(1); - ib.writeLengthCustom(16, new int[]{0}, new int[]{2}); - - seq_name_fill_later[2] = s.position(); - s.setOlderOffsetToThisPos(seq_ofs_pos[2]); - s.writeUI64(FILL_LATER); - s.writeUI64(0); - ib.writeConstLength(IggyIndexBuilder.CONST_SEQUENCE_SIZE); - for (int i = 0; i < 3; i++) { - if (sequenceNames.get(i) != null) { - s.setOlderOffsetToThisPos(seq_name_fill_later[i]); - ib.write16bitArray(sequenceNames.get(i).length() + 1); - s.writeWChar(sequenceNames.get(i)); - } - } - s.setOlderOffsetToThisPos(hdr.getSequence_end_ofs_pos()); - s.pad8bytes(); - ib.pad8bytes(); - - ib.writeConstLengthArray(IggyIndexBuilder.CONST_TYPE_INFO_SIZE, hdr.font_count); - s.setOlderOffsetToThisPos(hdr.getType_fonts_ofs_pos()); - //s.seek(hdr.getTypeFontsAddress(), SeekMode.SET); - for (int i = 0; i < hdr.font_count; i++) { - type_info[i].writeToDataStream(s); - } - - for (int i = 0; i < hdr.font_count; i++) { - ib.write16bitArray(type_info_name[i].length() + 1); - s.setOlderOffsetToThisPos(type_info[i].getLocal_name_ofs_pos()); - s.writeWChar(type_info_name[i]); - } - s.pad8bytes(); - ib.pad8bytes(); - - s.setOlderOffsetToThisPos(hdr.getDecl_strings_ofs_pos()); - //s.seek(hdr.getDeclStringsAddress(), SeekMode.SET); - decl_strings.writeToDataStream(s); - } - - @Override - public String toString() { - StringBuilder sb = new StringBuilder(); - sb.append("[\r\n"); - sb.append("name ").append(name).append("\r\n"); - return sb.toString(); - } - - public IggyDeclStrings getDeclStrings() { - return decl_strings; - } - -} +package com.jpexs.decompiler.flash.iggy; + +import com.jpexs.decompiler.flash.iggy.annotations.IggyFieldType; +import com.jpexs.decompiler.flash.iggy.streams.IggyIndexBuilder; +import com.jpexs.decompiler.flash.iggy.streams.ReadDataStreamInterface; +import com.jpexs.decompiler.flash.iggy.streams.SeekMode; +import com.jpexs.decompiler.flash.iggy.streams.StructureInterface; +import com.jpexs.decompiler.flash.iggy.streams.WriteDataStreamInterface; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +/** + * + * @author JPEXS + */ +public class IggySwf implements StructureInterface { + + final static int NO_OFFSET = 1; + + @IggyFieldType(value = DataType.wchar_t, count = 48) + String name; + + private List fonts = new ArrayList<>(); + + // private List font_data_addresses = new ArrayList<>(); + private List add_fonts = new ArrayList<>(); +// private List add_font_data_addresses = new ArrayList<>(); + + private IggyFlashHeader64 hdr; + + public IggySwf(ReadDataStreamInterface stream) throws IOException { + readFromDataStream(stream); + } + + private List texts = new ArrayList<>(); + + //private List text_data_addresses = new ArrayList<>(); + private List add_texts = new ArrayList<>(); + //private List add_text_data_addresses = new ArrayList<>(); + + //private byte font_add_data[]; + //private List font_additional_size = new ArrayList<>(); + private IggyFontBinInfo font_bin_info[]; + + private List sequenceNames = new ArrayList<>(); + //private List sequenceValues = new ArrayList<>(); + + private IggyFontTypeInfo type_info[]; + + private String type_info_name[]; + + private IggyDeclStrings decl_strings; + + private long ofs_additional; + + private long additional_address; + + public IggyFlashHeader64 getHdr() { + return hdr; + } + + public List getFonts() { + return fonts; + } + + public List getAddFonts() { + return add_fonts; + } + + public List getTexts() { + return texts; + } + + public List getAddTexts() { + return add_texts; + } + + @Override + public void readFromDataStream(ReadDataStreamInterface s) throws IOException { + this.hdr = new IggyFlashHeader64(s); + //Save all font bytes to buffer for later easy modification + //here is offset[0] - 184 + name = s.readWChar(); + //here is offset[1] - 230 + int pad8 = 8 - (int) (s.position() % 8); + if (pad8 > 8) { + s.seek(pad8, SeekMode.CUR); + } + //here is offset [2] - 232 + s.seek(hdr.getBaseAddress(), SeekMode.SET); + s.readUI64(); //pad 1 + + List itemsAddresses = new ArrayList<>(); + + while (true) { + long offset = s.readUI64(); + if (offset == 1) { + break; + } + itemsAddresses.add(offset + s.position() - 8); + } + if (hdr.getImported_guid() != 0) { + ofs_additional = s.readUI64(); + additional_address = ofs_additional == 1 ? 0 : ofs_additional + s.position() - 8; + } + for (Long addr : itemsAddresses) { + s.seek(addr, SeekMode.SET); + int kind = s.readUI8(); + s.seek(-1, SeekMode.CUR); + switch (kind) { + case 22 /*FONT*/: + IggyFont font = new IggyFont(s); + //font_data_addresses.add(addr); + fonts.add(font); + break; + case 6 /*TEXT*/: + IggyText text = new IggyText(s); + //text_data_addresses.add(addr); + texts.add(text); + break; + default: + throw new RuntimeException("Unknown item kind: " + kind); + } + } + + if (additional_address != 0) { + s.seek(additional_address, SeekMode.SET); + List additionalItemsAddresses = new ArrayList<>(); + while (true) { + long offset = s.readUI64(); + if (offset == 1) { + break; + } + additionalItemsAddresses.add(offset + s.position() - 8); + } + for (Long addr : additionalItemsAddresses) { + s.seek(addr, SeekMode.SET); + int kind = s.readUI8(); + s.seek(-1, SeekMode.CUR); + switch (kind) { + case 22 /*FONT*/: + IggyFont font = new IggyFont(s); + //add_font_data_addresses.add(addr); + add_fonts.add(font); + break; + case 6 /*TEXT*/: + IggyText text = new IggyText(s); + //add_text_data_addresses.add(addr); + add_texts.add(text); + break; + default: + throw new RuntimeException("Unknown imported item kind: " + kind); + } + } + } + s.seek(hdr.getFontEndAddress(), SeekMode.SET); + //here is offset [4] - 856 ? + font_bin_info = new IggyFontBinInfo[(int) hdr.font_count]; + for (int i = 0; i < hdr.font_count; i++) { + font_bin_info[i] = new IggyFontBinInfo(s); + } + + sequenceNames = new ArrayList<>(); + + long seq_addresses[] = new long[]{hdr.getSequenceStartAddress1(), hdr.getSequenceStartAddress2(), hdr.getSequenceStartAddress3()}; + long seq_name_addresses[] = new long[3]; + for (int i = 0; i < 3; i++) { + if (seq_addresses[i] == 0) { + seq_name_addresses[i] = 0; + //0 + } else { + s.seek(seq_addresses[i], SeekMode.SET); + long ofs_seq_name = s.readUI64(); + seq_name_addresses[i] = ofs_seq_name == 1 ? 0 : ofs_seq_name + s.position() - 8; + s.readUI64(); //is this crucial? + } + } + + for (int i = 0; i < 3; i++) { + if (seq_name_addresses[i] > 0) { + s.seek(seq_name_addresses[i], SeekMode.SET); + sequenceNames.add(s.readWChar()); + } else { + sequenceNames.add(null); + } + } + s.pad8bytes(); + + //sequence = new IggySequence(s); + s.seek(hdr.getTypeFontsAddress(), SeekMode.SET); + type_info = new IggyFontTypeInfo[(int) hdr.font_count]; + type_info_name = new String[(int) hdr.font_count]; + for (int i = 0; i < hdr.font_count; i++) { + type_info[i] = new IggyFontTypeInfo(s); + } + for (int i = 0; i < hdr.font_count; i++) { + s.seek(type_info[i].getLocal_name_ofs_pos() + type_info[i].ofs_local_name, SeekMode.SET); + type_info_name[i] = s.readWChar(); + } + + s.seek(hdr.getDeclStringsAddress(), SeekMode.SET); + decl_strings = new IggyDeclStrings(s); + /*WriteDataStreamInterface outs = new TemporaryDataStream(); + writeToDataStream(outs); + Helper.writeFile("d:\\Dropbox\\jpexs-laptop\\iggi\\parts\\swf_out.bin", outs.getAllBytes());*/ + } + + public String getName() { + return name; + } + + @Override + public void writeToDataStream(WriteDataStreamInterface s) throws IOException { + IggyIndexBuilder ib = s.getIndexing(); + hdr.writeToDataStream(s); + s.writeWChar(name); + s.pad8bytes(); + s.writeUI64(1); + ib.write16bitArray(name.length() + 1); + ib.writeTwoPaddingBytes(); + ib.write64bitPointerArray(64); + long posBeforeOffsets = s.position(); + + final int FILL_LATER = 1; + + List fontPosFillLater = new ArrayList<>(); + + for (int i = 0; i < fonts.size(); i++) { + fontPosFillLater.add(s.position()); + s.writeUI64(FILL_LATER); + } + List textPosFillLater = new ArrayList<>(); + for (int i = 0; i < texts.size(); i++) { + textPosFillLater.add(s.position()); + s.writeUI64(FILL_LATER); + } + s.writeUI64(1); + + long addPosFillLater = s.position(); + s.writeUI64(FILL_LATER); + long posAfter = posBeforeOffsets + 64 * 8; + long curPos = s.position(); + long numLeft = posAfter - curPos; + long ofsLeft = numLeft / 8; + for (int i = 0; i < ofsLeft - 1; i++) { + s.writeUI64(FILL_LATER); + } + + for (int i = 0; i < fonts.size(); i++) { + s.setOlderOffsetToThisPos(fontPosFillLater.get(i)); + fonts.get(i).writeToDataStream(s); + } + for (int i = 0; i < texts.size(); i++) { + s.setOlderOffsetToThisPos(textPosFillLater.get(i)); + texts.get(i).writeToDataStream(s); + } + + if (!add_fonts.isEmpty() || !add_texts.isEmpty()) { + s.setOlderOffsetToThisPos(addPosFillLater); + + List addFontPosFillLater = new ArrayList<>(); + + for (int i = 0; i < add_fonts.size(); i++) { + addFontPosFillLater.add(s.position()); + s.writeUI64(FILL_LATER); + } + List addTextPosFillLater = new ArrayList<>(); + for (int i = 0; i < add_texts.size(); i++) { + addTextPosFillLater.add(s.position()); + s.writeUI64(FILL_LATER); + } + s.writeUI64(FILL_LATER); + for (int i = 0; i < add_fonts.size(); i++) { + s.setOlderOffsetToThisPos(addFontPosFillLater.get(i)); + add_fonts.get(i).writeToDataStream(s); + } + for (int i = 0; i < add_texts.size(); i++) { + s.setOlderOffsetToThisPos(addTextPosFillLater.get(i)); + add_texts.get(i).writeToDataStream(s); + } + } + s.setOlderOffsetToThisPos(hdr.getFont_end_ofs_pos()); + ib.writeConstLengthArray(IggyIndexBuilder.CONST_BIN_INFO_SIZE, hdr.font_count); + for (int i = 0; i < hdr.font_count; i++) { + font_bin_info[i].writeToDataStream(s); + } + + long seq_ofs_pos[] = new long[]{hdr.getSequence_start1_ofs_pos(), hdr.getSequence_start2_ofs_pos(), hdr.getSequence_start3_ofs_pos()}; + long off_seq_expected[] = new long[]{hdr.off_sequence_start1, hdr.off_sequence_start2, hdr.off_sequence_start3}; + + long seq_name_fill_later[] = new long[3]; + + s.setOlderOffsetToThisPos(seq_ofs_pos[0]); + s.writeUI64(1); + s.writeUI64(1); + ib.writeLengthCustom(16, new int[]{0}, new int[]{2}); + + seq_name_fill_later[2] = s.position(); + s.setOlderOffsetToThisPos(seq_ofs_pos[2]); + s.writeUI64(FILL_LATER); + s.writeUI64(0); + ib.writeConstLength(IggyIndexBuilder.CONST_SEQUENCE_SIZE); + for (int i = 0; i < 3; i++) { + if (sequenceNames.get(i) != null) { + s.setOlderOffsetToThisPos(seq_name_fill_later[i]); + ib.write16bitArray(sequenceNames.get(i).length() + 1); + s.writeWChar(sequenceNames.get(i)); + } + } + s.setOlderOffsetToThisPos(hdr.getSequence_end_ofs_pos()); + s.pad8bytes(); + ib.pad8bytes(); + + ib.writeConstLengthArray(IggyIndexBuilder.CONST_TYPE_INFO_SIZE, hdr.font_count); + s.setOlderOffsetToThisPos(hdr.getType_fonts_ofs_pos()); + //s.seek(hdr.getTypeFontsAddress(), SeekMode.SET); + for (int i = 0; i < hdr.font_count; i++) { + type_info[i].writeToDataStream(s); + } + + for (int i = 0; i < hdr.font_count; i++) { + ib.write16bitArray(type_info_name[i].length() + 1); + s.setOlderOffsetToThisPos(type_info[i].getLocal_name_ofs_pos()); + s.writeWChar(type_info_name[i]); + } + s.pad8bytes(); + ib.pad8bytes(); + + s.setOlderOffsetToThisPos(hdr.getDecl_strings_ofs_pos()); + //s.seek(hdr.getDeclStringsAddress(), SeekMode.SET); + decl_strings.writeToDataStream(s); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("[\r\n"); + sb.append("name ").append(name).append("\r\n"); + return sb.toString(); + } + + public IggyDeclStrings getDeclStrings() { + return decl_strings; + } +} diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/iggy/conversion/IggySwfBundle.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/iggy/conversion/IggySwfBundle.java index e2010e7ed..1b05846ab 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/iggy/conversion/IggySwfBundle.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/iggy/conversion/IggySwfBundle.java @@ -1,120 +1,109 @@ -package com.jpexs.decompiler.flash.iggy.conversion; - -import com.jpexs.decompiler.flash.SWF; -import com.jpexs.decompiler.flash.SWFBundle; -import com.jpexs.decompiler.flash.iggy.IggyFile; -import com.jpexs.decompiler.flash.iggy.IggyFont; -import com.jpexs.decompiler.flash.tags.DefineFont2Tag; -import com.jpexs.decompiler.flash.tags.Tag; -import com.jpexs.decompiler.flash.tags.base.CharacterTag; -import com.jpexs.helpers.Helper; -import com.jpexs.helpers.MemoryInputStream; -import com.jpexs.helpers.ReReadableInputStream; -import com.jpexs.helpers.streams.SeekableInputStream; -import java.io.ByteArrayOutputStream; -import java.io.File; -import java.io.FileInputStream; -import java.io.IOException; -import java.io.InputStream; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.TreeSet; -import java.util.logging.Level; -import java.util.logging.Logger; - -/** - * - * @author JPEXS - */ -public class IggySwfBundle implements SWFBundle { - - private IggyFile iggyFile; - - public IggySwfBundle(InputStream is) throws IOException { - this(is, null); - } - - public IggySwfBundle(File filename) throws IOException { - this(null, filename); - } - - protected IggySwfBundle(InputStream is, File filename) throws IOException { - initBundle(is, filename); - } - - protected void initBundle(InputStream is, File filename) throws IOException { - if (filename == null) { - filename = File.createTempFile("bundle", ".iggy"); - Helper.saveStream(is, filename); - } - iggyFile = new IggyFile(filename); - } - - @Override - public int length() { - return 1; - } - - @Override - public Set getKeys() { - Set ret = new TreeSet<>(); - for (int i = 0; i < length(); i++) { - ret.add(iggyFile.getSwfName()); - } - return ret; - } - - private int keyToSwfIndex(String key) { - for (int i = 0; i < length(); i++) { - if (key.equals(iggyFile.getSwfName())) { - return i; - } - } - throw new IllegalArgumentException("Key " + key + " does not exist!"); - } - - @Override - public SeekableInputStream getSWF(String key) throws IOException { - SWF swf = IggyToSwfConvertor.getSwf(iggyFile); - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - swf.saveTo(baos); - MemoryInputStream mis = new MemoryInputStream(baos.toByteArray()); - return mis; - } - - @Override - public Map getAll() throws IOException { - Map ret = new HashMap<>(); - for (String key : getKeys()) { - ret.put(key, getSWF(key)); - } - return ret; - } - - @Override - public String getExtension() { - return "iggy"; - } - - @Override - public boolean isReadOnly() { - return false; - } - - @Override - public boolean putSWF(String key, InputStream is) throws IOException { - try { - SWF swf = new SWF(is, false, false); - SwfToIggyConvertor.updateIggy(iggyFile.getSwf(), swf); - iggyFile.saveChanges(); - return true; - } catch (InterruptedException ex) { - return false; - } - - } - -} +package com.jpexs.decompiler.flash.iggy.conversion; + +import com.jpexs.decompiler.flash.SWF; +import com.jpexs.decompiler.flash.SWFBundle; +import com.jpexs.decompiler.flash.iggy.IggyFile; +import com.jpexs.helpers.Helper; +import com.jpexs.helpers.MemoryInputStream; +import com.jpexs.helpers.streams.SeekableInputStream; +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.util.HashMap; +import java.util.Map; +import java.util.Set; +import java.util.TreeSet; + +/** + * + * @author JPEXS + */ +public class IggySwfBundle implements SWFBundle { + + private IggyFile iggyFile; + + public IggySwfBundle(InputStream is) throws IOException { + this(is, null); + } + + public IggySwfBundle(File filename) throws IOException { + this(null, filename); + } + + protected IggySwfBundle(InputStream is, File filename) throws IOException { + initBundle(is, filename); + } + + protected void initBundle(InputStream is, File filename) throws IOException { + if (filename == null) { + filename = File.createTempFile("bundle", ".iggy"); + Helper.saveStream(is, filename); + } + iggyFile = new IggyFile(filename); + } + + @Override + public int length() { + return 1; + } + + @Override + public Set getKeys() { + Set ret = new TreeSet<>(); + for (int i = 0; i < length(); i++) { + ret.add(iggyFile.getSwfName()); + } + return ret; + } + + private int keyToSwfIndex(String key) { + for (int i = 0; i < length(); i++) { + if (key.equals(iggyFile.getSwfName())) { + return i; + } + } + throw new IllegalArgumentException("Key " + key + " does not exist!"); + } + + @Override + public SeekableInputStream getSWF(String key) throws IOException { + SWF swf = IggyToSwfConvertor.getSwf(iggyFile); + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + swf.saveTo(baos); + MemoryInputStream mis = new MemoryInputStream(baos.toByteArray()); + return mis; + } + + @Override + public Map getAll() throws IOException { + Map ret = new HashMap<>(); + for (String key : getKeys()) { + ret.put(key, getSWF(key)); + } + return ret; + } + + @Override + public String getExtension() { + return "iggy"; + } + + @Override + public boolean isReadOnly() { + return false; + } + + @Override + public boolean putSWF(String key, InputStream is) throws IOException { + try { + SWF swf = new SWF(is, false, false); + SwfToIggyConvertor.updateIggy(iggyFile.getSwf(), swf); + iggyFile.saveChanges(); + return true; + } catch (InterruptedException ex) { + return false; + } + + } +} diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/locales/AppResources_ca.properties b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/locales/AppResources_ca.properties index 8a9ca4b7d..2a1286504 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/locales/AppResources_ca.properties +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/locales/AppResources_ca.properties @@ -19,6 +19,8 @@ decompilationError.timeout.description = No s'ha descompilat degut al l\u00edmit decompilationError.obfuscated = El codi pot estar ofuscat decompilationError.errorType = Tipus d'error decompilationError.error.description = No s'ha descompilat degut a l'error +decompilationError.actionCount = Recompte d'accions: +decompilationError.instructionCount = Recompe d'instruccions: decompilation.skipped = S'ha om\u00e8s la descompilaci\u00f3 decompilation.unsupported = No suportat pel descompilador diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/graph/Graph.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/graph/Graph.java index 99fa23bc1..8c91abaf3 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/graph/Graph.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/graph/Graph.java @@ -1040,8 +1040,8 @@ public class Graph { private void getPrecontinues(String path, BaseLocalData localData, GraphPart parent, GraphPart part, Set allParts, List loops, List stopPart) throws InterruptedException { try { markLevels(path, localData, part, allParts, loops); - } catch (ThreadDeath | InterruptedException iex) { - throw iex; + } catch (ThreadDeath | InterruptedException ex) { + throw ex; } catch (Throwable ex) { //It is unusual code so markLevels failed, nevermind, it can still work } diff --git a/src/com/jpexs/decompiler/flash/gui/MainPanel.java b/src/com/jpexs/decompiler/flash/gui/MainPanel.java index 5b03d5f71..02782ff58 100644 --- a/src/com/jpexs/decompiler/flash/gui/MainPanel.java +++ b/src/com/jpexs/decompiler/flash/gui/MainPanel.java @@ -18,6 +18,7 @@ package com.jpexs.decompiler.flash.gui; import com.jpexs.decompiler.flash.AbortRetryIgnoreHandler; import com.jpexs.decompiler.flash.ApplicationInfo; +import com.jpexs.decompiler.flash.DecompilerPool; import com.jpexs.decompiler.flash.EventListener; import com.jpexs.decompiler.flash.ReadOnlyTagList; import com.jpexs.decompiler.flash.SWF; @@ -245,6 +246,8 @@ public final class MainPanel extends JPanel implements TreeSelectionListener, Se private final MainFrameStatusPanel statusPanel; + private Thread taskThread; + private final MainFrameMenu mainMenu; private final JProgressBar progressBar = new JProgressBar(0, 100); @@ -843,6 +846,29 @@ public final class MainPanel extends JPanel implements TreeSelectionListener, Se } mainMenu.updateComponents(swf); + + if (taskThread != null) { + taskThread.interrupt(); + } + + Thread t = new Thread() { + @Override + public void run() { + while (!Thread.currentThread().isInterrupted()) { + DecompilerPool d = swf.getDecompilerPool(); + statusPanel.setStatus(swf.getFileTitle() + " " + d.getStat()); + + try { + Thread.sleep(100); + } catch (InterruptedException ex) { + break; + } + } + } + }; + + t.start(); + taskThread = t; } private void updateUi() { diff --git a/src/com/jpexs/decompiler/flash/gui/abc/ABCPanel.java b/src/com/jpexs/decompiler/flash/gui/abc/ABCPanel.java index 2c99fa210..12076c7f9 100644 --- a/src/com/jpexs/decompiler/flash/gui/abc/ABCPanel.java +++ b/src/com/jpexs/decompiler/flash/gui/abc/ABCPanel.java @@ -68,6 +68,7 @@ import com.jpexs.decompiler.flash.gui.abc.tablemodels.UIntTableModel; import com.jpexs.decompiler.flash.gui.controls.JPersistentSplitPane; import com.jpexs.decompiler.flash.gui.editor.LinkHandler; import com.jpexs.decompiler.flash.gui.tagtree.TagTreeModel; +import com.jpexs.decompiler.flash.helpers.HighlightedText; import com.jpexs.decompiler.flash.importers.As3ScriptReplaceException; import com.jpexs.decompiler.flash.importers.As3ScriptReplaceExceptionItem; import com.jpexs.decompiler.flash.importers.As3ScriptReplacerInterface; @@ -100,6 +101,7 @@ import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Objects; +import java.util.concurrent.Future; import java.util.logging.Level; import java.util.logging.Logger; import java.util.regex.Pattern; @@ -207,38 +209,45 @@ public class ABCPanel extends JPanel implements ItemListener, SearchListener> futures = new ArrayList<>(); + try { + loop: + for (final ScriptPack pack : allpacks) { + pos++; + if (!pack.isSimple && Configuration.ignoreCLikePackages.get()) { continue; } - for (String ns : ignoredNss) { - if (fullName.startsWith(ns + ".")) { - continue loop; + if (Configuration._ignoreAdditionalFlexClasses.get()) { + String fullName = pack.getClassPath().packageStr.add(pack.getClassPath().className, pack.getClassPath().namespaceSuffix).toRawString(); + if (ignoredClasses.contains(fullName)) { + continue; + } + for (String ns : ignoredNss) { + if (fullName.startsWith(ns + ".")) { + continue loop; + } } } - } - String workText = AppStrings.translate("work.searching"); - String decAdd = ""; - if (!SWF.isCached(pack)) { - decAdd = ", " + AppStrings.translate("work.decompiling"); - } - - Main.startWork(workText + " \"" + txt + "\"" + decAdd + " - (" + pos + "/" + allpacks.size() + ") " + pack.getClassPath().toString() + "... ", worker); - try { - if (pat.matcher(SWF.getCached(pack).text).find()) { - ABCPanelSearchResult searchResult = new ABCPanelSearchResult(pack); - found.add(searchResult); + String workText = AppStrings.translate("work.searching"); + String decAdd = ""; + if (!SWF.isCached(pack)) { + decAdd = ", " + AppStrings.translate("work.decompiling"); } - } catch (InterruptedException ex) { - break; + + Main.startWork(workText + " \"" + txt + "\"" + decAdd + " - (" + pos + "/" + allpacks.size() + ") " + pack.getClassPath().toString() + "... ", worker); + Future text = SWF.getCachedFuture(pack, (HighlightedText result) -> { + if (pat.matcher(result.text).find()) { + ABCPanelSearchResult searchResult = new ABCPanelSearchResult(pack); + found.add(searchResult); + } + }); + + futures.add(text); + } + } catch (InterruptedException ex) { + for (Future future : futures) { + future.cancel(true); } } } diff --git a/src/com/jpexs/decompiler/flash/gui/player/FlashPlayerPanel.java b/src/com/jpexs/decompiler/flash/gui/player/FlashPlayerPanel.java index 4e9da7b4e..0261f0f6d 100644 --- a/src/com/jpexs/decompiler/flash/gui/player/FlashPlayerPanel.java +++ b/src/com/jpexs/decompiler/flash/gui/player/FlashPlayerPanel.java @@ -172,7 +172,7 @@ public final class FlashPlayerPanel extends Panel implements Closeable, MediaDis } }; - // hack: Kernel32.INSTANCE.ConnectNamedPipe never completes in AciveXControl static constructor + // hack: Kernel32.INSTANCE.ConnectNamedPipe never completes in ActiveXControl static constructor flash = CancellableWorker.call(callable, 5, TimeUnit.SECONDS); } catch (ActiveXException | TimeoutException | InterruptedException | ExecutionException ex) { throw new FlashUnsupportedException(); @@ -205,7 +205,6 @@ public final class FlashPlayerPanel extends Panel implements Closeable, MediaDis timer = new Timer(); timer.schedule(new TimerTask() { - private boolean isPlaying = false; private int currentFrame = 0;