diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/IdentifiersDeobfuscation.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/IdentifiersDeobfuscation.java index 232303cac..a84604f27 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/IdentifiersDeobfuscation.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/IdentifiersDeobfuscation.java @@ -157,10 +157,10 @@ public class IdentifiersDeobfuscation { return sb.toString(); } - public void deobfuscateInstanceNames(boolean as3, HashMap namesMap, RenameType renameType, List tags, Map selected) { + public void deobfuscateInstanceNames(boolean as3, HashMap namesMap, RenameType renameType, Iterable tags, Map selected) { for (Tag t : tags) { if (t instanceof DefineSpriteTag) { - deobfuscateInstanceNames(as3, namesMap, renameType, ((DefineSpriteTag) t).subTags, selected); + deobfuscateInstanceNames(as3, namesMap, renameType, ((DefineSpriteTag) t).getTags(), selected); } if (t instanceof PlaceObjectTypeTag) { PlaceObjectTypeTag po = (PlaceObjectTypeTag) t; diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/ReadOnlyTagList.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/ReadOnlyTagList.java new file mode 100644 index 000000000..00c21dc5c --- /dev/null +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/ReadOnlyTagList.java @@ -0,0 +1,62 @@ +/* + * Copyright (C) 2010-2015 JPEXS, All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3.0 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. + */ +package com.jpexs.decompiler.flash; + +import com.jpexs.decompiler.flash.tags.Tag; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +/** + * + * @author JPEXS + */ +public class ReadOnlyTagList implements Iterable { + + public static final ReadOnlyTagList EMPTY = new ReadOnlyTagList(new ArrayList<>()); + + private final List list; + + public ReadOnlyTagList(List list) { + this.list = list; + } + + @Override + public Iterator iterator() { + return list.iterator(); + } + + public int size() { + return list.size(); + } + + public boolean isEmpty() { + return list.isEmpty(); + } + + public Tag get(int index) { + return list.get(index); + } + + public int indexOf(Tag tag) { + return list.indexOf(tag); + } + + public ArrayList toArrayList() { + return new ArrayList<>(list); + } +} 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 340c6b803..ed8feeada 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/SWF.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/SWF.java @@ -131,6 +131,7 @@ import com.jpexs.decompiler.flash.types.MATRIX; import com.jpexs.decompiler.flash.types.RECT; import com.jpexs.decompiler.flash.types.SHAPE; import com.jpexs.decompiler.flash.types.annotations.Internal; +import com.jpexs.decompiler.flash.types.annotations.SWFField; import com.jpexs.decompiler.flash.types.filters.BlendComposite; import com.jpexs.decompiler.flash.types.filters.FILTER; import com.jpexs.decompiler.flash.xfl.FLAVersion; @@ -207,9 +208,12 @@ public final class SWF implements SWFContainerItem, Timelined { /** * Tags inside of file */ - public List tags = new ArrayList<>(); + @SWFField + private List tags = new ArrayList<>(); @Internal + public ReadOnlyTagList readOnlyTags; + public boolean hasEndTag = true; /** @@ -293,6 +297,9 @@ public final class SWF implements SWFContainerItem, Timelined { private static final Logger logger = Logger.getLogger(SWF.class.getName()); + @Internal + private boolean isModified; + @Internal private Timeline timeline; @@ -346,14 +353,16 @@ public final class SWF implements SWFContainerItem, Timelined { resetTimelines(this); updateCharacters(); - for (Tag tag : tags) { + for (Tag tag : getTags()) { if (tag instanceof DefineSpriteTag) { DefineSpriteTag spriteTag = (DefineSpriteTag) tag; - for (Tag tag1 : spriteTag.subTags) { + for (Tag tag1 : spriteTag.getTags()) { tag1.setSwf(null); } - spriteTag.subTags.clear(); + for (int i = spriteTag.getTags().size() - 1; i >= 0; i--) { + spriteTag.removeTag(i); + } } if (tag instanceof DefineBinaryDataTag) { @@ -401,7 +410,7 @@ public final class SWF implements SWFContainerItem, Timelined { synchronized (this) { if (characters == null) { Map chars = new HashMap<>(); - parseCharacters(tags, chars); + parseCharacters(getTags(), chars); characters = Collections.unmodifiableMap(chars); } } @@ -415,7 +424,7 @@ public final class SWF implements SWFContainerItem, Timelined { synchronized (this) { if (dependentCharacters == null) { Map> dep = new HashMap<>(); - for (Tag tag : tags) { + for (Tag tag : getTags()) { if (tag instanceof CharacterTag) { int characterId = ((CharacterTag) tag).getCharacterId(); Set needed = new HashSet<>(); @@ -529,7 +538,7 @@ public final class SWF implements SWFContainerItem, Timelined { synchronized (this) { if (abcList == null) { ArrayList newAbcList = new ArrayList<>(); - getAbcTags(tags, newAbcList); + getAbcTags(getTags(), newAbcList); abcList = newAbcList; } } @@ -544,7 +553,7 @@ public final class SWF implements SWFContainerItem, Timelined { } public MetadataTag getMetadata() { - for (Tag t : tags) { + for (Tag t : getTags()) { if (t instanceof MetadataTag) { return (MetadataTag) t; } @@ -554,7 +563,7 @@ public final class SWF implements SWFContainerItem, Timelined { } public FileAttributesTag getFileAttributes() { - for (Tag t : tags) { + for (Tag t : getTags()) { if (t instanceof FileAttributesTag) { return (FileAttributesTag) t; } @@ -564,7 +573,7 @@ public final class SWF implements SWFContainerItem, Timelined { } public SetBackgroundColorTag getBackgroundColor() { - for (Tag t : tags) { + for (Tag t : getTags()) { if (t instanceof SetBackgroundColorTag) { return (SetBackgroundColorTag) t; } @@ -574,7 +583,7 @@ public final class SWF implements SWFContainerItem, Timelined { } public EnableTelemetryTag getEnableTelemetry() { - for (Tag t : tags) { + for (Tag t : getTags()) { if (t instanceof EnableTelemetryTag) { return (EnableTelemetryTag) t; } @@ -597,7 +606,7 @@ public final class SWF implements SWFContainerItem, Timelined { if (jtt == null) { synchronized (this) { if (jtt == null) { - for (Tag t : tags) { + for (Tag t : getTags()) { if (t instanceof JPEGTablesTag) { jtt = (JPEGTablesTag) t; break; @@ -611,7 +620,7 @@ public final class SWF implements SWFContainerItem, Timelined { } public String getDocumentClass() { - for (Tag t : tags) { + for (Tag t : getTags()) { if (t instanceof SymbolClassTag) { SymbolClassTag sc = (SymbolClassTag) t; for (int i = 0; i < sc.tags.size(); i++) { @@ -672,7 +681,7 @@ public final class SWF implements SWFContainerItem, Timelined { public void resetTimelines(Timelined timelined) { timelined.resetTimeline(); if (timelined instanceof SWF) { - for (Tag t : ((SWF) timelined).tags) { + for (Tag t : ((SWF) timelined).getTags()) { if (t instanceof Timelined) { resetTimelines((Timelined) t); } @@ -680,7 +689,7 @@ public final class SWF implements SWFContainerItem, Timelined { } } - private void parseCharacters(List list, Map characters) { + private void parseCharacters(Iterable list, Map characters) { for (Tag t : list) { if (t instanceof CharacterTag) { int characterId = ((CharacterTag) t).getCharacterId(); @@ -693,7 +702,7 @@ public final class SWF implements SWFContainerItem, Timelined { } } if (t instanceof DefineSpriteTag) { - parseCharacters(((DefineSpriteTag) t).getSubTags(), characters); + parseCharacters(((DefineSpriteTag) t).getTags(), characters); } } } @@ -717,7 +726,7 @@ public final class SWF implements SWFContainerItem, Timelined { return false; } path.add(sprite.spriteId); - for (Tag t : sprite.subTags) { + for (Tag t : sprite.getTags()) { if (t instanceof DefineSpriteTag) { if (!isSpriteValid((DefineSpriteTag) t, path)) { return false; @@ -751,7 +760,7 @@ public final class SWF implements SWFContainerItem, Timelined { */ public List getTagData(int tagId) { List ret = new ArrayList<>(); - for (Tag tag : tags) { + for (Tag tag : getTags()) { if (tag.getId() == tagId) { ret.add(tag); } @@ -817,7 +826,7 @@ public final class SWF implements SWFContainerItem, Timelined { sos.writeFIXED8(frameRate); sos.writeUI16(frameCount); - sos.writeTags(tags); + sos.writeTags(getTags()); if (hasEndTag) { sos.writeUI16(0); } @@ -940,7 +949,11 @@ public final class SWF implements SWFContainerItem, Timelined { @Override public boolean isModified() { - for (Tag tag : tags) { + if (isModified) { + return true; + } + + for (Tag tag : getTags()) { if (tag.isModified()) { return true; } @@ -948,14 +961,21 @@ public final class SWF implements SWFContainerItem, Timelined { return false; } + @Override + public void setModified(boolean value) { + isModified = value; + } + public void clearModified() { - for (Tag tag : tags) { + for (Tag tag : getTags()) { if (tag.isModified()) { tag.createOriginalData(); tag.setModified(false); } } + isModified = false; + try { uncompressedData = saveToByteArray(); } catch (IOException ex) { @@ -1093,6 +1113,7 @@ public final class SWF implements SWFContainerItem, Timelined { hasEndTag = false; } this.tags = tags; + readOnlyTags = null; if (!checkOnly) { checkInvalidSprites(); updateCharacters(); @@ -1174,10 +1195,10 @@ public final class SWF implements SWFContainerItem, Timelined { return new Date(); } - private static void getAbcTags(List list, List actionScripts) { + private static void getAbcTags(Iterable list, List actionScripts) { for (Tag t : list) { if (t instanceof DefineSpriteTag) { - getAbcTags(((DefineSpriteTag) t).getSubTags(), actionScripts); + getAbcTags(((DefineSpriteTag) t).getTags(), actionScripts); } if (t instanceof ABCContainerTag) { actionScripts.add((ABCContainerTag) t); @@ -1187,7 +1208,7 @@ public final class SWF implements SWFContainerItem, Timelined { public void assignExportNamesToSymbols() { HashMap exportNames = new HashMap<>(); - for (Tag t : tags) { + for (Tag t : getTags()) { if (t instanceof ExportAssetsTag) { ExportAssetsTag eat = (ExportAssetsTag) t; for (int i = 0; i < eat.tags.size(); i++) { @@ -1199,7 +1220,7 @@ public final class SWF implements SWFContainerItem, Timelined { } } } - for (Tag t : tags) { + for (Tag t : getTags()) { if (t instanceof CharacterTag) { CharacterTag ct = (CharacterTag) t; if (exportNames.containsKey(ct.getCharacterId())) { @@ -1211,7 +1232,7 @@ public final class SWF implements SWFContainerItem, Timelined { public void assignClassesToSymbols() { HashMap classes = new HashMap<>(); - for (Tag t : tags) { + for (Tag t : getTags()) { if (t instanceof SymbolClassTag) { SymbolClassTag sct = (SymbolClassTag) t; for (int i = 0; i < sct.tags.size(); i++) { @@ -1221,7 +1242,7 @@ public final class SWF implements SWFContainerItem, Timelined { } } } - for (Tag t : tags) { + for (Tag t : getTags()) { if (t instanceof CharacterTag) { CharacterTag ct = (CharacterTag) t; if (classes.containsKey(ct.getCharacterId())) { @@ -1608,7 +1629,7 @@ public final class SWF implements SWFContainerItem, Timelined { public final void addEventListener(EventListener listener) { listeners.add(listener); - for (Tag t : tags) { + for (Tag t : getTags()) { if (t instanceof ABCContainerTag) { (((ABCContainerTag) t).getABC()).addEventListener(listener); } @@ -1617,7 +1638,7 @@ public final class SWF implements SWFContainerItem, Timelined { public final void removeEventListener(EventListener listener) { listeners.remove(listener); - for (Tag t : tags) { + for (Tag t : getTags()) { if (t instanceof ABCContainerTag) { (((ABCContainerTag) t).getABC()).removeEventListener(listener); } @@ -1630,13 +1651,13 @@ public final class SWF implements SWFContainerItem, Timelined { } } - public static void populateVideoFrames(int streamId, List tags, HashMap output) { + public static void populateVideoFrames(int streamId, Iterable tags, HashMap output) { for (Tag t : tags) { if (t instanceof VideoFrameTag) { output.put(((VideoFrameTag) t).frameNum, (VideoFrameTag) t); } if (t instanceof DefineSpriteTag) { - populateVideoFrames(streamId, ((DefineSpriteTag) t).getSubTags(), output); + populateVideoFrames(streamId, ((DefineSpriteTag) t).getTags(), output); } } } @@ -1907,7 +1928,7 @@ public final class SWF implements SWFContainerItem, Timelined { return ret; } - private void getVariables(List tags, String path, List> variables, HashMap actionsMap, List functions, HashMap strings, HashMap usageTypes) throws InterruptedException { + private void getVariables(Iterable tags, String path, List> variables, HashMap actionsMap, List functions, HashMap strings, HashMap usageTypes) throws InterruptedException { List processed = new ArrayList<>(); for (Tag t : tags) { String subPath = path + "/" + t.toString(); @@ -1921,7 +1942,7 @@ public final class SWF implements SWFContainerItem, Timelined { } } if (t instanceof DefineSpriteTag) { - getVariables(((DefineSpriteTag) t).getSubTags(), path + "/" + t.toString(), variables, actionsMap, functions, strings, usageTypes); + getVariables(((DefineSpriteTag) t).getTags(), path + "/" + t.toString(), variables, actionsMap, functions, strings, usageTypes); } } } @@ -1964,19 +1985,19 @@ public final class SWF implements SWFContainerItem, Timelined { } public int deobfuscateAS3Identifiers(RenameType renameType) { - for (Tag tag : tags) { + for (Tag tag : getTags()) { if (tag instanceof ABCContainerTag) { ((ABCContainerTag) tag).getABC().deobfuscateIdentifiers(deobfuscated, renameType, true); tag.setModified(true); } } - for (Tag tag : tags) { + for (Tag tag : getTags()) { if (tag instanceof ABCContainerTag) { ((ABCContainerTag) tag).getABC().deobfuscateIdentifiers(deobfuscated, renameType, false); tag.setModified(true); } } - for (Tag tag : tags) { + for (Tag tag : getTags()) { if (tag instanceof SymbolClassTag) { SymbolClassTag sc = (SymbolClassTag) tag; for (int i = 0; i < sc.names.size(); i++) { @@ -1988,7 +2009,7 @@ public final class SWF implements SWFContainerItem, Timelined { sc.setModified(true); } } - deobfuscation.deobfuscateInstanceNames(true, deobfuscated, renameType, tags, new HashMap<>()); + deobfuscation.deobfuscateInstanceNames(true, deobfuscated, renameType, getTags(), new HashMap<>()); return deobfuscated.size(); } @@ -2026,7 +2047,7 @@ public final class SWF implements SWFContainerItem, Timelined { HashMap usageTypes = new HashMap<>(); int ret = 0; - getVariables(tags, "", allVariableNames, actionsMap, allFunctions, allStrings, usageTypes); + getVariables(getTags(), "", allVariableNames, actionsMap, allFunctions, allStrings, usageTypes); informListeners("rename", ""); int fc = 0; for (MyEntry it : allVariableNames) { @@ -2036,13 +2057,13 @@ public final class SWF implements SWFContainerItem, Timelined { informListeners("rename", "classes"); int classCount = 0; - for (Tag t : tags) { + for (Tag t : getTags()) { if (t instanceof DoInitActionTag) { classCount++; } } int cnt = 0; - for (Tag t : tags) { + for (Tag t : getTags()) { if (t instanceof DoInitActionTag) { cnt++; informListeners("rename", "class " + cnt + "/" + classCount); @@ -2252,7 +2273,7 @@ public final class SWF implements SWFContainerItem, Timelined { src.setModified(); } - deobfuscation.deobfuscateInstanceNames(false, deobfuscated, renameType, tags, selected); + deobfuscation.deobfuscateInstanceNames(false, deobfuscated, renameType, getTags(), selected); return ret; } @@ -2303,7 +2324,7 @@ public final class SWF implements SWFContainerItem, Timelined { public void clearImageCache() { frameCache.clear(); rectCache.clear(); - for (Tag tag : tags) { + for (Tag tag : getTags()) { if (tag instanceof ImageTag) { ((ImageTag) tag).clearCache(); } @@ -2317,10 +2338,20 @@ public final class SWF implements SWFContainerItem, Timelined { IdentifiersDeobfuscation.clearCache(); } + public void clearReadOnlyListCache() { + readOnlyTags = null; + for (Tag tag : tags) { + if (tag instanceof DefineSpriteTag) { + ((DefineSpriteTag) tag).clearReadOnlyListCache(); + } + } + } + public void clearAllCache() { characters = null; abcList = null; timeline = null; + clearReadOnlyListCache(); clearImageCache(); clearScriptCache(); Cache.clearAll(); @@ -2876,13 +2907,15 @@ public final class SWF implements SWFContainerItem, Timelined { private void removeTagWithDependenciesFromTimeline(Tag toRemove, Timeline timeline) { Map stage = new HashMap<>(); Set dependingChars = new HashSet<>(); + Timelined timelined = timeline.timelined; + ReadOnlyTagList tags = timelined.getTags(); if (toRemove instanceof CharacterTag) { int characterId = ((CharacterTag) toRemove).getCharacterId(); if (characterId != 0) { dependingChars.add(characterId); - for (int i = 0; i < timeline.tags.size(); i++) { - Tag t = timeline.tags.get(i); + for (int i = 0; i < tags.size(); i++) { + Tag t = tags.get(i); if (t instanceof CharacterIdTag) { CharacterIdTag c = (CharacterIdTag) t; Set needed = new HashSet<>(); @@ -2895,8 +2928,8 @@ public final class SWF implements SWFContainerItem, Timelined { } } - for (int i = 0; i < timeline.tags.size(); i++) { - Tag t = timeline.tags.get(i); + for (int i = 0; i < tags.size(); i++) { + Tag t = tags.get(i); if (t instanceof RemoveTag) { RemoveTag rt = (RemoveTag) t; int depth = rt.getDepth(); @@ -2904,7 +2937,7 @@ public final class SWF implements SWFContainerItem, Timelined { int currentCharId = stage.get(depth); stage.remove(depth); if (dependingChars.contains(currentCharId)) { - timeline.tags.remove(i); + timelined.removeTag(i); i--; continue; } @@ -2917,7 +2950,7 @@ public final class SWF implements SWFContainerItem, Timelined { if (placeCharId != 0) { stage.put(depth, placeCharId); if (dependingChars.contains(placeCharId)) { - timeline.tags.remove(i); + timelined.removeTag(i); i--; continue; } @@ -2926,7 +2959,7 @@ public final class SWF implements SWFContainerItem, Timelined { if (t instanceof CharacterIdTag) { CharacterIdTag c = (CharacterIdTag) t; if (dependingChars.contains(c.getCharacterId())) { - timeline.tags.remove(i); + timelined.removeTag(i); i--; continue; } @@ -2935,13 +2968,13 @@ public final class SWF implements SWFContainerItem, Timelined { t.getNeededCharacters(needed); for (int dep : dependingChars) { if (needed.contains(dep)) { - timeline.tags.remove(i); + timelined.removeTag(i); i--; //continue; } } if (t == toRemove) { - timeline.tags.remove(i); + timelined.removeTag(i); i--; continue; } @@ -2958,10 +2991,12 @@ public final class SWF implements SWFContainerItem, Timelined { characterId = ((CharacterTag) toRemove).getCharacterId(); modified = timeline.removeCharacter(characterId); } - for (int i = 0; i < timeline.tags.size(); i++) { - Tag t = timeline.tags.get(i); + Timelined timelined = timeline.timelined; + ReadOnlyTagList tags = timelined.getTags(); + for (int i = 0; i < tags.size(); i++) { + Tag t = tags.get(i); if (t == toRemove) { - timeline.tags.remove(t); + timelined.removeTag(t); i--; continue; } @@ -3002,6 +3037,16 @@ public final class SWF implements SWFContainerItem, Timelined { clearImageCache(); } + public void removeTag(int index) { + setModified(true); + tags.remove(index); + } + + public void removeTag(Tag tag) { + setModified(true); + tags.remove(tag); + } + public void removeTag(Tag tag, boolean removeDependencies) { Timelined timelined = tag.getTimelined(); removeTagInternal(timelined, tag, removeDependencies); @@ -3012,39 +3057,75 @@ public final class SWF implements SWFContainerItem, Timelined { private void removeTagInternal(Timelined timelined, Tag tag, boolean removeDependencies) { if (tag instanceof ShowFrameTag || ShowFrameTag.isNestedTagType(tag.getId())) { - List tags; - if (timelined instanceof DefineSpriteTag) { - DefineSpriteTag sprite = (DefineSpriteTag) timelined; - tags = sprite.getSubTags(); - } else { - tags = this.tags; - } - tags.remove(tag); - if (timelined instanceof DefineSpriteTag) { - DefineSpriteTag sprite = (DefineSpriteTag) timelined; - sprite.setModified(true); - } + timelined.removeTag(tag); + timelined.setModified(true); timelined.resetTimeline(); } else { // timeline should be always the swf here if (removeDependencies) { removeTagWithDependenciesFromTimeline(tag, timelined.getTimeline()); - if (timelined instanceof DefineSpriteTag) { - DefineSpriteTag sprite = (DefineSpriteTag) timelined; - sprite.setModified(true); - } + timelined.setModified(true); } else { - removeTagFromTimeline(tag, timelined.getTimeline()); + boolean modified = removeTagFromTimeline(tag, timelined.getTimeline()); + if (modified) { + timelined.setModified(true); + } } } } + @Override + public ReadOnlyTagList getTags() { + if (readOnlyTags == null) { + readOnlyTags = new ReadOnlyTagList(tags); + } + + return readOnlyTags; + } + + /** + * Adds a tag to the SWF + * + * @param tag + */ + @Override + public void addTag(Tag tag) { + setModified(true); + tags.add(tag); + } + + /** + * Adds a tag to the SWF + * + * @param index + * @param tag + */ + @Override + public void addTag(int index, Tag tag) { + setModified(true); + tags.add(index, tag); + } + + /** + * Replaces a tag in the SWF + * + * @param oldTag + * @param newTag + */ + public void replaceTag(Tag oldTag, Tag newTag) { + setModified(true); + int index = tags.indexOf(oldTag); + if (index != -1) { + tags.set(index, newTag); + } + } + /** * Adds a tag to the SWF * If targetTreeItem is: * - Frame: adds the tag to the Frame. Frame can be a frame of the main * timeline or a DefineSprite frame - * - DefineSprite: adds the tag to the and of the DefineSprite's tag list + * - DefineSprite: adds the tag to the end of the DefineSprite's tag list * - Any other tag in the SWF: adds the new tag exactly before the specified * tag * - Other: adds the tag to the end of the SWF's tag list @@ -3064,13 +3145,7 @@ public final class SWF implements SWFContainerItem, Timelined { tag.setTimelined(timelined); - List tags; - if (timelined instanceof DefineSpriteTag) { - DefineSpriteTag sprite = (DefineSpriteTag) timelined; - tags = sprite.subTags; - } else { - tags = swf.tags; - } + ReadOnlyTagList tags = timelined.getTags(); int index; if (frame != null) { @@ -3082,11 +3157,11 @@ public final class SWF implements SWFContainerItem, Timelined { } else if (timelined instanceof DefineSpriteTag) { index = -1; } else if (targetTreeItem instanceof Tag) { - if (tag instanceof CharacterIdTag && targetTreeItem instanceof CharacterTag) { + if (tag instanceof CharacterIdTag && !(tag instanceof CharacterTag) && targetTreeItem instanceof CharacterTag) { ((CharacterIdTag) tag).setCharacterId(((CharacterTag) targetTreeItem).getCharacterId()); } - index = tags.indexOf(targetTreeItem); // todo: honfika: why not index + 1? + index = tags.indexOf((Tag) targetTreeItem); // todo: honfika: why not index + 1? } else { index = -1; if (tag instanceof CharacterTag) { @@ -3101,9 +3176,9 @@ public final class SWF implements SWFContainerItem, Timelined { } if (index > -1) { - tags.add(index, tag); + timelined.addTag(index, tag); } else { - tags.add(tag); + timelined.addTag(tag); } timelined.resetTimeline(); @@ -3147,7 +3222,7 @@ public final class SWF implements SWFContainerItem, Timelined { int maxId = Math.max(tags.size(), getNextCharacterId()); int id = maxId; // first set the chatacter ids to surely not used ids - for (Tag tag : tags) { + for (Tag tag : getTags()) { if (tag instanceof CharacterTag) { CharacterTag characterTag = (CharacterTag) tag; replaceCharacter(characterTag.getCharacterId(), id++); @@ -3155,7 +3230,7 @@ public final class SWF implements SWFContainerItem, Timelined { } // then set them to 1,2,3... id = 1; - for (Tag tag : tags) { + for (Tag tag : getTags()) { if (tag instanceof CharacterTag) { CharacterTag characterTag = (CharacterTag) tag; replaceCharacter(characterTag.getCharacterId(), id++); @@ -3165,7 +3240,7 @@ public final class SWF implements SWFContainerItem, Timelined { public boolean replaceCharacter(int oldCharacterId, int newCharacterId) { boolean modified = false; - for (Tag tag : tags) { + for (Tag tag : getTags()) { boolean modified2 = false; if (tag instanceof CharacterIdTag) { CharacterIdTag characterIdTag = (CharacterIdTag) tag; @@ -3343,7 +3418,7 @@ public final class SWF implements SWFContainerItem, Timelined { * @return the tag or null if not found */ public DebugIDTag getDebugId() { - for (Tag t : tags) { + for (Tag t : getTags()) { if (t instanceof DebugIDTag) { return (DebugIDTag) t; } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/SWFInputStream.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/SWFInputStream.java index 460ffce4b..a314cd201 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/SWFInputStream.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/SWFInputStream.java @@ -1081,7 +1081,7 @@ public class SWFInputStream implements AutoCloseable { // out.println(Utils.formatHex((int)tag.getPos(), 8) + ": " + Utils.indent(level, "") + Utils.format(tag.toString(), 25 - 2*level) + " tagId="+tag.getId()+" len="+tag.getOrigDataLength()+": "+Utils.bytesToHexString(64, tag.getData(version), 0)); if (tag instanceof DefineSpriteTag) { int i = 0; - for (Tag subTag : ((DefineSpriteTag) tag).getSubTags()) { + for (Tag subTag : ((DefineSpriteTag) tag).getTags()) { dumpTag(out, subTag, i++, level + 1); } } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/SWFOutputStream.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/SWFOutputStream.java index c91d9e83f..41c084ce3 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/SWFOutputStream.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/SWFOutputStream.java @@ -506,7 +506,7 @@ public class SWFOutputStream extends OutputStream { * @param tags List of tag values * @throws IOException */ - public void writeTags(List tags) throws IOException { + public void writeTags(Iterable tags) throws IOException { for (Tag tag : tags) { tag.writeTag(this); } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/SWFSearch.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/SWFSearch.java index ef6ee2f9c..c81b599b6 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/SWFSearch.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/SWFSearch.java @@ -93,7 +93,7 @@ public class SWFSearch { SWF swf = noCheck ? new SWF(pmi) : new SWF(pmi, null, null, null, false, true, true); boolean valid = swf.fileSize > 0 && swf.version > 0 - && (!swf.tags.isEmpty() || noCheck) + && (!swf.getTags().isEmpty() || noCheck) && swf.version <= SWF.MAX_VERSION; if (valid) { long limit = pmi.getPos(); diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/BinaryDataExporter.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/BinaryDataExporter.java index 5d6c8adf6..7a5b622af 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/BinaryDataExporter.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/BinaryDataExporter.java @@ -18,6 +18,7 @@ package com.jpexs.decompiler.flash.exporters; import com.jpexs.decompiler.flash.AbortRetryIgnoreHandler; import com.jpexs.decompiler.flash.EventListener; +import com.jpexs.decompiler.flash.ReadOnlyTagList; import com.jpexs.decompiler.flash.RetryTask; import com.jpexs.decompiler.flash.exporters.settings.BinaryDataExportSettings; import com.jpexs.decompiler.flash.tags.DefineBinaryDataTag; @@ -38,7 +39,7 @@ import java.util.List; */ public class BinaryDataExporter { - public List exportBinaryData(AbortRetryIgnoreHandler handler, String outdir, List tags, BinaryDataExportSettings settings, EventListener evl) throws IOException, InterruptedException { + public List exportBinaryData(AbortRetryIgnoreHandler handler, String outdir, ReadOnlyTagList tags, BinaryDataExportSettings settings, EventListener evl) throws IOException, InterruptedException { List ret = new ArrayList<>(); if (tags.isEmpty()) { return ret; diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/FontExporter.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/FontExporter.java index d14c41969..dba60a7b2 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/FontExporter.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/FontExporter.java @@ -23,6 +23,7 @@ import com.google.typography.font.tools.conversion.woff.WoffWriter; import com.jpexs.decompiler.flash.AbortRetryIgnoreHandler; import com.jpexs.decompiler.flash.ApplicationInfo; import com.jpexs.decompiler.flash.EventListener; +import com.jpexs.decompiler.flash.ReadOnlyTagList; import com.jpexs.decompiler.flash.RetryTask; import com.jpexs.decompiler.flash.SWF; import com.jpexs.decompiler.flash.SWFInputStream; @@ -57,7 +58,7 @@ import java.util.logging.Logger; */ public class FontExporter { - public List exportFonts(AbortRetryIgnoreHandler handler, String outdir, List tags, final FontExportSettings settings, EventListener evl) throws IOException, InterruptedException { + public List exportFonts(AbortRetryIgnoreHandler handler, String outdir, ReadOnlyTagList tags, final FontExportSettings settings, EventListener evl) throws IOException, InterruptedException { List ret = new ArrayList<>(); if (tags.isEmpty()) { return ret; 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 101938446..e8f624806 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 @@ -34,6 +34,7 @@ import com.jpexs.decompiler.flash.helpers.BMPFile; import com.jpexs.decompiler.flash.helpers.ImageHelper; import com.jpexs.decompiler.flash.tags.DefineSpriteTag; import com.jpexs.decompiler.flash.tags.SetBackgroundColorTag; +import com.jpexs.decompiler.flash.tags.Tag; import com.jpexs.decompiler.flash.tags.base.CharacterTag; import com.jpexs.decompiler.flash.tags.enums.ImageFormat; import com.jpexs.decompiler.flash.timeline.DepthState; @@ -144,7 +145,7 @@ public class FrameExporter { public List exportFrames(AbortRetryIgnoreHandler handler, String outdir, final SWF swf, int containerId, List frames, final FrameExportSettings settings, final EventListener evl) throws IOException, InterruptedException { final List ret = new ArrayList<>(); - if (swf.tags.isEmpty()) { + if (swf.getTags().isEmpty()) { return ret; } Timeline tim0; @@ -180,7 +181,8 @@ public class FrameExporter { if (settings.mode == FrameExportMode.SVG) { for (int i = 0; i < frames.size(); i++) { if (evl != null) { - evl.handleExportingEvent("frame", i + 1, frames.size(), tim.parentTag == null ? "" : tim.parentTag.getName()); + Tag parentTag = tim.getParentTag(); + evl.handleExportingEvent("frame", i + 1, frames.size(), parentTag == null ? "" : parentTag.getName()); } final int fi = i; @@ -205,7 +207,8 @@ public class FrameExporter { }, handler).run(); if (evl != null) { - evl.handleExportedEvent("frame", i + 1, frames.size(), tim.parentTag == null ? "" : tim.parentTag.getName()); + Tag parentTag = tim.getParentTag(); + evl.handleExportedEvent("frame", i + 1, frames.size(), parentTag == null ? "" : parentTag.getName()); } } @@ -214,7 +217,8 @@ public class FrameExporter { if (settings.mode == FrameExportMode.CANVAS) { if (evl != null) { - evl.handleExportingEvent("canvas", 1, 1, tim.parentTag == null ? "" : tim.parentTag.getName()); + Tag parentTag = tim.getParentTag(); + evl.handleExportingEvent("canvas", 1, 1, parentTag == null ? "" : parentTag.getName()); } final Timeline ftim = tim; @@ -319,7 +323,8 @@ public class FrameExporter { }, handler).run(); if (evl != null) { - evl.handleExportedEvent("canvas", 1, 1, tim.parentTag == null ? "" : tim.parentTag.getName()); + Tag parentTag = tim.getParentTag(); + evl.handleExportedEvent("canvas", 1, 1, parentTag == null ? "" : parentTag.getName()); } return ret; } @@ -346,14 +351,17 @@ public class FrameExporter { return null; } + Tag parentTag = tim.getParentTag(); + String tagName = parentTag == null ? "" : parentTag.getName(); + if (evl != null) { - evl.handleExportingEvent("frame", pos + 1, fframes.size(), tim.parentTag == null ? "" : tim.parentTag.getName()); + evl.handleExportingEvent("frame", pos + 1, fframes.size(), tagName); } BufferedImage result = SWF.frameToImageGet(ftim, fframes.get(pos++), 0, null, 0, ftim.displayRect, new Matrix(), new ColorTransform(), fbackgroundColor, false, settings.zoom).getBufferedImage(); if (evl != null) { - evl.handleExportedEvent("frame", pos, fframes.size(), tim.parentTag == null ? "" : tim.parentTag.getName()); + evl.handleExportedEvent("frame", pos, fframes.size(), tagName); } return result; diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/ImageExporter.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/ImageExporter.java index cb7f0aead..75000719f 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/ImageExporter.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/ImageExporter.java @@ -18,6 +18,7 @@ package com.jpexs.decompiler.flash.exporters; import com.jpexs.decompiler.flash.AbortRetryIgnoreHandler; import com.jpexs.decompiler.flash.EventListener; +import com.jpexs.decompiler.flash.ReadOnlyTagList; import com.jpexs.decompiler.flash.RetryTask; import com.jpexs.decompiler.flash.exporters.modes.ImageExportMode; import com.jpexs.decompiler.flash.exporters.settings.ImageExportSettings; @@ -42,7 +43,7 @@ import java.util.List; */ public class ImageExporter { - public List exportImages(AbortRetryIgnoreHandler handler, String outdir, List tags, ImageExportSettings settings, EventListener evl) throws IOException, InterruptedException { + public List exportImages(AbortRetryIgnoreHandler handler, String outdir, ReadOnlyTagList tags, ImageExportSettings settings, EventListener evl) throws IOException, InterruptedException { List ret = new ArrayList<>(); if (tags.isEmpty()) { return ret; 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 acaa6730f..101b46e74 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 @@ -18,6 +18,7 @@ package com.jpexs.decompiler.flash.exporters; import com.jpexs.decompiler.flash.AbortRetryIgnoreHandler; import com.jpexs.decompiler.flash.EventListener; +import com.jpexs.decompiler.flash.ReadOnlyTagList; import com.jpexs.decompiler.flash.RetryTask; import com.jpexs.decompiler.flash.SWF; import com.jpexs.decompiler.flash.exporters.commonshape.ExportRectangle; @@ -51,7 +52,7 @@ import java.util.Set; public class MorphShapeExporter { //TODO: implement morphshape export. How to handle 65536 frames? - public List exportMorphShapes(AbortRetryIgnoreHandler handler, final String outdir, List tags, final MorphShapeExportSettings settings, EventListener evl) throws IOException, InterruptedException { + public List exportMorphShapes(AbortRetryIgnoreHandler handler, final String outdir, ReadOnlyTagList tags, final MorphShapeExportSettings settings, EventListener evl) throws IOException, InterruptedException { List ret = new ArrayList<>(); if (tags.isEmpty()) { return ret; diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/MovieExporter.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/MovieExporter.java index 01b7c109e..bacbe617a 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/MovieExporter.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/MovieExporter.java @@ -18,6 +18,7 @@ package com.jpexs.decompiler.flash.exporters; import com.jpexs.decompiler.flash.AbortRetryIgnoreHandler; import com.jpexs.decompiler.flash.EventListener; +import com.jpexs.decompiler.flash.ReadOnlyTagList; import com.jpexs.decompiler.flash.RetryTask; import com.jpexs.decompiler.flash.SWF; import com.jpexs.decompiler.flash.SWFInputStream; @@ -49,7 +50,7 @@ import java.util.List; */ public class MovieExporter { - public List exportMovies(AbortRetryIgnoreHandler handler, String outdir, List tags, final MovieExportSettings settings, EventListener evl) throws IOException, InterruptedException { + public List exportMovies(AbortRetryIgnoreHandler handler, String outdir, ReadOnlyTagList tags, final MovieExportSettings settings, EventListener evl) throws IOException, InterruptedException { List ret = new ArrayList<>(); if (tags.isEmpty()) { return ret; @@ -97,7 +98,7 @@ public class MovieExporter { public byte[] exportMovie(DefineVideoStreamTag videoStream, MovieExportMode mode) throws IOException { SWF swf = videoStream.getSwf(); HashMap frames = new HashMap<>(); - SWF.populateVideoFrames(videoStream.characterID, swf.tags, frames); + SWF.populateVideoFrames(videoStream.characterID, swf.getTags(), frames); if (frames.isEmpty()) { return SWFInputStream.BYTE_ARRAY_EMPTY; } 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 2d50093e6..7db211829 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 @@ -18,6 +18,7 @@ package com.jpexs.decompiler.flash.exporters; import com.jpexs.decompiler.flash.AbortRetryIgnoreHandler; import com.jpexs.decompiler.flash.EventListener; +import com.jpexs.decompiler.flash.ReadOnlyTagList; import com.jpexs.decompiler.flash.RetryTask; import com.jpexs.decompiler.flash.SWF; import com.jpexs.decompiler.flash.exporters.commonshape.ExportRectangle; @@ -57,7 +58,7 @@ import java.util.Set; */ public class ShapeExporter { - public List exportShapes(AbortRetryIgnoreHandler handler, final String outdir, List tags, final ShapeExportSettings settings, EventListener evl) throws IOException, InterruptedException { + public List exportShapes(AbortRetryIgnoreHandler handler, final String outdir, ReadOnlyTagList tags, final ShapeExportSettings settings, EventListener evl) throws IOException, InterruptedException { List ret = new ArrayList<>(); if (tags.isEmpty()) { return ret; diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/SoundExporter.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/SoundExporter.java index 59b8450c4..4d6489b51 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/SoundExporter.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/SoundExporter.java @@ -18,6 +18,7 @@ package com.jpexs.decompiler.flash.exporters; import com.jpexs.decompiler.flash.AbortRetryIgnoreHandler; import com.jpexs.decompiler.flash.EventListener; +import com.jpexs.decompiler.flash.ReadOnlyTagList; import com.jpexs.decompiler.flash.RetryTask; import com.jpexs.decompiler.flash.SWF; import com.jpexs.decompiler.flash.SWFInputStream; @@ -52,7 +53,7 @@ import java.util.List; */ public class SoundExporter { - public List exportSounds(AbortRetryIgnoreHandler handler, String outdir, List tags, final SoundExportSettings settings, EventListener evl) throws IOException, InterruptedException { + public List exportSounds(AbortRetryIgnoreHandler handler, String outdir, ReadOnlyTagList tags, final SoundExportSettings settings, EventListener evl) throws IOException, InterruptedException { List ret = new ArrayList<>(); if (tags.isEmpty()) { return ret; diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/SymbolClassExporter.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/SymbolClassExporter.java index 3d2f79c7d..ccdd90f00 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/SymbolClassExporter.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/SymbolClassExporter.java @@ -17,6 +17,7 @@ package com.jpexs.decompiler.flash.exporters; import com.jpexs.decompiler.flash.EventListener; +import com.jpexs.decompiler.flash.ReadOnlyTagList; import com.jpexs.decompiler.flash.tags.ExportAssetsTag; import com.jpexs.decompiler.flash.tags.SymbolClassTag; import com.jpexs.decompiler.flash.tags.Tag; @@ -39,7 +40,7 @@ public class SymbolClassExporter { public static final String SYMBOL_CLASS_EXPORT_FILENAME = "symbols.csv"; - public List exportNames(final String outdir, List tags, EventListener evl) throws IOException { + public List exportNames(final String outdir, ReadOnlyTagList tags, EventListener evl) throws IOException { List ret = new ArrayList<>(); int count = 0; for (Tag t : tags) { diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/TextExporter.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/TextExporter.java index da936ebc2..7e5feb0a8 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/TextExporter.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/TextExporter.java @@ -18,6 +18,7 @@ package com.jpexs.decompiler.flash.exporters; import com.jpexs.decompiler.flash.AbortRetryIgnoreHandler; import com.jpexs.decompiler.flash.EventListener; +import com.jpexs.decompiler.flash.ReadOnlyTagList; import com.jpexs.decompiler.flash.RetryTask; import com.jpexs.decompiler.flash.configuration.Configuration; import com.jpexs.decompiler.flash.exporters.commonshape.ExportRectangle; @@ -48,7 +49,7 @@ public class TextExporter { public static final String TEXT_EXPORT_FILENAME_PLAIN = "textsplain.txt"; - public List exportTexts(AbortRetryIgnoreHandler handler, String outdir, List tags, final TextExportSettings settings, EventListener evl) throws IOException, InterruptedException { + public List exportTexts(AbortRetryIgnoreHandler handler, String outdir, ReadOnlyTagList tags, final TextExportSettings settings, EventListener evl) throws IOException, InterruptedException { List ret = new ArrayList<>(); if (tags.isEmpty()) { return ret; diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/importers/ImageImporter.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/importers/ImageImporter.java index f2b19f54f..61b61f7f6 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/importers/ImageImporter.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/importers/ImageImporter.java @@ -96,7 +96,7 @@ public class ImageImporter extends TagImporter { } imageTag.setModified(true); - swf.tags.set(swf.tags.indexOf(it), imageTag); + swf.replaceTag(it, imageTag); swf.updateCharacters(); return imageTag; } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/importers/ShapeImporter.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/importers/ShapeImporter.java index e5db7d64f..35c03ec4c 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/importers/ShapeImporter.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/importers/ShapeImporter.java @@ -16,6 +16,7 @@ */ package com.jpexs.decompiler.flash.importers; +import com.jpexs.decompiler.flash.ReadOnlyTagList; import com.jpexs.decompiler.flash.SWF; import com.jpexs.decompiler.flash.exporters.ShapeExporter; import com.jpexs.decompiler.flash.exporters.commonshape.Matrix; @@ -95,7 +96,9 @@ public class ShapeImporter { private final Set shownWarnings = new HashSet<>(); - private final SvgColor TRANSPARENT = new SvgColor(new Color(0, true)); + private final Color TRANSPARENT = new Color(0, true); + + private final SvgColor SVG_TRANSPARENT = new SvgColor(TRANSPARENT); private ShapeTag shapeTag; @@ -169,13 +172,7 @@ public class ShapeImporter { throw new Error("Unsupported image type tag."); } - int idx = swf.tags.indexOf(st); - if (idx != -1) { - swf.tags.add(idx, imageTag); - } else { - swf.tags.add(imageTag); - } - + swf.addTag(imageTag, st); swf.updateCharacters(); return imageTag; } @@ -518,7 +515,6 @@ public class ShapeImporter { serz.command = 'Z'; x = startPoint.x; y = startPoint.y; - serz.params = new double[]{x, y}; pathCommands.add(serz); break; case 'L': @@ -821,13 +817,10 @@ public class ShapeImporter { double sqrt2RYHalf = Math.sqrt(2) * ry / 2; double sqrt2Minus1RY = (Math.sqrt(2) - 1) * ry; - Point startPoint = new Point(0, 0); List pathCommands = new ArrayList<>(); PathCommand scr = new PathCommand(); scr.command = 'M'; scr.params = new double[]{cx + rx, cy}; - startPoint.x = cx + rx; - startPoint.y = cy; pathCommands.add(scr); double[] points = new double[]{ @@ -871,16 +864,12 @@ public class ShapeImporter { PathCommand serz = new PathCommand(); serz.command = 'Z'; - serz.params = new double[]{startPoint.x, startPoint.y}; pathCommands.add(serz); processCommands(shapeNum, shapes, pathCommands, transform, style); } private void processRect(int shapeNum, SHAPEWITHSTYLE shapes, Element childElement, Matrix transform, SvgStyle style) { - - Point startPoint = new Point(0, 0); - String attr = childElement.getAttribute("x"); double x = attr.length() > 0 ? Double.parseDouble(attr) : 0; @@ -920,8 +909,6 @@ public class ShapeImporter { scr.command = 'M'; scr.params = new double[]{x + width, y + ry}; pathCommands.add(scr); - startPoint.x = x + width; - startPoint.y = y + ry; double sqrt2RXHalf = Math.sqrt(2) * rx / 2; double sqrt2Minus1RX = (Math.sqrt(2) - 1) * rx; @@ -969,8 +956,6 @@ public class ShapeImporter { PathCommand scr = new PathCommand(); scr.command = 'M'; scr.params = new double[]{x, y}; - startPoint.x = x; - startPoint.y = y; pathCommands.add(scr); double[] points = new double[]{ @@ -990,7 +975,6 @@ public class ShapeImporter { PathCommand serz = new PathCommand(); serz.command = 'Z'; - serz.params = new double[]{startPoint.x, startPoint.y}; pathCommands.add(serz); processCommands(shapeNum, shapes, pathCommands, transform, style); @@ -1036,7 +1020,6 @@ public class ShapeImporter { String data = childElement.getAttribute("points"); char command = 'M'; - Point startPoint = new Point(0, 0); double x0 = 0; double y0 = 0; @@ -1057,7 +1040,6 @@ public class ShapeImporter { scr.params = new double[]{x, y}; pathCommands.add(scr); - startPoint = new Point(x, y); break; case 'L': PathCommand serl = new PathCommand(); @@ -1077,7 +1059,6 @@ public class ShapeImporter { if (close) { PathCommand serz = new PathCommand(); serz.command = 'Z'; - serz.params = new double[]{startPoint.x, startPoint.y}; pathCommands.add(serz); } @@ -1101,13 +1082,13 @@ public class ShapeImporter { SWF swf = new SWF(); DefineShape4Tag st = new DefineShape4Tag(swf); st = (DefineShape4Tag) (new ShapeImporter().importSvg(st, svgDataS)); - swf.tags.add(st); + swf.addTag(st); SerializableImage si = new SerializableImage(800, 600, BufferedImage.TYPE_4BYTE_ABGR); BitmapExporter.export(swf, st.shapes, Color.yellow, si, new Matrix(), new ColorTransform()); List li = new ArrayList<>(); li.add(st); ImageIO.write(si.getBufferedImage(), "PNG", new File(name + ".imported.png")); - new ShapeExporter().exportShapes(null, "./outex/", li, new ShapeExportSettings(ShapeExportMode.SVG, 1), null); + new ShapeExporter().exportShapes(null, "./outex/", new ReadOnlyTagList(li), new ShapeExportSettings(ShapeExportMode.SVG, 1), null); } //Test for SVG @@ -1641,11 +1622,11 @@ public class ShapeImporter { } private Color parseColor(String rgbStr) { - SvgFill fill = parseFill(new HashMap<>(), rgbStr); + SvgFill fill = parseFill(new HashMap<>(), rgbStr, null); return fill.toColor(); } - private SvgFill parseFill(Map idMap, String rgbStr) { + private SvgFill parseFill(Map idMap, String rgbStr, SvgStyle style) { if (rgbStr == null) { return null; } @@ -1653,7 +1634,7 @@ public class ShapeImporter { // named colors from: http://www.w3.org/TR/SVG/types.html#ColorKeywords switch (rgbStr) { case "none": - return TRANSPARENT; + return SVG_TRANSPARENT; case "aliceblue": return new SvgColor(240, 248, 255); case "antiquewhite": @@ -1959,11 +1940,11 @@ public class ShapeImporter { if (e != null) { String tagName = e.getTagName(); if ("linearGradient".equals(tagName)) { - return parseGradient(idMap, e, new SvgStyle()); //? new style + return parseGradient(idMap, e, new SvgStyle(style)); //? new style } if ("radialGradient".equals(tagName)) { - return parseGradient(idMap, e, new SvgStyle()); //? new style + return parseGradient(idMap, e, new SvgStyle(style)); //? new style } if ("pattern".equals(tagName)) { @@ -2168,6 +2149,8 @@ public class ShapeImporter { class SvgStyle implements Cloneable { + public Color color; + public SvgFill fill; public double opacity; @@ -2190,6 +2173,8 @@ public class ShapeImporter { public double strokeMiterLimit; + public SvgStyle parentStyle; + public SvgStyle() { fill = new SvgColor(Color.black); fillOpacity = 1; @@ -2204,6 +2189,11 @@ public class ShapeImporter { strokeMiterLimit = 4; } + public SvgStyle(SvgStyle parentStyle) { + this(); + this.parentStyle = parentStyle; + } + public SvgFill getFillWithOpacity() { if (fill == null) { return null; @@ -2272,15 +2262,26 @@ public class ShapeImporter { } switch (name) { + case "color": { + Color color = parseColor(value); + if (color != null) { + style.color = color == TRANSPARENT ? null : color; + } + } + break; case "fill": { - SvgFill fill = parseFill(idMap, value); + SvgFill fill = parseFill(idMap, value, style); if (fill != null) { - style.fill = fill == TRANSPARENT ? null : fill; + style.fill = fill == SVG_TRANSPARENT ? null : fill; } } break; case "stop-color": { - if ("inherit".equals(value) || "currentColor".equals(value)) { + if ("currentColor".equals(value)) { + if (style.parentStyle != null) { + style.stopColor = style.parentStyle.color; + } + } else if ("inherit".equals(value)) { showWarning(value + "StopColorNotSupported", "The stop color value '" + value + "' is not supported."); } else { style.stopColor = parseColor(value); @@ -2302,9 +2303,9 @@ public class ShapeImporter { } break; case "stroke": { - SvgFill strokeFill = parseFill(idMap, value); + SvgFill strokeFill = parseFill(idMap, value, style); if (strokeFill != null) { - style.strokeFill = strokeFill == TRANSPARENT ? null : strokeFill; + style.strokeFill = strokeFill == SVG_TRANSPARENT ? null : strokeFill; } } break; @@ -2362,7 +2363,7 @@ public class ShapeImporter { SvgStyle result = clone(); String[] styles = new String[]{ - "fill", "fill-opacity", + "color", "fill", "fill-opacity", "stroke", "stroke-width", "stroke-opacity", "stroke-linecap", "stroke-linejoin", "stroke-miterlimit", "opacity", "stop-color", "stop-opacity" }; diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/importers/SwfXmlImporter.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/importers/SwfXmlImporter.java index ef0a0f561..d6593d501 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/importers/SwfXmlImporter.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/importers/SwfXmlImporter.java @@ -142,6 +142,7 @@ public class SwfXmlImporter { DocumentBuilder docBuilder = docFactory.newDocumentBuilder(); Document doc = docBuilder.parse(new InputSource(new StringReader(xml))); processElement(doc.getDocumentElement(), swf, swf, null); + swf.clearAllCache(); } catch (ParserConfigurationException | SAXException ex) { logger.log(Level.SEVERE, null, ex); } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/importers/SymbolClassImporter.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/importers/SymbolClassImporter.java index 0d2fe6ae5..28dd5d26c 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/importers/SymbolClassImporter.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/importers/SymbolClassImporter.java @@ -42,7 +42,7 @@ public class SymbolClassImporter { nameMap.put(characterId, name); } - for (Tag tag : swf.tags) { + for (Tag tag : swf.getTags()) { if (tag instanceof ExportAssetsTag) { ExportAssetsTag eat = (ExportAssetsTag) tag; for (int i = 0; i < eat.tags.size(); i++) { 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 7a97708bb..d8c3543e7 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 @@ -80,12 +80,6 @@ public class DefineButton2Tag extends ButtonTag implements ASMSourceContainer { */ public List actions = new ArrayList<>(); - private Timeline timeline; - - private boolean isSingleFrameInitialized; - - private boolean isSingleFrame; - /** * Constructor * @@ -258,40 +252,7 @@ public class DefineButton2Tag extends ButtonTag implements ASMSourceContainer { } @Override - public boolean isSingleFrame() { - if (!isSingleFrameInitialized) { - initialiteIsSingleFrame(); - } - return isSingleFrame; - } - - private synchronized void initialiteIsSingleFrame() { - if (!isSingleFrameInitialized) { - isSingleFrame = getTimeline().isSingleFrame(); - isSingleFrameInitialized = true; - } - } - - @Override - public Timeline getTimeline() { - if (timeline != null) { - return timeline; - } - - timeline = new Timeline(swf, this, new ArrayList<>(), buttonId, getRect()); - initTimeline(timeline); - return timeline; - } - - @Override - public void resetTimeline() { - if (timeline != null) { - timeline.reset(swf, this, new ArrayList<>(), buttonId, getRect()); - initTimeline(timeline); - } - } - - private void initTimeline(Timeline timeline) { + protected void initTimeline(Timeline timeline) { int maxDepth = 0; Frame frameUp = new Frame(timeline, 0); Frame frameDown = new Frame(timeline, 0); 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 696baf0ed..8d2d0bee6 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 @@ -78,12 +78,6 @@ public class DefineButtonTag extends ButtonTag implements ASMSource { @HideInRawEdit public ByteArrayRange actionBytes; - private Timeline timeline; - - private boolean isSingleFrameInitialized; - - private boolean isSingleFrame; - private String scriptName = "-"; @Override @@ -322,21 +316,6 @@ public class DefineButtonTag extends ButtonTag implements ASMSource { return 1; } - @Override - public boolean isSingleFrame() { - if (!isSingleFrameInitialized) { - initialiteIsSingleFrame(); - } - return isSingleFrame; - } - - private synchronized void initialiteIsSingleFrame() { - if (!isSingleFrameInitialized) { - isSingleFrame = getTimeline().isSingleFrame(); - isSingleFrameInitialized = true; - } - } - @Override public GraphTextWriter getActionSourcePrefix(GraphTextWriter writer) { return writer; @@ -358,27 +337,9 @@ public class DefineButtonTag extends ButtonTag implements ASMSource { } @Override - public Timeline getTimeline() { - if (timeline != null) { - return timeline; - } - - timeline = new Timeline(swf, this, new ArrayList<>(), buttonId, getRect()); - initTimeline(timeline); - return timeline; - } - - @Override - public void resetTimeline() { - if (timeline != null) { - timeline.reset(swf, this, new ArrayList<>(), buttonId, getRect()); - initTimeline(timeline); - } - } - - private void initTimeline(Timeline timeline) { + protected void initTimeline(Timeline timeline) { ColorTransform clrTrans = null; - for (Tag t : swf.tags) { + for (Tag t : swf.getTags()) { if (t instanceof DefineButtonCxformTag) { DefineButtonCxformTag cx = (DefineButtonCxformTag) t; clrTrans = cx.buttonColorTransform; @@ -417,17 +378,23 @@ public class DefineButtonTag extends ButtonTag implements ASMSource { } timeline.addFrame(frameUp); + if (frameOver.layers.isEmpty()) { frameOver = frameUp; } + timeline.addFrame(frameOver); + if (frameDown.layers.isEmpty()) { frameDown = frameOver; } + timeline.addFrame(frameDown); + if (frameHit.layers.isEmpty()) { frameHit = frameUp; } + timeline.addFrame(frameHit); } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineFont2Tag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineFont2Tag.java index ba64d8b1c..8e85b96d9 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineFont2Tag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineFont2Tag.java @@ -466,7 +466,7 @@ public class DefineFont2Tag extends FontTag { } @Override - public String getCharacters(List tags) { + public String getCharacters() { StringBuilder ret = new StringBuilder(); for (int i : codeTable) { ret.append((char) i); diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineFont3Tag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineFont3Tag.java index d9dde1ce2..5847c35ff 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineFont3Tag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineFont3Tag.java @@ -396,12 +396,12 @@ public class DefineFont3Tag extends FontTag { public void addCharacter(char character, Font font) { //Font Align Zones will be removed as adding new character zones is not supported:-( - for (int i = 0; i < swf.tags.size(); i++) { - Tag t = swf.tags.get(i); + for (int i = 0; i < swf.getTags().size(); i++) { + Tag t = swf.getTags().get(i); if (t instanceof DefineFontAlignZonesTag) { DefineFontAlignZonesTag fa = (DefineFontAlignZonesTag) t; if (fa.fontID == fontId) { - swf.tags.remove(i); + swf.removeTag(t); i--; } } @@ -467,7 +467,7 @@ public class DefineFont3Tag extends FontTag { } @Override - public String getCharacters(List tags) { + public String getCharacters() { StringBuilder ret = new StringBuilder(); for (int i : codeTable) { ret.append((char) i); diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineFontTag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineFontTag.java index 6bf46e9bb..412c866c3 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineFontTag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineFontTag.java @@ -139,7 +139,7 @@ public class DefineFontTag extends FontTag { private void ensureFontInfo() { if (fontInfoTag == null) { - for (Tag t : swf.tags) { + for (Tag t : swf.getTags()) { if (t instanceof DefineFontInfoTag) { if (((DefineFontInfoTag) t).fontId == fontId) { fontInfoTag = (DefineFontInfoTag) t; @@ -331,7 +331,7 @@ public class DefineFontTag extends FontTag { } @Override - public String getCharacters(List tags) { + public String getCharacters() { StringBuilder ret = new StringBuilder(); ensureFontInfo(); if (fontInfoTag != null) { 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 b6dff339b..aca45716b 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 @@ -16,6 +16,7 @@ */ package com.jpexs.decompiler.flash.tags; +import com.jpexs.decompiler.flash.ReadOnlyTagList; import com.jpexs.decompiler.flash.SWF; import com.jpexs.decompiler.flash.SWFInputStream; import com.jpexs.decompiler.flash.SWFOutputStream; @@ -33,6 +34,8 @@ import com.jpexs.decompiler.flash.types.BasicType; import com.jpexs.decompiler.flash.types.ColorTransform; import com.jpexs.decompiler.flash.types.MATRIX; import com.jpexs.decompiler.flash.types.RECT; +import com.jpexs.decompiler.flash.types.annotations.Internal; +import com.jpexs.decompiler.flash.types.annotations.SWFField; import com.jpexs.decompiler.flash.types.annotations.SWFType; import com.jpexs.decompiler.flash.types.annotations.SWFVersion; import com.jpexs.helpers.ByteArrayRange; @@ -74,7 +77,11 @@ public class DefineSpriteTag extends CharacterTag implements DrawableTag, Timeli /** * A series of tags */ - public List subTags; + @SWFField + private List subTags; + + @Internal + public ReadOnlyTagList readOnlyTags; public boolean hasEndTag; @@ -121,6 +128,7 @@ public class DefineSpriteTag extends CharacterTag implements DrawableTag, Timeli subTags.remove(subTags.size() - 1); } this.subTags = subTags; + readOnlyTags = null; } /** @@ -133,7 +141,7 @@ public class DefineSpriteTag extends CharacterTag implements DrawableTag, Timeli public void getData(SWFOutputStream sos) throws IOException { sos.writeUI16(spriteId); sos.writeUI16(frameCount); - sos.writeTags(subTags); + sos.writeTags(getTags()); if (hasEndTag) { sos.writeUI16(0); } @@ -142,7 +150,7 @@ public class DefineSpriteTag extends CharacterTag implements DrawableTag, Timeli @Override public Timeline getTimeline() { if (timeline == null) { - timeline = new Timeline(swf, this, subTags, spriteId, getRect()); + timeline = new Timeline(swf, this, spriteId, getRect()); } return timeline; } @@ -150,7 +158,7 @@ public class DefineSpriteTag extends CharacterTag implements DrawableTag, Timeli @Override public void resetTimeline() { if (timeline != null) { - timeline.reset(swf, this, subTags, spriteId, getRect()); + timeline.reset(swf, this, spriteId, getRect()); } } @@ -208,7 +216,7 @@ public class DefineSpriteTag extends CharacterTag implements DrawableTag, Timeli ret = new RECT(Integer.MAX_VALUE, Integer.MIN_VALUE, Integer.MAX_VALUE, Integer.MIN_VALUE); HashMap depthMap = new HashMap<>(); boolean foundSomething = false; - for (Tag t : subTags) { + for (Tag t : getTags()) { MATRIX m = null; int characterId = -1; if (t instanceof PlaceObjectTypeTag) { @@ -268,14 +276,10 @@ public class DefineSpriteTag extends CharacterTag implements DrawableTag, Timeli return ret; } - public List getSubTags() { - return subTags; - } - @Override public void setModified(boolean value) { if (!value) { - for (Tag subTag : subTags) { + for (Tag subTag : getTags()) { subTag.setModified(false); } } @@ -283,17 +287,50 @@ public class DefineSpriteTag extends CharacterTag implements DrawableTag, Timeli super.setModified(value); } + @Override + public ReadOnlyTagList getTags() { + if (readOnlyTags == null) { + readOnlyTags = new ReadOnlyTagList(subTags); + } + + return readOnlyTags; + } + + @Override + public void removeTag(int index) { + setModified(true); + subTags.remove(index); + } + + @Override + public void removeTag(Tag tag) { + setModified(true); + subTags.remove(tag); + } + + @Override + public void addTag(Tag tag) { + setModified(true); + subTags.add(tag); + } + + @Override + public void addTag(int index, Tag tag) { + setModified(true); + subTags.add(index, tag); + } + @Override public void createOriginalData() { super.createOriginalData(); - for (Tag subTag : subTags) { + for (Tag subTag : getTags()) { subTag.createOriginalData(); } } @Override public void getNeededCharacters(Set needed) { - for (Tag t : subTags) { + for (Tag t : getTags()) { if (t instanceof CharacterIdTag) { needed.add(((CharacterIdTag) t).getCharacterId()); } @@ -374,11 +411,15 @@ public class DefineSpriteTag extends CharacterTag implements DrawableTag, Timeli if (super.isModified()) { return true; } - for (Tag t : subTags) { + for (Tag t : getTags()) { if (t.isModified()) { return true; } } return false; } + + public void clearReadOnlyListCache() { + readOnlyTags = null; + } } 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 3d86d4ca4..5ff815b0b 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 @@ -152,7 +152,7 @@ public abstract class Tag implements NeedsCharacters, Exportable, Serializable { if (deep) { if (this instanceof DefineSpriteTag) { DefineSpriteTag sprite = (DefineSpriteTag) this; - for (Tag subTag : sprite.subTags) { + for (Tag subTag : sprite.getTags()) { subTag.setSwf(swf); } } @@ -426,6 +426,10 @@ public abstract class Tag implements NeedsCharacters, Exportable, Serializable { return SWFInputStream.resolveTag(copy, 0, false, true, false); } + public boolean canUndo() { + return originalRange != null && isModified(); + } + public void undo() throws InterruptedException, IOException { byte[] data = getOriginalData(); if (data == null) { //If the tag is newly created in GUI it has no original data @@ -534,8 +538,9 @@ public abstract class Tag implements NeedsCharacters, Exportable, Serializable { } public void setModified(boolean value) { + boolean oldValue = modified; modified = value; - if (value) { + if (value && oldValue != value) { informListeners(); } } @@ -607,7 +612,7 @@ public abstract class Tag implements NeedsCharacters, Exportable, Serializable { } public void getDependentCharacters(Set dependent) { - for (Tag tag : swf.tags) { + for (Tag tag : swf.getTags()) { if (tag instanceof CharacterTag) { Set needed = new HashSet<>(); tag.getNeededCharactersDeep(needed); 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 337e1de16..ee016f941 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 @@ -16,11 +16,13 @@ */ package com.jpexs.decompiler.flash.tags.base; +import com.jpexs.decompiler.flash.ReadOnlyTagList; import com.jpexs.decompiler.flash.SWF; import com.jpexs.decompiler.flash.exporters.commonshape.Matrix; import com.jpexs.decompiler.flash.exporters.commonshape.SVGExporter; import com.jpexs.decompiler.flash.tags.DefineButtonSoundTag; import com.jpexs.decompiler.flash.tags.Tag; +import com.jpexs.decompiler.flash.timeline.Timeline; import com.jpexs.decompiler.flash.timeline.Timelined; import com.jpexs.decompiler.flash.types.BUTTONRECORD; import com.jpexs.decompiler.flash.types.ColorTransform; @@ -47,6 +49,12 @@ public abstract class ButtonTag extends CharacterTag implements DrawableTag, Tim public static int FRAME_HITTEST = 3; + private Timeline timeline; + + private boolean isSingleFrameInitialized; + + private boolean isSingleFrame; + public ButtonTag(SWF swf, int id, String name, ByteArrayRange data) { super(swf, id, name, data); } @@ -81,7 +89,7 @@ public abstract class ButtonTag extends CharacterTag implements DrawableTag, Tim } public DefineButtonSoundTag getSounds() { - for (Tag t : swf.tags) { + for (Tag t : swf.getTags()) { if (t instanceof DefineButtonSoundTag) { DefineButtonSoundTag st = (DefineButtonSoundTag) t; if (st.buttonId == getCharacterId()) { @@ -96,4 +104,61 @@ public abstract class ButtonTag extends CharacterTag implements DrawableTag, Tim public void toHtmlCanvas(StringBuilder result, double unitDivisor) { getTimeline().toHtmlCanvas(result, unitDivisor, Arrays.asList(0)); //TODO: handle states? } + + @Override + public boolean isSingleFrame() { + if (!isSingleFrameInitialized) { + initialiteIsSingleFrame(); + } + return isSingleFrame; + } + + private synchronized void initialiteIsSingleFrame() { + if (!isSingleFrameInitialized) { + isSingleFrame = getTimeline().isSingleFrame(); + isSingleFrameInitialized = true; + } + } + + @Override + public Timeline getTimeline() { + if (timeline != null) { + return timeline; + } + + timeline = new Timeline(swf, this, getCharacterId(), getRect()); + initTimeline(timeline); + return timeline; + } + + @Override + public void resetTimeline() { + if (timeline != null) { + timeline.reset(swf, this, getCharacterId(), getRect()); + initTimeline(timeline); + } + } + + protected abstract void initTimeline(Timeline timeline); + + @Override + public ReadOnlyTagList getTags() { + return ReadOnlyTagList.EMPTY; + } + + @Override + public void removeTag(int index) { + } + + @Override + public void removeTag(Tag tag) { + } + + @Override + public void addTag(Tag tag) { + } + + @Override + public void addTag(int index, Tag tag) { + } } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/base/FontTag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/base/FontTag.java index 8ce597858..fca1cbcfb 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/base/FontTag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/base/FontTag.java @@ -153,7 +153,7 @@ public abstract class FontTag extends CharacterTag implements AloneTag, Drawable return fontStyle; } - public abstract String getCharacters(List tags); + public abstract String getCharacters(); @Override public String getName() { @@ -209,7 +209,7 @@ public abstract class FontTag extends CharacterTag implements AloneTag, Drawable } protected void shiftGlyphIndices(int fontId, int startIndex) { - for (Tag t : swf.tags) { + for (Tag t : swf.getTags()) { List textRecords = null; if (t instanceof StaticTextTag) { textRecords = ((StaticTextTag) t).textRecords; @@ -379,7 +379,7 @@ public abstract class FontTag extends CharacterTag implements AloneTag, Drawable } public DefineFontNameTag getFontNameTag() { - for (Tag t : swf.tags) { + for (Tag t : swf.getTags()) { if (t instanceof DefineFontNameTag) { DefineFontNameTag dfn = (DefineFontNameTag) t; if (dfn.fontId == getFontId()) { diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/gfx/DefineCompactedFont.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/gfx/DefineCompactedFont.java index 6c62cb6db..1db281ab1 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/gfx/DefineCompactedFont.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/gfx/DefineCompactedFont.java @@ -21,7 +21,6 @@ import com.jpexs.decompiler.flash.SWFInputStream; import com.jpexs.decompiler.flash.SWFOutputStream; import com.jpexs.decompiler.flash.helpers.FontHelper; import com.jpexs.decompiler.flash.tags.DefineFont2Tag; -import com.jpexs.decompiler.flash.tags.Tag; import com.jpexs.decompiler.flash.tags.base.FontTag; import com.jpexs.decompiler.flash.types.KERNINGRECORD; import com.jpexs.decompiler.flash.types.LANGCODE; @@ -316,7 +315,7 @@ public final class DefineCompactedFont extends FontTag { } @Override - public String getCharacters(List tags) { + public String getCharacters() { FontType ft = fonts.get(0); StringBuilder ret = new StringBuilder(ft.glyphInfo.size()); for (GlyphInfoType gi : ft.glyphInfo) { 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 12f03bc4d..658d2469b 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 @@ -70,14 +70,10 @@ public class Timeline { public Timelined timelined; - public Tag parentTag; - public int maxDepth; public int fontFrameNum = -1; - public List tags; - private final List frames = new ArrayList<>(); private final Map depthMaxFrame = new HashMap<>(); @@ -135,11 +131,15 @@ public class Timeline { return soundStramBlocks.get(head); } - public void reset(SWF swf) { - reset(swf, null, swf.tags, 0, swf.displayRect); + public Tag getParentTag() { + return timelined instanceof Tag ? (Tag) timelined : null; } - public void reset(SWF swf, Tag parentTag, List tags, int id, RECT displayRect) { + public void reset(SWF swf) { + reset(swf, swf, 0, swf.displayRect); + } + + public void reset(SWF swf, Timelined timelined, int id, RECT displayRect) { initialized = false; frames.clear(); depthMaxFrame.clear(); @@ -152,9 +152,7 @@ public class Timeline { this.swf = swf; this.displayRect = displayRect; this.frameRate = swf.frameRate; - this.timelined = parentTag == null ? swf : (Timelined) parentTag; - this.parentTag = parentTag; - this.tags = tags; + this.timelined = timelined; as2RootPackage = new AS2Package(null, null, swf); } @@ -207,17 +205,15 @@ public class Timeline { } public Timeline(SWF swf) { - this(swf, null, swf.tags, 0, swf.displayRect); + this(swf, swf, 0, swf.displayRect); } - public Timeline(SWF swf, Tag parentTag, List tags, int id, RECT displayRect) { + public Timeline(SWF swf, Timelined timelined, int id, RECT displayRect) { this.id = id; this.swf = swf; this.displayRect = displayRect; this.frameRate = swf.frameRate; - this.timelined = parentTag == null ? swf : (Timelined) parentTag; - this.parentTag = parentTag; - this.tags = tags; + this.timelined = timelined; as2RootPackage = new AS2Package(null, null, swf); } @@ -226,7 +222,7 @@ public class Timeline { Frame frame = new Frame(this, frameIdx++); frame.layersChanged = true; boolean newFrameNeeded = false; - for (Tag t : tags) { + for (Tag t : timelined.getTags()) { boolean isNested = ShowFrameTag.isNestedTagType(t.getId()); if (isNested) { newFrameNeeded = true; @@ -348,9 +344,9 @@ public class Timeline { calculateMaxDepthFrames(); createASPackages(); - if (parentTag == null) { + if (timelined instanceof SWF) { // popuplate only for main timeline - populateSoundStreamBlocks(0, tags); + populateSoundStreamBlocks(0, timelined.getTags()); } initialized = true; @@ -433,7 +429,7 @@ public class Timeline { } } - private void populateSoundStreamBlocks(int containerId, List tags) { + private void populateSoundStreamBlocks(int containerId, Iterable tags) { List blocks = null; for (Tag t : tags) { if (t instanceof SoundStreamHeadTypeTag) { @@ -446,7 +442,7 @@ public class Timeline { if (t instanceof DefineSpriteTag) { DefineSpriteTag sprite = (DefineSpriteTag) t; - populateSoundStreamBlocks(sprite.getCharacterId(), sprite.getSubTags()); + populateSoundStreamBlocks(sprite.getCharacterId(), sprite.getTags()); } if (blocks == null) { @@ -487,8 +483,8 @@ public class Timeline { public boolean replaceCharacter(int oldCharacterId, int newCharacterId) { boolean modified = false; - for (int i = 0; i < tags.size(); i++) { - Tag t = tags.get(i); + for (int i = 0; i < timelined.getTags().size(); i++) { + Tag t = timelined.getTags().get(i); if (t instanceof CharacterIdTag && ((CharacterIdTag) t).getCharacterId() == oldCharacterId) { ((CharacterIdTag) t).setCharacterId(newCharacterId); ((Tag) t).setModified(true); @@ -500,10 +496,10 @@ public class Timeline { public boolean removeCharacter(int characterId) { boolean modified = false; - for (int i = 0; i < tags.size(); i++) { - Tag t = tags.get(i); + for (int i = 0; i < timelined.getTags().size(); i++) { + Tag t = timelined.getTags().get(i); if (t instanceof CharacterIdTag && ((CharacterIdTag) t).getCharacterId() == characterId) { - tags.remove(i); + timelined.removeTag(i); i--; modified = true; } @@ -726,7 +722,7 @@ public class Timeline { public boolean equals(Object obj) { if (obj instanceof Timeline) { Timeline timelineObj = (Timeline) obj; - return timelined.equals(timelineObj.timelined) && parentTag == timelineObj.parentTag; + return timelined.equals(timelineObj.timelined); } return false; diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/timeline/Timelined.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/timeline/Timelined.java index d6ac774ff..ba5059b76 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/timeline/Timelined.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/timeline/Timelined.java @@ -16,6 +16,8 @@ */ package com.jpexs.decompiler.flash.timeline; +import com.jpexs.decompiler.flash.ReadOnlyTagList; +import com.jpexs.decompiler.flash.tags.Tag; import com.jpexs.decompiler.flash.tags.base.BoundedTag; /** @@ -27,4 +29,16 @@ public interface Timelined extends BoundedTag { public Timeline getTimeline(); public void resetTimeline(); + + public void setModified(boolean value); + + public ReadOnlyTagList getTags(); + + public void removeTag(int index); + + public void removeTag(Tag tag); + + public void addTag(Tag tag); + + public void addTag(int index, Tag tag); } 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 aa14ade00..f818a9700 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 @@ -17,6 +17,7 @@ package com.jpexs.decompiler.flash.xfl; import com.jpexs.decompiler.flash.AbortRetryIgnoreHandler; +import com.jpexs.decompiler.flash.ReadOnlyTagList; import com.jpexs.decompiler.flash.RetryTask; import com.jpexs.decompiler.flash.SWF; import com.jpexs.decompiler.flash.SWFCompression; @@ -216,8 +217,8 @@ public class XFLConverter { + "" - + "" - + ""); + + "" + + ""); } private static void convertLineStyle(HashMap characters, LINESTYLE2 ls, int shapeNum, StringBuilder ret) { @@ -759,7 +760,7 @@ public class XFLConverter { return layers; } - private static int getLayerCount(List tags) { + private static int getLayerCount(ReadOnlyTagList tags) { int maxDepth = 0; for (Tag t : tags) { if (t instanceof PlaceObjectTypeTag) { @@ -776,11 +777,11 @@ public class XFLConverter { return maxDepth; } - private static void walkShapeUsages(List timeLineTags, HashMap characters, HashMap usages) { + private static void walkShapeUsages(ReadOnlyTagList timeLineTags, HashMap characters, HashMap usages) { for (Tag t : timeLineTags) { if (t instanceof DefineSpriteTag) { DefineSpriteTag sprite = (DefineSpriteTag) t; - walkShapeUsages(sprite.subTags, characters, usages); + walkShapeUsages(sprite.getTags(), characters, usages); } if (t instanceof PlaceObjectTypeTag) { PlaceObjectTypeTag po = (PlaceObjectTypeTag) t; @@ -811,7 +812,7 @@ public class XFLConverter { } } - private static List getNonLibraryShapes(List tags, HashMap characters) { + private static List getNonLibraryShapes(ReadOnlyTagList tags, HashMap characters) { HashMap usages = new HashMap<>(); walkShapeUsages(tags, characters, usages); List ret = new ArrayList<>(); @@ -829,7 +830,7 @@ public class XFLConverter { return ret; } - private static HashMap getCharacters(List tags) { + private static HashMap getCharacters(ReadOnlyTagList tags) { HashMap ret = new HashMap<>(); int maxId = 0; for (Tag t : tags) { @@ -1029,7 +1030,7 @@ public class XFLConverter { } } - private static String convertSymbolInstance(String name, MATRIX matrix, ColorTransform colorTransform, boolean cacheAsBitmap, int blendMode, List filters, boolean isVisible, RGBA backgroundColor, CLIPACTIONS clipActions, CharacterTag tag, HashMap characters, List tags, FLAVersion flaVersion) { + private static String convertSymbolInstance(String name, MATRIX matrix, ColorTransform colorTransform, boolean cacheAsBitmap, int blendMode, List filters, boolean isVisible, RGBA backgroundColor, CLIPACTIONS clipActions, CharacterTag tag, HashMap characters, ReadOnlyTagList tags, FLAVersion flaVersion) { StringBuilder ret = new StringBuilder(); if (matrix == null) { matrix = new MATRIX(); @@ -1167,7 +1168,7 @@ public class XFLConverter { return date.getTime() / 1000; } - private static void convertLibrary(SWF swf, Map characterVariables, Map characterClasses, List nonLibraryShapes, String backgroundColor, List tags, HashMap characters, HashMap files, HashMap datfiles, FLAVersion flaVersion, StringBuilder ret) { + private static void convertLibrary(SWF swf, Map characterVariables, Map characterClasses, List nonLibraryShapes, String backgroundColor, ReadOnlyTagList tags, HashMap characters, HashMap files, HashMap datfiles, FLAVersion flaVersion, StringBuilder ret) { //TODO: Imported assets //linkageImportForRS="true" linkageIdentifier="xxx" linkageURL="yyy.swf" @@ -1303,10 +1304,10 @@ public class XFLConverter { symbolStr.append(""); } else if (symbol instanceof DefineSpriteTag) { DefineSpriteTag sprite = (DefineSpriteTag) symbol; - if (sprite.subTags.isEmpty()) { //probably AS2 class + if (sprite.getTags().isEmpty()) { //probably AS2 class continue; } - symbolStr.append(convertTimeline(sprite.spriteId, nonLibraryShapes, backgroundColor, tags, sprite.getSubTags(), characters, "Symbol " + symbol.getCharacterId(), flaVersion, files)); + symbolStr.append(convertTimeline(sprite.spriteId, nonLibraryShapes, backgroundColor, tags, sprite.getTags(), characters, "Symbol " + symbol.getCharacterId(), flaVersion, files)); } else if (symbol instanceof ShapeTag) { itemIcon = "1"; ShapeTag shape = (ShapeTag) symbol; @@ -1632,7 +1633,7 @@ public class XFLConverter { } } - private static void convertFrame(boolean shapeTween, HashMap characters, List tags, SoundStreamHeadTypeTag soundStreamHead, StartSoundTag startSound, int frame, int duration, String actionScript, String elements, HashMap files, StringBuilder ret) { + private static void convertFrame(boolean shapeTween, HashMap characters, ReadOnlyTagList tags, SoundStreamHeadTypeTag soundStreamHead, StartSoundTag startSound, int frame, int duration, String actionScript, String elements, HashMap files, StringBuilder ret) { DefineSoundTag sound = null; if (startSound != null) { for (Tag t : tags) { @@ -1759,7 +1760,7 @@ public class XFLConverter { return ret.toString(); } - private static void convertFrames(String prevStr, String afterStr, List nonLibraryShapes, List tags, List timelineTags, HashMap characters, int depth, FLAVersion flaVersion, HashMap files, StringBuilder ret) { + private static void convertFrames(String prevStr, String afterStr, List nonLibraryShapes, ReadOnlyTagList tags, ReadOnlyTagList timelineTags, HashMap characters, int depth, FLAVersion flaVersion, HashMap files, StringBuilder ret) { StringBuilder ret2 = new StringBuilder(); prevStr += ""; int frame = -1; @@ -1785,7 +1786,7 @@ public class XFLConverter { MorphShapeTag shapeTweener = null; //Add ShowFrameTag to the end when there is one last missing - List timTags = new ArrayList<>(timelineTags); + List timTags = timelineTags.toArrayList(); boolean needsFrameAdd = false; SWF swf = null; for (int i = timTags.size() - 1; i >= 0; i--) { @@ -1933,7 +1934,7 @@ public class XFLConverter { } } - private static void convertFonts(List tags, StringBuilder ret) { + private static void convertFonts(ReadOnlyTagList tags, StringBuilder ret) { StringBuilder ret2 = new StringBuilder(); for (Tag t : tags) { if (t instanceof FontTag) { @@ -1960,7 +1961,7 @@ public class XFLConverter { } String embedRanges = ""; - String fontChars = font.getCharacters(tags); + String fontChars = font.getCharacters(); if ("".equals(fontChars)) { continue; } @@ -2003,7 +2004,7 @@ public class XFLConverter { } } - private static String convertActionScriptLayer(int spriteId, List tags, List timeLineTags, String backgroundColor) { + private static String convertActionScriptLayer(int spriteId, ReadOnlyTagList tags, ReadOnlyTagList timeLineTags, String backgroundColor) { StringBuilder ret = new StringBuilder(); String script = ""; @@ -2065,7 +2066,7 @@ public class XFLConverter { return retStr; } - private static String convertLabelsLayer(int spriteId, List tags, List timeLineTags, String backgroundColor) { + private static String convertLabelsLayer(int spriteId, ReadOnlyTagList tags, ReadOnlyTagList timeLineTags, String backgroundColor) { StringBuilder ret = new StringBuilder(); int duration = 0; int frame = 0; @@ -2121,7 +2122,7 @@ public class XFLConverter { return retStr; } - private static void convertSoundLayer(int layerIndex, String backgroundColor, HashMap characters, List tags, List timeLineTags, HashMap files, StringBuilder ret) { + private static void convertSoundLayer(int layerIndex, String backgroundColor, HashMap characters, ReadOnlyTagList tags, ReadOnlyTagList timeLineTags, HashMap files, StringBuilder ret) { StringBuilder ret2 = new StringBuilder(); StartSoundTag lastStartSound = null; SoundStreamHeadTypeTag lastSoundStreamHead = null; @@ -2179,7 +2180,7 @@ public class XFLConverter { if (ret2.length() > 0) { ret.append("" + "").append(ret2).append("" - + ""); + + ""); } } @@ -2193,7 +2194,7 @@ public class XFLConverter { return outlineColor.toHexRGB(); } - private static String convertTimeline(int spriteId, List nonLibraryShapes, String backgroundColor, List tags, List timelineTags, HashMap characters, String name, FLAVersion flaVersion, HashMap files) { + private static String convertTimeline(int spriteId, List nonLibraryShapes, String backgroundColor, ReadOnlyTagList tags, ReadOnlyTagList timelineTags, HashMap characters, String name, FLAVersion flaVersion, HashMap files) { StringBuilder ret = new StringBuilder(); ret.append(""); ret.append(""); @@ -2292,7 +2293,7 @@ public class XFLConverter { }, handler).run(); } - private static Map getCharacterClasses(List tags) { + private static Map getCharacterClasses(ReadOnlyTagList tags) { Map ret = new HashMap<>(); for (Tag t : tags) { if (t instanceof SymbolClassTag) { @@ -2307,7 +2308,7 @@ public class XFLConverter { return ret; } - private static Map getCharacterVariables(List tags) { + private static Map getCharacterVariables(ReadOnlyTagList tags) { Map ret = new HashMap<>(); for (Tag t : tags) { if (t instanceof ExportAssetsTag) { @@ -2337,7 +2338,7 @@ public class XFLConverter { } SWF swf = tag.getSwf(); - for (Tag t : swf.tags) { + for (Tag t : swf.getTags()) { if (t instanceof CSMTextSettingsTag) { CSMTextSettingsTag c = (CSMTextSettingsTag) t; if (c.textID == tag.getCharacterId()) { @@ -2427,7 +2428,7 @@ public class XFLConverter { fontName = null; textHeight = rec.textHeight; font = swf.getFont(fontId); - for (Tag t : swf.tags) { + for (Tag t : swf.getTags()) { if (t instanceof DefineFontNameTag) { if (((DefineFontNameTag) t).fontId == fontId) { fontName = ((DefineFontNameTag) t).fontName; @@ -2552,7 +2553,7 @@ public class XFLConverter { } if (det.html) { - ret.append(convertHTMLText(swf.tags, det, txt)); + ret.append(convertHTMLText(swf.getTags(), det, txt)); } else { ret.append(""); ret.append("").append(xmlString(txt)).append(""); @@ -2571,7 +2572,7 @@ public class XFLConverter { } if (det.hasFont) { String fontName = null; - for (Tag u : swf.tags) { + for (Tag u : swf.getTags()) { if (u instanceof DefineFontNameTag) { if (((DefineFontNameTag) u).fontId == det.fontId) { fontName = ((DefineFontNameTag) u).fontName; @@ -2677,10 +2678,10 @@ public class XFLConverter { } final HashMap files = new HashMap<>(); final HashMap datfiles = new HashMap<>(); - HashMap characters = getCharacters(swf.tags); - List nonLibraryShapes = getNonLibraryShapes(swf.tags, characters); - Map characterClasses = getCharacterClasses(swf.tags); - Map characterVariables = getCharacterVariables(swf.tags); + HashMap characters = getCharacters(swf.getTags()); + List nonLibraryShapes = getNonLibraryShapes(swf.getTags(), characters); + Map characterClasses = getCharacterClasses(swf.getTags()); + Map characterVariables = getCharacterVariables(swf.getTags()); String backgroundColor = "#ffffff"; SetBackgroundColorTag setBgColorTag = swf.getBackgroundColor(); @@ -2701,22 +2702,22 @@ public class XFLConverter { domDocument.append(" height=\"").append(doubleToString(height)).append("\""); } domDocument.append(">"); - convertFonts(swf.tags, domDocument); - convertLibrary(swf, characterVariables, characterClasses, nonLibraryShapes, backgroundColor, swf.tags, characters, files, datfiles, flaVersion, domDocument); + convertFonts(swf.getTags(), domDocument); + convertLibrary(swf, characterVariables, characterClasses, nonLibraryShapes, backgroundColor, swf.getTags(), characters, files, datfiles, flaVersion, domDocument); domDocument.append(""); - domDocument.append(convertTimeline(0, nonLibraryShapes, backgroundColor, swf.tags, swf.tags, characters, "Scene 1", flaVersion, files)); + domDocument.append(convertTimeline(0, nonLibraryShapes, backgroundColor, swf.getTags(), swf.getTags(), characters, "Scene 1", flaVersion, files)); domDocument.append(""); domDocument.append(""); String domDocumentStr = prettyFormatXML(domDocument.toString()); - for (Tag t : swf.tags) { + for (Tag t : swf.getTags()) { if (t instanceof DoInitActionTag) { DoInitActionTag dia = (DoInitActionTag) t; int chid = dia.getCharacterId(); if (characters.containsKey(chid)) { if (characters.get(chid) instanceof DefineSpriteTag) { DefineSpriteTag sprite = (DefineSpriteTag) characters.get(chid); - if (sprite.subTags.isEmpty()) { + if (sprite.getTags().isEmpty()) { String data = convertActionScript(dia); String expName = dia.getSwf().getExportName(dia.spriteId); expName = expName != null ? expName : "_unk_"; @@ -3136,7 +3137,7 @@ public class XFLConverter { ret.append(""); } - private static String convertHTMLText(List tags, DefineEditTextTag det, String html) { + private static String convertHTMLText(ReadOnlyTagList tags, DefineEditTextTag det, String html) { HTMLTextParser tparser = new HTMLTextParser(tags, det); XMLReader parser; try { @@ -3190,7 +3191,7 @@ public class XFLConverter { private String alignment = null; - private final List tags; + private final ReadOnlyTagList tags; private boolean bold = false; @@ -3216,7 +3217,7 @@ public class XFLConverter { public void warning(SAXParseException e) throws SAXException { } - public HTMLTextParser(List tags, DefineEditTextTag det) { + public HTMLTextParser(ReadOnlyTagList tags, DefineEditTextTag det) { if (det.hasFont) { String fontName = null; FontTag ft = null; diff --git a/libsrc/ffdec_lib/test/com/jpexs/decompiler/flash/ActionScript2Test.java b/libsrc/ffdec_lib/test/com/jpexs/decompiler/flash/ActionScript2Test.java index 5ca1900b3..f7a698044 100644 --- a/libsrc/ffdec_lib/test/com/jpexs/decompiler/flash/ActionScript2Test.java +++ b/libsrc/ffdec_lib/test/com/jpexs/decompiler/flash/ActionScript2Test.java @@ -66,7 +66,7 @@ public class ActionScript2Test extends ActionScript2TestBase { int f = 0; DoActionTag lastDoa = null; - for (Tag t : swf.tags) { + for (Tag t : swf.getTags()) { if (t instanceof DoActionTag) { lastDoa = (DoActionTag) t; } diff --git a/libsrc/ffdec_lib/test/com/jpexs/decompiler/flash/ActionScript2TestBase.java b/libsrc/ffdec_lib/test/com/jpexs/decompiler/flash/ActionScript2TestBase.java index f1b89e932..93ef04069 100644 --- a/libsrc/ffdec_lib/test/com/jpexs/decompiler/flash/ActionScript2TestBase.java +++ b/libsrc/ffdec_lib/test/com/jpexs/decompiler/flash/ActionScript2TestBase.java @@ -1,16 +1,16 @@ /* * Copyright (C) 2010-2015 JPEXS, All rights reserved. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3.0 of the License, or (at your option) any later version. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library. */ @@ -28,7 +28,7 @@ public class ActionScript2TestBase extends ActionScriptTestBase { protected SWF swf; protected DoActionTag getFirstActionTag() { - for (Tag t : swf.tags) { + for (Tag t : swf.getTags()) { if (t instanceof DoActionTag) { return (DoActionTag) t; } diff --git a/libsrc/ffdec_lib/test/com/jpexs/decompiler/flash/ActionScript3ExecuteTest.java b/libsrc/ffdec_lib/test/com/jpexs/decompiler/flash/ActionScript3ExecuteTest.java index 51b5afdf7..3d0ae677b 100644 --- a/libsrc/ffdec_lib/test/com/jpexs/decompiler/flash/ActionScript3ExecuteTest.java +++ b/libsrc/ffdec_lib/test/com/jpexs/decompiler/flash/ActionScript3ExecuteTest.java @@ -56,7 +56,7 @@ public class ActionScript3ExecuteTest { swf = new SWF(is, false); }*/ DoABC2Tag tag = null; - for (Tag t : swf.tags) { + for (Tag t : swf.getTags()) { if (t instanceof DoABC2Tag) { tag = (DoABC2Tag) t; break; diff --git a/libsrc/ffdec_lib/test/com/jpexs/decompiler/flash/ActionScript3Test.java b/libsrc/ffdec_lib/test/com/jpexs/decompiler/flash/ActionScript3Test.java index cefa59ce3..6d86b2cca 100644 --- a/libsrc/ffdec_lib/test/com/jpexs/decompiler/flash/ActionScript3Test.java +++ b/libsrc/ffdec_lib/test/com/jpexs/decompiler/flash/ActionScript3Test.java @@ -59,7 +59,7 @@ public class ActionScript3Test extends ActionScriptTestBase { //Main.initLogging(false); swf = new SWF(new BufferedInputStream(new FileInputStream("testdata/as3/as3.swf")), false); DoABC2Tag tag = null; - for (Tag t : swf.tags) { + for (Tag t : swf.getTags()) { if (t instanceof DoABC2Tag) { tag = (DoABC2Tag) t; break; diff --git a/libsrc/ffdec_lib/test/com/jpexs/decompiler/flash/RecompileTest.java b/libsrc/ffdec_lib/test/com/jpexs/decompiler/flash/RecompileTest.java index 8ded84fd5..244e36e7a 100644 --- a/libsrc/ffdec_lib/test/com/jpexs/decompiler/flash/RecompileTest.java +++ b/libsrc/ffdec_lib/test/com/jpexs/decompiler/flash/RecompileTest.java @@ -85,7 +85,7 @@ public class RecompileTest extends FileTestBase { try { Configuration.debugCopy.set(false); SWF swf = new SWF(new BufferedInputStream(new FileInputStream(filePath)), false, false); - for (Tag tag : swf.tags) { + for (Tag tag : swf.getTags()) { if (!(tag instanceof TagStub)) { Tag tag2 = tag.cloneTag(); if (tag2 instanceof TagStub) { diff --git a/libsrc/ffdec_lib/test/com/jpexs/decompiler/flash/SwfXmlExportImportTest.java b/libsrc/ffdec_lib/test/com/jpexs/decompiler/flash/SwfXmlExportImportTest.java index 49b286ef7..43b90d6af 100644 --- a/libsrc/ffdec_lib/test/com/jpexs/decompiler/flash/SwfXmlExportImportTest.java +++ b/libsrc/ffdec_lib/test/com/jpexs/decompiler/flash/SwfXmlExportImportTest.java @@ -99,13 +99,13 @@ public class SwfXmlExportImportTest extends FileTestBase { SWF swf2 = new SWF(); new SwfXmlImporter().importSwf(swf2, xml); - if (swf.tags.size() != swf2.tags.size()) { + if (swf.getTags().size() != swf2.getTags().size()) { throw new NotSameException(0); } - for (int i = 0; i < swf.tags.size(); i++) { - Tag oldTag = swf.tags.get(i); - Tag newTag = swf2.tags.get(i); + for (int i = 0; i < swf.getTags().size(); i++) { + Tag oldTag = swf.getTags().get(i); + Tag newTag = swf2.getTags().get(i); if (oldTag.getClass() != newTag.getClass()) { throw new NotSameException(0); } @@ -113,12 +113,12 @@ public class SwfXmlExportImportTest extends FileTestBase { if (oldTag instanceof DefineSpriteTag) { DefineSpriteTag oldSprite = (DefineSpriteTag) oldTag; DefineSpriteTag newSprite = (DefineSpriteTag) newTag; - if (oldSprite.subTags.size() != newSprite.subTags.size()) { + if (oldSprite.getTags().size() != newSprite.getTags().size()) { throw new NotSameException(0); } - for (int k = 0; k < oldSprite.subTags.size(); k++) { - compareTags(oldSprite.subTags.get(k), newSprite.subTags.get(k)); + for (int k = 0; k < oldSprite.getTags().size(); k++) { + compareTags(oldSprite.getTags().get(k), newSprite.getTags().get(k)); } } else if (!(oldTag instanceof FontTag)) { compareTags(oldTag, newTag); diff --git a/libsrc/ffdec_lib/test/com/jpexs/decompiler/flash/generators/AS2Generator.java b/libsrc/ffdec_lib/test/com/jpexs/decompiler/flash/generators/AS2Generator.java index 6c9ef9425..a68d0e9fd 100644 --- a/libsrc/ffdec_lib/test/com/jpexs/decompiler/flash/generators/AS2Generator.java +++ b/libsrc/ffdec_lib/test/com/jpexs/decompiler/flash/generators/AS2Generator.java @@ -1,16 +1,16 @@ /* * Copyright (C) 2010-2015 JPEXS, All rights reserved. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3.0 of the License, or (at your option) any later version. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library. */ @@ -45,7 +45,7 @@ public class AS2Generator { DoActionTag doa = null; int frame = 0; StringBuilder s = new StringBuilder(); - for (Tag t : swf.tags) { + for (Tag t : swf.getTags()) { if (t instanceof DoActionTag) { doa = (DoActionTag) t; } diff --git a/libsrc/ffdec_lib/test/com/jpexs/decompiler/flash/generators/AS3Generator.java b/libsrc/ffdec_lib/test/com/jpexs/decompiler/flash/generators/AS3Generator.java index 6bf8efa32..69b0c2731 100644 --- a/libsrc/ffdec_lib/test/com/jpexs/decompiler/flash/generators/AS3Generator.java +++ b/libsrc/ffdec_lib/test/com/jpexs/decompiler/flash/generators/AS3Generator.java @@ -49,7 +49,7 @@ public class AS3Generator { Configuration.autoDeobfuscate.set(false); SWF swf = new SWF(new BufferedInputStream(new FileInputStream("testdata/as3/as3.swf")), false); DoABC2Tag tag = null; - for (Tag t : swf.tags) { + for (Tag t : swf.getTags()) { if (t instanceof DoABC2Tag) { tag = (DoABC2Tag) t; break; diff --git a/src/com/jpexs/decompiler/flash/console/CommandLineArgumentParser.java b/src/com/jpexs/decompiler/flash/console/CommandLineArgumentParser.java index c6b70f13c..9d25db769 100644 --- a/src/com/jpexs/decompiler/flash/console/CommandLineArgumentParser.java +++ b/src/com/jpexs/decompiler/flash/console/CommandLineArgumentParser.java @@ -20,6 +20,7 @@ import com.jpexs.decompiler.flash.AbortRetryIgnoreHandler; import com.jpexs.decompiler.flash.ApplicationInfo; import com.jpexs.decompiler.flash.EventListener; import com.jpexs.decompiler.flash.IdentifiersDeobfuscation; +import com.jpexs.decompiler.flash.ReadOnlyTagList; import com.jpexs.decompiler.flash.SWF; import com.jpexs.decompiler.flash.SWFBundle; import com.jpexs.decompiler.flash.SWFCompression; @@ -1098,7 +1099,7 @@ public class CommandLineArgumentParser { swf.swfList = new SWFList(); swf.swfList.sourceInfo = sourceInfo; boolean found = false; - for (Tag tag : swf.tags) { + for (Tag tag : swf.getTags()) { if (tag.getId() == tagId) { found = true; break; @@ -1140,7 +1141,7 @@ public class CommandLineArgumentParser { swf.swfList = new SWFList(); swf.swfList.sourceInfo = sourceInfo; boolean found = false; - for (Tag tag : swf.tags) { + for (Tag tag : swf.getTags()) { if (tag instanceof JPEGTablesTag) { JPEGTablesTag jtt = (JPEGTablesTag) tag; if (ImageTag.hasErrorHeader(jtt.jpegData)) { @@ -1326,7 +1327,7 @@ public class CommandLineArgumentParser { } List extags = new ArrayList<>(); - for (Tag t : swf.tags) { + for (Tag t : swf.getTags()) { if (t instanceof CharacterIdTag) { CharacterIdTag c = (CharacterIdTag) t; if (selectionIds.contains(c.getCharacterId())) { @@ -1385,37 +1386,37 @@ public class CommandLineArgumentParser { if (exportAll || exportFormats.contains("image")) { System.out.println("Exporting images..."); - new ImageExporter().exportImages(handler, outDir + (multipleExportTypes ? File.separator + ImageExportSettings.EXPORT_FOLDER_NAME : ""), extags, new ImageExportSettings(enumFromStr(formats.get("image"), ImageExportMode.class)), evl); + new ImageExporter().exportImages(handler, outDir + (multipleExportTypes ? File.separator + ImageExportSettings.EXPORT_FOLDER_NAME : ""), new ReadOnlyTagList(extags), new ImageExportSettings(enumFromStr(formats.get("image"), ImageExportMode.class)), evl); } if (exportAll || exportFormats.contains("shape")) { System.out.println("Exporting shapes..."); - new ShapeExporter().exportShapes(handler, outDir + (multipleExportTypes ? File.separator + ShapeExportSettings.EXPORT_FOLDER_NAME : ""), extags, new ShapeExportSettings(enumFromStr(formats.get("shape"), ShapeExportMode.class), zoom), evl); + new ShapeExporter().exportShapes(handler, outDir + (multipleExportTypes ? File.separator + ShapeExportSettings.EXPORT_FOLDER_NAME : ""), new ReadOnlyTagList(extags), new ShapeExportSettings(enumFromStr(formats.get("shape"), ShapeExportMode.class), zoom), evl); } if (exportAll || exportFormats.contains("morphshape")) { System.out.println("Exporting morphshapes..."); - new MorphShapeExporter().exportMorphShapes(handler, outDir + (multipleExportTypes ? File.separator + MorphShapeExportSettings.EXPORT_FOLDER_NAME : ""), extags, new MorphShapeExportSettings(enumFromStr(formats.get("morphshape"), MorphShapeExportMode.class), zoom), evl); + new MorphShapeExporter().exportMorphShapes(handler, outDir + (multipleExportTypes ? File.separator + MorphShapeExportSettings.EXPORT_FOLDER_NAME : ""), new ReadOnlyTagList(extags), new MorphShapeExportSettings(enumFromStr(formats.get("morphshape"), MorphShapeExportMode.class), zoom), evl); } if (exportAll || exportFormats.contains("movie")) { System.out.println("Exporting movies..."); - new MovieExporter().exportMovies(handler, outDir + (multipleExportTypes ? File.separator + MovieExportSettings.EXPORT_FOLDER_NAME : ""), extags, new MovieExportSettings(enumFromStr(formats.get("movie"), MovieExportMode.class)), evl); + new MovieExporter().exportMovies(handler, outDir + (multipleExportTypes ? File.separator + MovieExportSettings.EXPORT_FOLDER_NAME : ""), new ReadOnlyTagList(extags), new MovieExportSettings(enumFromStr(formats.get("movie"), MovieExportMode.class)), evl); } if (exportAll || exportFormats.contains("font")) { System.out.println("Exporting fonts..."); - new FontExporter().exportFonts(handler, outDir + (multipleExportTypes ? File.separator + FontExportSettings.EXPORT_FOLDER_NAME : ""), extags, new FontExportSettings(enumFromStr(formats.get("font"), FontExportMode.class)), evl); + new FontExporter().exportFonts(handler, outDir + (multipleExportTypes ? File.separator + FontExportSettings.EXPORT_FOLDER_NAME : ""), new ReadOnlyTagList(extags), new FontExportSettings(enumFromStr(formats.get("font"), FontExportMode.class)), evl); } if (exportAll || exportFormats.contains("sound")) { System.out.println("Exporting sounds..."); - new SoundExporter().exportSounds(handler, outDir + (multipleExportTypes ? File.separator + SoundExportSettings.EXPORT_FOLDER_NAME : ""), extags, new SoundExportSettings(enumFromStr(formats.get("sound"), SoundExportMode.class)), evl); + new SoundExporter().exportSounds(handler, outDir + (multipleExportTypes ? File.separator + SoundExportSettings.EXPORT_FOLDER_NAME : ""), new ReadOnlyTagList(extags), new SoundExportSettings(enumFromStr(formats.get("sound"), SoundExportMode.class)), evl); } if (exportAll || exportFormats.contains("binarydata")) { System.out.println("Exporting binaryData..."); - new BinaryDataExporter().exportBinaryData(handler, outDir + (multipleExportTypes ? File.separator + BinaryDataExportSettings.EXPORT_FOLDER_NAME : ""), extags, new BinaryDataExportSettings(enumFromStr(formats.get("binarydata"), BinaryDataExportMode.class)), evl); + new BinaryDataExporter().exportBinaryData(handler, outDir + (multipleExportTypes ? File.separator + BinaryDataExportSettings.EXPORT_FOLDER_NAME : ""), new ReadOnlyTagList(extags), new BinaryDataExportSettings(enumFromStr(formats.get("binarydata"), BinaryDataExportMode.class)), evl); } if (exportAll || exportFormats.contains("text")) { @@ -1424,7 +1425,7 @@ public class CommandLineArgumentParser { if (singleTextFile == null) { singleTextFile = Configuration.textExportSingleFile.get(); } - new TextExporter().exportTexts(handler, outDir + (multipleExportTypes ? File.separator + TextExportSettings.EXPORT_FOLDER_NAME : ""), extags, new TextExportSettings(enumFromStr(formats.get("text"), TextExportMode.class), singleTextFile, zoom), evl); + new TextExporter().exportTexts(handler, outDir + (multipleExportTypes ? File.separator + TextExportSettings.EXPORT_FOLDER_NAME : ""), new ReadOnlyTagList(extags), new TextExportSettings(enumFromStr(formats.get("text"), TextExportMode.class), singleTextFile, zoom), evl); } FrameExporter frameExporter = new FrameExporter(); @@ -1883,7 +1884,7 @@ public class CommandLineArgumentParser { SWF swf = new SWF(is, Configuration.parallelSpeedUp.get()); int totalPages = 0; - for (Tag t : swf.tags) { + for (Tag t : swf.getTags()) { if (t instanceof DefineSpriteTag) { DefineSpriteTag ds = (DefineSpriteTag) t; if ("page1".equals(ds.getExportName())) { @@ -1898,7 +1899,7 @@ public class CommandLineArgumentParser { int page = 0; - for (Tag t : swf.tags) { + for (Tag t : swf.getTags()) { if (t instanceof DefineSpriteTag) { DefineSpriteTag ds = (DefineSpriteTag) t; if ("page1".equals(ds.getExportName())) { @@ -2378,8 +2379,8 @@ public class CommandLineArgumentParser { System.err.println("Tag number should be integer"); System.exit(1); } - if (tagNo < 0 || tagNo >= swf.tags.size()) { - System.err.println("Tag number does not exist. Tag number should be between 0 and " + (swf.tags.size() - 1)); + if (tagNo < 0 || tagNo >= swf.getTags().size()) { + System.err.println("Tag number does not exist. Tag number should be between 0 and " + (swf.getTags().size() - 1)); System.exit(1); } @@ -2394,7 +2395,7 @@ public class CommandLineArgumentParser { Collections.sort(tagNumbersToRemove); for (int i = tagNumbersToRemove.size() - 1; i >= 0; i--) { - swf.tags.remove((int) tagNumbersToRemove.get(i)); + swf.removeTag((int) tagNumbersToRemove.get(i)); } try { @@ -2705,7 +2706,7 @@ public class CommandLineArgumentParser { pw.println("height=" + doubleToString(swf.displayRect.getHeight() / SWF.unitDivisor)); pw.println("frameCount=" + swf.frameCount); pw.println("frameRate=" + doubleToString(swf.frameRate)); - for (Tag t : swf.tags) { + for (Tag t : swf.getTags()) { if (t instanceof SetBackgroundColorTag) { pw.println("backgroundColor=" + ((SetBackgroundColorTag) t).backgroundColor.toHexRGB()); } @@ -2717,7 +2718,7 @@ public class CommandLineArgumentParser { pw.println(); pw.println("[tags]"); - pw.println("tagCount=" + swf.tags.size()); + pw.println("tagCount=" + swf.getTags().size()); pw.println("hasEndTag=" + swf.hasEndTag); pw.println("characterCount=" + (swf.getCharacters().size())); pw.println("maxCharacterId=" + (swf.getNextCharacterId() - 1)); diff --git a/src/com/jpexs/decompiler/flash/gui/FontPanel.java b/src/com/jpexs/decompiler/flash/gui/FontPanel.java index 68c00ed4b..718f30f0c 100644 --- a/src/com/jpexs/decompiler/flash/gui/FontPanel.java +++ b/src/com/jpexs/decompiler/flash/gui/FontPanel.java @@ -134,8 +134,7 @@ public class FontPanel extends JPanel { private void fontAddChars(FontTag ft, Set selChars, Font font) { FontTag f = (FontTag) mainPanel.tagTree.getCurrentTreeItem(); - SWF swf = ft.getSwf(); - String oldchars = f.getCharacters(swf.tags); + String oldchars = f.getCharacters(); for (int ic : selChars) { char c = (char) ic; if (oldchars.indexOf((int) c) == -1) { @@ -182,7 +181,8 @@ public class FontPanel extends JPanel { int fontId = ft.getFontId(); if (updateTextsCheckBox.isSelected()) { - for (Tag tag : swf.tags) { + SWF swf = ft.getSwf(); + for (Tag tag : swf.getTags()) { if (tag instanceof TextTag) { TextTag textTag = (TextTag) tag; if (textTag.getFontIds().contains(fontId)) { @@ -208,7 +208,7 @@ public class FontPanel extends JPanel { fontDescentLabel.setText(ft.getDescent() == -1 ? translate("value.unknown") : Integer.toString(ft.getDescent())); fontAscentLabel.setText(ft.getAscent() == -1 ? translate("value.unknown") : Integer.toString(ft.getAscent())); fontLeadingLabel.setText(ft.getLeading() == -1 ? translate("value.unknown") : Integer.toString(ft.getLeading())); - String chars = ft.getCharacters(swf.tags); + String chars = ft.getCharacters(); fontCharactersTextArea.setText(chars); fontCharactersScrollPane.getVerticalScrollBar().scrollRectToVisible(new Rectangle(0, 0, 1, 1)); setAllowSave(false); diff --git a/src/com/jpexs/decompiler/flash/gui/LoadFromMemoryFrame.java b/src/com/jpexs/decompiler/flash/gui/LoadFromMemoryFrame.java index e584f3b5e..7fc6f415d 100644 --- a/src/com/jpexs/decompiler/flash/gui/LoadFromMemoryFrame.java +++ b/src/com/jpexs/decompiler/flash/gui/LoadFromMemoryFrame.java @@ -140,7 +140,7 @@ public class LoadFromMemoryFrame extends AppFrame { long limit = pmi.getPos(); is.seek(0); is = new ReReadableInputStream(new LimitedInputStream(is, limit)); - if (swf.fileSize > 0 && swf.version > 0 && !swf.tags.isEmpty() && swf.version < 25/*Needs to be fixed when SWF versions reaches this value*/) { + if (swf.fileSize > 0 && swf.version > 0 && !swf.getTags().isEmpty() && swf.version < 25/*Needs to be fixed when SWF versions reaches this value*/) { SwfInMemory s = new SwfInMemory(is, swf.version, swf.fileSize, proc); String p = translate("swfitem").replace("%version%", Integer.toString(swf.version)).replace("%size%", Long.toString(swf.fileSize)); publish(s); diff --git a/src/com/jpexs/decompiler/flash/gui/MainPanel.java b/src/com/jpexs/decompiler/flash/gui/MainPanel.java index a27b8ea81..ff4f59846 100644 --- a/src/com/jpexs/decompiler/flash/gui/MainPanel.java +++ b/src/com/jpexs/decompiler/flash/gui/MainPanel.java @@ -19,6 +19,7 @@ package com.jpexs.decompiler.flash.gui; import com.jpexs.decompiler.flash.AbortRetryIgnoreHandler; import com.jpexs.decompiler.flash.ApplicationInfo; import com.jpexs.decompiler.flash.EventListener; +import com.jpexs.decompiler.flash.ReadOnlyTagList; import com.jpexs.decompiler.flash.SWF; import com.jpexs.decompiler.flash.SWFBundle; import com.jpexs.decompiler.flash.SWFSourceInfo; @@ -858,17 +859,20 @@ public final class MainPanel extends JPanel implements TreeSelectionListener, Se return true; } - public boolean closeAll() { - boolean modified = false; + public boolean isModified() { for (SWFList swfList : swfs) { for (SWF swf : swfList) { if (swf.isModified()) { - modified = true; + return true; } } } - if (modified) { + return false; + } + + public boolean closeAll() { + if (isModified()) { boolean closeConfirmResult = closeConfirmation(swfs.size() == 1 ? swfs.get(0) : null); if (!closeConfirmResult) { return false; @@ -1167,47 +1171,47 @@ public final class MainPanel extends JPanel implements TreeSelectionListener, Se EventListener evl = swf.getExportEventListener(); if (export.isOptionEnabled(ImageExportMode.class)) { - ret.addAll(new ImageExporter().exportImages(handler, selFile2 + File.separator + ImageExportSettings.EXPORT_FOLDER_NAME, images, + ret.addAll(new ImageExporter().exportImages(handler, selFile2 + File.separator + ImageExportSettings.EXPORT_FOLDER_NAME, new ReadOnlyTagList(images), new ImageExportSettings(export.getValue(ImageExportMode.class)), evl)); } if (export.isOptionEnabled(ShapeExportMode.class)) { - ret.addAll(new ShapeExporter().exportShapes(handler, selFile2 + File.separator + ShapeExportSettings.EXPORT_FOLDER_NAME, shapes, + ret.addAll(new ShapeExporter().exportShapes(handler, selFile2 + File.separator + ShapeExportSettings.EXPORT_FOLDER_NAME, new ReadOnlyTagList(shapes), new ShapeExportSettings(export.getValue(ShapeExportMode.class), export.getZoom()), evl)); } if (export.isOptionEnabled(MorphShapeExportMode.class)) { - ret.addAll(new MorphShapeExporter().exportMorphShapes(handler, selFile2 + File.separator + MorphShapeExportSettings.EXPORT_FOLDER_NAME, morphshapes, + ret.addAll(new MorphShapeExporter().exportMorphShapes(handler, selFile2 + File.separator + MorphShapeExportSettings.EXPORT_FOLDER_NAME, new ReadOnlyTagList(morphshapes), new MorphShapeExportSettings(export.getValue(MorphShapeExportMode.class), export.getZoom()), evl)); } if (export.isOptionEnabled(TextExportMode.class)) { - ret.addAll(new TextExporter().exportTexts(handler, selFile2 + File.separator + TextExportSettings.EXPORT_FOLDER_NAME, texts, + ret.addAll(new TextExporter().exportTexts(handler, selFile2 + File.separator + TextExportSettings.EXPORT_FOLDER_NAME, new ReadOnlyTagList(texts), new TextExportSettings(export.getValue(TextExportMode.class), Configuration.textExportSingleFile.get(), export.getZoom()), evl)); } if (export.isOptionEnabled(MovieExportMode.class)) { - ret.addAll(new MovieExporter().exportMovies(handler, selFile2 + File.separator + MovieExportSettings.EXPORT_FOLDER_NAME, movies, + ret.addAll(new MovieExporter().exportMovies(handler, selFile2 + File.separator + MovieExportSettings.EXPORT_FOLDER_NAME, new ReadOnlyTagList(movies), new MovieExportSettings(export.getValue(MovieExportMode.class)), evl)); } if (export.isOptionEnabled(SoundExportMode.class)) { - ret.addAll(new SoundExporter().exportSounds(handler, selFile2 + File.separator + SoundExportSettings.EXPORT_FOLDER_NAME, sounds, + ret.addAll(new SoundExporter().exportSounds(handler, selFile2 + File.separator + SoundExportSettings.EXPORT_FOLDER_NAME, new ReadOnlyTagList(sounds), new SoundExportSettings(export.getValue(SoundExportMode.class)), evl)); } if (export.isOptionEnabled(BinaryDataExportMode.class)) { - ret.addAll(new BinaryDataExporter().exportBinaryData(handler, selFile2 + File.separator + BinaryDataExportSettings.EXPORT_FOLDER_NAME, binaryData, + ret.addAll(new BinaryDataExporter().exportBinaryData(handler, selFile2 + File.separator + BinaryDataExportSettings.EXPORT_FOLDER_NAME, new ReadOnlyTagList(binaryData), new BinaryDataExportSettings(export.getValue(BinaryDataExportMode.class)), evl)); } if (export.isOptionEnabled(FontExportMode.class)) { - ret.addAll(new FontExporter().exportFonts(handler, selFile2 + File.separator + FontExportSettings.EXPORT_FOLDER_NAME, fonts, + ret.addAll(new FontExporter().exportFonts(handler, selFile2 + File.separator + FontExportSettings.EXPORT_FOLDER_NAME, new ReadOnlyTagList(fonts), new FontExportSettings(export.getValue(FontExportMode.class)), evl)); } if (export.isOptionEnabled(SymbolClassExportMode.class)) { - ret.addAll(new SymbolClassExporter().exportNames(selFile2, symbolNames, evl)); + ret.addAll(new SymbolClassExporter().exportNames(selFile2, new ReadOnlyTagList(symbolNames), evl)); } FrameExporter frameExporter = new FrameExporter(); @@ -1278,47 +1282,47 @@ public final class MainPanel extends JPanel implements TreeSelectionListener, Se EventListener evl = swf.getExportEventListener(); if (export.isOptionEnabled(ImageExportMode.class)) { - new ImageExporter().exportImages(handler, Path.combine(selFile, ImageExportSettings.EXPORT_FOLDER_NAME), swf.tags, + new ImageExporter().exportImages(handler, Path.combine(selFile, ImageExportSettings.EXPORT_FOLDER_NAME), swf.getTags(), new ImageExportSettings(export.getValue(ImageExportMode.class)), evl); } if (export.isOptionEnabled(ShapeExportMode.class)) { - new ShapeExporter().exportShapes(handler, Path.combine(selFile, ShapeExportSettings.EXPORT_FOLDER_NAME), swf.tags, + new ShapeExporter().exportShapes(handler, Path.combine(selFile, ShapeExportSettings.EXPORT_FOLDER_NAME), swf.getTags(), new ShapeExportSettings(export.getValue(ShapeExportMode.class), export.getZoom()), evl); } if (export.isOptionEnabled(MorphShapeExportMode.class)) { - new MorphShapeExporter().exportMorphShapes(handler, Path.combine(selFile, MorphShapeExportSettings.EXPORT_FOLDER_NAME), swf.tags, + new MorphShapeExporter().exportMorphShapes(handler, Path.combine(selFile, MorphShapeExportSettings.EXPORT_FOLDER_NAME), swf.getTags(), new MorphShapeExportSettings(export.getValue(MorphShapeExportMode.class), export.getZoom()), evl); } if (export.isOptionEnabled(TextExportMode.class)) { - new TextExporter().exportTexts(handler, Path.combine(selFile, TextExportSettings.EXPORT_FOLDER_NAME), swf.tags, + new TextExporter().exportTexts(handler, Path.combine(selFile, TextExportSettings.EXPORT_FOLDER_NAME), swf.getTags(), new TextExportSettings(export.getValue(TextExportMode.class), Configuration.textExportSingleFile.get(), export.getZoom()), evl); } if (export.isOptionEnabled(MovieExportMode.class)) { - new MovieExporter().exportMovies(handler, Path.combine(selFile, MovieExportSettings.EXPORT_FOLDER_NAME), swf.tags, + new MovieExporter().exportMovies(handler, Path.combine(selFile, MovieExportSettings.EXPORT_FOLDER_NAME), swf.getTags(), new MovieExportSettings(export.getValue(MovieExportMode.class)), evl); } if (export.isOptionEnabled(SoundExportMode.class)) { - new SoundExporter().exportSounds(handler, Path.combine(selFile, SoundExportSettings.EXPORT_FOLDER_NAME), swf.tags, + new SoundExporter().exportSounds(handler, Path.combine(selFile, SoundExportSettings.EXPORT_FOLDER_NAME), swf.getTags(), new SoundExportSettings(export.getValue(SoundExportMode.class)), evl); } if (export.isOptionEnabled(BinaryDataExportMode.class)) { - new BinaryDataExporter().exportBinaryData(handler, Path.combine(selFile, BinaryDataExportSettings.EXPORT_FOLDER_NAME), swf.tags, + new BinaryDataExporter().exportBinaryData(handler, Path.combine(selFile, BinaryDataExportSettings.EXPORT_FOLDER_NAME), swf.getTags(), new BinaryDataExportSettings(export.getValue(BinaryDataExportMode.class)), evl); } if (export.isOptionEnabled(FontExportMode.class)) { - new FontExporter().exportFonts(handler, Path.combine(selFile, FontExportSettings.EXPORT_FOLDER_NAME), swf.tags, + new FontExporter().exportFonts(handler, Path.combine(selFile, FontExportSettings.EXPORT_FOLDER_NAME), swf.getTags(), new FontExportSettings(export.getValue(FontExportMode.class)), evl); } if (export.isOptionEnabled(SymbolClassExportMode.class)) { - new SymbolClassExporter().exportNames(selFile, swf.tags, evl); + new SymbolClassExporter().exportNames(selFile, swf.getTags(), evl); } FrameExporter frameExporter = new FrameExporter(); @@ -1366,63 +1370,63 @@ public final class MainPanel extends JPanel implements TreeSelectionListener, Se if (export.isOptionEnabled(ImageExportMode.class)) { for (ImageExportMode exportMode : ImageExportMode.values()) { - new ImageExporter().exportImages(handler, Path.combine(selFile, ImageExportSettings.EXPORT_FOLDER_NAME, exportMode.name()), swf.tags, + new ImageExporter().exportImages(handler, Path.combine(selFile, ImageExportSettings.EXPORT_FOLDER_NAME, exportMode.name()), swf.getTags(), new ImageExportSettings(exportMode), evl); } } if (export.isOptionEnabled(ShapeExportMode.class)) { for (ShapeExportMode exportMode : ShapeExportMode.values()) { - new ShapeExporter().exportShapes(handler, Path.combine(selFile, ShapeExportSettings.EXPORT_FOLDER_NAME, exportMode.name()), swf.tags, + new ShapeExporter().exportShapes(handler, Path.combine(selFile, ShapeExportSettings.EXPORT_FOLDER_NAME, exportMode.name()), swf.getTags(), new ShapeExportSettings(exportMode, export.getZoom()), evl); } } if (export.isOptionEnabled(MorphShapeExportMode.class)) { for (MorphShapeExportMode exportMode : MorphShapeExportMode.values()) { - new MorphShapeExporter().exportMorphShapes(handler, Path.combine(selFile, MorphShapeExportSettings.EXPORT_FOLDER_NAME, exportMode.name()), swf.tags, + new MorphShapeExporter().exportMorphShapes(handler, Path.combine(selFile, MorphShapeExportSettings.EXPORT_FOLDER_NAME, exportMode.name()), swf.getTags(), new MorphShapeExportSettings(exportMode, export.getZoom()), evl); } } if (export.isOptionEnabled(TextExportMode.class)) { for (TextExportMode exportMode : TextExportMode.values()) { - new TextExporter().exportTexts(handler, Path.combine(selFile, TextExportSettings.EXPORT_FOLDER_NAME, exportMode.name()), swf.tags, + new TextExporter().exportTexts(handler, Path.combine(selFile, TextExportSettings.EXPORT_FOLDER_NAME, exportMode.name()), swf.getTags(), new TextExportSettings(exportMode, Configuration.textExportSingleFile.get(), export.getZoom()), evl); } } if (export.isOptionEnabled(MovieExportMode.class)) { for (MovieExportMode exportMode : MovieExportMode.values()) { - new MovieExporter().exportMovies(handler, Path.combine(selFile, MovieExportSettings.EXPORT_FOLDER_NAME, exportMode.name()), swf.tags, + new MovieExporter().exportMovies(handler, Path.combine(selFile, MovieExportSettings.EXPORT_FOLDER_NAME, exportMode.name()), swf.getTags(), new MovieExportSettings(exportMode), evl); } } if (export.isOptionEnabled(SoundExportMode.class)) { for (SoundExportMode exportMode : SoundExportMode.values()) { - new SoundExporter().exportSounds(handler, Path.combine(selFile, SoundExportSettings.EXPORT_FOLDER_NAME, exportMode.name()), swf.tags, + new SoundExporter().exportSounds(handler, Path.combine(selFile, SoundExportSettings.EXPORT_FOLDER_NAME, exportMode.name()), swf.getTags(), new SoundExportSettings(exportMode), evl); } } if (export.isOptionEnabled(BinaryDataExportMode.class)) { for (BinaryDataExportMode exportMode : BinaryDataExportMode.values()) { - new BinaryDataExporter().exportBinaryData(handler, Path.combine(selFile, BinaryDataExportSettings.EXPORT_FOLDER_NAME, exportMode.name()), swf.tags, + new BinaryDataExporter().exportBinaryData(handler, Path.combine(selFile, BinaryDataExportSettings.EXPORT_FOLDER_NAME, exportMode.name()), swf.getTags(), new BinaryDataExportSettings(exportMode), evl); } } if (export.isOptionEnabled(FontExportMode.class)) { for (FontExportMode exportMode : FontExportMode.values()) { - new FontExporter().exportFonts(handler, Path.combine(selFile, FontExportSettings.EXPORT_FOLDER_NAME, exportMode.name()), swf.tags, + new FontExporter().exportFonts(handler, Path.combine(selFile, FontExportSettings.EXPORT_FOLDER_NAME, exportMode.name()), swf.getTags(), new FontExportSettings(exportMode), evl); } } if (export.isOptionEnabled(SymbolClassExportMode.class)) { for (SymbolClassExportMode exportMode : SymbolClassExportMode.values()) { - new SymbolClassExporter().exportNames(selFile, swf.tags, evl); + new SymbolClassExporter().exportNames(selFile, swf.getTags(), evl); } } @@ -1783,7 +1787,7 @@ public final class MainPanel extends JPanel implements TreeSelectionListener, Se pat = Pattern.compile(Pattern.quote(txt), ignoreCase ? (Pattern.CASE_INSENSITIVE | Pattern.UNICODE_CASE) : 0); } List textTags = new ArrayList<>(); - for (Tag tag : swf.tags) { + for (Tag tag : swf.getTags()) { if (tag instanceof TextTag) { textTags.add((TextTag) tag); } @@ -1834,7 +1838,7 @@ public final class MainPanel extends JPanel implements TreeSelectionListener, Se } else { pat = Pattern.compile(Pattern.quote(txt), ignoreCase ? (Pattern.CASE_INSENSITIVE | Pattern.UNICODE_CASE) : 0); } - for (Tag tag : swf.tags) { + for (Tag tag : swf.getTags()) { if (tag instanceof TextTag) { TextTag textTag = (TextTag) tag; if (pat.matcher(textTag.getFormattedText().text).find()) { @@ -2403,7 +2407,7 @@ public final class MainPanel extends JPanel implements TreeSelectionListener, Se return; } - List tags = new ArrayList<>(swf.tags); + List tags = swf.getTags().toArrayList(); List toRemove = new ArrayList<>(); for (Tag tag : tags) { System.out.println(tag.getClass()); @@ -3232,17 +3236,9 @@ public final class MainPanel extends JPanel implements TreeSelectionListener, Se } else if (treeItem instanceof Frame && internalViewer) { Frame fn = (Frame) treeItem; SWF swf = fn.getSwf(); - List controlTags = swf.tags; - int containerId = 0; - RECT rect = swf.displayRect; - int totalFrameCount = swf.frameCount; Timelined timelined = swf; if (fn.timeline.timelined instanceof DefineSpriteTag) { DefineSpriteTag parentSprite = (DefineSpriteTag) fn.timeline.timelined; - controlTags = parentSprite.subTags; - containerId = parentSprite.spriteId; - rect = parentSprite.getRect(); - totalFrameCount = parentSprite.frameCount; timelined = parentSprite; } @@ -3311,35 +3307,35 @@ public final class MainPanel extends JPanel implements TreeSelectionListener, Se SWF swf = item.swf; switch (folderName) { case TagTreeModel.FOLDER_SHAPES: - for (Tag tag : swf.tags) { + for (Tag tag : swf.getTags()) { if (tag instanceof ShapeTag) { folderPreviewItems.add(tag); } } break; case TagTreeModel.FOLDER_MORPHSHAPES: - for (Tag tag : swf.tags) { + for (Tag tag : swf.getTags()) { if (tag instanceof MorphShapeTag) { folderPreviewItems.add(tag); } } break; case TagTreeModel.FOLDER_SPRITES: - for (Tag tag : swf.tags) { + for (Tag tag : swf.getTags()) { if (tag instanceof DefineSpriteTag) { folderPreviewItems.add(tag); } } break; case TagTreeModel.FOLDER_BUTTONS: - for (Tag tag : swf.tags) { + for (Tag tag : swf.getTags()) { if (tag instanceof ButtonTag) { folderPreviewItems.add(tag); } } break; case TagTreeModel.FOLDER_FONTS: - for (Tag tag : swf.tags) { + for (Tag tag : swf.getTags()) { if (tag instanceof FontTag) { folderPreviewItems.add(tag); } @@ -3351,14 +3347,14 @@ public final class MainPanel extends JPanel implements TreeSelectionListener, Se } break; case TagTreeModel.FOLDER_IMAGES: - for (Tag tag : swf.tags) { + for (Tag tag : swf.getTags()) { if (tag instanceof ImageTag) { folderPreviewItems.add(tag); } } break; case TagTreeModel.FOLDER_TEXTS: - for (Tag tag : swf.tags) { + for (Tag tag : swf.getTags()) { if (tag instanceof TextTag) { folderPreviewItems.add(tag); } @@ -3399,7 +3395,7 @@ public final class MainPanel extends JPanel implements TreeSelectionListener, Se @Override public Timeline getTimeline() { if (tim == null) { - Timeline timeline = new Timeline(tag.getSwf(), null, new ArrayList<>(), ((CharacterTag) tag).getCharacterId(), getRect()); + Timeline timeline = new Timeline(tag.getSwf(), this, ((CharacterTag) tag).getCharacterId(), getRect()); initTimeline(timeline); tim = timeline; } @@ -3410,7 +3406,7 @@ public final class MainPanel extends JPanel implements TreeSelectionListener, Se @Override public void resetTimeline() { if (tim != null) { - tim.reset(tag.getSwf(), null, new ArrayList<>(), ((CharacterTag) tag).getCharacterId(), getRect()); + tim.reset(tag.getSwf(), this, ((CharacterTag) tag).getCharacterId(), getRect()); initTimeline(tim); } } @@ -3473,6 +3469,31 @@ public final class MainPanel extends JPanel implements TreeSelectionListener, Se public int hashCode() { return tag.hashCode(); } + + @Override + public void setModified(boolean value) { + } + + @Override + public ReadOnlyTagList getTags() { + return ReadOnlyTagList.EMPTY; + } + + @Override + public void removeTag(int index) { + } + + @Override + public void removeTag(Tag tag) { + } + + @Override + public void addTag(Tag tag) { + } + + @Override + public void addTag(int index, Tag tag) { + } }; } diff --git a/src/com/jpexs/decompiler/flash/gui/PreviewPanel.java b/src/com/jpexs/decompiler/flash/gui/PreviewPanel.java index d3fc51d46..2ea4e1af8 100644 --- a/src/com/jpexs/decompiler/flash/gui/PreviewPanel.java +++ b/src/com/jpexs/decompiler/flash/gui/PreviewPanel.java @@ -624,7 +624,7 @@ public class PreviewPanel extends JPersistentSplitPane implements TagEditorPanel HashMap videoFrames = new HashMap<>(); if (treeItem instanceof DefineVideoStreamTag) { DefineVideoStreamTag vs = (DefineVideoStreamTag) treeItem; - SWF.populateVideoFrames(vs.getCharacterId(), swf.tags, videoFrames); + SWF.populateVideoFrames(vs.getCharacterId(), swf.getTags(), videoFrames); frameCount = videoFrames.size(); } @@ -697,7 +697,7 @@ public class PreviewPanel extends JPersistentSplitPane implements TagEditorPanel Frame fn = (Frame) treeItem; Timelined parent = fn.timeline.timelined; List doneCharacters = new ArrayList<>(); - for (Tag t : fn.timeline.tags) { + for (Tag t : parent.getTags()) { if (t instanceof FileAttributesTag || t instanceof SetBackgroundColorTag) { continue; } @@ -1028,7 +1028,7 @@ public class PreviewPanel extends JPersistentSplitPane implements TagEditorPanel } else if (treeItem instanceof DefineSpriteTag) { DefineSpriteTag s = (DefineSpriteTag) treeItem; Tag lastTag = null; - for (Tag t : s.subTags) { + for (Tag t : s.getTags()) { if (t instanceof EndTag) { break; } else if (t instanceof PlaceObjectTypeTag) { @@ -1042,7 +1042,7 @@ public class PreviewPanel extends JPersistentSplitPane implements TagEditorPanel lastTag = t; } } - if (!s.subTags.isEmpty() && (lastTag != null) && (!(lastTag instanceof ShowFrameTag))) { + if (!s.getTags().isEmpty() && (lastTag != null) && (!(lastTag instanceof ShowFrameTag))) { new ShowFrameTag(swf).writeTag(sos2); } } else { diff --git a/src/com/jpexs/decompiler/flash/gui/debugger/DebuggerTools.java b/src/com/jpexs/decompiler/flash/gui/debugger/DebuggerTools.java index 16b9128a5..26bdf832a 100644 --- a/src/com/jpexs/decompiler/flash/gui/debugger/DebuggerTools.java +++ b/src/com/jpexs/decompiler/flash/gui/debugger/DebuggerTools.java @@ -129,7 +129,7 @@ public class DebuggerTools { ScriptPack found = getDebuggerScriptPack(swf); if (found != null) { ABCContainerTag tag = found.abc.parentTag; - swf.tags.remove((Tag) tag); + swf.removeTag((Tag) tag); swf.getAbcList().remove(tag); //Change all debugger calls to normal trace / Loader @@ -188,7 +188,7 @@ public class DebuggerTools { } //Add to target SWF ((Tag) ds).setSwf(swf); - swf.tags.add(swf.tags.indexOf(firstAbc), (Tag) ds); + swf.addTag((Tag) ds, (Tag) firstAbc); swf.getAbcList().add(swf.getAbcList().indexOf(firstAbc), ds); ((Tag) ds).setModified(true); } diff --git a/src/com/jpexs/decompiler/flash/gui/tagtree/TagTreeContextMenu.java b/src/com/jpexs/decompiler/flash/gui/tagtree/TagTreeContextMenu.java index b57a4521e..8e515f9f6 100644 --- a/src/com/jpexs/decompiler/flash/gui/tagtree/TagTreeContextMenu.java +++ b/src/com/jpexs/decompiler/flash/gui/tagtree/TagTreeContextMenu.java @@ -478,9 +478,9 @@ public class TagTreeContextMenu extends JPopupMenu { SWF sourceSwf = items.get(0).getSwf(); for (TreeItem item : items) { Tag tag = (Tag) item; - sourceSwf.tags.remove(tag); + sourceSwf.removeTag(tag); tag.setSwf(targetSwf, true); - targetSwf.tags.add(tag); + targetSwf.addTag(tag); chechUniqueCharacterId(tag); targetSwf.updateCharacters(); tag.setModified(true); @@ -505,7 +505,7 @@ public class TagTreeContextMenu extends JPopupMenu { Tag tag = (Tag) item; Tag copyTag = tag.cloneTag(); copyTag.setSwf(targetSwf, true); - targetSwf.tags.add(copyTag); + targetSwf.addTag(copyTag); chechUniqueCharacterId(copyTag); targetSwf.updateCharacters(); copyTag.setModified(true); @@ -546,7 +546,7 @@ public class TagTreeContextMenu extends JPopupMenu { if (!copiedTags.contains(neededTag)) { copyTag = neededTag.cloneTag(); copyTag.setSwf(targetSwf, true); - targetSwf.tags.add(copyTag); + targetSwf.addTag(copyTag); int oldCharacterId = neededTag.getCharacterId(); int newCharacterId = chechUniqueCharacterId(copyTag); changedCharacterIds.put(oldCharacterId, newCharacterId); @@ -561,7 +561,7 @@ public class TagTreeContextMenu extends JPopupMenu { copyTag = tag.cloneTag(); copyTag.setSwf(targetSwf, true); - targetSwf.tags.add(copyTag); + targetSwf.addTag(copyTag); if (tag instanceof CharacterTag) { CharacterTag characterTag = (CharacterTag) copyTag; int oldCharacterId = characterTag.getCharacterId(); diff --git a/src/com/jpexs/decompiler/flash/gui/tagtree/TagTreeModel.java b/src/com/jpexs/decompiler/flash/gui/tagtree/TagTreeModel.java index 0a9a08954..39579fc48 100644 --- a/src/com/jpexs/decompiler/flash/gui/tagtree/TagTreeModel.java +++ b/src/com/jpexs/decompiler/flash/gui/tagtree/TagTreeModel.java @@ -172,7 +172,7 @@ public class TagTreeModel implements TreeModel { private List getSoundStreams(DefineSpriteTag sprite) { List ret = new ArrayList<>(); - for (Tag t : sprite.subTags) { + for (Tag t : sprite.getTags()) { if (t instanceof SoundStreamHeadTypeTag) { ret.add((SoundStreamHeadTypeTag) t); } @@ -196,7 +196,7 @@ public class TagTreeModel implements TreeModel { List others = new ArrayList<>(); List emptyFolders = new ArrayList<>(); Map> mappedTags = new HashMap<>(); - for (Tag t : swf.tags) { + for (Tag t : swf.getTags()) { TreeNodeType ttype = TagTree.getTreeNodeType(t); switch (ttype) { case SHAPE: diff --git a/test/com/jpexs/decompiler/flash/gui/AdobeFlashExecutor.java b/test/com/jpexs/decompiler/flash/gui/AdobeFlashExecutor.java index 629f3194d..c82aabe35 100644 --- a/test/com/jpexs/decompiler/flash/gui/AdobeFlashExecutor.java +++ b/test/com/jpexs/decompiler/flash/gui/AdobeFlashExecutor.java @@ -152,7 +152,6 @@ public class AdobeFlashExecutor { Map asms = swf.getASMs(true); ASMSource asm = asms.get("\\frame_1\\DoAction"); - int asmIndex = swf.tags.indexOf(asm); ActionList actionsList = asm.getActions(); FastActionList actions = new FastActionList(actionsList); @@ -173,7 +172,7 @@ public class AdobeFlashExecutor { actions2.add(new ActionReturn()); doaTag.setActions(actions2); - swf.tags.add(asmIndex, doaTag); + swf.addTag(doaTag, asm); i++; } @@ -211,7 +210,7 @@ public class AdobeFlashExecutor { SWF swf = new SWF(new BufferedInputStream(new FileInputStream(runFileAs3)), false); swf.version = SWF.MAX_VERSION; DoABC2Tag abcTag = null; - for (Tag t : swf.tags) { + for (Tag t : swf.getTags()) { if (t instanceof DoABC2Tag) { abcTag = ((DoABC2Tag) t); break;