Multi thread AS search

This commit is contained in:
honfika@gmail.com
2016-12-24 18:52:09 +01:00
parent 40e31a5f99
commit 5f2ffd0089
18 changed files with 1277 additions and 789 deletions

View File

@@ -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<HighlightedText> submitTask(ASMSource src, ActionList actions, ScriptDecompiledListener<HighlightedText> listener) {
Future<HighlightedText> f = executor.submit(new Callable<HighlightedText>() {
@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<HighlightedText> submitTask(ScriptPack pack, ScriptDecompiledListener<HighlightedText> listener) {
Future<HighlightedText> f = executor.submit(new Callable<HighlightedText>() {
@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<HighlightedText> 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<HighlightedText> 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)) {
}
}
}

View File

@@ -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;

View File

@@ -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<SoundTag, byte[]> soundCache = Cache.getInstance(false, false, "sound");
@Internal
private final Cache<ASMSource, ActionList> as2PcodeCache = Cache.getInstance(true, true, "as2pcode");
public final AS2Cache as2Cache = new AS2Cache();
@Internal
private final Cache<ASMSource, HighlightedText> as2Cache = Cache.getInstance(true, false, "as2");
public final AS3Cache as3Cache = new AS3Cache();
@Internal
private final Cache<ScriptPack, HighlightedText> as3Cache = Cache.getInstance(true, false, "as3");
private static final DecompilerPool decompilerPool = new DecompilerPool();
public static List<String> 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<DisassemblyListener> 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<HighlightedText> getCachedFuture(ASMSource src, ActionList actions, ScriptDecompiledListener<HighlightedText> 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<HighlightedText> getCachedFuture(ScriptPack pack, ScriptDecompiledListener<HighlightedText> 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<CharacterTag, RECT> 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

View File

@@ -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<ASMSource, HighlightedText> cache = Cache.getInstance(true, false, "as2");
private final Cache<ASMSource, ActionList> 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);
}
}
}

View File

@@ -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<ScriptPack, HighlightedText> 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);
}
}
}

View File

@@ -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<T> {
public void onComplete(T result);
}

View File

@@ -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<Integer> parallelSpeedUpThreadCount = null;
private static final ConfigurationItem<Integer> parallelSpeedUpThreadCount = null;
@ConfigurationDefaultBoolean(false)
@ConfigurationCategory("script")
@@ -926,7 +926,7 @@ public class Configuration {
}
public static Map<String, Field> getConfigurationFields() {
Field[] fields = Configuration.class.getFields();
Field[] fields = Configuration.class.getDeclaredFields();
Map<String, Field> result = new HashMap<>();
for (Field field : fields) {
if (ConfigurationItem.class.isAssignableFrom(field.getType())) {

View File

@@ -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<IggySubFileEntry> subFileEntries = new ArrayList<>();
private List<byte[]> 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<IggySubFileEntry> subFileEntries = new ArrayList<>();
private List<byte[]> 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);
}
}
}

View File

@@ -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;

View File

@@ -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;
}
}

View File

@@ -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);
}
}

View File

@@ -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<IggyFont> fonts = new ArrayList<>();
// private List<Long> font_data_addresses = new ArrayList<>();
private List<IggyFont> add_fonts = new ArrayList<>();
// private List<Long> add_font_data_addresses = new ArrayList<>();
private IggyFlashHeader64 hdr;
public IggySwf(ReadDataStreamInterface stream) throws IOException {
readFromDataStream(stream);
}
private List<IggyText> texts = new ArrayList<>();
//private List<Long> text_data_addresses = new ArrayList<>();
private List<IggyText> add_texts = new ArrayList<>();
//private List<Long> add_text_data_addresses = new ArrayList<>();
//private byte font_add_data[];
//private List<Long> font_additional_size = new ArrayList<>();
private IggyFontBinInfo font_bin_info[];
private List<String> sequenceNames = new ArrayList<>();
//private List<Long> 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<IggyFont> getFonts() {
return fonts;
}
public List<IggyFont> getAddFonts() {
return add_fonts;
}
public List<IggyText> getTexts() {
return texts;
}
public List<IggyText> 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<Long> 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<Long> 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<Long> fontPosFillLater = new ArrayList<>();
for (int i = 0; i < fonts.size(); i++) {
fontPosFillLater.add(s.position());
s.writeUI64(FILL_LATER);
}
List<Long> 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<Long> addFontPosFillLater = new ArrayList<>();
for (int i = 0; i < add_fonts.size(); i++) {
addFontPosFillLater.add(s.position());
s.writeUI64(FILL_LATER);
}
List<Long> 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<IggyFont> fonts = new ArrayList<>();
// private List<Long> font_data_addresses = new ArrayList<>();
private List<IggyFont> add_fonts = new ArrayList<>();
// private List<Long> add_font_data_addresses = new ArrayList<>();
private IggyFlashHeader64 hdr;
public IggySwf(ReadDataStreamInterface stream) throws IOException {
readFromDataStream(stream);
}
private List<IggyText> texts = new ArrayList<>();
//private List<Long> text_data_addresses = new ArrayList<>();
private List<IggyText> add_texts = new ArrayList<>();
//private List<Long> add_text_data_addresses = new ArrayList<>();
//private byte font_add_data[];
//private List<Long> font_additional_size = new ArrayList<>();
private IggyFontBinInfo font_bin_info[];
private List<String> sequenceNames = new ArrayList<>();
//private List<Long> 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<IggyFont> getFonts() {
return fonts;
}
public List<IggyFont> getAddFonts() {
return add_fonts;
}
public List<IggyText> getTexts() {
return texts;
}
public List<IggyText> 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<Long> 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<Long> 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<Long> fontPosFillLater = new ArrayList<>();
for (int i = 0; i < fonts.size(); i++) {
fontPosFillLater.add(s.position());
s.writeUI64(FILL_LATER);
}
List<Long> 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<Long> addFontPosFillLater = new ArrayList<>();
for (int i = 0; i < add_fonts.size(); i++) {
addFontPosFillLater.add(s.position());
s.writeUI64(FILL_LATER);
}
List<Long> 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;
}
}

View File

@@ -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<String> getKeys() {
Set<String> 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<String, SeekableInputStream> getAll() throws IOException {
Map<String, SeekableInputStream> 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<String> getKeys() {
Set<String> 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<String, SeekableInputStream> getAll() throws IOException {
Map<String, SeekableInputStream> 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;
}
}
}

View File

@@ -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

View File

@@ -1040,8 +1040,8 @@ public class Graph {
private void getPrecontinues(String path, BaseLocalData localData, GraphPart parent, GraphPart part, Set<GraphPart> allParts, List<Loop> loops, List<GraphPart> 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
}