diff --git a/CHANGELOG.md b/CHANGELOG.md index b5f1992df..4fe627b71 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -29,6 +29,7 @@ All notable changes to this project will be documented in this file. - GFX - DefineExternalImage2, FontTextureInfo - IdType field recognition - [PR194] Support for XDG base directory specification (env variable `XDG_CONFIG_HOME`) - FLA export - ImportAssets/2 tag support +- FLA export - export in frame 1 flag support ### Fixed - Debugger - getting children of top level variables 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 41ab39055..8b0df5753 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 @@ -84,6 +84,7 @@ import com.jpexs.decompiler.flash.tags.SetBackgroundColorTag; import com.jpexs.decompiler.flash.tags.ShowFrameTag; import com.jpexs.decompiler.flash.tags.SoundStreamBlockTag; import com.jpexs.decompiler.flash.tags.StartSoundTag; +import com.jpexs.decompiler.flash.tags.SymbolClassTag; import com.jpexs.decompiler.flash.tags.Tag; import com.jpexs.decompiler.flash.tags.base.ASMSource; import com.jpexs.decompiler.flash.tags.base.ButtonAction; @@ -281,7 +282,7 @@ public class XFLConverter { StraightEdgeRecordAdvanced ser = (StraightEdgeRecordAdvanced) record; Point2D p = new Point2D.Double(x + ser.deltaX, y + ser.deltaY); p = new Matrix(mat).transform(p); - + return "| " + formatEdgeDouble(p.getX()) + " " + formatEdgeDouble(p.getY()); } else if (record instanceof CurvedEdgeRecordAdvanced) { CurvedEdgeRecordAdvanced cer = (CurvedEdgeRecordAdvanced) record; @@ -670,7 +671,7 @@ public class XFLConverter { fillsStr.writeEndElement(); strokesStr.writeEndElement(); - + boolean hasEdge = false; XFLXmlWriter currentLayer = new XFLXmlWriter(); if (fillStyleCount > 0 || lineStyleCount > 0) { @@ -834,7 +835,7 @@ public class XFLConverter { } } return layers; - } + } private static int getMaxDepth(ReadOnlyTagList tags) { int maxDepth = 0; @@ -1457,38 +1458,16 @@ public class XFLConverter { return date.getTime() / 1000; } - private void convertLibrary(Set characters, Reference lastImportedId, Map characterNameMap, SWF swf, Map characterVariables, Map characterClasses, Map characterScriptPacks, List nonLibraryShapes, String backgroundColor, ReadOnlyTagList tags, HashMap files, HashMap datfiles, FLAVersion flaVersion, XFLXmlWriter writer, Map placeToMaskedSymbol, List multiUsageMorphShapes, StatusStack statusStack) throws XMLStreamException { - Map characterImportLinkageURL = new IdentityHashMap<>(); - for (Tag tag : swf.getTags()) { - if (tag instanceof ImportTag) { - ImportTag it = (ImportTag) tag; - Map assets = it.getAssets(); - for (int chid : assets.keySet()) { - CharacterTag cht = swf.getCharacter(chid); - characterImportLinkageURL.put(cht, it.getUrl()); - } - } - } - - for (CharacterTag ct : characters) { - String cls = characterClasses.get(ct); - if (cls != null) { - String sourceUrl = swf.getClassSourceUrl(cls); - if (sourceUrl != null) { - characterImportLinkageURL.put(ct, sourceUrl); - } - } - } - + private void convertLibrary(Set charactersExportedInFirstFrame, Map characterImportLinkageURL, Set characters, Reference lastImportedId, Map characterNameMap, SWF swf, Map characterVariables, Map characterClasses, Map characterScriptPacks, List nonLibraryShapes, String backgroundColor, ReadOnlyTagList tags, HashMap files, HashMap datfiles, FLAVersion flaVersion, XFLXmlWriter writer, Map placeToMaskedSymbol, List multiUsageMorphShapes, StatusStack statusStack) throws XMLStreamException { statusStack.pushStatus("media"); - convertMedia(lastImportedId, characterNameMap, characterImportLinkageURL, characters, swf, characterVariables, characterClasses, tags, files, datfiles, writer, statusStack); + convertMedia(charactersExportedInFirstFrame, lastImportedId, characterNameMap, characterImportLinkageURL, characters, swf, characterVariables, characterClasses, tags, files, datfiles, writer, statusStack); statusStack.popStatus(); statusStack.pushStatus("symbols"); - convertSymbols(characterImportLinkageURL, characters, lastImportedId, characterNameMap, swf, characterVariables, characterClasses, characterScriptPacks, nonLibraryShapes, backgroundColor, tags, files, flaVersion, writer, placeToMaskedSymbol, multiUsageMorphShapes, statusStack); + convertSymbols(charactersExportedInFirstFrame, characterImportLinkageURL, characters, lastImportedId, characterNameMap, swf, characterVariables, characterClasses, characterScriptPacks, nonLibraryShapes, backgroundColor, tags, files, flaVersion, writer, placeToMaskedSymbol, multiUsageMorphShapes, statusStack); statusStack.popStatus(); } - private void convertSymbols(Map characterImportLinkageURL, Set characters, Reference lastImportedId, Map characterNameMap, SWF swf, Map characterVariables, Map characterClasses, Map characterScriptPacks, List nonLibraryShapes, String backgroundColor, ReadOnlyTagList tags, HashMap files, FLAVersion flaVersion, XFLXmlWriter writer, Map placeToMaskedSymbol, List multiUsageMorphShapes, StatusStack statusStack) throws XMLStreamException { + private void convertSymbols(Set charactersExportedInFirstFrame, Map characterImportLinkageURL, Set characters, Reference lastImportedId, Map characterNameMap, SWF swf, Map characterVariables, Map characterClasses, Map characterScriptPacks, List nonLibraryShapes, String backgroundColor, ReadOnlyTagList tags, HashMap files, FLAVersion flaVersion, XFLXmlWriter writer, Map placeToMaskedSymbol, List multiUsageMorphShapes, StatusStack statusStack) throws XMLStreamException { //boolean hasSymbol = false; Reference nextClipId = new Reference<>(-1); writer.writeStartElement("symbols"); @@ -1530,6 +1509,9 @@ public class XFLConverter { symbolStr.writeAttribute("linkageIdentifier", characterVariables.get(symbol)); } if (linkageExportForAS) { + if (!charactersExportedInFirstFrame.contains(symbol)) { + symbolStr.writeAttribute("linkageExportInFirstFrame", "false"); + } symbolStr.writeAttribute("linkageExportForAS", true); } @@ -1958,7 +1940,7 @@ public class XFLConverter { writer.writeAttribute("sampleCount", soundSampleCount); } - private void convertMedia(Reference lastImportedId, Map characterNameMap, Map characterImportLinkageURL, Set characters, SWF swf, Map characterVariables, Map characterClasses, ReadOnlyTagList tags, HashMap files, HashMap datfiles, XFLXmlWriter writer, StatusStack statusStack) throws XMLStreamException { + private void convertMedia(Set charactersExportedInFirstFrame, Reference lastImportedId, Map characterNameMap, Map characterImportLinkageURL, Set characters, SWF swf, Map characterVariables, Map characterClasses, ReadOnlyTagList tags, HashMap files, HashMap datfiles, XFLXmlWriter writer, StatusStack statusStack) throws XMLStreamException { boolean hasMedia = false; for (CharacterTag symbol : characters) { if (symbol instanceof ImageTag @@ -2055,6 +2037,9 @@ public class XFLConverter { } } if (isBitmapData) { + if (!charactersExportedInFirstFrame.contains(symbol)) { + writer.writeAttribute("linkageExportInFirstFrame", "false"); + } writer.writeAttribute("linkageExportForAS", true); writer.writeAttribute("linkageClassName", characterClasses.get(symbol)); } @@ -2089,6 +2074,9 @@ public class XFLConverter { writer.writeAttribute("linkageIdentifier", characterVariables.get(symbol)); } if (linkageExportForAS) { + if (!charactersExportedInFirstFrame.contains(symbol)) { + writer.writeAttribute("linkageExportInFirstFrame", "false"); + } writer.writeAttribute("linkageExportForAS", true); } @@ -2178,6 +2166,10 @@ public class XFLConverter { writer.writeAttribute("linkageIdentifier", characterVariables.get(symbol)); } if (linkageExportForAS) { + if (!charactersExportedInFirstFrame.contains(symbol)) { + writer.writeAttribute("linkageExportInFirstFrame", "false"); + } + writer.writeAttribute("linkageExportForAS", true); } writer.writeEndElement(); @@ -2674,7 +2666,7 @@ public class XFLConverter { } } - private static void convertFonts(Reference lastImportedId, Map characterNameMap, SWF swf, Set characters, Map characterClasses, XFLXmlWriter writer, StatusStack statusStack) throws XMLStreamException { + private static void convertFonts(Set charactersExportedInFirstFrame, Reference lastImportedId, Map characterNameMap, SWF swf, Set characters, Map characterClasses, XFLXmlWriter writer, StatusStack statusStack) throws XMLStreamException { boolean hasFont = false; int fontCounter = 0; for (CharacterTag t : characters) { @@ -2768,6 +2760,10 @@ public class XFLConverter { writer.writeAttribute("linkageClassName", characterClasses.get(font)); } if (linkageExportForAS) { + if (!charactersExportedInFirstFrame.contains(ct)) { + writer.writeAttribute("linkageExportInFirstFrame", "false"); + } + writer.writeAttribute("linkageExportForAS", true); } @@ -3843,7 +3839,7 @@ public class XFLConverter { //depthToFramesList.get(d).remove((Integer) fr); for (int i = 1; i < places.size(); i++) { multiLevelsPlaces.add(places.get(i)); - } + } } } } @@ -4645,9 +4641,58 @@ public class XFLConverter { Reference lastImportedId = new Reference<>(0); Map characterNameMap = new IdentityHashMap<>(); - convertFonts(lastImportedId, characterNameMap, swf, characters, characterClasses, domDocument, statusStack); + Set charactersExportedInFirstFrame = new LinkedIdentityHashSet<>(); + Map characterImportLinkageURL = new IdentityHashMap<>(); + int frame = 1; + for (Tag tag : swf.getTags()) { + if (tag instanceof ImportTag) { + ImportTag it = (ImportTag) tag; + Map assets = it.getAssets(); + for (int chid : assets.keySet()) { + CharacterTag cht = swf.getCharacter(chid); + characterImportLinkageURL.put(cht, it.getUrl()); + } + } + if (frame == 1) { + if (tag instanceof ExportAssetsTag) { + ExportAssetsTag et = (ExportAssetsTag) tag; + for (int id : et.tags) { + CharacterTag ct = swf.getCharacter(id); + if (ct != null) { + charactersExportedInFirstFrame.add(ct); + } + } + } + if (tag instanceof SymbolClassTag) { + SymbolClassTag sc = (SymbolClassTag) tag; + for (int id : sc.tags) { + if (id == 0) { //document class + continue; + } + CharacterTag ct = swf.getCharacter(id); + if (ct != null) { + charactersExportedInFirstFrame.add(ct); + } + } + } + } + if (tag instanceof ShowFrameTag) { + frame++; + } + } - convertLibrary(characters, lastImportedId, characterNameMap, swf, characterVariables, characterClasses, characterScriptPacks, nonLibraryShapes, backgroundColor, swf.getTags(), files, datfiles, flaVersion, domDocument, placeToMaskedSymbol, multiUsageMorphShapes, statusStack); + for (CharacterTag ct : characters) { + String cls = characterClasses.get(ct); + if (cls != null) { + String sourceUrl = swf.getClassSourceUrl(cls); + if (sourceUrl != null) { + characterImportLinkageURL.put(ct, sourceUrl); + } + } + } + convertFonts(charactersExportedInFirstFrame, lastImportedId, characterNameMap, swf, characters, characterClasses, domDocument, statusStack); + + convertLibrary(charactersExportedInFirstFrame, characterImportLinkageURL, characters, lastImportedId, characterNameMap, swf, characterVariables, characterClasses, characterScriptPacks, nonLibraryShapes, backgroundColor, swf.getTags(), files, datfiles, flaVersion, domDocument, placeToMaskedSymbol, multiUsageMorphShapes, statusStack); //domDocument.writeStartElement("timelines"); ScriptPack documentScriptPack = null;