diff --git a/CHANGELOG.md b/CHANGELOG.md index 6375dbde2..dc41276e0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -24,6 +24,8 @@ All notable changes to this project will be documented in this file. - [#2589] SVG export - subsprite animation, sprite offsets - [#1893] Video - incorrect frame size - [#2572] SVG import - incorrect stroke width when transform contains rotation/shear +- [#2595] FLA export - incorrect handling of imported fonts +- FLA export - incorrect handling of imported sprites ### Changed - [#2575] dumpSWF CLI command only allows single SWF dump (no imports, etc.) @@ -4083,6 +4085,7 @@ Major version of SWF to XML export changed to 2. [#2589]: https://www.free-decompiler.com/flash/issues/2589 [#1893]: https://www.free-decompiler.com/flash/issues/1893 [#2572]: https://www.free-decompiler.com/flash/issues/2572 +[#2595]: https://www.free-decompiler.com/flash/issues/2595 [#2556]: https://www.free-decompiler.com/flash/issues/2556 [#2536]: https://www.free-decompiler.com/flash/issues/2536 [#2537]: https://www.free-decompiler.com/flash/issues/2537 diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/DefineBeforeUsageFixer.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/DefineBeforeUsageFixer.java index d509bf4ff..88a85853c 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/DefineBeforeUsageFixer.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/DefineBeforeUsageFixer.java @@ -42,7 +42,8 @@ public class DefineBeforeUsageFixer { for (int i = 0; i < tags.size(); i++) { Tag t = tags.get(i); Set needed = new LinkedHashSet<>(); - t.getNeededCharactersDeep(needed); + Set neededClasses = new LinkedHashSet<>(); + t.getNeededCharactersDeep(needed, neededClasses); for (int chId : needed) { if (walkedCharacters.contains(chId)) { continue; @@ -76,5 +77,5 @@ public class DefineBeforeUsageFixer { } } return i; - } + } } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/SWF.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/SWF.java index 95f9f2ca3..1d521fc0c 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/SWF.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/SWF.java @@ -392,6 +392,12 @@ public final class SWF implements SWFContainerItem, Timelined, Openable { */ @Internal private volatile Map> dependentFrames; + + /** + * Map of class to Set of dependent frame numbers. + */ + @Internal + private volatile Map> dependentClassFrames; /** * List of ABC container tags. @@ -1106,7 +1112,9 @@ public final class SWF implements SWFContainerItem, Timelined, Openable { int characterId = ((CharacterTag) tag).getCharacterId(); if (characterId != -1) { Set needed = new HashSet<>(); - tag.getNeededCharacters(needed, this); + Set neededClasses = new HashSet<>(); + //TODO: compute classes + tag.getNeededCharacters(needed, neededClasses, this); for (Integer needed1 : needed) { Set s = dep.get(needed1); if (s == null) { @@ -1197,23 +1205,35 @@ public final class SWF implements SWFContainerItem, Timelined, Openable { */ public void computeDependentFrames() { Map> dep = new HashMap<>(); + Map> depCls = new HashMap<>(); Timeline tim = getTimeline(); for (int i = 0; i < tim.getFrameCount(); i++) { Frame frame = tim.getFrame(i); Set needed = new HashSet<>(); - frame.getNeededCharactersDeep(needed); + Set neededClasses = new HashSet<>(); + frame.getNeededCharactersDeep(needed, neededClasses); for (Integer needed1 : needed) { - Set s = dep.get(needed1); + Set s = dep.get(needed1); if (s == null) { s = new HashSet<>(); dep.put(needed1, s); } + s.add(i); + } + for (String needed1 : neededClasses) { + Set s = depCls.get(needed1); + if (s == null) { + s = new HashSet<>(); + depCls.put(needed1, s); + } + s.add(i); } } dependentFrames = dep; + dependentClassFrames = depCls; } /** @@ -1234,6 +1254,24 @@ public final class SWF implements SWFContainerItem, Timelined, Openable { return dependentFrames.get(characterId); } + /** + * Gets dependent frames for specified AS3 class. + * + * @param characterClass Character id + * @return Set of dependent characterids + */ + public Set getDependentFramesByClass(String characterClass) { + if (dependentClassFrames == null) { + synchronized (this) { + if (dependentClassFrames == null) { + computeDependentFrames(); + } + } + } + + return dependentClassFrames.get(characterClass); + } + /** * Gets character tag by character id * @@ -6185,14 +6223,16 @@ public final class SWF implements SWFContainerItem, Timelined, Openable { } Set ct = new HashSet<>(); Map> characterToNeeded = new HashMap<>(); - + for (Tag t : getTags()) { if (t instanceof CharacterTag) { CharacterTag cht = (CharacterTag) t; if (cht.getCharacterId() != -1) { Set needed = new HashSet<>(); - cht.getNeededCharacters(needed, this); - characterToNeeded.put(cht.getCharacterId(), needed); + Set neededClasses = new HashSet<>(); + cht.getNeededCharacters(needed, neededClasses, this); + //TODO: check cyclic classes + characterToNeeded.put(cht.getCharacterId(), needed); } } } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/FrameExporter.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/FrameExporter.java index 96a8d3ef7..0a7405a8e 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/FrameExporter.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/FrameExporter.java @@ -397,8 +397,9 @@ public class FrameExporter { fos.write(Utf8Helper.getBytes("\r\n")); fos.write(Utf8Helper.getBytes("var scalingGrids = {};\r\nvar boundRects = {};\r\n")); Set library = new HashSet<>(); - ftim.getNeededCharacters(fframes, library); - + Set libraryClasses = new HashSet<>(); + ftim.getNeededCharacters(fframes, library, libraryClasses); + //FIXME!!! Handle Library Classes SWF.libraryToHtmlCanvas(fswf, library, fos); String currentName = ftim.id == 0 ? "main" : SWF.getTypePrefix(fswf.getCharacter(ftim.id)) + ftim.id; diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/MorphShapeExporter.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/MorphShapeExporter.java index cc65c2f04..944fcf4cd 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/MorphShapeExporter.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/MorphShapeExporter.java @@ -254,10 +254,12 @@ public class MorphShapeExporter { CanvasMorphShapeExporter cse = new CanvasMorphShapeExporter(mst.getShapeNum(), ((Tag) mst).getSwf(), mst.getShapeAtRatio(0), mst.getShapeAtRatio(DefineMorphShapeTag.MAX_RATIO), new CXFORMWITHALPHA(), SWF.unitDivisor, deltaX, deltaY); cse.export(); Set needed = new HashSet<>(); + Set neededClasses = new HashSet<>(); CharacterTag ct = ((CharacterTag) mst); needed.add(ct.getCharacterId()); - ct.getNeededCharactersDeep(needed); + ct.getNeededCharactersDeep(needed, neededClasses); ByteArrayOutputStream baos = new ByteArrayOutputStream(); + //FIXME!!! Handle Library Classes SWF.libraryToHtmlCanvas(ct.getSwf(), needed, baos); fos.write(Utf8Helper.getBytes(cse.getHtml(new String(baos.toByteArray(), Utf8Helper.charset), SWF.getTypePrefix(mst) + mst.getCharacterId(), mst.getRect()))); } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/PreviewExporter.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/PreviewExporter.java index a58b84dea..e38308f41 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/PreviewExporter.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/PreviewExporter.java @@ -366,6 +366,7 @@ public class PreviewExporter { } Set doneCharacters = new LinkedHashSet<>(); + Set doneCharacterClasses = new LinkedHashSet<>(); if (treeItem instanceof Frame) { Frame fn = (Frame) treeItem; Timelined parent = fn.timeline.timelined; @@ -384,7 +385,7 @@ public class PreviewExporter { } Set needed = new LinkedHashSet<>(); - t.getNeededCharactersDeep(needed); + t.getNeededCharactersDeep(needed, new LinkedHashSet<>()); for (int n : needed) { if (!doneCharacters.contains(n)) { writeTag(swf.getCharacter(n), sos2, doneCharacters); @@ -398,7 +399,7 @@ public class PreviewExporter { int characterId = ((CharacterTag) t).getCharacterId(); if (characterId != -1) { writeTag(t, sos2, doneCharacters); - } + } } } @@ -432,7 +433,7 @@ public class PreviewExporter { //empty } else { Set needed = new HashSet<>(); - ((Tag) treeItem).getNeededCharactersDeep(needed); + ((Tag) treeItem).getNeededCharactersDeep(needed, new HashSet<>()); for (int n : needed) { if (isSprite && chtId == n) { continue; @@ -706,7 +707,7 @@ public class PreviewExporter { } doneCharacters.add(chId); } - + t.writeTagNoScripts(sos); if (t instanceof CharacterIdTag) { List chIdTags = t.getSwf().getCharacterIdTags(((CharacterIdTag) t).getCharacterId()); @@ -715,7 +716,7 @@ public class PreviewExporter { if (!(chIdTag instanceof PlaceObjectTypeTag || chIdTag instanceof RemoveTag)) { Set needed = new LinkedHashSet<>(); - ((Tag) chIdTag).getNeededCharactersDeep(needed); + ((Tag) chIdTag).getNeededCharactersDeep(needed, new HashSet<>()); for (int n : needed) { if (!doneCharacters.contains(n)) { writeTag(((Tag) chIdTag).getSwf().getCharacter(n), sos, doneCharacters); diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/ShapeExporter.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/ShapeExporter.java index 48351afa8..160b82275 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/ShapeExporter.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/ShapeExporter.java @@ -173,9 +173,11 @@ public class ShapeExporter { CanvasShapeExporter cse = new CanvasShapeExporter(st.getWindingRule(), st.getShapeNum(), null, SWF.unitDivisor / settings.zoom, ((Tag) st).getSwf(), shp, new CXFORMWITHALPHA(), deltaX, deltaY); cse.export(); Set needed = new HashSet<>(); + Set neededClasses = new HashSet<>(); needed.add(st.getCharacterId()); - st.getNeededCharactersDeep(needed); + st.getNeededCharactersDeep(needed, neededClasses); ByteArrayOutputStream baos = new ByteArrayOutputStream(); + //FIXME!!! Handle Library Classes SWF.libraryToHtmlCanvas(st.getSwf(), needed, baos); fos.write(Utf8Helper.getBytes(cse.getHtml(new String(baos.toByteArray(), Utf8Helper.charset), SWF.getTypePrefix(st) + st.getCharacterId(), st.getRect()))); } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/script/AS3ScriptExporter.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/script/AS3ScriptExporter.java index 65fd55689..eb72ffc5b 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/script/AS3ScriptExporter.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/script/AS3ScriptExporter.java @@ -684,12 +684,16 @@ public class AS3ScriptExporter { } Set neededCharacters = new LinkedHashSet<>(); + Set neededCharacterClasses = new LinkedHashSet<>(); List symbolClassIds = new ArrayList<>(); List symbolClassNames = new ArrayList<>(); for (CharacterTag st : assetsTagList) { - st.getNeededCharactersDeep(neededCharacters); + st.getNeededCharactersDeep(neededCharacters, neededCharacterClasses); neededCharacters.add(swf.getCharacterId(st)); } + + //TODO: handle neededCharacterClasses? + for (int n : neededCharacters) { CharacterTag ct = (CharacterTag) swf.getCharacter(n); if (ct == null) { diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/importers/SpriteImporter.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/importers/SpriteImporter.java index 4dc74d743..af2b2c8a4 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/importers/SpriteImporter.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/importers/SpriteImporter.java @@ -69,7 +69,9 @@ public class SpriteImporter { Set dependentCharacters = swf.getDependentCharacters(ch); if (dependentCharacters.isEmpty()) { Set needed = new LinkedHashSet<>(); - ct.getNeededCharacters(needed, swf); + Set neededClasses = new LinkedHashSet<>(); + ct.getNeededCharacters(needed, neededClasses, swf); + //TODO: handle classes? List attachedTags = swf.getCharacterIdTags(ch); for (CharacterIdTag cit : attachedTags) { if (cit instanceof Tag) { diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/CSMSettingsTag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/CSMSettingsTag.java index edca78269..579f9a74c 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/CSMSettingsTag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/CSMSettingsTag.java @@ -131,7 +131,7 @@ public class CSMSettingsTag extends Tag implements CharacterIdTag { } @Override - public void getNeededCharacters(Set needed, SWF swf) { + public void getNeededCharacters(Set needed, Set neededClasses, SWF swf) { needed.add(textID); } } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineButton2Tag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineButton2Tag.java index 87b1976ca..e3e541640 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineButton2Tag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineButton2Tag.java @@ -370,7 +370,7 @@ public class DefineButton2Tag extends ButtonTag implements ASMSourceContainer { } @Override - public void getNeededCharacters(Set needed, SWF swf) { + public void getNeededCharacters(Set needed, Set neededClasses, SWF swf) { for (BUTTONRECORD rec : characters) { needed.add(rec.characterId); } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineButtonCxformTag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineButtonCxformTag.java index e2cd52b82..db72c985a 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineButtonCxformTag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineButtonCxformTag.java @@ -104,7 +104,7 @@ public class DefineButtonCxformTag extends Tag implements CharacterModifier { } @Override - public void getNeededCharacters(Set needed, SWF swf) { + public void getNeededCharacters(Set needed, Set neededClasses, SWF swf) { needed.add(buttonId); } } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineButtonSoundTag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineButtonSoundTag.java index 432f7f528..84c26322f 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineButtonSoundTag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineButtonSoundTag.java @@ -144,7 +144,7 @@ public class DefineButtonSoundTag extends Tag implements CharacterModifier { } @Override - public void getNeededCharacters(Set needed, SWF swf) { + public void getNeededCharacters(Set needed, Set neededClasses, SWF swf) { if (buttonSoundChar0 != 0) { needed.add(buttonSoundChar0); } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineButtonTag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineButtonTag.java index d4b66d144..4d595aa6c 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineButtonTag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineButtonTag.java @@ -323,7 +323,7 @@ public class DefineButtonTag extends ButtonTag implements ASMSourceContainer { } @Override - public void getNeededCharacters(Set needed, SWF swf) { + public void getNeededCharacters(Set needed, Set neededClasses, SWF swf) { for (BUTTONRECORD rec : characters) { needed.add(rec.characterId); } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineEditTextTag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineEditTextTag.java index 37be55c59..e4c725b48 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineEditTextTag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineEditTextTag.java @@ -1237,16 +1237,24 @@ public class DefineEditTextTag extends TextTag { } @Override - public void getNeededCharacters(Set needed, SWF swf) { + public void getNeededCharacters(Set needed, Set neededClasses, SWF swf) { if (hasFont) { - needed.add(fontId); + needed.add(fontId); + } + if (hasFontClass) { + neededClasses.add(fontClass); } if (html && hasText) { List chs = getTextWithStyle(); for (CharacterWithStyle ch : chs) { if (ch.style.font != null) { - needed.add(swf.getCharacterId(ch.style.font)); - } + int subFontId = swf.getCharacterId(ch.style.font); + if (subFontId != -1) { + needed.add(subFontId); + } else { + neededClasses.addAll(ch.style.font.getClassNames()); + } + } } } } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineFontAlignZonesTag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineFontAlignZonesTag.java index 1963541ef..6f860d269 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineFontAlignZonesTag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineFontAlignZonesTag.java @@ -123,7 +123,7 @@ public class DefineFontAlignZonesTag extends Tag implements CharacterModifier { } @Override - public void getNeededCharacters(Set needed, SWF swf) { + public void getNeededCharacters(Set needed, Set neededClasses, SWF swf) { needed.add(fontID); } } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineFontInfo2Tag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineFontInfo2Tag.java index 54b278569..db16ea9ad 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineFontInfo2Tag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineFontInfo2Tag.java @@ -188,7 +188,7 @@ public class DefineFontInfo2Tag extends FontInfoTag { } @Override - public void getNeededCharacters(Set needed, SWF swf) { + public void getNeededCharacters(Set needed, Set neededClasses, SWF swf) { needed.add(fontID); } } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineFontInfoTag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineFontInfoTag.java index b07708879..6965a7836 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineFontInfoTag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineFontInfoTag.java @@ -189,7 +189,7 @@ public class DefineFontInfoTag extends FontInfoTag { } @Override - public void getNeededCharacters(Set needed, SWF swf) { + public void getNeededCharacters(Set needed, Set neededClasses, SWF swf) { needed.add(fontID); } } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineFontNameTag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineFontNameTag.java index 834f5089b..715bf7775 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineFontNameTag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineFontNameTag.java @@ -101,7 +101,7 @@ public class DefineFontNameTag extends Tag implements CharacterModifier { } @Override - public void getNeededCharacters(Set needed, SWF swf) { + public void getNeededCharacters(Set needed, Set neededClasses, SWF swf) { needed.add(fontId); } } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineScalingGridTag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineScalingGridTag.java index 46efb49f0..dce78f145 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineScalingGridTag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineScalingGridTag.java @@ -231,7 +231,7 @@ public class DefineScalingGridTag extends Tag implements CharacterModifier { } @Override - public void getNeededCharacters(Set needed, SWF swf) { + public void getNeededCharacters(Set needed, Set neededClasses, SWF swf) { needed.add(characterId); } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineSpriteTag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineSpriteTag.java index 31ac93c2d..077b9e6ed 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineSpriteTag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineSpriteTag.java @@ -419,7 +419,7 @@ public class DefineSpriteTag extends DrawableTag implements Timelined { } @Override - public void getNeededCharacters(Set needed, SWF swf) { + public void getNeededCharacters(Set needed, Set neededClasses, SWF swf) { for (Tag t : getTags()) { if ( (t instanceof PlaceObjectTypeTag) @@ -427,7 +427,7 @@ public class DefineSpriteTag extends DrawableTag implements Timelined { || (t instanceof StartSound2Tag) || (t instanceof VideoFrameTag) ) { - t.getNeededCharacters(needed, swf); + t.getNeededCharacters(needed, neededClasses, swf); } } } @@ -538,15 +538,13 @@ public class DefineSpriteTag extends DrawableTag implements Timelined { } @Override - public Set getMissingNeededCharacters(Set needed) { - Set ret = new LinkedHashSet<>(); + public void getMissingNeededCharacters(Set needed, Set neededClasses, Set resultNeeded, Set resultNeededClasses) { for (Tag tag : getTags()) { Set subNeeded = new HashSet<>(); - tag.getNeededCharactersDeep(subNeeded); - Set sub = tag.getMissingNeededCharacters(subNeeded); - ret.addAll(sub); - } - return ret; + Set subNeededClasses = new HashSet<>(); + tag.getNeededCharactersDeep(subNeeded, subNeededClasses); + tag.getMissingNeededCharacters(subNeeded, subNeededClasses, resultNeeded, resultNeededClasses); + } } @Override 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 25e3a4702..0bcefd0a0 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 @@ -294,7 +294,7 @@ public class DoInitActionTag extends Tag implements CharacterIdTag, ASMSource { } @Override - public void getNeededCharacters(Set needed, SWF swf) { + public void getNeededCharacters(Set needed, Set neededClasses, SWF swf) { needed.add(spriteId); } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/ExportAssetsTag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/ExportAssetsTag.java index a54ae58a5..4f2d61b25 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/ExportAssetsTag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/ExportAssetsTag.java @@ -155,7 +155,7 @@ public class ExportAssetsTag extends SymbolClassTypeTag { } @Override - public void getNeededCharacters(Set needed, SWF swf) { + public void getNeededCharacters(Set needed, Set neededClasses, SWF swf) { needed.addAll(tags); } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/FreeCharacterTag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/FreeCharacterTag.java index 694b7ff90..7fc9fcf26 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/FreeCharacterTag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/FreeCharacterTag.java @@ -87,7 +87,7 @@ public class FreeCharacterTag extends Tag implements CharacterIdTag { } @Override - public void getNeededCharacters(Set needed, SWF swf) { + public void getNeededCharacters(Set needed, Set neededClasses, SWF swf) { needed.add(characterId); } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/NameCharacterTag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/NameCharacterTag.java index 12fe8cf96..941512123 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/NameCharacterTag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/NameCharacterTag.java @@ -105,7 +105,7 @@ public class NameCharacterTag extends Tag implements CharacterModifier { } @Override - public void getNeededCharacters(Set needed, SWF swf) { + public void getNeededCharacters(Set needed, Set neededClasses, SWF swf) { needed.add(characterId); } } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/PlaceObject2Tag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/PlaceObject2Tag.java index d0b37fb0d..60068a99f 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/PlaceObject2Tag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/PlaceObject2Tag.java @@ -327,7 +327,7 @@ public class PlaceObject2Tag extends PlaceObjectTypeTag implements ASMSourceCont } @Override - public void getNeededCharacters(Set needed, SWF swf) { + public void getNeededCharacters(Set needed, Set neededClasses, SWF swf) { if (placeFlagHasCharacter) { needed.add(characterId); } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/PlaceObject3Tag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/PlaceObject3Tag.java index ec69cc0de..e3a5703b0 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/PlaceObject3Tag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/PlaceObject3Tag.java @@ -543,7 +543,7 @@ public class PlaceObject3Tag extends PlaceObjectTypeTag implements ASMSourceCont } @Override - public void getNeededCharacters(Set needed, SWF swf) { + public void getNeededCharacters(Set needed, Set neededClasses, SWF swf) { if (placeFlagHasCharacter) { needed.add(characterId); } @@ -551,6 +551,8 @@ public class PlaceObject3Tag extends PlaceObjectTypeTag implements ASMSourceCont int chId = swf.getCharacterId(swf.getCharacterByClass(className)); if (chId != -1) { needed.add(chId); + } else { + neededClasses.add(className); } } } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/PlaceObject4Tag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/PlaceObject4Tag.java index a35a7fed4..376c39ef6 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/PlaceObject4Tag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/PlaceObject4Tag.java @@ -564,7 +564,7 @@ public class PlaceObject4Tag extends PlaceObjectTypeTag implements ASMSourceCont } @Override - public void getNeededCharacters(Set needed, SWF swf) { + public void getNeededCharacters(Set needed, Set neededClasses, SWF swf) { if (placeFlagHasCharacter) { needed.add(characterId); } @@ -572,6 +572,8 @@ public class PlaceObject4Tag extends PlaceObjectTypeTag implements ASMSourceCont int chId = swf.getCharacterId(swf.getCharacterByClass(className)); if (chId != -1) { needed.add(chId); + } else { + neededClasses.add(className); } } } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/PlaceObjectTag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/PlaceObjectTag.java index 26d347700..83a9cee7f 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/PlaceObjectTag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/PlaceObjectTag.java @@ -143,7 +143,7 @@ public class PlaceObjectTag extends PlaceObjectTypeTag { } @Override - public void getNeededCharacters(Set needed, SWF swf) { + public void getNeededCharacters(Set needed, Set neededClasses, SWF swf) { needed.add(characterId); } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/RemoveObjectTag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/RemoveObjectTag.java index 8352b2602..5657992ad 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/RemoveObjectTag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/RemoveObjectTag.java @@ -112,7 +112,7 @@ public class RemoveObjectTag extends RemoveTag implements CharacterIdTag { } @Override - public void getNeededCharacters(Set needed, SWF swf) { + public void getNeededCharacters(Set needed, Set neededClasses, SWF swf) { needed.add(characterId); } } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/StartSound2Tag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/StartSound2Tag.java index 9bdbb3e05..0c4db1d41 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/StartSound2Tag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/StartSound2Tag.java @@ -92,7 +92,7 @@ public class StartSound2Tag extends Tag { } @Override - public void getNeededCharacters(Set needed, SWF swf) { + public void getNeededCharacters(Set needed, Set neededClasses, SWF swf) { int characterId = swf.getCharacterId(swf.getCharacterByClass(soundClassName)); needed.add(characterId); } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/StartSoundTag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/StartSoundTag.java index f0f70c2a4..9fd7b1d9d 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/StartSoundTag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/StartSoundTag.java @@ -104,7 +104,7 @@ public class StartSoundTag extends Tag implements CharacterIdTag { } @Override - public void getNeededCharacters(Set needed, SWF swf) { + public void getNeededCharacters(Set needed, Set neededClasses, SWF swf) { needed.add(soundId); } } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/SymbolClassTag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/SymbolClassTag.java index a768f54eb..955b24c6f 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/SymbolClassTag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/SymbolClassTag.java @@ -145,7 +145,7 @@ public class SymbolClassTag extends SymbolClassTypeTag { } @Override - public void getNeededCharacters(Set needed, SWF swf) { + public void getNeededCharacters(Set needed, Set neededClasses, SWF swf) { for (int t : tags) { if (t != 0) { //main class needed.add(t); diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/Tag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/Tag.java index dc20751c8..102ffdc62 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/Tag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/Tag.java @@ -842,41 +842,51 @@ public abstract class Tag implements NeedsCharacters, Exportable, Serializable { } @Override - public void getNeededCharacters(Set needed, SWF swf) { - } + public void getNeededCharacters(Set needed, Set neededClasses, SWF swf) { + } /** * Gets missing needed characters. * @param needed Needed - * @return Missing needed characters + * @param neededClasses Needed classes */ - public Set getMissingNeededCharacters(Set needed) { + public void getMissingNeededCharacters(Set needed, Set neededClasses, Set resultNeeded, Set resultNeededClasses) { Set needed2 = new LinkedHashSet<>(needed); - if (needed2.isEmpty()) { - return new LinkedHashSet<>(); + Set needed2Classes = new LinkedHashSet<>(neededClasses); + if (needed2.isEmpty() && needed2Classes.isEmpty()) { + resultNeeded.clear(); + resultNeededClasses.clear(); + return; } Timelined tim = getTimelined(); if (tim == null) { - return needed2; + resultNeeded.addAll(needed2); + resultNeededClasses.addAll(needed2Classes); + return; } ReadOnlyTagList tags = tim.getTags(); for (int i = tags.indexOf(this) - 1; i >= 0; i--) { if (tags.get(i) instanceof ImportTag) { ImportTag it = (ImportTag) tags.get(i); needed2.removeAll(it.getAssets().keySet()); - if (needed2.isEmpty()) { - return needed2; + if (needed2.isEmpty() && needed2Classes.isEmpty()) { + resultNeeded.addAll(needed2); + resultNeededClasses.addAll(needed2Classes); + return; } } if (tags.get(i) instanceof CharacterTag) { int charId = ((CharacterTag) tags.get(i)).getCharacterId(); - needed2.remove(charId); - if (needed2.isEmpty()) { - return needed2; + needed2.remove(charId); + needed2Classes.removeAll(((CharacterTag) tags.get(i)).getClassNames()); + + if (needed2.isEmpty() && needed2Classes.isEmpty()) { + resultNeeded.addAll(needed2); + resultNeededClasses.addAll(needed2Classes); + return; } } - } - return needed2; + } } @Override @@ -888,16 +898,17 @@ public abstract class Tag implements NeedsCharacters, Exportable, Serializable { public boolean removeCharacter(int characterId) { return false; } - + /** * Gets needed characters deep. - * @param needed Needed + * @param needed Needed character ids + * @param neededClasses Needed classes */ - public void getNeededCharactersDeep(Set needed) { + public void getNeededCharactersDeep(Set needed, Set neededClasses) { Set needed2 = new LinkedHashSet<>(); - getNeededCharacters(needed2, swf); + getNeededCharacters(needed2, neededClasses, swf); List needed3 = new ArrayList<>(needed2); - + for (int i = 0; i < needed3.size(); i++) { int characterId = needed3.get(i); if (swf == null) { @@ -909,7 +920,7 @@ public abstract class Tag implements NeedsCharacters, Exportable, Serializable { if (character.isImported()) { continue; } - character.getNeededCharacters(needed4, swf); + character.getNeededCharacters(needed4, neededClasses, swf); List newItems = new ArrayList<>(); for (int n : needed4) { int index = needed3.indexOf((Integer) n); @@ -937,12 +948,13 @@ public abstract class Tag implements NeedsCharacters, Exportable, Serializable { } } - private void getDependentCharactersOnTimelined(Timelined timelined, Set dependent) { + private void getDependentCharactersOnTimelined(Timelined timelined, Set dependent, Set dependentClasses) { for (Tag tag : timelined.getTags()) { if (tag instanceof CharacterTag) { if (((CharacterTag) tag).getCharacterId() != -1) { Set needed = new HashSet<>(); - tag.getNeededCharactersDeep(needed); + Set neededClasses = new HashSet<>(); + tag.getNeededCharactersDeep(needed, neededClasses); for (int dep : dependent) { if (needed.contains(dep)) { dependent.add(((CharacterTag) tag).getCharacterId()); @@ -952,17 +964,18 @@ public abstract class Tag implements NeedsCharacters, Exportable, Serializable { } } if (tag instanceof DefineSpriteTag) { - getDependentCharactersOnTimelined((DefineSpriteTag) tag, dependent); + getDependentCharactersOnTimelined((DefineSpriteTag) tag, dependent, dependentClasses); } } } /** * Gets dependent characters. - * @param dependent Result + * @param dependent Result - dependent character ids + * @param dependentClasses Result - dependent classes */ - public void getDependentCharacters(Set dependent) { - getDependentCharactersOnTimelined(swf, dependent); + public void getDependentCharacters(Set dependent, Set dependentClasses) { + getDependentCharactersOnTimelined(swf, dependent, dependentClasses); } /** diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/VideoFrameTag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/VideoFrameTag.java index a08ff263f..035444c2d 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/VideoFrameTag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/VideoFrameTag.java @@ -100,7 +100,7 @@ public class VideoFrameTag extends Tag implements CharacterIdTag { } @Override - public void getNeededCharacters(Set needed, SWF swf) { + public void getNeededCharacters(Set needed, Set neededClasses, SWF swf) { needed.add(streamID); } } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/base/ButtonTag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/base/ButtonTag.java index 298fc5cf9..a7c0042ec 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/base/ButtonTag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/base/ButtonTag.java @@ -99,7 +99,7 @@ public abstract class ButtonTag extends DrawableTag implements Timelined { public abstract boolean trackAsMenu(); @Override - public void getNeededCharacters(Set needed, SWF swf) { + public void getNeededCharacters(Set needed, Set neededClasses, SWF swf) { for (BUTTONRECORD r : getRecords()) { needed.add(r.characterId); } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/base/MorphShapeTag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/base/MorphShapeTag.java index a50cbc5e3..431b95309 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/base/MorphShapeTag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/base/MorphShapeTag.java @@ -149,10 +149,10 @@ public abstract class MorphShapeTag extends DrawableTag { } @Override - public void getNeededCharacters(Set needed, SWF swf) { - morphFillStyles.getNeededCharacters(needed, swf); - startEdges.getNeededCharacters(needed, swf); - endEdges.getNeededCharacters(needed, swf); + public void getNeededCharacters(Set needed, Set neededClasses, SWF swf) { + morphFillStyles.getNeededCharacters(needed, neededClasses, swf); + startEdges.getNeededCharacters(needed, neededClasses, swf); + endEdges.getNeededCharacters(needed, neededClasses, swf); } @Override diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/base/NeedsCharacters.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/base/NeedsCharacters.java index c843470c4..3a5a9c121 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/base/NeedsCharacters.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/base/NeedsCharacters.java @@ -29,10 +29,11 @@ public interface NeedsCharacters { /** * Get needed characters. * - * @param needed Result + * @param needed Result - needed character ids + * @param neededClasses Result - needed classes * @param swf SWF file */ - public void getNeededCharacters(Set needed, SWF swf); + public void getNeededCharacters(Set needed, Set neededClasses, SWF swf); /** * Replace character. diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/base/ShapeTag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/base/ShapeTag.java index e3c3b0c44..ea5ba43d6 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/base/ShapeTag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/base/ShapeTag.java @@ -139,10 +139,10 @@ public abstract class ShapeTag extends DrawableTag implements LazyObject { } @Override - public void getNeededCharacters(Set needed, SWF swf) { + public void getNeededCharacters(Set needed, Set neededClasses, SWF swf) { SHAPEWITHSTYLE shapes = getShapes(); if (shapes != null) { - getShapes().getNeededCharacters(needed, swf); + getShapes().getNeededCharacters(needed, neededClasses, swf); } } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/base/StaticTextTag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/base/StaticTextTag.java index e06912601..ff1781b27 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/base/StaticTextTag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/base/StaticTextTag.java @@ -982,11 +982,11 @@ public abstract class StaticTextTag extends TextTag { } @Override - public void getNeededCharacters(Set needed, SWF swf) { + public void getNeededCharacters(Set needed, Set neededClasses, SWF swf) { for (TEXTRECORD tr : textRecords) { if (tr.styleFlagsHasFont) { needed.add(tr.fontId); - } + } } } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/timeline/Frame.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/timeline/Frame.java index 0c527c552..649c0908f 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/timeline/Frame.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/timeline/Frame.java @@ -262,9 +262,10 @@ public class Frame implements TreeItem, Exportable { /** * Get needed characters for this frame to deepest level. * - * @param needed Result + * @param needed Result - needed character ids + * @param neededClasses Result - needed classes */ - public void getNeededCharactersDeep(Set needed) { + public void getNeededCharactersDeep(Set needed, Set neededClasses) { for (Tag t : innerTags) { if (t instanceof PlaceObjectTypeTag) { PlaceObjectTypeTag place = (PlaceObjectTypeTag) t; @@ -272,7 +273,7 @@ public class Frame implements TreeItem, Exportable { if (characterId != -1) { CharacterTag character = place.getSwf().getCharacter(characterId); if (character != null) { - character.getNeededCharactersDeep(needed); + character.getNeededCharactersDeep(needed, neededClasses); } needed.add(characterId); } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/timeline/Timeline.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/timeline/Timeline.java index 5bc39c7a3..c3a417518 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/timeline/Timeline.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/timeline/Timeline.java @@ -957,11 +957,12 @@ public class Timeline { /** * Gets needed characters for this timeline. * - * @param usedCharacters Result + * @param usedCharacters Result - used characters + * @param usedClasses Result - used classes */ - public void getNeededCharacters(Set usedCharacters) { + public void getNeededCharacters(Set usedCharacters, Set usedClasses) { for (int i = 0; i < getFrameCount(); i++) { - getNeededCharacters(i, usedCharacters); + getNeededCharacters(i, usedCharacters, usedClasses); } } @@ -969,11 +970,12 @@ public class Timeline { * Gets needed characters for this timeline. * * @param frames List of frames - * @param usedCharacters Result + * @param usedCharacters Result - used character ids + * @param usedClasses Result - used classes */ - public void getNeededCharacters(List frames, Set usedCharacters) { + public void getNeededCharacters(List frames, Set usedCharacters, Set usedClasses) { for (int frame = 0; frame < getFrameCount(); frame++) { - getNeededCharacters(frame, usedCharacters); + getNeededCharacters(frame, usedCharacters, usedClasses); } } @@ -981,9 +983,10 @@ public class Timeline { * Gets needed characters for a frame. * * @param frame Frame index - * @param usedCharacters Result + * @param usedCharacters Result - used character ids + * @param usedClasses Result - used classes */ - public void getNeededCharacters(int frame, Set usedCharacters) { + public void getNeededCharacters(int frame, Set usedCharacters, Set usedClasses) { Frame frameObj = getFrame(frame); for (int depth : frameObj.layers.keySet()) { DepthState layer = frameObj.layers.get(depth); @@ -992,7 +995,8 @@ public class Timeline { continue; } usedCharacters.add(ch.getCharacterId()); - ch.getNeededCharactersDeep(usedCharacters); + usedClasses.addAll(ch.getClassNames()); + ch.getNeededCharactersDeep(usedCharacters, usedClasses); } } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/FILLSTYLE.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/FILLSTYLE.java index d8a277c35..b8094a3fc 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/FILLSTYLE.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/FILLSTYLE.java @@ -137,7 +137,7 @@ public class FILLSTYLE implements NeedsCharacters, FieldChangeObserver, Serializ public MATRIX bitmapMatrix; @Override - public void getNeededCharacters(Set needed, SWF swf) { + public void getNeededCharacters(Set needed, Set neededClasses, SWF swf) { if ((fillStyleType == REPEATING_BITMAP) || (fillStyleType == CLIPPED_BITMAP) || (fillStyleType == NON_SMOOTHED_REPEATING_BITMAP) diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/FILLSTYLEARRAY.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/FILLSTYLEARRAY.java index 2d5d6682f..5944c6746 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/FILLSTYLEARRAY.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/FILLSTYLEARRAY.java @@ -56,9 +56,9 @@ public class FILLSTYLEARRAY implements NeedsCharacters, Serializable { } @Override - public void getNeededCharacters(Set needed, SWF swf) { + public void getNeededCharacters(Set needed, Set neededClasses, SWF swf) { for (FILLSTYLE fs : fillStyles) { - fs.getNeededCharacters(needed, swf); + fs.getNeededCharacters(needed, neededClasses, swf); } } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/LINESTYLE.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/LINESTYLE.java index 468c245a0..50fca4723 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/LINESTYLE.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/LINESTYLE.java @@ -46,7 +46,7 @@ public class LINESTYLE implements NeedsCharacters, Serializable, ILINESTYLE { public RGB color; @Override - public void getNeededCharacters(Set needed, SWF swf) { + public void getNeededCharacters(Set needed, Set neededClasses, SWF swf) { } @Override diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/LINESTYLE2.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/LINESTYLE2.java index a69f53d00..c18df9e64 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/LINESTYLE2.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/LINESTYLE2.java @@ -149,9 +149,9 @@ public class LINESTYLE2 implements NeedsCharacters, Serializable, ILINESTYLE { public FILLSTYLE fillType; @Override - public void getNeededCharacters(Set needed, SWF swf) { + public void getNeededCharacters(Set needed, Set neededClasses, SWF swf) { if (hasFillFlag) { - fillType.getNeededCharacters(needed, swf); + fillType.getNeededCharacters(needed, neededClasses, swf); } } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/LINESTYLEARRAY.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/LINESTYLEARRAY.java index 58ef014ea..6a3dd00c4 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/LINESTYLEARRAY.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/LINESTYLEARRAY.java @@ -102,15 +102,15 @@ public class LINESTYLEARRAY implements NeedsCharacters, Serializable { } @Override - public void getNeededCharacters(Set needed, SWF swf) { + public void getNeededCharacters(Set needed, Set neededClasses, SWF swf) { if (lineStyles != null) { for (ILINESTYLE ls : lineStyles) { - ls.getNeededCharacters(needed, swf); + ls.getNeededCharacters(needed, neededClasses, swf); } } if (lineStyles != null) { for (ILINESTYLE ls : lineStyles2) { - ls.getNeededCharacters(needed, swf); + ls.getNeededCharacters(needed, neededClasses, swf); } } } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/MORPHFILLSTYLE.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/MORPHFILLSTYLE.java index 796d00a49..ddf4d1b85 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/MORPHFILLSTYLE.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/MORPHFILLSTYLE.java @@ -136,7 +136,7 @@ public class MORPHFILLSTYLE implements NeedsCharacters, Serializable { public MATRIX endBitmapMatrix; @Override - public void getNeededCharacters(Set needed, SWF swf) { + public void getNeededCharacters(Set needed, Set neededClasses, SWF swf) { if ((fillStyleType == REPEATING_BITMAP) || (fillStyleType == CLIPPED_BITMAP) || (fillStyleType == NON_SMOOTHED_REPEATING_BITMAP) diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/MORPHFILLSTYLEARRAY.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/MORPHFILLSTYLEARRAY.java index cdea9585b..b019d5470 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/MORPHFILLSTYLEARRAY.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/MORPHFILLSTYLEARRAY.java @@ -34,9 +34,9 @@ public class MORPHFILLSTYLEARRAY implements NeedsCharacters, Serializable { public MORPHFILLSTYLE[] fillStyles; @Override - public void getNeededCharacters(Set needed, SWF swf) { + public void getNeededCharacters(Set needed, Set neededClasses, SWF swf) { for (MORPHFILLSTYLE fs : fillStyles) { - fs.getNeededCharacters(needed, swf); + fs.getNeededCharacters(needed, neededClasses, swf); } } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/SHAPE.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/SHAPE.java index fe88e462a..6fb24b54c 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/SHAPE.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/SHAPE.java @@ -69,9 +69,9 @@ public class SHAPE implements NeedsCharacters, Serializable { } @Override - public void getNeededCharacters(Set needed, SWF swf) { + public void getNeededCharacters(Set needed, Set neededClasses, SWF swf) { for (SHAPERECORD r : shapeRecords) { - r.getNeededCharacters(needed, swf); + r.getNeededCharacters(needed, neededClasses, swf); } } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/SHAPEWITHSTYLE.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/SHAPEWITHSTYLE.java index d5d0a78cd..0b220a606 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/SHAPEWITHSTYLE.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/SHAPEWITHSTYLE.java @@ -47,11 +47,11 @@ public class SHAPEWITHSTYLE extends SHAPE implements NeedsCharacters, Serializab public LINESTYLEARRAY lineStyles; @Override - public void getNeededCharacters(Set needed, SWF swf) { - fillStyles.getNeededCharacters(needed, swf); - lineStyles.getNeededCharacters(needed, swf); + public void getNeededCharacters(Set needed, Set neededClasses, SWF swf) { + fillStyles.getNeededCharacters(needed, neededClasses, swf); + lineStyles.getNeededCharacters(needed, neededClasses, swf); for (SHAPERECORD r : shapeRecords) { - r.getNeededCharacters(needed, swf); + r.getNeededCharacters(needed, neededClasses, swf); } } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/shaperecords/SHAPERECORD.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/shaperecords/SHAPERECORD.java index 8e209ae09..4b6c209b3 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/shaperecords/SHAPERECORD.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/shaperecords/SHAPERECORD.java @@ -62,7 +62,7 @@ public abstract class SHAPERECORD implements Cloneable, NeedsCharacters, Seriali public abstract void calculateBits(); @Override - public void getNeededCharacters(Set needed, SWF swf) { + public void getNeededCharacters(Set needed, Set neededClasses, SWF swf) { } @Override diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/shaperecords/StyleChangeRecord.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/shaperecords/StyleChangeRecord.java index 05f70cfb3..0d6a4bb4f 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/shaperecords/StyleChangeRecord.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/shaperecords/StyleChangeRecord.java @@ -85,9 +85,9 @@ public final class StyleChangeRecord extends SHAPERECORD implements Cloneable { public int numLineBits; @Override - public void getNeededCharacters(Set needed, SWF swf) { + public void getNeededCharacters(Set needed, Set neededClasses, SWF swf) { if (stateNewStyles) { - fillStyles.getNeededCharacters(needed, swf); + fillStyles.getNeededCharacters(needed, neededClasses, swf); } } 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 5095e300f..df2e26903 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 @@ -528,7 +528,7 @@ public class XFLConverter { ImageTag it = (ImageTag) bitmapCh; writer.writeStartElement("BitmapFill"); - writer.writeAttribute("bitmapPath", getSymbolName(lastImportedId, characterNameMap, swf, bitmapCh, "Bitmap") + it.getImageFormat().getExtension()); + writer.writeAttribute("bitmapPath", getSymbolName(lastImportedId, characterNameMap, swf, bitmapCh, "Bitmap", true) + it.getImageFormat().getExtension()); if ((fs.fillStyleType == FILLSTYLE.CLIPPED_BITMAP) || (fs.fillStyleType == FILLSTYLE.NON_SMOOTHED_CLIPPED_BITMAP)) { writer.writeAttribute("bitmapIsClipped", true); @@ -1123,6 +1123,7 @@ public class XFLConverter { return ret; } + private static void walkNeededClasses(Set ret, ReadOnlyTagList tags) { for (Tag t : tags) { if (t instanceof DefineSpriteTag) { @@ -1144,10 +1145,12 @@ public class XFLConverter { } } } + private static void walkNeededCharacters(Set result, CharacterTag ct) { Set needed = new HashSet<>(); - ct.getNeededCharactersDeep(needed); + Set neededClasses = new HashSet<>(); + ct.getNeededCharactersDeep(needed, neededClasses); for (int n : needed) { CharacterTag nc = ct.getSwf().getCharacter(n); if (result.contains(nc)) { @@ -1155,10 +1158,23 @@ public class XFLConverter { } result.add(nc); walkNeededCharacters(result, nc); + /*if (nc instanceof DefineSpriteTag) { + DefineSpriteTag sp = (DefineSpriteTag) nc; + walkNeededClasses(result, sp.getTags()); + }*/ + } + + for (String n : neededClasses) { + CharacterTag nc = ct.getSwf().getCharacterByClass(n); + if (result.contains(nc)) { + continue; + } + result.add(nc); + /*walkNeededCharacters(result, nc); if (nc instanceof DefineSpriteTag) { DefineSpriteTag sp = (DefineSpriteTag) nc; walkNeededClasses(result, sp.getTags()); - } + }*/ } } @@ -1337,24 +1353,43 @@ public class XFLConverter { } private static String getSymbolName(Reference lastImportedId, Map characterNameMap, SWF swf, CharacterTag tag) { - return getSymbolName(lastImportedId, characterNameMap, swf, tag, "Symbol"); + return getSymbolName(lastImportedId, characterNameMap, swf, tag, true); + } + + private static String getSymbolName(Reference lastImportedId, Map characterNameMap, SWF swf, CharacterTag tag, boolean fullPath) { + return getSymbolName(lastImportedId, characterNameMap, swf, tag, "Symbol", fullPath); } private static String getSymbolName(Reference lastImportedId, Map characterNameMap, SWF swf, CharacterTag tag, String kind) { + return getSymbolName(lastImportedId, characterNameMap, swf, tag, kind, true); + } + + private static String getSymbolName(Reference lastImportedId, Map characterNameMap, SWF swf, CharacterTag tag, String kind, boolean fullPath) { if (tag == null) { return "null"; } - if (characterNameMap.containsKey(tag)) { - return characterNameMap.get(tag); + if (!characterNameMap.containsKey(tag)) { + int characterId = swf.getCharacterId(tag); + if (characterId == -1) { + lastImportedId.setVal(lastImportedId.getVal() + 1); + if (tag instanceof FontTag) { + //The font must have unique name (without folder) + characterNameMap.put(tag, "imported/Imported Font " + lastImportedId.getVal()); + } else { + characterNameMap.put(tag, "imported/" + kind + " " + lastImportedId.getVal()); + } + } else { + characterNameMap.put(tag, kind + " " + characterId); + } } - int characterId = swf.getCharacterId(tag); - if (characterId == -1) { - lastImportedId.setVal(lastImportedId.getVal() + 1); - characterNameMap.put(tag, "imported/" + kind + " " + lastImportedId.getVal()); - } else { - characterNameMap.put(tag, kind + " " + characterId); + + String ret = characterNameMap.get(tag); + + if (ret.contains("/") && !fullPath) { + return ret.substring(ret.lastIndexOf("/") + 1); } - return characterNameMap.get(tag); + + return ret; } private String getMaskedSymbolName(int symbolId) { //FIXME: Does this work with importassets??? @@ -1628,7 +1663,7 @@ public class XFLConverter { if (symbol instanceof ButtonTag) { symbolStr.writeStartElement("timeline"); itemIcon = "0"; - symbolStr.writeStartElement("DOMTimeline", new String[]{"name", getSymbolName(lastImportedId, characterNameMap, swf, symbol), "currentFrame", "0"}); + symbolStr.writeStartElement("DOMTimeline", new String[]{"name", getSymbolName(lastImportedId, characterNameMap, swf, symbol, false), "currentFrame", "0"}); symbolStr.writeStartElement("layers"); ButtonTag button = (ButtonTag) symbol; @@ -1840,7 +1875,7 @@ public class XFLConverter { symbolStr.writeStartElement("timeline"); itemIcon = "1"; ShapeTag shape = (ShapeTag) symbol; - symbolStr.writeStartElement("DOMTimeline", new String[]{"name", getSymbolName(lastImportedId, characterNameMap, swf, symbol), "currentFrame", "0"}); + symbolStr.writeStartElement("DOMTimeline", new String[]{"name", getSymbolName(lastImportedId, characterNameMap, swf, symbol, false), "currentFrame", "0"}); symbolStr.writeStartElement("layers"); SHAPEWITHSTYLE shapeWithStyle = shape.getShapes(); if (shapeWithStyle != null) { @@ -2099,7 +2134,8 @@ public class XFLConverter { for (Tag tag : swf.getTags()) { if (tag instanceof ShapeTag) { Set needed = new HashSet<>(); - tag.getNeededCharacters(needed, swf); + Set neededClasses = new HashSet<>(); + tag.getNeededCharacters(needed, neededClasses, swf); ShapeTag sht = (ShapeTag) tag; if (needed.contains(imageTag.getCharacterId())) { List fs = new ArrayList<>(); @@ -4499,7 +4535,7 @@ public class XFLConverter { if (classNames.size() == 1) { writer.writeAttribute("linkageClassName", classNames.get(0)); } - if (symbolId == -1) { + if (sprite == null && symbolId == -1) { writer.writeStartElement("timelines"); } else { writer.writeStartElement("timeline"); @@ -4525,7 +4561,7 @@ public class XFLConverter { if (!lastShowFrame) { fc++; } - if (symbolId == -1) { + if (sprite == null && symbolId == -1) { if (sceneLabelTag != null) { for (int i = 0; i < sceneLabelTag.sceneOffsets.length; i++) { scenes.add(new Scene( @@ -4578,7 +4614,11 @@ public class XFLConverter { scenes.add(scene); } } else { - Scene scene = new Scene(0, fc - 1, spriteName); + String simpleSpriteName = spriteName; + if (simpleSpriteName.contains("/")) { + simpleSpriteName = spriteName.substring(spriteName.lastIndexOf("/") + 1); + } + Scene scene = new Scene(0, fc - 1, simpleSpriteName); scene.timelineSubTags = timelineTags; scenes.add(scene); } @@ -5211,7 +5251,7 @@ public class XFLConverter { } if (font != null && characterImportLinkageURL.containsKey(font)) { - psFontName = getSymbolName(lastImportedId, characterNameMap, swf, font, "Font") + "*"; + psFontName = getSymbolName(lastImportedId, characterNameMap, swf, font, "Font", false) + "*"; } } newline = false; @@ -5257,7 +5297,12 @@ public class XFLConverter { } else if (tag instanceof DefineEditTextTag) { DefineEditTextTag det = (DefineEditTextTag) tag; String tagName; - FontTag ft = det.getSwf().getFont(det.fontId); + FontTag ft = null; + if (det.hasFont) { + ft = det.getSwf().getFont(det.fontId); + } else if (det.hasFontClass) { + ft = det.getSwf().getFontByClass(det.fontClass); + } if (normalizedFonts.containsKey(det.fontId)) { ft = normalizedFonts.get(det.fontId); @@ -5354,8 +5399,8 @@ public class XFLConverter { RGBA textColor = null; if (det.hasTextColor) { textColor = det.textColor; - } - if (det.hasFont) { + } + if (det.hasFont || det.hasFontClass) { String fontName = null; if (ft != null) { DefineFontNameTag dfn = (DefineFontNameTag) ft.getSwf().getCharacterIdTag(ft.getCharacterId(), DefineFontNameTag.ID); @@ -5379,7 +5424,7 @@ public class XFLConverter { fontFace = new Font(installedFont, (italic ? Font.ITALIC : 0) | (bold ? Font.BOLD : 0) | (!italic && !bold ? Font.PLAIN : 0), size < 0 ? 10 : size).getPSName(); } if (characterImportLinkageURL.containsKey(ft)) { - fontFace = getSymbolName(lastImportedId, characterNameMap, swf, ft, "Font") + "*"; + fontFace = getSymbolName(lastImportedId, characterNameMap, swf, ft, "Font", false) + "*"; } } } @@ -5559,6 +5604,7 @@ public class XFLConverter { double width = twipToPixel(swf.displayRect.getWidth()); double height = twipToPixel(swf.displayRect.getHeight()); + boolean hasImport = false; XFLXmlWriter domDocument = new XFLXmlWriter(); try { @@ -5625,7 +5671,8 @@ public class XFLConverter { CharacterTag cht = swf.getCharacter(chid); characterImportLinkageURL.put(cht, it.getUrl()); } - } + hasImport = true; + } if (frame == 1) { if (tag instanceof ExportAssetsTag) { ExportAssetsTag et = (ExportAssetsTag) tag; @@ -5663,6 +5710,19 @@ public class XFLConverter { } } } + + + if (hasImport) { + domDocument.writeStartElement("folders"); + domDocument.writeStartElement("DOMFolderItem", new String[] { + "name", "imported", + "itemID", generateItemId(lastItemIdNumber), + "isExpanded", "false" + }); + domDocument.writeEndElement(); + domDocument.writeEndElement(); //folders + } + convertFonts(lastItemIdNumber, lastImportedId, characterNameMap, swf, characters, domDocument, statusStack, characterVariables, characterClasses, charactersExportedInFirstFrame, characterImportLinkageURL); Set smallShapes = getSmallShapes(swf); @@ -6114,12 +6174,17 @@ public class XFLConverter { } final String outfileF = zipfile; + final boolean fHasImport = hasImport; new RetryTask(() -> { try (ZipOutputStream out = new ZipOutputStream(new FileOutputStream(outfileF))) { out.putNextEntry(new ZipEntry("DOMDocument.xml")); out.write(Utf8Helper.getBytes(domDocumentF)); out.putNextEntry(new ZipEntry("PublishSettings.xml")); out.write(Utf8Helper.getBytes(publishSettingsF)); + out.putNextEntry(new ZipEntry("LIBRARY/")); + if (fHasImport) { + out.putNextEntry(new ZipEntry("LIBRARY/imported/")); + } for (String fileName : files.keySet()) { out.putNextEntry(new ZipEntry("LIBRARY/" + fileName)); out.write(files.get(fileName)); @@ -6141,6 +6206,10 @@ public class XFLConverter { writeFile(handler, Utf8Helper.getBytes(publishSettingsStr), xflDataDir.getAbsolutePath() + File.separator + "PublishSettings.xml"); File libraryDir = new File(xflDataDir.getAbsolutePath() + File.separator + "LIBRARY"); libraryDir.mkdir(); + if (hasImport) { + File importedDir = new File(xflDataDir.getAbsolutePath() + File.separator + "LIBRARY" + File.separator + "imported"); + importedDir.mkdir(); + } File binDir = new File(xflDataDir.getAbsolutePath() + File.separator + "bin"); binDir.mkdir(); for (String fileName : files.keySet()) { @@ -6302,9 +6371,15 @@ public class XFLConverter { Map characterNameMap, SWF swf ) { - if (det.hasFont) { + if (det.hasFont || det.hasFontClass) { String fontName = null; - FontTag ft = (FontTag) det.getSwf().getCharacter(det.fontId); + FontTag ft = null; + if (det.hasFont) { + ft = (FontTag) det.getSwf().getCharacter(det.fontId); + } + if (det.hasFontClass) { + ft = det.getSwf().getFontByClass(det.fontClass); + } if (ft != null) { DefineFontNameTag fnt = ft.getFontNameTag(); if (fnt != null) { @@ -6329,7 +6404,7 @@ public class XFLConverter { } if (characterImportLinkageURL.containsKey(ft)) { - fontFace = getSymbolName(lastImportedId, characterNameMap, swf, ft, "Font") + "*"; + fontFace = getSymbolName(lastImportedId, characterNameMap, swf, ft, "Font", false) + "*"; } fontFaceStack.push(fontFace); fontSizeStack.push(size); @@ -6459,7 +6534,7 @@ public class XFLConverter { } if (characterImportLinkageURL.containsKey(ft)) { - fontFace = getSymbolName(lastImportedId, characterNameMap, swf, ft, "Font") + "*"; + fontFace = getSymbolName(lastImportedId, characterNameMap, swf, ft, "Font", false) + "*"; } break; } diff --git a/src/com/jpexs/decompiler/flash/gui/MainPanel.java b/src/com/jpexs/decompiler/flash/gui/MainPanel.java index d9f572a4c..5fb3e618a 100644 --- a/src/com/jpexs/decompiler/flash/gui/MainPanel.java +++ b/src/com/jpexs/decompiler/flash/gui/MainPanel.java @@ -426,7 +426,9 @@ public final class MainPanel extends JPanel implements TreeSelectionListener, Se private static final Logger logger = Logger.getLogger(MainPanel.class.getName()); private Map> neededCharacters = new WeakHashMap<>(); + private Map> neededCharacterClasses = new WeakHashMap<>(); private Map> missingNeededCharacters = new WeakHashMap<>(); + private Map> missingNeededCharacterClasses = new WeakHashMap<>(); private CalculateMissingNeededThread calculateMissingNeededThread; @@ -4925,21 +4927,28 @@ public final class MainPanel extends JPanel implements TreeSelectionListener, Se List sel = getAllSelected(); Set needed = new HashSet<>(); + Set neededClasses = new HashSet<>(); for (TreeItem item : sel) { if (item instanceof CharacterTag) { CharacterTag characterTag = (CharacterTag) item; - characterTag.getNeededCharactersDeep(needed); + characterTag.getNeededCharactersDeep(needed, neededClasses); needed.add(characterTag.getCharacterId()); } } List tagsToRemove = new ArrayList<>(); - for (Tag tag : swf.getTags()) { + loopt: for (Tag tag : swf.getTags()) { if (tag instanceof CharacterTag) { CharacterTag characterTag = (CharacterTag) tag; - if (!needed.contains(characterTag.getCharacterId())) { - tagsToRemove.add(tag); + for (String cls : characterTag.getClassNames()) { + if (neededClasses.contains(cls)) { + continue loopt; + } } + if (needed.contains(characterTag.getCharacterId())) { + continue loopt; + } + tagsToRemove.add(tag); } } @@ -6485,13 +6494,20 @@ public final class MainPanel extends JPanel implements TreeSelectionListener, Se tag.getTagInfo(tagInfo); Set needed; + Set neededClasses; + if (neededCharacters.containsKey(treeItem)) { needed = neededCharacters.get(treeItem); + neededClasses = neededCharacterClasses.get(treeItem); } else { needed = new LinkedHashSet<>(); - tag.getNeededCharactersDeep(needed); + neededClasses = new LinkedHashSet<>(); + tag.getNeededCharactersDeep(needed, neededClasses); neededCharacters.put(treeItem, needed); + neededCharacterClasses.put(treeItem, neededClasses); } + + if (needed.size() > 0) { tagInfo.addInfo("general", "neededCharacters", Helper.joinStrings(needed, ", ")); @@ -6826,7 +6842,7 @@ public final class MainPanel extends JPanel implements TreeSelectionListener, Se } } - private static void calculateMissingNeededCharacters(Map> neededMap, Map> missingNeededCharacters, Timelined tim) { + private static void calculateMissingNeededCharacters(Map> neededMap, Map> missingNeededCharacters, Map> missingNeededCharacterClasses, Timelined tim) { List tags = tim.getTags().toArrayList(); Map> nestedTags = new HashMap<>(); for (Tag t : tags) { @@ -6844,7 +6860,8 @@ public final class MainPanel extends JPanel implements TreeSelectionListener, Se characterId = ((CharacterIdTag) t).getCharacterId(); } Set needed = new LinkedHashSet<>(); - t.getNeededCharactersDeep(needed); + Set neededClasses = new LinkedHashSet<>(); + t.getNeededCharactersDeep(needed, neededClasses); neededMap.put(t, needed); if ((t instanceof CharacterIdTag) && !(t instanceof PlaceObjectTypeTag)) { needed = new HashSet<>(); @@ -6853,15 +6870,21 @@ public final class MainPanel extends JPanel implements TreeSelectionListener, Se if ((t instanceof PlaceObjectTypeTag) && (characterId != -1) && nestedTags.containsKey(characterId)) { for (CharacterIdTag n : nestedTags.get(characterId)) { - ((Tag) n).getNeededCharactersDeep(needed); + ((Tag) n).getNeededCharactersDeep(needed, neededClasses); } } - missingNeededCharacters.put(t, t.getMissingNeededCharacters(needed)); + Set resultNeeded = new LinkedHashSet<>(); + Set resultNeededClasses = new LinkedHashSet<>(); + t.getMissingNeededCharacters(needed, neededClasses, resultNeeded, resultNeededClasses); + + missingNeededCharacters.put(t, resultNeeded); + missingNeededCharacterClasses.put(t, resultNeededClasses); if (characterId != -1 && tim.getTimeline().swf.getCharacter(characterId) == null) { missingNeededCharacters.get(t).add(characterId); } - + + //FIXME: missingNeededCharacterClasses ?? } /*if (t instanceof DefineSpriteTag) { calculateMissingNeededCharacters(neededMap, missingNeededCharacters, (DefineSpriteTag) t); @@ -6871,19 +6894,21 @@ public final class MainPanel extends JPanel implements TreeSelectionListener, Se private void calculateMissingNeededCharacters() { Map> missingNeededCharacters = new WeakHashMap<>(); + Map> missingNeededCharacterClasses = new WeakHashMap<>(); Map> neededCharacters = new WeakHashMap<>(); List swfsLists = new ArrayList<>(openables); for (OpenableList swfList : swfsLists) { for (Openable openable : swfList) { if (openable instanceof SWF) { - calculateMissingNeededCharacters(neededCharacters, missingNeededCharacters, (SWF) openable); + calculateMissingNeededCharacters(neededCharacters, missingNeededCharacters, missingNeededCharacterClasses, (SWF) openable); //TODO: how about SubSWFs??? } } } this.neededCharacters = neededCharacters; this.missingNeededCharacters = missingNeededCharacters; + tagTree.setMissingNeededCharacters(missingNeededCharacters); tagListTree.setMissingNeededCharacters(missingNeededCharacters); } diff --git a/src/com/jpexs/decompiler/flash/gui/TimelinedMaker.java b/src/com/jpexs/decompiler/flash/gui/TimelinedMaker.java index 4065665f5..d9724a88c 100644 --- a/src/com/jpexs/decompiler/flash/gui/TimelinedMaker.java +++ b/src/com/jpexs/decompiler/flash/gui/TimelinedMaker.java @@ -81,7 +81,9 @@ public class TimelinedMaker { jpegTablesTag = imageTag.getSwf().getJtt(); } Set needed = new LinkedHashSet<>(); - imageTag.getNeededCharacters(needed, swf); + Set neededClasses = new LinkedHashSet<>(); + //TODO: handle classes? + imageTag.getNeededCharacters(needed, neededClasses, swf); List neededCopies = new ArrayList<>(); for (int n : needed) { diff --git a/src/com/jpexs/decompiler/flash/gui/tagtree/TagTreeContextMenu.java b/src/com/jpexs/decompiler/flash/gui/tagtree/TagTreeContextMenu.java index 26c1a733d..6fbf58063 100644 --- a/src/com/jpexs/decompiler/flash/gui/tagtree/TagTreeContextMenu.java +++ b/src/com/jpexs/decompiler/flash/gui/tagtree/TagTreeContextMenu.java @@ -168,8 +168,10 @@ import java.io.OutputStream; import java.lang.reflect.InvocationTargetException; import java.util.ArrayList; import java.util.Arrays; +import java.util.Collections; import java.util.HashMap; import java.util.HashSet; +import java.util.IdentityHashMap; import java.util.LinkedHashSet; import java.util.List; import java.util.Locale; @@ -2609,7 +2611,9 @@ public class TagTreeContextMenu extends JPopupMenu { AlterCharacterTag alterTag = new AlterCharacterTag(targetSwf, targetSameNameCharacter.getCharacterId()); Set needed = new LinkedHashSet<>(); - targetSameNameCharacter.getNeededCharacters(needed, targetSwf); + Set neededClasses = new LinkedHashSet<>(); + //TODO: handle classes? + targetSameNameCharacter.getNeededCharacters(needed, neededClasses, targetSwf); int ind = realTargetTimelined.indexOfTag(targetSameNameCharacter); realTargetTimelined.removeTag(ind); realTargetTimelined.addTag(ind, alterTag); @@ -5066,20 +5070,32 @@ public class TagTreeContextMenu extends JPopupMenu { Set newItems = new LinkedHashSet<>(); for (TreeItem item : items) { Set needed = new LinkedHashSet<>(); + Set neededClasses = new LinkedHashSet<>(); Tag tag = (Tag) item; - tag.getNeededCharactersDeep(needed); + tag.getNeededCharactersDeep(needed, neededClasses); if (tag instanceof CharacterTag) { needed.add(((CharacterTag) tag).getCharacterId()); + for (String cls : ((CharacterTag) tag).getClassNames()) { + neededClasses.add(cls); + } } + + Set neededChars = Collections.newSetFromMap(new IdentityHashMap<>()); for (Integer characterId : needed) { CharacterTag neededTag = sourceSwf.getCharacter(characterId); + neededChars.add(neededTag); + } + for (String cls : neededClasses) { + neededChars.add(sourceSwf.getCharacterByClass(cls)); + } + for (CharacterTag neededTag : neededChars) { newItems.add(neededTag); List mappedClasses = AbstractTagTree.getMappedTagIdsForClass(neededTag.getClass()); ReadOnlyTagList tags = neededTag.getTimelined().getTags(); for (int i = tags.indexOf(neededTag) + 1; i < tags.size(); i++) { if (tags.get(i) instanceof CharacterIdTag) { CharacterIdTag characterIdTag = (CharacterIdTag) tags.get(i); - if (mappedClasses.contains(((Tag) characterIdTag).getId()) && characterIdTag.getCharacterId() == characterId) { + if (mappedClasses.contains(((Tag) characterIdTag).getId()) && characterIdTag.getCharacterId() == neededTag.getCharacterId() && ((Tag) characterIdTag).getSwf() == neededTag.getSwf()) { newItems.add((Tag) characterIdTag); } } @@ -6065,7 +6081,9 @@ public class TagTreeContextMenu extends JPopupMenu { Set dependentCharacters = swf.getDependentCharacters(ch); if (dependentCharacters.isEmpty()) { Set needed = new LinkedHashSet<>(); - ct.getNeededCharacters(needed, swf); + Set neededClasses = new LinkedHashSet<>(); + //TODO: handle classes? + ct.getNeededCharacters(needed, neededClasses, swf); List attachedTags = swf.getCharacterIdTags(ch); for (CharacterIdTag cit : attachedTags) { if (cit instanceof Tag) {