Merge origin/master

This commit is contained in:
Jindra Petřík
2015-12-28 16:39:07 +01:00
69 changed files with 3879 additions and 2700 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;
@@ -29,7 +30,6 @@ import com.jpexs.decompiler.flash.exporters.shape.CanvasShapeExporter;
import com.jpexs.decompiler.flash.helpers.BMPFile;
import com.jpexs.decompiler.flash.helpers.ImageHelper;
import com.jpexs.decompiler.flash.tags.Tag;
import com.jpexs.decompiler.flash.tags.base.CharacterTag;
import com.jpexs.decompiler.flash.tags.base.RenderContext;
import com.jpexs.decompiler.flash.tags.base.ShapeTag;
import com.jpexs.decompiler.flash.tags.enums.ImageFormat;
@@ -57,7 +57,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;
@@ -80,28 +80,25 @@ public class ShapeExporter {
int currentIndex = 1;
for (final Tag t : tags) {
if (t instanceof ShapeTag) {
final ShapeTag st = (ShapeTag) t;
if (evl != null) {
evl.handleExportingEvent("shape", currentIndex, count, t.getName());
}
int characterID = 0;
if (t instanceof CharacterTag) {
characterID = ((CharacterTag) t).getCharacterId();
}
String ext = "svg";
int characterID = st.getCharacterId();
String ext = ".svg";
if (settings.mode == ShapeExportMode.PNG) {
ext = "png";
ext = ".png";
}
if (settings.mode == ShapeExportMode.BMP) {
ext = "bmp";
ext = ".bmp";
}
if (settings.mode == ShapeExportMode.CANVAS) {
ext = "html";
ext = ".html";
}
final File file = new File(outdir + File.separator + characterID + "." + ext);
final File file = new File(outdir + File.separator + Helper.makeFileName(st.getCharacterExportFileName() + ext));
new RetryTask(() -> {
ShapeTag st = (ShapeTag) t;
switch (settings.mode) {
case SVG:
try (OutputStream fos = new BufferedOutputStream(new FileOutputStream(file))) {

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

@@ -240,6 +240,18 @@ public final class Matrix implements Cloneable {
+ rotateSkew1 + ", " + scaleY + ", " + translateX + ", " + translateY + ")";
}
public static String[] parseSvgNumberList(String params) {
while (params.contains(" ")) {
params = params.replaceAll(" ", " ");
}
params = params.trim();
params = params.replace(", ", ",");
params = params.replace(" ", ",");
String[] args = params.split(",");
return args;
}
public static Matrix parseSvgMatrix(String transformStr, double translateDivisor, double unitDivisor) {
Matrix ret = new Matrix();
while (transformStr != null && transformStr.length() > 0) {
@@ -247,14 +259,7 @@ public final class Matrix implements Cloneable {
transformStr = transformStr.substring(funcName.length() + 1);
String params = transformStr.split("\\)")[0];
transformStr = transformStr.substring(params.length() + 1).trim();
while (params.contains(" ")) {
params = params.replaceAll(" ", " ");
}
params = params.trim();
params = params.replace(", ", ",");
params = params.replace(" ", ",");
String[] args = params.split(",");
String[] args = parseSvgNumberList(params);
funcName = funcName.trim();
switch (funcName) {
case "matrix":

View File

@@ -52,6 +52,8 @@ public class SWFDecompilerPlugin {
private static final List<SWFDecompilerListener> listeners = new ArrayList<>();
public static String[] customParameters = new String[0];
public static File getPluginsDir() {
File pluginPath = null;

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

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

@@ -0,0 +1,35 @@
/*
* 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.importers.svg;
import java.awt.Color;
/**
*
* @author JPEXS
*/
class SvgBitmapFill extends SvgFill {
public String patternTransform;
public int characterId;
@Override
public Color toColor() {
return Color.BLACK;
}
}

View File

@@ -0,0 +1,383 @@
/*
* 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.importers.svg;
import java.awt.Color;
/**
*
* @author JPEXS
*/
class SvgColor extends SvgFill {
public Color color;
public SvgColor(int r, int g, int b, int opacity) {
this(new Color(r, g, b, opacity));
}
public SvgColor(int r, int g, int b) {
this(new Color(r, g, b));
}
public SvgColor(Color color) {
this.color = color;
}
@Override
public Color toColor() {
return this.color;
}
public static SvgColor parse(String colorString) {
if (colorString == null) {
return null;
}
// named colors from: http://www.w3.org/TR/SVG/types.html#ColorKeywords
switch (colorString) {
case "aliceblue":
return new SvgColor(240, 248, 255);
case "antiquewhite":
return new SvgColor(250, 235, 215);
case "aqua":
return new SvgColor(0, 255, 255);
case "aquamarine":
return new SvgColor(127, 255, 212);
case "azure":
return new SvgColor(240, 255, 255);
case "beige":
return new SvgColor(245, 245, 220);
case "bisque":
return new SvgColor(255, 228, 196);
case "black":
return new SvgColor(0, 0, 0);
case "blanchedalmond":
return new SvgColor(255, 235, 205);
case "blue":
return new SvgColor(0, 0, 255);
case "blueviolet":
return new SvgColor(138, 43, 226);
case "brown":
return new SvgColor(165, 42, 42);
case "burlywood":
return new SvgColor(222, 184, 135);
case "cadetblue":
return new SvgColor(95, 158, 160);
case "chartreuse":
return new SvgColor(127, 255, 0);
case "chocolate":
return new SvgColor(210, 105, 30);
case "coral":
return new SvgColor(255, 127, 80);
case "cornflowerblue":
return new SvgColor(100, 149, 237);
case "cornsilk":
return new SvgColor(255, 248, 220);
case "crimson":
return new SvgColor(220, 20, 60);
case "cyan":
return new SvgColor(0, 255, 255);
case "darkblue":
return new SvgColor(0, 0, 139);
case "darkcyan":
return new SvgColor(0, 139, 139);
case "darkgoldenrod":
return new SvgColor(184, 134, 11);
case "darkgray":
return new SvgColor(169, 169, 169);
case "darkgreen":
return new SvgColor(0, 100, 0);
case "darkgrey":
return new SvgColor(169, 169, 169);
case "darkkhaki":
return new SvgColor(189, 183, 107);
case "darkmagenta":
return new SvgColor(139, 0, 139);
case "darkolivegreen":
return new SvgColor(85, 107, 47);
case "darkorange":
return new SvgColor(255, 140, 0);
case "darkorchid":
return new SvgColor(153, 50, 204);
case "darkred":
return new SvgColor(139, 0, 0);
case "darksalmon":
return new SvgColor(233, 150, 122);
case "darkseagreen":
return new SvgColor(143, 188, 143);
case "darkslateblue":
return new SvgColor(72, 61, 139);
case "darkslategray":
return new SvgColor(47, 79, 79);
case "darkslategrey":
return new SvgColor(47, 79, 79);
case "darkturquoise":
return new SvgColor(0, 206, 209);
case "darkviolet":
return new SvgColor(148, 0, 211);
case "deeppink":
return new SvgColor(255, 20, 147);
case "deepskyblue":
return new SvgColor(0, 191, 255);
case "dimgray":
return new SvgColor(105, 105, 105);
case "dimgrey":
return new SvgColor(105, 105, 105);
case "dodgerblue":
return new SvgColor(30, 144, 255);
case "firebrick":
return new SvgColor(178, 34, 34);
case "floralwhite":
return new SvgColor(255, 250, 240);
case "forestgreen":
return new SvgColor(34, 139, 34);
case "fuchsia":
return new SvgColor(255, 0, 255);
case "gainsboro":
return new SvgColor(220, 220, 220);
case "ghostwhite":
return new SvgColor(248, 248, 255);
case "gold":
return new SvgColor(255, 215, 0);
case "goldenrod":
return new SvgColor(218, 165, 32);
case "gray":
return new SvgColor(128, 128, 128);
case "grey":
return new SvgColor(128, 128, 128);
case "green":
return new SvgColor(0, 128, 0);
case "greenyellow":
return new SvgColor(173, 255, 47);
case "honeydew":
return new SvgColor(240, 255, 240);
case "hotpink":
return new SvgColor(255, 105, 180);
case "indianred":
return new SvgColor(205, 92, 92);
case "indigo":
return new SvgColor(75, 0, 130);
case "ivory":
return new SvgColor(255, 255, 240);
case "khaki":
return new SvgColor(240, 230, 140);
case "lavender":
return new SvgColor(230, 230, 250);
case "lavenderblush":
return new SvgColor(255, 240, 245);
case "lawngreen":
return new SvgColor(124, 252, 0);
case "lemonchiffon":
return new SvgColor(255, 250, 205);
case "lightblue":
return new SvgColor(173, 216, 230);
case "lightcoral":
return new SvgColor(240, 128, 128);
case "lightcyan":
return new SvgColor(224, 255, 255);
case "lightgoldenrodyellow":
return new SvgColor(250, 250, 210);
case "lightgray":
return new SvgColor(211, 211, 211);
case "lightgreen":
return new SvgColor(144, 238, 144);
case "lightgrey":
return new SvgColor(211, 211, 211);
case "lightpink":
return new SvgColor(255, 182, 193);
case "lightsalmon":
return new SvgColor(255, 160, 122);
case "lightseagreen":
return new SvgColor(32, 178, 170);
case "lightskyblue":
return new SvgColor(135, 206, 250);
case "lightslategray":
return new SvgColor(119, 136, 153);
case "lightslategrey":
return new SvgColor(119, 136, 153);
case "lightsteelblue":
return new SvgColor(176, 196, 222);
case "lightyellow":
return new SvgColor(255, 255, 224);
case "lime":
return new SvgColor(0, 255, 0);
case "limegreen":
return new SvgColor(50, 205, 50);
case "linen":
return new SvgColor(250, 240, 230);
case "magenta":
return new SvgColor(255, 0, 255);
case "maroon":
return new SvgColor(128, 0, 0);
case "mediumaquamarine":
return new SvgColor(102, 205, 170);
case "mediumblue":
return new SvgColor(0, 0, 205);
case "mediumorchid":
return new SvgColor(186, 85, 211);
case "mediumpurple":
return new SvgColor(147, 112, 219);
case "mediumseagreen":
return new SvgColor(60, 179, 113);
case "mediumslateblue":
return new SvgColor(123, 104, 238);
case "mediumspringgreen":
return new SvgColor(0, 250, 154);
case "mediumturquoise":
return new SvgColor(72, 209, 204);
case "mediumvioletred":
return new SvgColor(199, 21, 133);
case "midnightblue":
return new SvgColor(25, 25, 112);
case "mintcream":
return new SvgColor(245, 255, 250);
case "mistyrose":
return new SvgColor(255, 228, 225);
case "moccasin":
return new SvgColor(255, 228, 181);
case "navajowhite":
return new SvgColor(255, 222, 173);
case "navy":
return new SvgColor(0, 0, 128);
case "oldlace":
return new SvgColor(253, 245, 230);
case "olive":
return new SvgColor(128, 128, 0);
case "olivedrab":
return new SvgColor(107, 142, 35);
case "orange":
return new SvgColor(255, 165, 0);
case "orangered":
return new SvgColor(255, 69, 0);
case "orchid":
return new SvgColor(218, 112, 214);
case "palegoldenrod":
return new SvgColor(238, 232, 170);
case "palegreen":
return new SvgColor(152, 251, 152);
case "paleturquoise":
return new SvgColor(175, 238, 238);
case "palevioletred":
return new SvgColor(219, 112, 147);
case "papayawhip":
return new SvgColor(255, 239, 213);
case "peachpuff":
return new SvgColor(255, 218, 185);
case "peru":
return new SvgColor(205, 133, 63);
case "pink":
return new SvgColor(255, 192, 203);
case "plum":
return new SvgColor(221, 160, 221);
case "powderblue":
return new SvgColor(176, 224, 230);
case "purple":
return new SvgColor(128, 0, 128);
case "red":
return new SvgColor(255, 0, 0);
case "rosybrown":
return new SvgColor(188, 143, 143);
case "royalblue":
return new SvgColor(65, 105, 225);
case "saddlebrown":
return new SvgColor(139, 69, 19);
case "salmon":
return new SvgColor(250, 128, 114);
case "sandybrown":
return new SvgColor(244, 164, 96);
case "seagreen":
return new SvgColor(46, 139, 87);
case "seashell":
return new SvgColor(255, 245, 238);
case "sienna":
return new SvgColor(160, 82, 45);
case "silver":
return new SvgColor(192, 192, 192);
case "skyblue":
return new SvgColor(135, 206, 235);
case "slateblue":
return new SvgColor(106, 90, 205);
case "slategray":
return new SvgColor(112, 128, 144);
case "slategrey":
return new SvgColor(112, 128, 144);
case "snow":
return new SvgColor(255, 250, 250);
case "springgreen":
return new SvgColor(0, 255, 127);
case "steelblue":
return new SvgColor(70, 130, 180);
case "tan":
return new SvgColor(210, 180, 140);
case "teal":
return new SvgColor(0, 128, 128);
case "thistle":
return new SvgColor(216, 191, 216);
case "tomato":
return new SvgColor(255, 99, 71);
case "turquoise":
return new SvgColor(64, 224, 208);
case "violet":
return new SvgColor(238, 130, 238);
case "wheat":
return new SvgColor(245, 222, 179);
case "white":
return new SvgColor(255, 255, 255);
case "whitesmoke":
return new SvgColor(245, 245, 245);
case "yellow":
return new SvgColor(255, 255, 0);
case "yellowgreen":
return new SvgColor(154, 205, 50);
}
if (colorString.startsWith("#")) {
String s = colorString.substring(1);
if (s.length() == 3) {
s = "" + s.charAt(0) + s.charAt(0) + s.charAt(1) + s.charAt(1) + s.charAt(2) + s.charAt(2);
}
int i = Integer.parseInt(s, 16);
return new SvgColor(new Color(i, false));
} else if (colorString.startsWith("rgb")) {
colorString = colorString.substring(3).trim();
if (colorString.startsWith("(") && colorString.endsWith(")")) {
colorString = colorString.substring(1, colorString.length() - 1);
String[] args = colorString.split(",");
if (args.length == 3) {
String a0 = args[0].trim();
String a1 = args[1].trim();
String a2 = args[2].trim();
if (a0.endsWith("%") && a1.endsWith("%") && a2.endsWith("%")) {
int r = (int) Math.round(Double.parseDouble(a0.substring(0, a0.length() - 1)) * 255.0 / 100);
int g = (int) Math.round(Double.parseDouble(a1.substring(0, a1.length() - 1)) * 255.0 / 100);
int b = (int) Math.round(Double.parseDouble(a2.substring(0, a2.length() - 1)) * 255.0 / 100);
return new SvgColor(r, g, b);
} else {
int r = Integer.parseInt(a0);
int g = Integer.parseInt(a1);
int b = Integer.parseInt(a2);
return new SvgColor(r, g, b);
}
}
}
}
return null;
}
}

View File

@@ -0,0 +1,28 @@
/*
* 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.importers.svg;
import java.awt.Color;
/**
*
* @author JPEXS
*/
abstract class SvgFill implements Cloneable {
public abstract Color toColor();
}

View File

@@ -0,0 +1,45 @@
/*
* 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.importers.svg;
import java.awt.Color;
import java.util.List;
/**
*
* @author JPEXS
*/
abstract class SvgGradient extends SvgFill {
public List<SvgStop> stops;
public SvgGradientUnits gradientUnits;
public String gradientTransform;
public SvgSpreadMethod spreadMethod;
public SvgInterpolation interpolation;
@Override
public Color toColor() {
if (stops.isEmpty()) {
return Color.BLACK;
}
return stops.get(0).color;
}
}

View File

@@ -0,0 +1,26 @@
/*
* 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.importers.svg;
/**
*
* @author JPEXS
*/
enum SvgGradientUnits {
USER_SPACE_ON_USE, OBJECT_BOUNDING_BOX
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,26 @@
/*
* 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.importers.svg;
/**
*
* @author JPEXS
*/
enum SvgInterpolation {
SRGB, LINEAR_RGB
}

View File

@@ -0,0 +1,26 @@
/*
* 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.importers.svg;
/**
*
* @author JPEXS
*/
enum SvgLineCap {
BUTT, ROUND, SQUARE
}

View File

@@ -0,0 +1,26 @@
/*
* 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.importers.svg;
/**
*
* @author JPEXS
*/
enum SvgLineJoin {
MITER, ROUND, BEVEL
}

View File

@@ -0,0 +1,33 @@
/*
* 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.importers.svg;
/**
*
* @author JPEXS
*/
class SvgLinearGradient extends SvgGradient {
public String x1;
public String y1;
public String x2;
public String y2;
//xlink?
}

View File

@@ -14,7 +14,7 @@
* You should have received a copy of the GNU Lesser General Public
* License along with this library.
*/
package com.jpexs.decompiler.flash.importers;
package com.jpexs.decompiler.flash.importers.svg;
/**
*

View File

@@ -0,0 +1,35 @@
/*
* 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.importers.svg;
/**
*
* @author JPEXS
*/
class SvgRadialGradient extends SvgGradient {
public String cx;
public String cy;
public String r;
public String fx;
public String fy;
//xlink?
}

View File

@@ -0,0 +1,26 @@
/*
* 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.importers.svg;
/**
*
* @author JPEXS
*/
enum SvgSpreadMethod {
PAD, REFLECT, REPEAT
}

View File

@@ -0,0 +1,40 @@
/*
* 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.importers.svg;
import java.awt.Color;
/**
*
* @author JPEXS
*/
class SvgStop implements Comparable<SvgStop> {
public Color color;
public double offset;
public SvgStop(Color color, double offset) {
this.color = color;
this.offset = offset;
}
@Override
public int compareTo(SvgStop o) {
return (int) Math.signum(offset - o.offset);
}
}

View File

@@ -0,0 +1,680 @@
/*
* 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.importers.svg;
import com.jpexs.decompiler.flash.importers.ShapeImporter;
import com.jpexs.decompiler.flash.tags.base.ImageTag;
import com.jpexs.helpers.Helper;
import java.awt.Color;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.regex.Pattern;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
/**
*
* @author JPEXS
*/
class SvgStyle {
private final Element element;
private final SvgImporter importer;
private final Map<String, Element> idMap;
private final double epsilon = 0.001;
private final Random random = new Random();
public SvgStyle(SvgImporter importer, Map<String, Element> idMap, Element element) {
this.importer = importer;
this.idMap = idMap;
this.element = element;
}
private Map<String, String> getStyleAttributeValues(Element element) {
// todo: cache
Map<String, String> styleValues = new HashMap<>();
if (element.hasAttribute("style")) {
String[] styleDefs = element.getAttribute("style").split(";");
for (String styleDef : styleDefs) {
if (!styleDef.contains(":")) {
continue;
}
String[] parts = styleDef.split(":", 2);
String name = parts[0].trim();
String value = parts[1].trim();
SvgStyleProperty styleProperty = SvgStyleProperty.getByName(name);
if (styleProperty == null) {
importer.showWarning(name + "StyleNotSupported", "The style '" + name + "' is not supported.");
} else {
styleValues.put(name, value);
}
}
}
return styleValues;
}
private <E> E getValue(Element element, String name) {
return getValue(element, name, false);
}
@SuppressWarnings("unchecked")
private <E> E getValue(Element element, String name, boolean inherit) {
Map<String, String> styleValues = getStyleAttributeValues(element);
if (styleValues.containsKey(name)) {
String value = styleValues.get(name);
if ("inherit".equals(value)) {
if (element.getParentNode() instanceof Element) {
return getValue((Element) element.getParentNode(), name, true);
}
} else {
Object result = getStyleValue(this, name, value);
if (result != null) {
return (E) result;
}
}
}
if (element.hasAttribute(name)) {
String value = element.getAttribute(name).trim();
if ("inherit".equals(value)) {
if (element.getParentNode() instanceof Element) {
return getValue((Element) element.getParentNode(), name, true);
}
} else {
Object result = getStyleValue(this, name, value);
if (result != null) {
return (E) result;
}
}
}
SvgStyleProperty p = SvgStyleProperty.getByName(name);
if (inherit || p.isInherited() && element.getParentNode() instanceof Element) {
return getValue((Element) element.getParentNode(), name);
}
return (E) p.getInitialValue();
}
public Color getColor() {
return getValue(element, "color");
}
public SvgFill getFill() {
return getValue(element, "fill");
}
public double getFillOpacity() {
return getValue(element, "fill-opacity");
}
public SvgFill getStroke() {
return getValue(element, "stroke");
}
public double getStrokeWidth() {
return getValue(element, "stroke-width");
}
public double getStrokeOpacity() {
return getValue(element, "stroke-opacity");
}
public SvgLineCap getStrokeLineCap() {
return getValue(element, "stroke-linecap");
}
public SvgLineJoin getStrokeLineJoin() {
return getValue(element, "stroke-linejoin");
}
public double getStrokeMiterLimit() {
return getValue(element, "stroke-miterlimit");
}
public double getOpacity() {
return getValue(element, "opacity");
}
public Color getStopColor() {
return getValue(element, "stop-color");
}
public double getStopOpacity() {
return getValue(element, "stop-opacity");
}
public SvgFill getFillWithOpacity() {
SvgFill fill = getFill();
if (fill == null) {
return null;
}
if (!(fill instanceof SvgColor)) {
return fill;
}
Color fillColor = ((SvgColor) fill).color;
int opacity = (int) Math.round(getOpacity() * getFillOpacity() * 255);
if (opacity > 255) {
opacity = 255;
}
if (opacity < 0) {
opacity = 0;
}
if (opacity == 255) {
return fill;
}
return new SvgColor(fillColor.getRed(), fillColor.getGreen(), fillColor.getBlue(), opacity);
}
public SvgFill getStrokeFillWithOpacity() {
SvgFill strokeFill = getStroke();
if (strokeFill == null) {
return null;
}
if (!(strokeFill instanceof SvgColor)) {
return strokeFill;
}
Color strokeFillColor = ((SvgColor) strokeFill).color;
int opacity = (int) Math.round(getOpacity() * getStopOpacity() * 255);
if (opacity > 255) {
opacity = 255;
}
if (opacity < 0) {
opacity = 0;
}
if (opacity == 255) {
return strokeFill;
}
return new SvgColor(strokeFillColor.getRed(), strokeFillColor.getGreen(), strokeFillColor.getBlue(), opacity);
}
public SvgFill getStrokeColorWithOpacity() {
SvgFill strokeFill = getStroke();
if (strokeFill == null) {
return null;
}
if (!(strokeFill instanceof SvgColor)) {
return strokeFill;
}
Color strokeColor = ((SvgColor) strokeFill).color;
int opacity = (int) Math.round(getOpacity() * getStrokeOpacity() * 255);
if (opacity == 255) {
return strokeFill;
}
return new SvgColor(strokeColor.getRed(), strokeColor.getGreen(), strokeColor.getBlue(), opacity);
}
//FIXME - matrices
private SvgFill parseGradient(Map<String, Element> idMap, Element el) {
SvgGradientUnits gradientUnits = null;
String gradientTransform = null;
SvgSpreadMethod spreadMethod = null;
SvgInterpolation interpolation = null;
String x1 = null;
String y1 = null;
String x2 = null;
String y2 = null;
String cx = null;
String cy = null;
String fx = null;
String fy = null;
String r = null;
List<SvgStop> stops = new ArrayList<>();
//inheritance:
if (el.hasAttribute("xlink:href")) {
String parent = el.getAttribute("xlink:href");
if (parent.startsWith("#")) {
String parentId = parent.substring(1);
Element parent_el = idMap.get(parentId);
if (parent_el == null) {
importer.showWarning("fillNotSupported", "Parent gradient not found.");
return new SvgColor(random.nextInt(256), random.nextInt(256), random.nextInt(256));
}
if ("linearGradient".equals(el.getTagName()) && parent_el.getTagName().equals(el.getTagName())) {
SvgLinearGradient parentFill = (SvgLinearGradient) parseGradient(idMap, parent_el);
gradientUnits = parentFill.gradientUnits;
gradientTransform = parentFill.gradientTransform;
spreadMethod = parentFill.spreadMethod;
x1 = parentFill.x1;
y1 = parentFill.y1;
x2 = parentFill.x2;
y2 = parentFill.y2;
interpolation = parentFill.interpolation;
stops = parentFill.stops;
}
if ("radialGradient".equals(el.getTagName()) && parent_el.getTagName().equals(el.getTagName())) {
SvgRadialGradient parentFill = (SvgRadialGradient) parseGradient(idMap, parent_el);
gradientUnits = parentFill.gradientUnits;
gradientTransform = parentFill.gradientTransform;
spreadMethod = parentFill.spreadMethod;
cx = parentFill.cx;
cy = parentFill.cy;
fx = parentFill.fx;
fy = parentFill.fy;
r = parentFill.r;
interpolation = parentFill.interpolation;
stops = parentFill.stops;
}
} else {
importer.showWarning("fillNotSupported", "Parent gradient invalid.");
return new SvgColor(random.nextInt(256), random.nextInt(256), random.nextInt(256));
}
}
if (el.hasAttribute("gradientUnits")) {
switch (el.getAttribute("gradientUnits")) {
case "userSpaceOnUse":
gradientUnits = SvgGradientUnits.USER_SPACE_ON_USE;
break;
case "objectBoundingBox":
gradientUnits = SvgGradientUnits.OBJECT_BOUNDING_BOX;
break;
default:
importer.showWarning("fillNotSupported", "Unsupported gradientUnits: " + el.getAttribute("gradientUnits"));
return new SvgColor(random.nextInt(256), random.nextInt(256), random.nextInt(256));
}
}
if (el.hasAttribute("gradientTransform")) {
gradientTransform = el.getAttribute("gradientTransform");
}
if (el.hasAttribute("spreadMethod")) {
switch (el.getAttribute("spreadMethod")) {
case "pad":
spreadMethod = SvgSpreadMethod.PAD;
break;
case "reflect":
spreadMethod = SvgSpreadMethod.REFLECT;
break;
case "repeat":
spreadMethod = SvgSpreadMethod.REPEAT;
break;
}
}
if (el.hasAttribute("x1")) {
x1 = el.getAttribute("x1").trim();
}
if (el.hasAttribute("y1")) {
y1 = el.getAttribute("y1").trim();
}
if (el.hasAttribute("x2")) {
x2 = el.getAttribute("x2").trim();
}
if (el.hasAttribute("y2")) {
y2 = el.getAttribute("y2").trim();
}
if (el.hasAttribute("cx")) {
cx = el.getAttribute("cx").trim();
}
if (el.hasAttribute("cy")) {
cy = el.getAttribute("cy").trim();
}
if (el.hasAttribute("fx")) {
fx = el.getAttribute("fx").trim();
}
if (el.hasAttribute("fy")) {
fy = el.getAttribute("fy").trim();
}
if (el.hasAttribute("r")) {
r = el.getAttribute("r").trim();
}
if (el.hasAttribute("color-interpolation") && interpolation == null) { //prefer inherit
switch (el.getAttribute("color-interpolation")) {
case "sRGB":
interpolation = SvgInterpolation.SRGB;
break;
case "linearRGB":
interpolation = SvgInterpolation.LINEAR_RGB;
break;
case "auto": //without preference, put SRGB there
interpolation = SvgInterpolation.SRGB;
break;
}
}
if (interpolation == null) {
interpolation = SvgInterpolation.SRGB;
}
if (gradientUnits == null) {
gradientUnits = SvgGradientUnits.OBJECT_BOUNDING_BOX;
}
if (spreadMethod == null) {
spreadMethod = SvgSpreadMethod.PAD;
}
if (x1 == null) {
x1 = "0%";
}
if (y1 == null) {
y1 = "0%";
}
if (x2 == null) {
x2 = "100%";
}
if (y2 == null) {
y2 = "0%";
}
if (cx == null) {
cx = "50%";
}
if (cy == null) {
cy = "50%";
}
if (r == null) {
r = "50%";
}
if (fx == null) {
fx = cx;
}
if (fy == null) {
fy = cy;
}
NodeList stopNodes = el.getElementsByTagName("stop");
boolean stopsCleared = false;
for (int i = 0; i < stopNodes.getLength(); i++) {
Node node = stopNodes.item(i);
if (node instanceof Element) {
Element stopEl = (Element) node;
SvgStyle newStyle = new SvgStyle(importer, idMap, stopEl);
String offsetStr = stopEl.getAttribute("offset");
double offset = importer.parseNumberOrPercent(offsetStr);
Color color = newStyle.getStopColor();
if (color == null) {
color = Color.BLACK;
}
int alpha = (int) Math.round(newStyle.getStopOpacity() * 255);
color = new Color(color.getRed(), color.getGreen(), color.getBlue(), alpha);
if (!stopsCleared) { //It has some stop nodes -> remove all inherited stops
stopsCleared = true;
stops = new ArrayList<>();
}
stops.add(new SvgStop(color, offset));
}
}
if ("linearGradient".equals(el.getTagName())) {
SvgLinearGradient ret = new SvgLinearGradient();
ret.x1 = x1;
ret.y1 = y1;
ret.x2 = x2;
ret.y2 = y2;
ret.spreadMethod = spreadMethod;
ret.gradientTransform = gradientTransform;
ret.gradientUnits = gradientUnits;
ret.stops = fixStops(stops);
ret.interpolation = interpolation;
return ret;
} else if ("radialGradient".equals(el.getTagName())) {
SvgRadialGradient ret = new SvgRadialGradient();
ret.cx = cx;
ret.cy = cy;
ret.fx = fx;
ret.fy = fy;
ret.r = r;
ret.spreadMethod = spreadMethod;
ret.gradientTransform = gradientTransform;
ret.gradientUnits = gradientUnits;
ret.stops = fixStops(stops);
ret.interpolation = interpolation;
return ret;
} else {
return null;
}
}
private List<SvgStop> fixStops(List<SvgStop> stops) {
if (stops.isEmpty()) {
stops.add(new SvgStop(SvgTransparentFill.INSTANCE.toColor(), 0));
stops.add(new SvgStop(SvgTransparentFill.INSTANCE.toColor(), 1));
} else if (stops.size() == 1) {
SvgStop stop0 = stops.get(0);
stop0.offset = 0;
stops.add(new SvgStop(stop0.color, 1));
}
double offset = 0;
for (SvgStop stop : stops) {
if (stop.offset < offset) {
stop.offset = offset;
}
if (stop.offset > 1) {
stop.offset = 1;
}
offset = stop.offset;
}
if (Math.abs(offset - 1) > epsilon) {
stops.add(new SvgStop(stops.get(stops.size() - 1).color, 1));
}
return stops;
}
private SvgFill parseFill(Map<String, Element> idMap, String fillStr) {
if (fillStr == null) {
return null;
}
if (fillStr.equals("none")) {
return SvgTransparentFill.INSTANCE;
}
Pattern idPat = Pattern.compile("url\\(#([^)]+)\\).*");
java.util.regex.Matcher mPat = idPat.matcher(fillStr);
if (mPat.matches()) {
String elementId = mPat.group(1);
Element e = idMap.get(elementId);
if (e != null) {
String tagName = e.getTagName();
if ("linearGradient".equals(tagName)) {
return parseGradient(idMap, e);
}
if ("radialGradient".equals(tagName)) {
return parseGradient(idMap, e);
}
if ("pattern".equals(tagName)) {
Element element = null;
NodeList childNodes = e.getChildNodes();
for (int i = 0; i < childNodes.getLength(); i++) {
if (childNodes.item(i) instanceof Element) {
if (element != null) {
element = null;
break;
}
element = (Element) childNodes.item(i);
}
}
if (element != null && "image".equals(element.getTagName())) {
String attr = element.getAttribute("xlink:href").trim();
// this is ugly, but supports the format which is exported by FFDec
if (attr.startsWith("data:image/") && attr.contains("base64,")) {
String base64 = attr.substring(attr.indexOf("base64,") + 7);
byte[] data = Helper.base64StringToByteArray(base64);
try {
ImageTag imageTag = new ShapeImporter().addImage(importer.shapeTag, data, 0);
SvgBitmapFill bitmapFill = new SvgBitmapFill();
bitmapFill.characterId = imageTag.characterID;
if (e.hasAttribute("patternTransform")) {
bitmapFill.patternTransform = e.getAttribute("patternTransform");
}
return bitmapFill;
} catch (IOException ex) {
Logger.getLogger(ShapeImporter.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
}
importer.showWarning("fillNotSupported", "Unknown fill style. Random color assigned.");
return new SvgColor(random.nextInt(256), random.nextInt(256), random.nextInt(256));
}
fillStr = fillStr.substring(elementId.length() + 6).trim(); // remove url(#...)
}
SvgColor result = SvgColor.parse(fillStr);
if (result == null) {
importer.showWarning("fillNotSupported", "Unknown fill style. Random color assigned.");
return new SvgColor(random.nextInt(256), random.nextInt(256), random.nextInt(256));
}
return result;
}
private Object getStyleValue(SvgStyle style, String name, String value) {
if (value == null || value.length() == 0) {
return null;
}
try {
switch (name) {
case "color": {
Color color = SvgColor.parse(value).toColor();
if (color != null) {
return color;
}
}
break;
case "fill": {
if ("currentColor".equals(value)) {
return new SvgColor(style.getColor());
} else {
SvgFill fill = parseFill(idMap, value);
if (fill != null) {
return fill;
}
}
}
break;
case "fill-opacity": {
double opacity = Double.parseDouble(value);
return opacity;
}
case "stroke": {
if ("currentColor".equals(value)) {
return new SvgColor(style.getColor());
} else {
SvgFill stroke = parseFill(idMap, value);
if (stroke != null) {
return stroke;
}
}
}
break;
case "stroke-width": {
double strokeWidth = Double.parseDouble(value);
return strokeWidth;
}
case "stroke-opacity": {
double opacity = Double.parseDouble(value);
return opacity;
}
case "stroke-linecap": {
switch (value) {
case "butt":
return SvgLineCap.BUTT;
case "round":
return SvgLineCap.ROUND;
case "square":
return SvgLineCap.SQUARE;
}
}
break;
case "stroke-linejoin": {
switch (value) {
case "miter":
return SvgLineJoin.MITER;
case "round":
return SvgLineJoin.ROUND;
case "bevel":
return SvgLineJoin.BEVEL;
}
}
break;
case "stroke-miterlimit": {
double strokeMiterLimit = Double.parseDouble(value);
return strokeMiterLimit;
}
case "opacity": {
double opacity = Double.parseDouble(value);
return opacity;
}
case "stop-color": {
if ("currentColor".equals(value)) {
return style.getColor();
} else {
return SvgColor.parse(value).toColor();
}
}
case "stop-opacity": {
double stopOpacity = Double.parseDouble(value);
return stopOpacity;
}
}
} catch (NumberFormatException ex) {
//ignore
}
return null;
}
}

View File

@@ -0,0 +1,80 @@
/*
* 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.importers.svg;
import java.awt.Color;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
/**
*
* @author JPEXS
*/
public class SvgStyleProperty {
private final String name;
private final boolean inherited;
private final Object initial;
public SvgStyleProperty(String name, boolean inherited, Object initial) {
this.name = name;
this.inherited = inherited;
this.initial = initial;
}
public String name() {
return name;
}
public boolean isInherited() {
return inherited;
}
public Object getInitialValue() {
return initial;
}
private static final Map<String, SvgStyleProperty> properties;
static {
Map<String, SvgStyleProperty> p = new HashMap<>();
p.put("color", new SvgStyleProperty("color", true, Color.BLACK /* depends on user agent */));
p.put("fill", new SvgStyleProperty("fill", true, new SvgColor(Color.BLACK)));
p.put("fill-opacity", new SvgStyleProperty("fill-opacity", true, 1.0));
p.put("stroke", new SvgStyleProperty("stroke", true, null));
p.put("stroke-width", new SvgStyleProperty("stroke-width", true, 1.0));
p.put("stroke-opacity", new SvgStyleProperty("stroke-opacity", true, 1.0));
p.put("stroke-linecap", new SvgStyleProperty("stroke-linecap", true, SvgLineCap.BUTT));
p.put("stroke-linejoin", new SvgStyleProperty("stroke-linejoin", true, SvgLineJoin.MITER));
p.put("stroke-miterlimit", new SvgStyleProperty("stroke-miterlimit", true, 4.0));
p.put("opacity", new SvgStyleProperty("opacity", false, 1.0));
p.put("stop-color", new SvgStyleProperty("stop-color", false, Color.BLACK));
p.put("stop-opacity", new SvgStyleProperty("stop-opacity", false, 1.0));
properties = p;
}
public static Collection<SvgStyleProperty> getProperties() {
return properties.values();
}
public static SvgStyleProperty getByName(String name) {
return properties.get(name);
}
}

View File

@@ -0,0 +1,38 @@
/*
* 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.importers.svg;
import java.awt.Color;
/**
*
* @author JPEXS
*/
class SvgTransparentFill extends SvgFill {
private static final Color TRANSPARENT = new Color(0, true);
public static SvgTransparentFill INSTANCE = new SvgTransparentFill();
private SvgTransparentFill() {
}
@Override
public Color toColor() {
return TRANSPARENT;
}
}

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,13 +1961,21 @@ public class XFLConverter {
}
String embedRanges = "";
String fontChars = font.getCharacters(tags);
String fontChars = font.getCharacters();
if ("".equals(fontChars)) {
continue;
}
String embeddedCharacters = fontChars;
embeddedCharacters = embeddedCharacters.replace("\u00A0", ""); //nonbreak space
embeddedCharacters = embeddedCharacters.replace(".", "");
embeddedCharacters = embeddedCharacters.replace("\u00A0", ""); // nonbreak space
embeddedCharacters = embeddedCharacters.replace(".", ""); // todo: honfika: why?
for (char i = 0; i < 32; i++) {
if (i == 9 || i == 10 || i == 13) {
continue;
}
embeddedCharacters = embeddedCharacters.replace("" + i, ""); // not supported in xml
}
boolean hasAllRanges = false;
for (int r = 0; r < CharacterRanges.rangeCount(); r++) {
int[] codes = CharacterRanges.rangeCodes(r);
@@ -2003,7 +2012,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 +2074,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 +2130,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 +2188,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 +2202,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 +2301,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 +2316,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 +2346,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 +2436,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 +2561,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 +2580,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 +2686,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 +2710,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 +3145,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 +3199,7 @@ public class XFLConverter {
private String alignment = null;
private final List<Tag> tags;
private final ReadOnlyTagList tags;
private boolean bold = false;
@@ -3216,7 +3225,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;

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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