swf.tags and sprite.subtags are private to avoid modifying the list without setting the isModified flag + some small chages

This commit is contained in:
honfika@gmail.com
2015-12-27 10:19:27 +01:00
parent d62d0fbe1f
commit 16a27789e3
50 changed files with 659 additions and 433 deletions

View File

@@ -157,10 +157,10 @@ public class IdentifiersDeobfuscation {
return sb.toString();
}
public void deobfuscateInstanceNames(boolean as3, HashMap<DottedChain, DottedChain> namesMap, RenameType renameType, List<Tag> tags, Map<DottedChain, DottedChain> selected) {
public void deobfuscateInstanceNames(boolean as3, HashMap<DottedChain, DottedChain> namesMap, RenameType renameType, Iterable<Tag> tags, Map<DottedChain, DottedChain> 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;

View File

@@ -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<Tag> {
public static final ReadOnlyTagList EMPTY = new ReadOnlyTagList(new ArrayList<>());
private final List<Tag> list;
public ReadOnlyTagList(List<Tag> list) {
this.list = list;
}
@Override
public Iterator<Tag> 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<Tag> toArrayList() {
return new ArrayList<>(list);
}
}

View File

@@ -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<Tag> tags = new ArrayList<>();
@SWFField
private List<Tag> 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<Integer, CharacterTag> 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<Integer, Set<Integer>> dep = new HashMap<>();
for (Tag tag : tags) {
for (Tag tag : getTags()) {
if (tag instanceof CharacterTag) {
int characterId = ((CharacterTag) tag).getCharacterId();
Set<Integer> needed = new HashSet<>();
@@ -529,7 +538,7 @@ public final class SWF implements SWFContainerItem, Timelined {
synchronized (this) {
if (abcList == null) {
ArrayList<ABCContainerTag> 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<Tag> list, Map<Integer, CharacterTag> characters) {
private void parseCharacters(Iterable<Tag> list, Map<Integer, CharacterTag> 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<Tag> getTagData(int tagId) {
List<Tag> 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<Tag> list, List<ABCContainerTag> actionScripts) {
private static void getAbcTags(Iterable<Tag> list, List<ABCContainerTag> 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<Integer, String> 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<Integer, String> 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<Tag> tags, HashMap<Integer, VideoFrameTag> output) {
public static void populateVideoFrames(int streamId, Iterable<Tag> tags, HashMap<Integer, VideoFrameTag> 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<Tag> tags, String path, List<MyEntry<DirectValueActionItem, ConstantPool>> variables, HashMap<ASMSource, ActionList> actionsMap, List<GraphSourceItem> functions, HashMap<DirectValueActionItem, ConstantPool> strings, HashMap<DirectValueActionItem, String> usageTypes) throws InterruptedException {
private void getVariables(Iterable<Tag> tags, String path, List<MyEntry<DirectValueActionItem, ConstantPool>> variables, HashMap<ASMSource, ActionList> actionsMap, List<GraphSourceItem> functions, HashMap<DirectValueActionItem, ConstantPool> strings, HashMap<DirectValueActionItem, String> usageTypes) throws InterruptedException {
List<String> 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<DirectValueActionItem, String> 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<DirectValueActionItem, ConstantPool> 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<Integer, Integer> stage = new HashMap<>();
Set<Integer> 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<Integer> 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<Tag> 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<Tag> 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;
}

View File

@@ -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);
}
}

View File

@@ -506,7 +506,7 @@ public class SWFOutputStream extends OutputStream {
* @param tags List of tag values
* @throws IOException
*/
public void writeTags(List<Tag> tags) throws IOException {
public void writeTags(Iterable<Tag> tags) throws IOException {
for (Tag tag : tags) {
tag.writeTag(this);
}

View File

@@ -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();

View File

@@ -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<File> exportBinaryData(AbortRetryIgnoreHandler handler, String outdir, List<Tag> tags, BinaryDataExportSettings settings, EventListener evl) throws IOException, InterruptedException {
public List<File> exportBinaryData(AbortRetryIgnoreHandler handler, String outdir, ReadOnlyTagList tags, BinaryDataExportSettings settings, EventListener evl) throws IOException, InterruptedException {
List<File> ret = new ArrayList<>();
if (tags.isEmpty()) {
return ret;

View File

@@ -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<File> exportFonts(AbortRetryIgnoreHandler handler, String outdir, List<Tag> tags, final FontExportSettings settings, EventListener evl) throws IOException, InterruptedException {
public List<File> exportFonts(AbortRetryIgnoreHandler handler, String outdir, ReadOnlyTagList tags, final FontExportSettings settings, EventListener evl) throws IOException, InterruptedException {
List<File> ret = new ArrayList<>();
if (tags.isEmpty()) {
return ret;

View File

@@ -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<File> exportFrames(AbortRetryIgnoreHandler handler, String outdir, final SWF swf, int containerId, List<Integer> frames, final FrameExportSettings settings, final EventListener evl) throws IOException, InterruptedException {
final List<File> 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;

View File

@@ -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<File> exportImages(AbortRetryIgnoreHandler handler, String outdir, List<Tag> tags, ImageExportSettings settings, EventListener evl) throws IOException, InterruptedException {
public List<File> exportImages(AbortRetryIgnoreHandler handler, String outdir, ReadOnlyTagList tags, ImageExportSettings settings, EventListener evl) throws IOException, InterruptedException {
List<File> ret = new ArrayList<>();
if (tags.isEmpty()) {
return ret;

View File

@@ -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<File> exportMorphShapes(AbortRetryIgnoreHandler handler, final String outdir, List<Tag> tags, final MorphShapeExportSettings settings, EventListener evl) throws IOException, InterruptedException {
public List<File> exportMorphShapes(AbortRetryIgnoreHandler handler, final String outdir, ReadOnlyTagList tags, final MorphShapeExportSettings settings, EventListener evl) throws IOException, InterruptedException {
List<File> ret = new ArrayList<>();
if (tags.isEmpty()) {
return ret;

View File

@@ -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<File> exportMovies(AbortRetryIgnoreHandler handler, String outdir, List<Tag> tags, final MovieExportSettings settings, EventListener evl) throws IOException, InterruptedException {
public List<File> exportMovies(AbortRetryIgnoreHandler handler, String outdir, ReadOnlyTagList tags, final MovieExportSettings settings, EventListener evl) throws IOException, InterruptedException {
List<File> 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<Integer, VideoFrameTag> 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;
}

View File

@@ -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<File> exportShapes(AbortRetryIgnoreHandler handler, final String outdir, List<Tag> tags, final ShapeExportSettings settings, EventListener evl) throws IOException, InterruptedException {
public List<File> exportShapes(AbortRetryIgnoreHandler handler, final String outdir, ReadOnlyTagList tags, final ShapeExportSettings settings, EventListener evl) throws IOException, InterruptedException {
List<File> ret = new ArrayList<>();
if (tags.isEmpty()) {
return ret;

View File

@@ -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<File> exportSounds(AbortRetryIgnoreHandler handler, String outdir, List<Tag> tags, final SoundExportSettings settings, EventListener evl) throws IOException, InterruptedException {
public List<File> exportSounds(AbortRetryIgnoreHandler handler, String outdir, ReadOnlyTagList tags, final SoundExportSettings settings, EventListener evl) throws IOException, InterruptedException {
List<File> ret = new ArrayList<>();
if (tags.isEmpty()) {
return ret;

View File

@@ -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<File> exportNames(final String outdir, List<Tag> tags, EventListener evl) throws IOException {
public List<File> exportNames(final String outdir, ReadOnlyTagList tags, EventListener evl) throws IOException {
List<File> ret = new ArrayList<>();
int count = 0;
for (Tag t : tags) {

View File

@@ -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<File> exportTexts(AbortRetryIgnoreHandler handler, String outdir, List<Tag> tags, final TextExportSettings settings, EventListener evl) throws IOException, InterruptedException {
public List<File> exportTexts(AbortRetryIgnoreHandler handler, String outdir, ReadOnlyTagList tags, final TextExportSettings settings, EventListener evl) throws IOException, InterruptedException {
List<File> ret = new ArrayList<>();
if (tags.isEmpty()) {
return ret;

View File

@@ -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;
}

View File

@@ -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<String> 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<PathCommand> 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<Tag> 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<String, Element> idMap, String rgbStr) {
private SvgFill parseFill(Map<String, Element> 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"
};

View File

@@ -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);
}

View File

@@ -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++) {

View File

@@ -80,12 +80,6 @@ public class DefineButton2Tag extends ButtonTag implements ASMSourceContainer {
*/
public List<BUTTONCONDACTION> 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);

View File

@@ -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);
}

View File

@@ -466,7 +466,7 @@ public class DefineFont2Tag extends FontTag {
}
@Override
public String getCharacters(List<Tag> tags) {
public String getCharacters() {
StringBuilder ret = new StringBuilder();
for (int i : codeTable) {
ret.append((char) i);

View File

@@ -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<Tag> tags) {
public String getCharacters() {
StringBuilder ret = new StringBuilder();
for (int i : codeTable) {
ret.append((char) i);

View File

@@ -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<Tag> tags) {
public String getCharacters() {
StringBuilder ret = new StringBuilder();
ensureFontInfo();
if (fontInfoTag != null) {

View File

@@ -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<Tag> subTags;
@SWFField
private List<Tag> 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<Integer, Integer> 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<Tag> 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<Integer> 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;
}
}

View File

@@ -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<Integer> dependent) {
for (Tag tag : swf.tags) {
for (Tag tag : swf.getTags()) {
if (tag instanceof CharacterTag) {
Set<Integer> needed = new HashSet<>();
tag.getNeededCharactersDeep(needed);

View File

@@ -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) {
}
}

View File

@@ -153,7 +153,7 @@ public abstract class FontTag extends CharacterTag implements AloneTag, Drawable
return fontStyle;
}
public abstract String getCharacters(List<Tag> 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<TEXTRECORD> 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()) {

View File

@@ -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<Tag> tags) {
public String getCharacters() {
FontType ft = fonts.get(0);
StringBuilder ret = new StringBuilder(ft.glyphInfo.size());
for (GlyphInfoType gi : ft.glyphInfo) {

View File

@@ -70,14 +70,10 @@ public class Timeline {
public Timelined timelined;
public Tag parentTag;
public int maxDepth;
public int fontFrameNum = -1;
public List<Tag> tags;
private final List<Frame> frames = new ArrayList<>();
private final Map<Integer, Integer> 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<Tag> 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<Tag> 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<Tag> tags) {
private void populateSoundStreamBlocks(int containerId, Iterable<Tag> tags) {
List<SoundStreamBlockTag> 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;

View File

@@ -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);
}

View File

@@ -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 {
+ "<SolidColor color=\"")
.append(ls.color.toHexRGB()).append("\"")
.append(shapeNum == 3 ? " alpha=\"" + ((RGBA) ls.color).getAlphaFloat() + "\"" : "").append(" />"
+ "</fill>"
+ "</SolidStroke>");
+ "</fill>"
+ "</SolidStroke>");
}
private static void convertLineStyle(HashMap<Integer, CharacterTag> characters, LINESTYLE2 ls, int shapeNum, StringBuilder ret) {
@@ -759,7 +760,7 @@ public class XFLConverter {
return layers;
}
private static int getLayerCount(List<Tag> 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<Tag> timeLineTags, HashMap<Integer, CharacterTag> characters, HashMap<Integer, Integer> usages) {
private static void walkShapeUsages(ReadOnlyTagList timeLineTags, HashMap<Integer, CharacterTag> characters, HashMap<Integer, Integer> 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<Integer> getNonLibraryShapes(List<Tag> tags, HashMap<Integer, CharacterTag> characters) {
private static List<Integer> getNonLibraryShapes(ReadOnlyTagList tags, HashMap<Integer, CharacterTag> characters) {
HashMap<Integer, Integer> usages = new HashMap<>();
walkShapeUsages(tags, characters, usages);
List<Integer> ret = new ArrayList<>();
@@ -829,7 +830,7 @@ public class XFLConverter {
return ret;
}
private static HashMap<Integer, CharacterTag> getCharacters(List<Tag> tags) {
private static HashMap<Integer, CharacterTag> getCharacters(ReadOnlyTagList tags) {
HashMap<Integer, CharacterTag> 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<FILTER> filters, boolean isVisible, RGBA backgroundColor, CLIPACTIONS clipActions, CharacterTag tag, HashMap<Integer, CharacterTag> characters, List<Tag> tags, FLAVersion flaVersion) {
private static String convertSymbolInstance(String name, MATRIX matrix, ColorTransform colorTransform, boolean cacheAsBitmap, int blendMode, List<FILTER> filters, boolean isVisible, RGBA backgroundColor, CLIPACTIONS clipActions, CharacterTag tag, HashMap<Integer, CharacterTag> 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<Integer, String> characterVariables, Map<Integer, String> characterClasses, List<Integer> nonLibraryShapes, String backgroundColor, List<Tag> tags, HashMap<Integer, CharacterTag> characters, HashMap<String, byte[]> files, HashMap<String, byte[]> datfiles, FLAVersion flaVersion, StringBuilder ret) {
private static void convertLibrary(SWF swf, Map<Integer, String> characterVariables, Map<Integer, String> characterClasses, List<Integer> nonLibraryShapes, String backgroundColor, ReadOnlyTagList tags, HashMap<Integer, CharacterTag> characters, HashMap<String, byte[]> files, HashMap<String, byte[]> datfiles, FLAVersion flaVersion, StringBuilder ret) {
//TODO: Imported assets
//linkageImportForRS="true" linkageIdentifier="xxx" linkageURL="yyy.swf"
@@ -1303,10 +1304,10 @@ public class XFLConverter {
symbolStr.append("</DOMTimeline>");
} 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<Integer, CharacterTag> characters, List<Tag> tags, SoundStreamHeadTypeTag soundStreamHead, StartSoundTag startSound, int frame, int duration, String actionScript, String elements, HashMap<String, byte[]> files, StringBuilder ret) {
private static void convertFrame(boolean shapeTween, HashMap<Integer, CharacterTag> characters, ReadOnlyTagList tags, SoundStreamHeadTypeTag soundStreamHead, StartSoundTag startSound, int frame, int duration, String actionScript, String elements, HashMap<String, byte[]> 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<Integer> nonLibraryShapes, List<Tag> tags, List<Tag> timelineTags, HashMap<Integer, CharacterTag> characters, int depth, FLAVersion flaVersion, HashMap<String, byte[]> files, StringBuilder ret) {
private static void convertFrames(String prevStr, String afterStr, List<Integer> nonLibraryShapes, ReadOnlyTagList tags, ReadOnlyTagList timelineTags, HashMap<Integer, CharacterTag> characters, int depth, FLAVersion flaVersion, HashMap<String, byte[]> files, StringBuilder ret) {
StringBuilder ret2 = new StringBuilder();
prevStr += "<frames>";
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<Tag> timTags = new ArrayList<>(timelineTags);
List<Tag> 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<Tag> 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<Tag> tags, List<Tag> 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<Tag> tags, List<Tag> 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<Integer, CharacterTag> characters, List<Tag> tags, List<Tag> timeLineTags, HashMap<String, byte[]> files, StringBuilder ret) {
private static void convertSoundLayer(int layerIndex, String backgroundColor, HashMap<Integer, CharacterTag> characters, ReadOnlyTagList tags, ReadOnlyTagList timeLineTags, HashMap<String, byte[]> 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("<DOMLayer name=\"Layer ").append(layerIndex).append("\" color=\"").append(randomOutlineColor()).append("\">"
+ "<frames>").append(ret2).append("</frames>"
+ "</DOMLayer>");
+ "</DOMLayer>");
}
}
@@ -2193,7 +2194,7 @@ public class XFLConverter {
return outlineColor.toHexRGB();
}
private static String convertTimeline(int spriteId, List<Integer> nonLibraryShapes, String backgroundColor, List<Tag> tags, List<Tag> timelineTags, HashMap<Integer, CharacterTag> characters, String name, FLAVersion flaVersion, HashMap<String, byte[]> files) {
private static String convertTimeline(int spriteId, List<Integer> nonLibraryShapes, String backgroundColor, ReadOnlyTagList tags, ReadOnlyTagList timelineTags, HashMap<Integer, CharacterTag> characters, String name, FLAVersion flaVersion, HashMap<String, byte[]> files) {
StringBuilder ret = new StringBuilder();
ret.append("<DOMTimeline name=\"").append(name).append("\">");
ret.append("<layers>");
@@ -2292,7 +2293,7 @@ public class XFLConverter {
}, handler).run();
}
private static Map<Integer, String> getCharacterClasses(List<Tag> tags) {
private static Map<Integer, String> getCharacterClasses(ReadOnlyTagList tags) {
Map<Integer, String> ret = new HashMap<>();
for (Tag t : tags) {
if (t instanceof SymbolClassTag) {
@@ -2307,7 +2308,7 @@ public class XFLConverter {
return ret;
}
private static Map<Integer, String> getCharacterVariables(List<Tag> tags) {
private static Map<Integer, String> getCharacterVariables(ReadOnlyTagList tags) {
Map<Integer, String> 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("<DOMTextRun>");
ret.append("<characters>").append(xmlString(txt)).append("</characters>");
@@ -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<String, byte[]> files = new HashMap<>();
final HashMap<String, byte[]> datfiles = new HashMap<>();
HashMap<Integer, CharacterTag> characters = getCharacters(swf.tags);
List<Integer> nonLibraryShapes = getNonLibraryShapes(swf.tags, characters);
Map<Integer, String> characterClasses = getCharacterClasses(swf.tags);
Map<Integer, String> characterVariables = getCharacterVariables(swf.tags);
HashMap<Integer, CharacterTag> characters = getCharacters(swf.getTags());
List<Integer> nonLibraryShapes = getNonLibraryShapes(swf.getTags(), characters);
Map<Integer, String> characterClasses = getCharacterClasses(swf.getTags());
Map<Integer, String> 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("<timelines>");
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("</timelines>");
domDocument.append("</DOMDocument>");
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("<AdjustColorFilter brightness=\"").append(normBrightness(b)).append("\" contrast=\"").append(normContrast(c)).append("\" saturation=\"").append(normSaturation(s)).append("\" hue=\"").append(normHue(h)).append("\"/>");
}
private static String convertHTMLText(List<Tag> 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<Tag> 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<Tag> tags, DefineEditTextTag det) {
public HTMLTextParser(ReadOnlyTagList tags, DefineEditTextTag det) {
if (det.hasFont) {
String fontName = null;
FontTag ft = null;