diff --git a/CHANGELOG.md b/CHANGELOG.md index 74523da1a..ce2105a73 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,9 @@ All notable changes to this project will be documented in this file. - [#1485] Improved skins support, night mode - [#1681] AS3 - context menu for adding classes on packages +### Fixed +- [#1687] Slow speed of cyclic tags detection + ## [14.4.0] - 2021-04-05 ### Added - [#1015], [#1466], [#1513] Better error messages during saving, display message on out of memory @@ -2192,6 +2195,7 @@ All notable changes to this project will be documented in this file. [alpha 7]: https://github.com/jindrapetrik/jpexs-decompiler/releases/tag/alpha7 [#1485]: https://www.free-decompiler.com/flash/issues/1485 [#1681]: https://www.free-decompiler.com/flash/issues/1681 +[#1687]: https://www.free-decompiler.com/flash/issues/1687 [#1015]: https://www.free-decompiler.com/flash/issues/1015 [#1466]: https://www.free-decompiler.com/flash/issues/1466 [#1513]: https://www.free-decompiler.com/flash/issues/1513 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 ba0cc8ef5..54fa04d04 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/SWF.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/SWF.java @@ -359,6 +359,8 @@ public final class SWF implements SWFContainerItem, Timelined { @Internal private Map asmsCache; + private Set cyclicCharacters = null; + private static final DecompilerPool decompilerPool = new DecompilerPool(); public static final String AS2_PKG_PREFIX = "__Packages."; @@ -2653,6 +2655,7 @@ public final class SWF implements SWFContainerItem, Timelined { characters = null; characterIdTags = null; timeline = null; + cyclicCharacters = null; clearReadOnlyListCache(); clearImageCache(); clearScriptCache(); @@ -3842,4 +3845,54 @@ public final class SWF implements SWFContainerItem, Timelined { public RECT getRectWithStrokes() { return getRect(); } + + public Set getCyclicCharacters() { + if (cyclicCharacters != null) { + return cyclicCharacters; + } + Set ct = new HashSet<>(); + Map> characterToNeeded = new HashMap<>(); + + for (Tag t : getTags()) { + if (t instanceof CharacterTag) { + CharacterTag cht = (CharacterTag) t; + Set needed = new HashSet<>(); + cht.getNeededCharacters(needed); + characterToNeeded.put(cht.getCharacterId(), needed); + } + } + + for (int chid : characterToNeeded.keySet()) { + for (int n : characterToNeeded.get(chid)) { + if (searchNeeded(characterToNeeded, chid, n, new HashSet<>())) { + ct.add(chid); + } + } + } + + cyclicCharacters = ct; + return cyclicCharacters; + } + + private boolean searchNeeded(Map> characterToNeeded, int searched, int current, Set visited) { + if (visited.contains(current)) { + return false; + } + visited.add(current); + if (current == searched) { + return true; + } + + if (!characterToNeeded.containsKey(current)) { + return false; + } + + for (int n : characterToNeeded.get(current)) { + if (searchNeeded(characterToNeeded, searched, n, visited)) { + return true; + } + } + + return false; + } } 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 e50d8e59e..72b6178da 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 @@ -323,8 +323,7 @@ public class Timeline { } CharacterTag character = swf.getCharacter(characterId); if (character instanceof DefineSpriteTag) { - Stack cyStack = new Stack<>(); - if (isCyclic(timelined, cyStack)) { + if (swf.getCyclicCharacters().contains(characterId)) { fl.characterId = -1; } } @@ -1393,28 +1392,4 @@ public class Timeline { return false; } - - private boolean isCyclic(Timelined tim, Stack walked) { - for (Tag t : tim.getTags()) { - if (t instanceof PlaceObjectTypeTag) { - PlaceObjectTypeTag p = (PlaceObjectTypeTag) t; - int chid = p.getCharacterId(); - if (chid != -1) { - if (walked.contains(chid)) { - return true; - } - CharacterTag character = swf.getCharacter(chid); - if (character instanceof DefineSpriteTag) { - walked.push(chid); - if (isCyclic((DefineSpriteTag) character, walked)) { - walked.pop(); - return true; - } - walked.pop(); - } - } - } - } - return false; - } }