Fixed: #1396, #1254 FLA Export - AS3 frame scripts

This commit is contained in:
Jindra Petřík
2021-03-12 22:12:39 +01:00
parent 9c98482e59
commit 380e7071bd
16 changed files with 106 additions and 34 deletions
@@ -12,7 +12,8 @@
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library.␍ */
* License along with this library.
*/
package com.jpexs.decompiler.flash;
import com.jpexs.decompiler.flash.abc.ScriptPack;
@@ -95,7 +96,7 @@ public class DecompilerPool {
}
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);
pack.toSource(writer, script == null ? null : script.traits.traits, new ConvertData(), ScriptExportMode.AS, parallel, false);
HighlightedText result = new HighlightedText(writer);
SWF swf = pack.getSwf();
@@ -241,7 +241,7 @@ public class ScriptPack extends AS3ClassTreeItem {
}
}
public void toSource(GraphTextWriter writer, final List<Trait> traits, final ConvertData convertData, final ScriptExportMode exportMode, final boolean parallel) throws InterruptedException {
public void toSource(GraphTextWriter writer, final List<Trait> traits, final ConvertData convertData, final ScriptExportMode exportMode, final boolean parallel, boolean ignoreFrameScripts) throws InterruptedException {
writer.suspendMeasure();
int timeout = Configuration.decompilationTimeoutFile.get();
try {
@@ -295,7 +295,9 @@ public class ScriptPack extends AS3ClassTreeItem {
try (FileTextWriter writer = exportSettings.singleFile ? null : new FileTextWriter(Configuration.getCodeFormatting(), new FileOutputStream(file))) {
FileTextWriter writer2 = exportSettings.singleFile ? exportSettings.singleFileWriter : writer;
toSource(writer2, abc.script_info.get(scriptIndex).traits.traits, new ConvertData(), exportSettings.mode, parallel);
ConvertData convertData = new ConvertData();
convertData.ignoreFrameScripts = exportSettings.ignoreFrameScripts;
toSource(writer2, abc.script_info.get(scriptIndex).traits.traits, convertData, exportSettings.mode, parallel, exportSettings.ignoreFrameScripts);
} catch (FileNotFoundException ex) {
logger.log(Level.SEVERE, "The file path is probably too long", ex);
}
@@ -33,6 +33,8 @@ public class ConvertData {
public boolean thisHasDefaultToPrimitive;
public boolean ignoreFrameScripts;
public ConvertData() {
deobfuscationMode = Configuration.autoDeobfuscate.get() ? 1 : 0;
}
@@ -17,6 +17,11 @@
package com.jpexs.decompiler.flash.abc.types.traits;
import com.jpexs.decompiler.flash.abc.ABC;
import com.jpexs.decompiler.flash.abc.avm2.model.CallPropertyAVM2Item;
import com.jpexs.decompiler.flash.abc.avm2.model.FullMultinameAVM2Item;
import com.jpexs.decompiler.flash.abc.avm2.model.GetPropertyAVM2Item;
import com.jpexs.decompiler.flash.abc.avm2.model.IntegerValueAVM2Item;
import com.jpexs.decompiler.flash.abc.avm2.model.ThisAVM2Item;
import com.jpexs.decompiler.flash.abc.avm2.parser.script.AbcIndexing;
import com.jpexs.decompiler.flash.abc.types.ClassInfo;
import com.jpexs.decompiler.flash.abc.types.ConvertData;
@@ -33,12 +38,15 @@ import com.jpexs.decompiler.flash.helpers.NulWriter;
import com.jpexs.decompiler.flash.helpers.hilight.HighlightSpecialType;
import com.jpexs.decompiler.flash.search.MethodId;
import com.jpexs.decompiler.graph.DottedChain;
import com.jpexs.decompiler.graph.GraphTargetItem;
import com.jpexs.decompiler.graph.ScopeStack;
import com.jpexs.decompiler.graph.TypeItem;
import com.jpexs.helpers.Helper;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
/**
*
@@ -52,6 +60,8 @@ public class TraitClass extends Trait implements TraitWithSlot {
private boolean classInitializerIsEmpty;
private List<Integer> frameTraitNames = new ArrayList<>();
@Override
public void delete(ABC abc, boolean d) {
abc.deleteClass(class_info, d);
@@ -127,7 +137,7 @@ public class TraitClass extends Trait implements TraitWithSlot {
//static variables & constants
ClassInfo classInfo = abc.class_info.get(class_info);
classInfo.static_traits.toString(new Class[]{TraitSlotConst.class}, this, convertData, path +/*packageName +*/ "/" + instanceInfoName, abc, true, exportMode, false, scriptIndex, class_info, writer, fullyQualifiedNames, parallel);
classInfo.static_traits.toString(new Class[]{TraitSlotConst.class}, this, convertData, path +/*packageName +*/ "/" + instanceInfoName, abc, true, exportMode, false, scriptIndex, class_info, writer, fullyQualifiedNames, parallel, new ArrayList<>());
//static initializer
int bodyIndex = abc.findBodyIndex(classInfo.cinit_index);
@@ -155,7 +165,7 @@ public class TraitClass extends Trait implements TraitWithSlot {
}
//instance variables
instanceInfo.instance_traits.toString(new Class[]{TraitSlotConst.class}, this, convertData, path +/*packageName +*/ "/" + instanceInfoName, abc, false, exportMode, false, scriptIndex, class_info, writer, fullyQualifiedNames, parallel);
instanceInfo.instance_traits.toString(new Class[]{TraitSlotConst.class}, this, convertData, path +/*packageName +*/ "/" + instanceInfoName, abc, false, exportMode, false, scriptIndex, class_info, writer, fullyQualifiedNames, parallel, new ArrayList<>());
//instance initializer - constructor
if (!instanceInfo.isInterface()) {
@@ -195,10 +205,10 @@ public class TraitClass extends Trait implements TraitWithSlot {
}
//static methods
classInfo.static_traits.toString(new Class[]{TraitClass.class, TraitFunction.class, TraitMethodGetterSetter.class}, this, convertData, path +/*packageName +*/ "/" + instanceInfoName, abc, true, exportMode, false, scriptIndex, class_info, writer, fullyQualifiedNames, parallel);
classInfo.static_traits.toString(new Class[]{TraitClass.class, TraitFunction.class, TraitMethodGetterSetter.class}, this, convertData, path +/*packageName +*/ "/" + instanceInfoName, abc, true, exportMode, false, scriptIndex, class_info, writer, fullyQualifiedNames, parallel, new ArrayList<>());
//instance methods
instanceInfo.instance_traits.toString(new Class[]{TraitClass.class, TraitFunction.class, TraitMethodGetterSetter.class}, this, convertData, path +/*packageName +*/ "/" + instanceInfoName, abc, false, exportMode, false, scriptIndex, class_info, writer, fullyQualifiedNames, parallel);
instanceInfo.instance_traits.toString(new Class[]{TraitClass.class, TraitFunction.class, TraitMethodGetterSetter.class}, this, convertData, path +/*packageName +*/ "/" + instanceInfoName, abc, false, exportMode, false, scriptIndex, class_info, writer, fullyQualifiedNames, parallel, convertData.ignoreFrameScripts ? frameTraitNames : new ArrayList<>());
writer.endBlock(); // class
writer.endClass();
@@ -245,7 +255,55 @@ public class TraitClass extends Trait implements TraitWithSlot {
if (bodyIndex != -1) {
List<Traits> ts = new ArrayList<>();
ts.add(instanceInfo.instance_traits);
abc.bodies.get(bodyIndex).convert(convertData, path +/*packageName +*/ "/" + instanceInfoName + ".initializer", exportMode, false, instanceInfo.iinit_index, scriptIndex, class_info, abc, this, new ScopeStack(), GraphTextWriter.TRAIT_INSTANCE_INITIALIZER, writer, fullyQualifiedNames, ts, true, new HashSet<>());
MethodBody constructorBody = abc.bodies.get(bodyIndex);
constructorBody.convert(convertData, path +/*packageName +*/ "/" + instanceInfoName + ".initializer", exportMode, false, instanceInfo.iinit_index, scriptIndex, class_info, abc, this, new ScopeStack(), GraphTextWriter.TRAIT_INSTANCE_INITIALIZER, writer, fullyQualifiedNames, ts, true, new HashSet<>());
if (convertData.ignoreFrameScripts) {
//find all addFrameScript(xx,this.method) in constructor
/*
It looks like this:
CallPropertyAVM2Item
->propertyName == FullMultinameAVM2Item
-> resolvedMultinameName (String) "addFrameScript"
->arguments
->0 IntegerValueAVM2Item
->value (Long) 0 - zero based
->1 GetPropertyAVM2Item
->object (ThisAVM2Item)
->propertyName (FullMultinameAvm2Item)
->multinameIndex
->resolvedMultinameName (String) "frame1"
*/
if (constructorBody.convertedItems != null) {
for (int j = 0; j < constructorBody.convertedItems.size(); j++) {
GraphTargetItem ti = constructorBody.convertedItems.get(j);
if (ti instanceof CallPropertyAVM2Item) {
CallPropertyAVM2Item callProp = (CallPropertyAVM2Item) ti;
if (callProp.propertyName instanceof FullMultinameAVM2Item) {
FullMultinameAVM2Item propName = (FullMultinameAVM2Item) callProp.propertyName;
if ("addFrameScript".equals(propName.resolvedMultinameName)) {
for (int i = 0; i < callProp.arguments.size(); i += 2) {
if (callProp.arguments.get(i) instanceof IntegerValueAVM2Item) {
if (callProp.arguments.get(i + 1) instanceof GetPropertyAVM2Item) {
GetPropertyAVM2Item getProp = (GetPropertyAVM2Item) callProp.arguments.get(i + 1);
if (getProp.object instanceof ThisAVM2Item) {
if (getProp.propertyName instanceof FullMultinameAVM2Item) {
FullMultinameAVM2Item framePropName = (FullMultinameAVM2Item) getProp.propertyName;
int multinameIndex = framePropName.multinameIndex;
frameTraitNames.add(multinameIndex);
}
}
}
}
}
constructorBody.convertedItems.remove(j);
j--;
}
}
}
}
}
}
}
}
@@ -161,7 +161,7 @@ public class Traits implements Cloneable, Serializable {
}
}
public GraphTextWriter toString(Class[] traitTypes, Trait parent, ConvertData convertData, String path, ABC abc, boolean isStatic, ScriptExportMode exportMode, boolean makePackages, int scriptIndex, int classIndex, GraphTextWriter writer, List<DottedChain> fullyQualifiedNames, boolean parallel) throws InterruptedException {
public GraphTextWriter toString(Class[] traitTypes, Trait parent, ConvertData convertData, String path, ABC abc, boolean isStatic, ScriptExportMode exportMode, boolean makePackages, int scriptIndex, int classIndex, GraphTextWriter writer, List<DottedChain> fullyQualifiedNames, boolean parallel, List<Integer> ignoredTraitNames) throws InterruptedException {
List<Trait> ordered = new ArrayList<>(traits);
loopi:
@@ -222,6 +222,9 @@ public class Traits implements Cloneable, Serializable {
if (!trait.isVisible(isStatic, abc)) {
continue;
}
if (ignoredTraitNames.contains(trait.name_index)) {
continue;
}
writer.newLine();
int h = abc.getGlobalTraitId(TraitType.METHOD /*non-initializer*/, isStatic, classIndex, t);
if (trait instanceof TraitClass) {
@@ -12,7 +12,8 @@
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library.␍ */
* License along with this library.
*/
package com.jpexs.decompiler.flash.exporters.settings;
import com.jpexs.decompiler.flash.exporters.modes.ScriptExportMode;
@@ -32,9 +33,12 @@ public class ScriptExportSettings {
public FileTextWriter singleFileWriter;
public ScriptExportSettings(ScriptExportMode mode, boolean singleFile) {
public boolean ignoreFrameScripts;
public ScriptExportSettings(ScriptExportMode mode, boolean singleFile, boolean ignoreFrameScripts) {
this.mode = mode;
this.singleFile = singleFile;
this.ignoreFrameScripts = ignoreFrameScripts;
}
public String getFileExtension() {
@@ -12,7 +12,8 @@
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library.␍ */
* License along with this library.
*/
package com.jpexs.decompiler.flash.flexsdk;
import com.jpexs.decompiler.flash.SWF;
@@ -293,7 +294,7 @@ public class MxmlcAs3ScriptReplacer extends MxmlcRunner implements As3ScriptRepl
//This compiled code won't be used at all in original SWF,
//it is used only by Flex to properly compile current script
AS3ScriptExporter ex = new AS3ScriptExporter();
ex.exportActionScript3(swfCopy, null, tempDir.getAbsolutePath(), removedPacks, new ScriptExportSettings(ScriptExportMode.AS_METHOD_STUBS, false), false, null);
ex.exportActionScript3(swfCopy, null, tempDir.getAbsolutePath(), removedPacks, new ScriptExportSettings(ScriptExportMode.AS_METHOD_STUBS, false, false), false, null);
//now really remove the classes from SWF copy
for (ABC a : modAbcs) {
@@ -12,7 +12,8 @@
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library.␍ */
* License along with this library.
*/
package com.jpexs.decompiler.flash.importers;
import com.jpexs.decompiler.flash.abc.ScriptPack;
@@ -41,7 +42,7 @@ public class AS3ScriptImporter {
int importCount = 0;
for (ScriptPack pack : packs) {
try {
File file = pack.getExportFile(scriptsFolder, new ScriptExportSettings(ScriptExportMode.AS, false));
File file = pack.getExportFile(scriptsFolder, new ScriptExportSettings(ScriptExportMode.AS, false, false));
if (file.exists()) {
String fileName = file.getAbsolutePath();
String txt = Helper.readTextFile(fileName);
@@ -2535,9 +2535,7 @@ public class XFLConverter {
int constructorMethodIndex = instanceInfo.iinit_index;
MethodBody constructorBody = abc.findBody(constructorMethodIndex);
try {
if (constructorBody.convertedItems == null) {
constructorBody.convert(new ConvertData(), "??", ScriptExportMode.AS, true, constructorMethodIndex, pack.scriptIndex, classIndex, abc, null, new ScopeStack(), GraphTextWriter.TRAIT_INSTANCE_INITIALIZER, new NulWriter(), new ArrayList<>(), new ArrayList<>(), true, new HashSet<>());
}
constructorBody.convert(new ConvertData(), "??", ScriptExportMode.AS, false, constructorMethodIndex, pack.scriptIndex, classIndex, abc, null, new ScopeStack(), GraphTextWriter.TRAIT_INSTANCE_INITIALIZER, new NulWriter(), new ArrayList<>(), new ArrayList<>(), true, new HashSet<>());
Map<Integer, Integer> frameToTraitMultiname = new HashMap<>();
@@ -2563,12 +2561,12 @@ public class XFLConverter {
if (callProp.propertyName instanceof FullMultinameAVM2Item) {
FullMultinameAVM2Item propName = (FullMultinameAVM2Item) callProp.propertyName;
if ("addFrameScript".equals(propName.resolvedMultinameName)) {
if (callProp.arguments.size() == 2) {
if (callProp.arguments.get(0) instanceof IntegerValueAVM2Item) {
IntegerValueAVM2Item frameItem = (IntegerValueAVM2Item) callProp.arguments.get(0);
for (int i = 0; i < callProp.arguments.size(); i += 2) {
if (callProp.arguments.get(i) instanceof IntegerValueAVM2Item) {
IntegerValueAVM2Item frameItem = (IntegerValueAVM2Item) callProp.arguments.get(i);
int frame = frameItem.intValue();
if (callProp.arguments.get(1) instanceof GetPropertyAVM2Item) {
GetPropertyAVM2Item getProp = (GetPropertyAVM2Item) callProp.arguments.get(1);
if (callProp.arguments.get(i + 1) instanceof GetPropertyAVM2Item) {
GetPropertyAVM2Item getProp = (GetPropertyAVM2Item) callProp.arguments.get(i + 1);
if (getProp.object instanceof ThisAVM2Item) {
if (getProp.propertyName instanceof FullMultinameAVM2Item) {
FullMultinameAVM2Item framePropName = (FullMultinameAVM2Item) getProp.propertyName;
@@ -3790,7 +3788,7 @@ public class XFLConverter {
}
if (useAS3 && settings.exportScript) {
try {
ScriptExportSettings scriptExportSettings = new ScriptExportSettings(ScriptExportMode.AS, false);
ScriptExportSettings scriptExportSettings = new ScriptExportSettings(ScriptExportMode.AS, false, true);
swf.exportActionScript(handler, outDir.getAbsolutePath(), scriptExportSettings, parallel, null);
} catch (Exception ex) {
logger.log(Level.SEVERE, "Error during ActionScript3 export", ex);