From 21cb1d5cb981171c50c9dd769279a2f057fc69ed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jindra=20Pet=C5=99=C3=ADk?= Date: Wed, 28 Aug 2024 08:34:30 +0200 Subject: [PATCH] Fixed: #2293 FLA export - stackoverflow on multilevel clips extraction --- CHANGELOG.md | 3 + .../decompiler/flash/xfl/XFLConverter.java | 125 ++++++++++-------- 2 files changed, 70 insertions(+), 58 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c6be01dc2..80d8c02f8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,8 @@ All notable changes to this project will be documented in this file. ## [Unreleased] +### Fixed +- [#2293] FLA export - stackoverflow on multilevel clips extraction ## [21.0.4] - 2024-08-27 ### Fixed @@ -3528,6 +3530,7 @@ Major version of SWF to XML export changed to 2. [alpha 9]: https://github.com/jindrapetrik/jpexs-decompiler/compare/alpha8...alpha9 [alpha 8]: https://github.com/jindrapetrik/jpexs-decompiler/compare/alpha7...alpha8 [alpha 7]: https://github.com/jindrapetrik/jpexs-decompiler/releases/tag/alpha7 +[#2293]: https://www.free-decompiler.com/flash/issues/2293 [#2266]: https://www.free-decompiler.com/flash/issues/2266 [#2275]: https://www.free-decompiler.com/flash/issues/2275 [#2276]: https://www.free-decompiler.com/flash/issues/2276 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 7690c936c..2a36e7fc9 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 @@ -1707,7 +1707,7 @@ public class XFLConverter { } final ScriptPack spriteScriptPack = characterScriptPacks.containsKey(sprite) ? characterScriptPacks.get(sprite) : null; - extractMultilevelClips(lastItemIdNumber, lastImportedId, characterNameMap, sprite.getTags(), writer, swf, nextClipId, nonLibraryShapes, backgroundColor, flaVersion, files, placeToMaskedSymbol, multiUsageMorphShapes, statusStack); + extractMultilevelClips(lastItemIdNumber, lastImportedId, characterNameMap, sprite.getTags(), swf.getCharacterId(sprite), writer, swf, nextClipId, nonLibraryShapes, backgroundColor, flaVersion, files, placeToMaskedSymbol, multiUsageMorphShapes, statusStack); convertTimelines(lastImportedId, characterNameMap, swf, swf.getAbcIndex(), sprite, characterVariables.get(sprite), nonLibraryShapes, tags, sprite.getTags(), getSymbolName(lastImportedId, characterNameMap, swf, symbol), flaVersion, files, symbolStr, spriteScriptPack, placeToMaskedSymbol, multiUsageMorphShapes, statusStack); @@ -1750,7 +1750,7 @@ public class XFLConverter { } statusStack.pushStatus("extracting multilevel clips"); - extractMultilevelClips(lastItemIdNumber, lastImportedId, characterNameMap, swf.getTags(), writer, swf, nextClipId, nonLibraryShapes, backgroundColor, flaVersion, files, placeToMaskedSymbol, multiUsageMorphShapes, statusStack); + extractMultilevelClips(lastItemIdNumber, lastImportedId, characterNameMap, swf.getTags(), -1, writer, swf, nextClipId, nonLibraryShapes, backgroundColor, flaVersion, files, placeToMaskedSymbol, multiUsageMorphShapes, statusStack); statusStack.popStatus(); statusStack.pushStatus("converting multiusage morphshapes"); @@ -3178,6 +3178,7 @@ public class XFLConverter { Reference lastImportedId, Map characterNameMap, ReadOnlyTagList timelineTags, + int spriteId, XFLXmlWriter writer, SWF swf, Reference nextClipId, @@ -3191,7 +3192,7 @@ public class XFLConverter { ) throws XMLStreamException { XFLXmlWriter symbolStr = new XFLXmlWriter(); - extractMultilevelClips(lastItemIdNumber, lastImportedId, characterNameMap, timelineTags, writer, swf, nextClipId, nonLibraryShapes, backgroundColor, flaVersion, files, placeToMaskedSymbol, multiUsageMorphShapes, statusStack); + extractMultilevelClips(lastItemIdNumber, lastImportedId, characterNameMap, timelineTags, spriteId, writer, swf, nextClipId, nonLibraryShapes, backgroundColor, flaVersion, files, placeToMaskedSymbol, multiUsageMorphShapes, statusStack); if (nextClipId.getVal() < 0) { nextClipId.setVal(swf.getNextCharacterId()); @@ -3348,6 +3349,7 @@ public class XFLConverter { Reference lastImportedId, Map characterNameMap, ReadOnlyTagList timelineTags, + int spriteId, XFLXmlWriter writer, SWF swf, Reference nextClipId, @@ -3358,7 +3360,7 @@ public class XFLConverter { Map placeToMaskedSymbol, List multiUsageMorphShapes, StatusStack statusStack - ) throws XMLStreamException { + ) throws XMLStreamException { int f = 0; List clipPlaces = new ArrayList<>(); @@ -3474,7 +3476,7 @@ public class XFLConverter { continue; } delegatedPlaces.add(secondPlace); - + List delegatedTimeline = new ArrayList<>(); f = 0; boolean removed = false; @@ -3482,7 +3484,7 @@ public class XFLConverter { lastTag = null; //Map depthStates = new HashMap<>(); occupiedDepths.clear(); - + for (Tag t : timelineTags) { if (f < fr) { if (t instanceof PlaceObjectTypeTag) { @@ -3546,7 +3548,12 @@ public class XFLConverter { //set timelined? delegatedTimeline.add(showFrame); } - addExtractedClip(lastItemIdNumber, lastImportedId, characterNameMap, new ReadOnlyTagList(delegatedTimeline), writer, swf, nextClipId, nonLibraryShapes, backgroundColor, flaVersion, files, placeToMaskedSymbol, multiUsageMorphShapes, statusStack); + if (delegatedTimeline.size() == timelineTags.size()) { + //avoid recursion + //FIXME: this is wrong, needs to be fixed somehow + return; + } + addExtractedClip(lastItemIdNumber, lastImportedId, characterNameMap, new ReadOnlyTagList(delegatedTimeline), spriteId, writer, swf, nextClipId, nonLibraryShapes, backgroundColor, flaVersion, files, placeToMaskedSymbol, multiUsageMorphShapes, statusStack); placeToMaskedSymbol.put(secondPlace, new MultiLevelClip(secondPlace, nextClipId.getVal(), numFrames)); } } @@ -3957,65 +3964,67 @@ public class XFLConverter { } MultiLevelClip mlc = placeToMaskedSymbol.get(po2); + + if (mlc != null) { + writer.writeStartElement("DOMLayer", new String[]{ + "name", "Layer " + (index + 1) + (DEBUG_EXPORT_LAYER_DEPTHS ? " (depth " + po2.getDepth() + " clipdepth:" + po2.getClipDepth() + " maskedid:" + mlc.symbol + ")" : ""), + "color", randomOutlineColor(), + "parentLayerIndex", "" + parentIndex, + "locked", "true" + }); + writer.writeStartElement("frames"); - writer.writeStartElement("DOMLayer", new String[]{ - "name", "Layer " + (index + 1) + (DEBUG_EXPORT_LAYER_DEPTHS ? " (depth " + po2.getDepth() + " clipdepth:" + po2.getClipDepth() + " maskedid:" + mlc.symbol + ")" : ""), - "color", randomOutlineColor(), - "parentLayerIndex", "" + parentIndex, - "locked", "true" - }); - writer.writeStartElement("frames"); - - int clipFrame2 = 0; - for (int p2 = 0; p2 < clipPlaces.size() - 1; p2++) { - if (clipPlaces.get(p2) == po2) { - clipFrame2 = clipFrameSplitters.get(p2); + int clipFrame2 = 0; + for (int p2 = 0; p2 < clipPlaces.size() - 1; p2++) { + if (clipPlaces.get(p2) == po2) { + clipFrame2 = clipFrameSplitters.get(p2); + } + } + //int nextFrame2 = clipFinishFrames.get(po2); + + if (clipFrame2 > 0) { + writer.writeStartElement("DOMFrame", new String[]{ + "index", "0", + "duration", "" + clipFrame2, + "keyMode", "" + KEY_MODE_NORMAL + }); + writer.writeEmptyElement("elements"); + writer.writeEndElement(); } - } - //int nextFrame2 = clipFinishFrames.get(po2); - if (clipFrame2 > 0) { writer.writeStartElement("DOMFrame", new String[]{ - "index", "0", - "duration", "" + clipFrame2, + "index", "" + clipFrame2, + "duration", "" + mlc.numFrames, "keyMode", "" + KEY_MODE_NORMAL }); - writer.writeEmptyElement("elements"); + writer.writeStartElement("elements"); + writer.writeStartElement("DOMSymbolInstance", new String[]{ + "libraryItemName", getMaskedSymbolName(mlc.symbol), + "symbolType", "graphic", + "loop", "loop" + }); + + writer.writeStartElement("matrix"); + convertMatrix(new MATRIX(), writer); + writer.writeEndElement(); //matrix + + writer.writeStartElement("transformationPoint"); + writer.writeEmptyElement("Point"); + writer.writeEndElement(); //transformationPoint + + writer.writeEndElement(); //DOMSymbolInstance + writer.writeEndElement(); //elements + writer.writeEndElement(); //DOMFrame + + writer.writeEndElement(); //frames + writer.writeEndElement(); - } + index++; - writer.writeStartElement("DOMFrame", new String[]{ - "index", "" + clipFrame2, - "duration", "" + mlc.numFrames, - "keyMode", "" + KEY_MODE_NORMAL - }); - writer.writeStartElement("elements"); - writer.writeStartElement("DOMSymbolInstance", new String[]{ - "libraryItemName", getMaskedSymbolName(mlc.symbol), - "symbolType", "graphic", - "loop", "loop" - }); - - writer.writeStartElement("matrix"); - convertMatrix(new MATRIX(), writer); - writer.writeEndElement(); //matrix - - writer.writeStartElement("transformationPoint"); - writer.writeEmptyElement("Point"); - writer.writeEndElement(); //transformationPoint - - writer.writeEndElement(); //DOMSymbolInstance - writer.writeEndElement(); //elements - writer.writeEndElement(); //DOMFrame - - writer.writeEndElement(); //frames - - writer.writeEndElement(); - index++; - - for (int nd2 = po2.getDepth(); nd2 <= po2.getClipDepth(); nd2++) { - for (int i = clipFrame2; i < clipFrame2 + mlc.numFrames; i++) { - depthToFramesList.get(nd2).remove((Integer) i); + for (int nd2 = po2.getDepth(); nd2 <= po2.getClipDepth(); nd2++) { + for (int i = clipFrame2; i < clipFrame2 + mlc.numFrames; i++) { + depthToFramesList.get(nd2).remove((Integer) i); + } } } }