From db294e7a70fa769e6b9a83a9019bf338365da68c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jindra=20Pet=C5=99=C3=ADk?= Date: Tue, 16 Aug 2016 07:59:59 +0200 Subject: [PATCH] Reorder scripts and classes to be in position as original script. --- .../com/jpexs/decompiler/flash/abc/ABC.java | 44 +++++++++++ .../flash/flexsdk/As3ScriptReplacer.java | 77 ++++++++++++++++++- 2 files changed, 119 insertions(+), 2 deletions(-) diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/ABC.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/ABC.java index bce340f03..99425e1ab 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/ABC.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/ABC.java @@ -1266,6 +1266,50 @@ public class ABC { } } + public void reorganizeClasses(Map classIndexMap) { + for (MethodBody b : bodies) { + for (AVM2Instruction ins : b.getCode().code) { + for (int i = 0; i < ins.definition.operands.length; i++) { + if (ins.definition.operands[i] == AVM2Code.DAT_CLASS_INDEX) { + if (classIndexMap.containsKey(ins.operands[i])) { + ins.setOperand(i, classIndexMap.get(ins.operands[i]), b.getCode(), b); + } + } + } + } + } + for (ScriptInfo si : script_info) { + reorganizeClassesInTraits(si.traits, classIndexMap); + } + for (MethodBody b : bodies) { + reorganizeClassesInTraits(b.traits, classIndexMap); + } + Map backupInstanceInfos = new HashMap<>(); + Map backupClassInfos = new HashMap<>(); + for (int from : classIndexMap.keySet()) { + backupInstanceInfos.put(from, instance_info.get(from)); + backupClassInfos.put(from, class_info.get(from)); + } + for (int from : classIndexMap.keySet()) { + int to = classIndexMap.get(from); + instance_info.set(to, backupInstanceInfos.get(from)); + class_info.set(to, backupClassInfos.get(from)); + } + } + + private void reorganizeClassesInTraits(Traits traits, Map classIndexMap) { + for (Trait t : traits.traits) { + if (t instanceof TraitClass) { + TraitClass tc = (TraitClass) t; + reorganizeClassesInTraits(instance_info.get(tc.class_info).instance_traits, classIndexMap); + reorganizeClassesInTraits(class_info.get(tc.class_info).static_traits, classIndexMap); + if (classIndexMap.containsKey(tc.class_info)) { + tc.class_info = classIndexMap.get(tc.class_info); + } + } + } + } + public void removeClass(int index) { for (MethodBody b : bodies) { for (AVM2Instruction ins : b.getCode().code) { diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/flexsdk/As3ScriptReplacer.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/flexsdk/As3ScriptReplacer.java index 4cee8e3fa..06a1a54d9 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/flexsdk/As3ScriptReplacer.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/flexsdk/As3ScriptReplacer.java @@ -5,6 +5,8 @@ import com.jpexs.decompiler.flash.abc.ABC; import com.jpexs.decompiler.flash.abc.ScriptPack; import com.jpexs.decompiler.flash.abc.types.InstanceInfo; 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.configuration.Configuration; import com.jpexs.decompiler.flash.exporters.modes.ScriptExportMode; import com.jpexs.decompiler.flash.exporters.script.AS3ScriptExporter; @@ -22,7 +24,10 @@ import java.io.FileInputStream; import java.io.IOException; import java.nio.file.Files; import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; import java.util.List; +import java.util.Map; public class As3ScriptReplacer extends MxmlcRunner { @@ -152,7 +157,18 @@ public class As3ScriptReplacer extends MxmlcRunner { try (FileInputStream fis = new FileInputStream(compiledSwfFile)) { SWF newSWF = new SWF(fis, false, false); List newTags = newSWF.getAbcList(); + int oldScriptIndex = oldPack.scriptIndex; + int oldClassIndex = -1; + ScriptInfo oldScriptInfo = oldPack.abc.script_info.get(oldPack.scriptIndex); + for (Trait t : oldScriptInfo.traits.traits) { + if (t instanceof TraitClass) { + int traitClassIndex = ((TraitClass) t).class_info; + if (oldClassIndex == -1 || traitClassIndex < oldClassIndex) { + oldClassIndex = traitClassIndex; + } + } + } if (oldPack.isSimple) { oldScriptInfo.delete(oldPack.abc, true); } else { @@ -161,8 +177,65 @@ public class As3ScriptReplacer extends MxmlcRunner { oldPack.abc.pack(); // removes old classes/methods/scripts ABCContainerTag newTagsLast = newTags.get(newTags.size() - 1); ABC newLastAbc = newTagsLast.getABC(); - oldPack.abc.mergeABC(newLastAbc); - //TODO: reorder classes + Map classesMap = new HashMap<>(); + Map scriptsMap = new HashMap<>(); + + oldPack.abc.mergeABC(newLastAbc, + new HashMap<>(), + new HashMap<>(), + new HashMap<>(), + new HashMap<>(), + new HashMap<>(), + new HashMap<>(), + new HashMap<>(), + new HashMap<>(), + new HashMap<>(), + new HashMap<>(), + new HashMap<>(), + new HashMap<>(), + classesMap, + new HashMap<>(), + scriptsMap + ); + + //Reorder newly created scripts to be in place + //where old script was + List addedScriptIndices = new ArrayList<>(scriptsMap.values()); + Collections.sort(addedScriptIndices); + List addedScripts = new ArrayList<>(); + for (int i = addedScriptIndices.size() - 1; i >= 0; i--) { + int newScriptIndex = addedScriptIndices.get(i); + addedScripts.add(0, oldPack.abc.script_info.remove(newScriptIndex)); + } + for (int i = 0; i < addedScripts.size(); i++) { + oldPack.abc.script_info.add(oldScriptIndex + i, addedScripts.get(i)); + } + + //IMPORTANT: Map newly created classes to their position as they + //were in original script because FlashPlayer needs + //parent class to be defined earlier + if (oldClassIndex > -1) { + List addedClassIndices = new ArrayList<>(classesMap.values()); + Collections.sort(addedClassIndices); + int totalClassCount = oldPack.abc.class_info.size(); + Map classesRemap = new HashMap<>(); + for (int i = 0; i < addedClassIndices.size(); i++) { + classesRemap.put(addedClassIndices.get(i), oldClassIndex + i); + } + int mappingStart = oldClassIndex; + for (int i = oldClassIndex; i < totalClassCount; i++) { + if (!classesRemap.containsKey(i)) { + for (int j = mappingStart; j < totalClassCount; j++) { + if (!classesRemap.containsValue(j)) { + classesRemap.put(i, j); + mappingStart = j + 1; + break; + } + } + } + } + oldPack.abc.reorganizeClasses(classesRemap); + } ((Tag) oldPack.abc.parentTag).setModified(true); } } finally {