diff --git a/CHANGELOG.md b/CHANGELOG.md index b39b6519b..538de279e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,7 @@ All notable changes to this project will be documented in this file. - FileAttributes tag - SWF relative Urls flag - AS3 P-code editing class trait - [#355] Updated Chinese translation +- FLA Export - AS2 - Sprite linkage to class ### Fixed - [#1981] AS3 fully qualified (colliding) types in submethods diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/Action.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/Action.java index cc2d2d306..01e85c2e9 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/Action.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/Action.java @@ -857,6 +857,10 @@ public abstract class Action implements GraphSourceItem { return actionsToTree(insideDoInitAction, insideFunction, new HashMap<>(), new HashMap<>(), new HashMap<>(), actions, version, staticOperation, path, charset); } + public static GraphTextWriter actionsToSource(final ASMSource asm, final List actions, final String path, GraphTextWriter writer, String charset) throws InterruptedException { + return Action.actionsToSource(asm, actions, path, writer, charset, new ArrayList<>()); + } + /** * Converts list of actions to ActionScript source code * @@ -864,10 +868,12 @@ public abstract class Action implements GraphSourceItem { * @param actions List of actions * @param path * @param writer + * @param charset + * @param treeOperations * @return * @throws java.lang.InterruptedException */ - public static GraphTextWriter actionsToSource(final ASMSource asm, final List actions, final String path, GraphTextWriter writer, String charset) throws InterruptedException { + public static GraphTextWriter actionsToSource(final ASMSource asm, final List actions, final String path, GraphTextWriter writer, String charset, List treeOperations) throws InterruptedException { writer.suspendMeasure(); List tree = null; Throwable convertException = null; @@ -882,6 +888,9 @@ public abstract class Action implements GraphSourceItem { boolean insideDoInitAction = (asm instanceof DoInitActionTag); List tree = actionsToTree(insideDoInitAction, false, new HashMap<>(), new HashMap<>(), new HashMap<>(), actions, version, staticOperation, path, charset); SWFDecompilerPlugin.fireActionTreeCreated(tree, swf); + for (ActionTreeOperation treeOperation:treeOperations) { + treeOperation.run(tree); + } if (Configuration.autoDeobfuscate.get()) { new ActionDeobfuscator().actionTreeCreated(tree, swf); } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/ActionTreeOperation.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/ActionTreeOperation.java new file mode 100644 index 000000000..86b498ab8 --- /dev/null +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/ActionTreeOperation.java @@ -0,0 +1,28 @@ +/* + * Copyright (C) 2010-2023 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.action; + +import com.jpexs.decompiler.graph.GraphTargetItem; +import java.util.List; + +/** + * + * @author JPEXS + */ +public interface ActionTreeOperation { + public void run(List tree); +} diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DoActionTag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DoActionTag.java index 893b8d478..76cad6ff4 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DoActionTag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DoActionTag.java @@ -22,6 +22,7 @@ import com.jpexs.decompiler.flash.SWFInputStream; import com.jpexs.decompiler.flash.SWFOutputStream; import com.jpexs.decompiler.flash.action.Action; import com.jpexs.decompiler.flash.action.ActionList; +import com.jpexs.decompiler.flash.action.ActionTreeOperation; import com.jpexs.decompiler.flash.action.ConstantPoolTooBigException; import com.jpexs.decompiler.flash.dumpview.DumpInfoSpecialType; import com.jpexs.decompiler.flash.exporters.modes.ScriptExportMode; @@ -143,6 +144,15 @@ public class DoActionTag extends Tag implements ASMSource { return Action.actionsToSource(this, actions, getScriptName(), writer, getCharset()); } + + @Override + public GraphTextWriter getActionScriptSource(GraphTextWriter writer, ActionList actions, List treeOperations) throws InterruptedException { + if (actions == null) { + actions = getActions(); + } + + return Action.actionsToSource(this, actions, getScriptName(), writer, getCharset(), treeOperations); + } /** * Whether or not this object contains ASM source diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DoInitActionTag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DoInitActionTag.java index 770a2d473..1c0353260 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DoInitActionTag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DoInitActionTag.java @@ -22,6 +22,7 @@ import com.jpexs.decompiler.flash.SWFInputStream; import com.jpexs.decompiler.flash.SWFOutputStream; import com.jpexs.decompiler.flash.action.Action; import com.jpexs.decompiler.flash.action.ActionList; +import com.jpexs.decompiler.flash.action.ActionTreeOperation; import com.jpexs.decompiler.flash.action.ConstantPoolTooBigException; import com.jpexs.decompiler.flash.dumpview.DumpInfoSpecialType; import com.jpexs.decompiler.flash.exporters.modes.ScriptExportMode; @@ -152,6 +153,15 @@ public class DoInitActionTag extends Tag implements CharacterIdTag, ASMSource { return Action.actionsToSource(this, actions, getScriptName(), writer, getCharset()); } + + @Override + public GraphTextWriter getActionScriptSource(GraphTextWriter writer, ActionList actions, List treeOperations) throws InterruptedException { + if (actions == null) { + actions = getActions(); + } + + return Action.actionsToSource(this, actions, getScriptName(), writer, getCharset(), treeOperations); + } @Override public ActionList getActions() throws InterruptedException { @@ -269,5 +279,5 @@ public class DoInitActionTag extends Tag implements CharacterIdTag, ASMSource { @Override public void getNeededCharacters(Set needed) { needed.add(spriteId); - } + } } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/base/ASMSource.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/base/ASMSource.java index e02687b52..9f7b7687c 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/base/ASMSource.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/base/ASMSource.java @@ -19,6 +19,7 @@ package com.jpexs.decompiler.flash.tags.base; import com.jpexs.decompiler.flash.DisassemblyListener; import com.jpexs.decompiler.flash.action.Action; import com.jpexs.decompiler.flash.action.ActionList; +import com.jpexs.decompiler.flash.action.ActionTreeOperation; import com.jpexs.decompiler.flash.action.ConstantPoolTooBigException; import com.jpexs.decompiler.flash.exporters.modes.ScriptExportMode; import com.jpexs.decompiler.flash.helpers.GraphTextWriter; @@ -55,6 +56,17 @@ public interface ASMSource extends Exportable, HasSwfAndTag { */ public GraphTextWriter getActionScriptSource(GraphTextWriter writer, ActionList actions) throws InterruptedException; + /** + * Converts actions to ActionScript source with executing operation on the tree. + * + * @param writer + * @param actions + * @param treeOperations + * @return ASM source + * @throws java.lang.InterruptedException + */ + public GraphTextWriter getActionScriptSource(GraphTextWriter writer, ActionList actions, List treeOperations) throws InterruptedException; + /** * Whether or not this object contains ASM source * diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/base/ButtonAction.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/base/ButtonAction.java index 9e5c39a99..b16fa7431 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/base/ButtonAction.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/base/ButtonAction.java @@ -20,6 +20,7 @@ import com.jpexs.decompiler.flash.DisassemblyListener; import com.jpexs.decompiler.flash.SWF; import com.jpexs.decompiler.flash.action.Action; import com.jpexs.decompiler.flash.action.ActionList; +import com.jpexs.decompiler.flash.action.ActionTreeOperation; import com.jpexs.decompiler.flash.action.ConstantPoolTooBigException; import com.jpexs.decompiler.flash.exporters.modes.ScriptExportMode; import com.jpexs.decompiler.flash.helpers.GraphTextWriter; @@ -74,6 +75,15 @@ public class ButtonAction implements ASMSource { return Action.actionsToSource(this, actions, getScriptName(), writer, buttonTag.getCharset()); } + + @Override + public GraphTextWriter getActionScriptSource(GraphTextWriter writer, ActionList actions, List treeOperations) throws InterruptedException { + if (actions == null) { + actions = getActions(); + } + + return Action.actionsToSource(this, actions, getScriptName(), writer, buttonTag.getCharset(), treeOperations); + } /** * Whether or not this object contains ASM source diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/BUTTONCONDACTION.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/BUTTONCONDACTION.java index f4cb0660a..c9430ebc4 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/BUTTONCONDACTION.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/BUTTONCONDACTION.java @@ -21,6 +21,7 @@ import com.jpexs.decompiler.flash.SWF; import com.jpexs.decompiler.flash.SWFInputStream; import com.jpexs.decompiler.flash.action.Action; import com.jpexs.decompiler.flash.action.ActionList; +import com.jpexs.decompiler.flash.action.ActionTreeOperation; import com.jpexs.decompiler.flash.action.ConstantPoolTooBigException; import com.jpexs.decompiler.flash.dumpview.DumpInfoSpecialType; import com.jpexs.decompiler.flash.exporters.modes.ScriptExportMode; @@ -211,6 +212,15 @@ public class BUTTONCONDACTION implements ASMSource, Serializable, HasSwfAndTag { return Action.actionsToSource(this, actions, getScriptName(), writer, actions.getCharset()); } + + @Override + public GraphTextWriter getActionScriptSource(GraphTextWriter writer, ActionList actions, List treeOperations) throws InterruptedException { + if (actions == null) { + actions = getActions(); + } + + return Action.actionsToSource(this, actions, getScriptName(), writer, actions.getCharset(), treeOperations); + } /** * Whether or not this object contains ASM source diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/CLIPACTIONRECORD.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/CLIPACTIONRECORD.java index 2fdbb6c19..45556e672 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/CLIPACTIONRECORD.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/CLIPACTIONRECORD.java @@ -21,6 +21,7 @@ import com.jpexs.decompiler.flash.SWF; import com.jpexs.decompiler.flash.SWFInputStream; import com.jpexs.decompiler.flash.action.Action; import com.jpexs.decompiler.flash.action.ActionList; +import com.jpexs.decompiler.flash.action.ActionTreeOperation; import com.jpexs.decompiler.flash.action.ConstantPoolTooBigException; import com.jpexs.decompiler.flash.dumpview.DumpInfoSpecialType; import com.jpexs.decompiler.flash.exporters.modes.ScriptExportMode; @@ -250,6 +251,15 @@ public class CLIPACTIONRECORD implements ASMSource, Serializable, HasSwfAndTag { return Action.actionsToSource(this, actions, getScriptName(), writer, actions.getCharset()); } + + @Override + public GraphTextWriter getActionScriptSource(GraphTextWriter writer, ActionList actions, List treeOperations) throws InterruptedException { + if (actions == null) { + actions = getActions(); + } + + return Action.actionsToSource(this, actions, getScriptName(), writer, actions.getCharset(), treeOperations); + } /** * Whether or not this object contains ASM source diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/xfl/XFLConverter.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/xfl/XFLConverter.java index 1bb792681..94ac660b0 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/xfl/XFLConverter.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/xfl/XFLConverter.java @@ -16,6 +16,7 @@ */ package com.jpexs.decompiler.flash.xfl; +import com.jpexs.debugger.flash.GetVariableFlag; import com.jpexs.helpers.XmlPrettyFormat; import com.jpexs.decompiler.flash.xfl.shapefixer.CurvedEdgeRecordAdvanced; import com.jpexs.decompiler.flash.xfl.shapefixer.StraightEdgeRecordAdvanced; @@ -35,7 +36,12 @@ import com.jpexs.decompiler.flash.abc.avm2.model.GetLexAVM2Item; 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.AVM2ParseException; import com.jpexs.decompiler.flash.abc.avm2.parser.script.AbcIndexing; +import com.jpexs.decompiler.flash.abc.avm2.parser.script.ActionScriptLexer; +import com.jpexs.decompiler.flash.abc.avm2.parser.script.ParsedSymbol; +import com.jpexs.decompiler.flash.abc.avm2.parser.script.SymbolGroup; +import com.jpexs.decompiler.flash.abc.avm2.parser.script.SymbolType; import com.jpexs.decompiler.flash.abc.types.ConvertData; import com.jpexs.decompiler.flash.abc.types.InstanceInfo; import com.jpexs.decompiler.flash.abc.types.MethodBody; @@ -45,6 +51,12 @@ 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; +import com.jpexs.decompiler.flash.action.Action; +import com.jpexs.decompiler.flash.action.ActionTreeOperation; +import com.jpexs.decompiler.flash.action.model.CallMethodActionItem; +import com.jpexs.decompiler.flash.action.model.DirectValueActionItem; +import com.jpexs.decompiler.flash.action.model.GetMemberActionItem; +import com.jpexs.decompiler.flash.action.model.GetVariableActionItem; import com.jpexs.decompiler.flash.amf.amf3.Amf3Value; import com.jpexs.decompiler.flash.amf.amf3.types.ObjectType; import com.jpexs.decompiler.flash.configuration.Configuration; @@ -136,8 +148,10 @@ import com.jpexs.decompiler.flash.types.shaperecords.StyleChangeRecord; import com.jpexs.decompiler.flash.types.sound.MP3FRAME; import com.jpexs.decompiler.flash.types.sound.MP3SOUNDDATA; import com.jpexs.decompiler.flash.types.sound.SoundFormat; +import com.jpexs.decompiler.graph.Graph; import com.jpexs.decompiler.graph.GraphTargetItem; import com.jpexs.decompiler.graph.ScopeStack; +import com.jpexs.decompiler.graph.model.ScriptEndItem; import com.jpexs.helpers.Helper; import com.jpexs.helpers.Path; import com.jpexs.helpers.SerializableImage; @@ -165,6 +179,8 @@ import java.util.Random; import java.util.Set; import java.util.logging.Level; import java.util.logging.Logger; +import java.util.regex.Matcher; +import java.util.regex.Pattern; import java.util.zip.ZipEntry; import java.util.zip.ZipOutputStream; import javax.xml.parsers.DocumentBuilder; @@ -1476,15 +1492,19 @@ public class XFLConverter { writer.writeEndElement(); } - private static String convertActionScript12(ASMSource as) { + private static String convertActionScript12(ASMSource as, List treeOperations) { HighlightedTextWriter writer = new HighlightedTextWriter(Configuration.getCodeFormatting(), false); try { - as.getActionScriptSource(writer, null); + as.getActionScriptSource(writer, null, treeOperations); } catch (InterruptedException ex) { logger.log(Level.SEVERE, null, ex); } return writer.toString(); } + + private static String convertActionScript12(ASMSource as) { + return convertActionScript12(as, new ArrayList<>()); + } private static long getTimestamp(SWF swf) { Date date = swf.getFileModificationDate(); @@ -1543,10 +1563,10 @@ public class XFLConverter { symbolStr.writeAttribute("scaleGridTop", doubleToString(scalingGrid.splitter.Ymin / SWF.unitDivisor)); symbolStr.writeAttribute("scaleGridBottom", doubleToString(scalingGrid.splitter.Ymax / SWF.unitDivisor)); } - - symbolStr.writeStartElement("timeline"); + String itemIcon = null; if (symbol instanceof ButtonTag) { + symbolStr.writeStartElement("timeline"); itemIcon = "0"; symbolStr.writeStartElement("DOMTimeline", new String[]{"name", "Symbol " + symbol.getCharacterId(), "currentFrame", "0"}); symbolStr.writeStartElement("layers"); @@ -1696,15 +1716,17 @@ public class XFLConverter { } symbolStr.writeEndElement(); // layers symbolStr.writeEndElement(); // DOMTimeline + symbolStr.writeEndElement(); // timeline } else if (symbol instanceof DefineSpriteTag) { DefineSpriteTag sprite = (DefineSpriteTag) symbol; if (sprite.getTags().isEmpty()) { //probably AS2 class continue; } final ScriptPack spriteScriptPack = characterScriptPacks.containsKey(sprite.spriteId) ? characterScriptPacks.get(sprite.spriteId) : null; - convertTimeline(swf.getAbcIndex(), sprite.spriteId, nonLibraryShapes, backgroundColor, tags, sprite.getTags(), characters, "Symbol " + symbol.getCharacterId(), flaVersion, files, symbolStr, spriteScriptPack); + convertTimeline(swf.getAbcIndex(), sprite.spriteId, characterVariables.get(sprite.spriteId), nonLibraryShapes, backgroundColor, tags, sprite.getTags(), characters, "Symbol " + symbol.getCharacterId(), flaVersion, files, symbolStr, spriteScriptPack); } else if (symbol instanceof ShapeTag) { + symbolStr.writeStartElement("timeline"); itemIcon = "1"; ShapeTag shape = (ShapeTag) symbol; symbolStr.writeStartElement("DOMTimeline", new String[]{"name", "Symbol " + symbol.getCharacterId(), "currentFrame", "0"}); @@ -1716,8 +1738,9 @@ public class XFLConverter { symbolStr.writeEndElement(); // layers symbolStr.writeEndElement(); // DOMTimeline + symbolStr.writeEndElement(); // timeline } - symbolStr.writeEndElement(); // timeline + symbolStr.writeEndElement(); // DOMSymbolItem String symbolStr2 = prettyFormatXML(symbolStr.toString()); String symbolFile = "Symbol " + symbol.getCharacterId() + ".xml"; @@ -2684,20 +2707,12 @@ public class XFLConverter { return ret; } - private boolean convertActionScriptLayer(AbcIndexing abcIndex, int spriteId, ReadOnlyTagList tags, ReadOnlyTagList timeLineTags, String backgroundColor, XFLXmlWriter writer, ScriptPack scriptPack) throws XMLStreamException { + private boolean convertActionScriptLayer(String initClipScript, AbcIndexing abcIndex, int spriteId, ReadOnlyTagList tags, ReadOnlyTagList timeLineTags, String backgroundColor, XFLXmlWriter writer, ScriptPack scriptPack) throws XMLStreamException { boolean hasScript = false; - String script = ""; + String script = initClipScript; int duration = 0; - int frame = 0; - for (Tag t : tags) { - if (t instanceof DoInitActionTag) { - DoInitActionTag dia = (DoInitActionTag) t; - if (dia.spriteId == spriteId) { - script += convertActionScript12(dia); - } - } - } + int frame = 0; if (!script.isEmpty()) { script = "#initclip\r\n" + script + "#endinitclip\r\n"; } @@ -2764,7 +2779,7 @@ public class XFLConverter { return hasScript; } - private boolean convertLabelsLayer(int spriteId, ReadOnlyTagList tags, ReadOnlyTagList timeLineTags, String backgroundColor, XFLXmlWriter writer) throws XMLStreamException { + private boolean convertLabelsLayer(ReadOnlyTagList tags, ReadOnlyTagList timeLineTags, String backgroundColor, XFLXmlWriter writer) throws XMLStreamException { boolean hasLabel = false; Map> frameToLabels = new HashMap<>(); @@ -2920,12 +2935,116 @@ public class XFLConverter { return outlineColor.toHexRGB(); } - private void convertTimeline(AbcIndexing abcIndex, int spriteId, List nonLibraryShapes, String backgroundColor, ReadOnlyTagList tags, ReadOnlyTagList timelineTags, HashMap characters, String name, FLAVersion flaVersion, HashMap files, XFLXmlWriter writer, ScriptPack scriptPack) throws XMLStreamException { + private String getMembersToClassName(GraphTargetItem item) { + List ret = new ArrayList<>(); + while (item instanceof GetMemberActionItem) { + GetMemberActionItem mem = (GetMemberActionItem) item; + if (!(mem.memberName instanceof DirectValueActionItem)) { + return null; + } + DirectValueActionItem dv = ((DirectValueActionItem) mem.memberName); + if (!dv.isString()) { + return null; + } + ret.add(0, dv.getAsString()); + item = mem.object; + } + if (!(item instanceof GetVariableActionItem)) { + return null; + } + GetVariableActionItem gv = (GetVariableActionItem) item; + if (!(gv.name instanceof DirectValueActionItem)) { + return null; + } + DirectValueActionItem dv = ((DirectValueActionItem) gv.name); + if (!dv.isString()) { + return null; + } + String varName = dv.getAsString(); + ret.add(0, varName); + return String.join(".", ret); + } + + private void convertTimeline(AbcIndexing abcIndex, int spriteId, String linkageIdentifier, List nonLibraryShapes, String backgroundColor, ReadOnlyTagList tags, ReadOnlyTagList timelineTags, HashMap characters, String name, FLAVersion flaVersion, HashMap files, XFLXmlWriter writer, ScriptPack scriptPack) throws XMLStreamException { + + List classNames = new ArrayList<>(); + //Searches for Object.registerClass("linkageIdentifier",mypkg.MyClass); + ActionTreeOperation getRegisterClassOp = new ActionTreeOperation() { + @Override + public void run(List tree) { + List listToRemove = new ArrayList<>(); + List newClassNames = new ArrayList<>(); + for (int i = 0; i < tree.size(); i++) { + GraphTargetItem item = tree.get(i); + if (!(item instanceof CallMethodActionItem)) { + continue; + } + CallMethodActionItem callMethod = (CallMethodActionItem) item; + if (!(callMethod.scriptObject instanceof GetVariableActionItem)) { + continue; + } + GetVariableActionItem methodObject = (GetVariableActionItem)callMethod.scriptObject; + if (!(methodObject.name instanceof DirectValueActionItem)) { + continue; + } + if (methodObject.name == null || !methodObject.name.toString().equals("Object")) { + continue; + } + if (!(callMethod.methodName instanceof DirectValueActionItem)) { + continue; + } + if (!callMethod.methodName.toString().equals("registerClass")) { + continue; + } + if (callMethod.arguments.size() != 2) { + continue; + } + if (!(callMethod.arguments.get(0) instanceof DirectValueActionItem)) { + continue; + } + if (linkageIdentifier != null && !linkageIdentifier.equals(callMethod.arguments.get(0).toString())) { + continue; + } + String className = getMembersToClassName(callMethod.arguments.get(1)); + if (className == null) { + continue; + } + newClassNames.add(className); + listToRemove.add(i); + } + //There's only single one + if (listToRemove.size() != 1) { + return; + } + classNames.add(newClassNames.get(0)); + tree.remove((int)listToRemove.get(0)); + } + }; + List treeOps = new ArrayList<>(); + treeOps.add(getRegisterClassOp); + + String initClipScript = ""; + for (Tag t : tags) { + if (t instanceof DoInitActionTag) { + DoInitActionTag dia = (DoInitActionTag) t; + if (dia.spriteId == spriteId) { + initClipScript += convertActionScript12(dia, treeOps); + } + } + } + if (classNames.size() == 1) { + writer.writeAttribute("linkageClassName", classNames.get(0)); + } + if (spriteId == -1) { + writer.writeStartElement("timelines"); + } else { + writer.writeStartElement("timeline"); + } writer.writeStartElement("DOMTimeline", new String[]{"name", name}); writer.writeStartElement("layers"); - boolean hasLabel = convertLabelsLayer(spriteId, tags, timelineTags, backgroundColor, writer); - boolean hasScript = convertActionScriptLayer(abcIndex, spriteId, tags, timelineTags, backgroundColor, writer, scriptPack); + boolean hasLabel = convertLabelsLayer(tags, timelineTags, backgroundColor, writer); + boolean hasScript = convertActionScriptLayer(initClipScript, abcIndex, spriteId, tags, timelineTags, backgroundColor, writer, scriptPack); int index = 0; @@ -3053,8 +3172,9 @@ public class XFLConverter { } convertSoundLayer(timelineTags, files, writer); - writer.writeEndElement(); - writer.writeEndElement(); + writer.writeEndElement(); //layers + writer.writeEndElement(); //DOMTimeline + writer.writeEndElement(); //timeline/s } private void writeEmptyLayer(XFLXmlWriter writer, int frameCount) throws XMLStreamException { @@ -3624,10 +3744,10 @@ public class XFLConverter { convertFonts(swf.getTags(), domDocument); convertLibrary(swf, characterVariables, characterClasses, characterScriptPacks, nonLibraryShapes, backgroundColor, swf.getTags(), characters, files, datfiles, flaVersion, domDocument); - domDocument.writeStartElement("timelines"); + //domDocument.writeStartElement("timelines"); ScriptPack documentScriptPack = characterScriptPacks.containsKey(0) ? characterScriptPacks.get(0) : null; - convertTimeline(swf.getAbcIndex(), 0, nonLibraryShapes, backgroundColor, swf.getTags(), swf.getTags(), characters, "Scene 1", flaVersion, files, domDocument, documentScriptPack); - domDocument.writeEndElement(); + convertTimeline(swf.getAbcIndex(), -1, null, nonLibraryShapes, backgroundColor, swf.getTags(), swf.getTags(), characters, "Scene 1", flaVersion, files, domDocument, documentScriptPack); + //domDocument.writeEndElement(); if (hasAmfMetadata) { domDocument.writeStartElement("persistentData"); diff --git a/libsrc/ffdec_lib/testdata/as2/MyBlueSprite.as b/libsrc/ffdec_lib/testdata/as2/MyBlueSprite.as new file mode 100644 index 000000000..3a40cd47b --- /dev/null +++ b/libsrc/ffdec_lib/testdata/as2/MyBlueSprite.as @@ -0,0 +1,5 @@ +class MyBlueSprite extends MovieClip{ + public function MyBlueSprite(){ + super(); + } +} \ No newline at end of file diff --git a/libsrc/ffdec_lib/testdata/as2/as2.fla b/libsrc/ffdec_lib/testdata/as2/as2.fla index fc9b5c251..6d24adc45 100644 Binary files a/libsrc/ffdec_lib/testdata/as2/as2.fla and b/libsrc/ffdec_lib/testdata/as2/as2.fla differ diff --git a/libsrc/ffdec_lib/testdata/as2/as2.swf b/libsrc/ffdec_lib/testdata/as2/as2.swf index c87a0b252..fd9e20900 100644 Binary files a/libsrc/ffdec_lib/testdata/as2/as2.swf and b/libsrc/ffdec_lib/testdata/as2/as2.swf differ