diff --git a/CHANGELOG.md b/CHANGELOG.md index dcec0280e..3d659595a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ All notable changes to this project will be documented in this file. (including XML export), allows decide whether to write length in tag header as long - [#2073] Editing of frame count in SWF header (with warning that it won't update ShowFrame count) - Show font AS linkage class in its name in the tree (besides font name) +- [#2057] Show all assigned AS linkage classes in the item name (instead just one) ### Fixed - [#2043] StartSound2 tag handling @@ -3075,6 +3076,7 @@ Major version of SWF to XML export changed to 2. [#1449]: https://www.free-decompiler.com/flash/issues/1449 [#2070]: https://www.free-decompiler.com/flash/issues/2070 [#2073]: https://www.free-decompiler.com/flash/issues/2073 +[#2057]: https://www.free-decompiler.com/flash/issues/2057 [#2043]: https://www.free-decompiler.com/flash/issues/2043 [#2017]: https://www.free-decompiler.com/flash/issues/2017 [#2052]: https://www.free-decompiler.com/flash/issues/2052 diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/SWF.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/SWF.java index 549363459..e4db1e0d2 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/SWF.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/SWF.java @@ -397,7 +397,7 @@ public final class SWF implements SWFContainerItem, Timelined, Openable { private String charset = "UTF-8"; @Internal - private Map importedTagToClassMapping = new HashMap<>(); + private Map> importedTagToClassesMapping = new HashMap<>(); @Internal private Map importedTagToExportNameMapping = new HashMap<>(); @@ -800,7 +800,7 @@ public final class SWF implements SWFContainerItem, Timelined, Openable { } for (Tag t : getTags()) { if (t instanceof FontTag) { - if (fontClass.equals(((FontTag) t).getClassName())) { + if (((FontTag) t).getClassNames().contains(fontClass)) { return (FontTag) t; } } @@ -1627,12 +1627,12 @@ public final class SWF implements SWFContainerItem, Timelined, Openable { if (cht instanceof CharacterTag) { importedCharacters.add((CharacterTag) chtCopy); String exportName = ((CharacterTag) cht).getExportName(); - String className = ((CharacterTag) cht).getClassName(); + LinkedHashSet classNames = ((CharacterTag) cht).getClassNames(); if (exportName != null) { importedTagToExportNameMapping.put(importedId, exportName); } - if (className != null) { - importedTagToClassMapping.put(importedId, className); + if (!classNames.isEmpty()) { + importedTagToClassesMapping.put(importedId, classNames); } } else { chtCopy.setTimelined(this); @@ -1668,12 +1668,12 @@ public final class SWF implements SWFContainerItem, Timelined, Openable { if (cht instanceof CharacterTag) { importedCharacters.add((CharacterTag) chtCopy); String exportName = ((CharacterTag) cht).getExportName(); - String className = ((CharacterTag) cht).getClassName(); + LinkedHashSet classNames = ((CharacterTag) cht).getClassNames(); if (exportName != null) { importedTagToExportNameMapping.put(importedId, exportName); } - if (className != null) { - importedTagToClassMapping.put(importedId, className); + if (!classNames.isEmpty()) { + importedTagToClassesMapping.put(importedId, classNames); } } else { chtCopy.setSwf(this); @@ -1905,14 +1905,26 @@ public final class SWF implements SWFContainerItem, Timelined, Openable { } public void assignClassesToSymbols() { - HashMap classes = new HashMap<>(importedTagToClassMapping); + HashMap> classes = new HashMap<>(); + + for (int ch : importedTagToClassesMapping.keySet()) { + classes.put(ch, new LinkedHashSet<>(importedTagToClassesMapping.get(ch))); + } + + Set uniqueClasses = new HashSet<>(); for (Tag t : getTags()) { if (t instanceof SymbolClassTag) { SymbolClassTag sct = (SymbolClassTag) t; - for (int i = 0; i < sct.tags.size(); i++) { - if ((!classes.containsKey(sct.tags.get(i))) && (!classes.containsValue(sct.names.get(i)))) { - classes.put(sct.tags.get(i), sct.names.get(i)); + for (int i = 0; i < sct.tags.size(); i++) { + if (!classes.containsKey(sct.tags.get(i))) { + classes.put(sct.tags.get(i), new LinkedHashSet<>()); } + if (uniqueClasses.contains(sct.names.get(i))) { + //when two characters have assigned same class, only first assignment is valid + continue; + } + uniqueClasses.add(sct.names.get(i)); + classes.get(sct.tags.get(i)).add(sct.names.get(i)); } } } @@ -1924,14 +1936,16 @@ public final class SWF implements SWFContainerItem, Timelined, Openable { continue; } if (classes.containsKey(ct.getCharacterId())) { - ct.setClassName(classes.get(ct.getCharacterId())); + ct.setClassNames(classes.get((Integer)ct.getCharacterId())); } } } classToCharacter.clear(); for (int ch : classes.keySet()) { - classToCharacter.put(classes.get(ch), ch); + for (String cls:classes.get(ch)) { + classToCharacter.put(cls, ch); + } } } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/base/CharacterTag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/base/CharacterTag.java index 25f66af3c..33fabb55c 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/base/CharacterTag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/base/CharacterTag.java @@ -21,6 +21,7 @@ import com.jpexs.decompiler.flash.tags.DefineScalingGridTag; import com.jpexs.decompiler.flash.tags.Tag; import com.jpexs.helpers.ByteArrayRange; import com.jpexs.helpers.Helper; +import java.util.LinkedHashSet; /** * @@ -28,18 +29,22 @@ import com.jpexs.helpers.Helper; */ public abstract class CharacterTag extends Tag implements CharacterIdTag { - protected String className; + protected LinkedHashSet classNames = new LinkedHashSet<>(); public CharacterTag(SWF swf, int id, String name, ByteArrayRange data) { super(swf, id, name, data); } - public void setClassName(String className) { - this.className = className; + public void setClassNames(LinkedHashSet classNames) { + this.classNames = new LinkedHashSet<>(classNames); } - public String getClassName() { - return className; + public LinkedHashSet getClassNames() { + return new LinkedHashSet<>(classNames); + } + + public void addClassName(String className) { + classNames.add(className); } @Override @@ -48,8 +53,8 @@ public abstract class CharacterTag extends Tag implements CharacterIdTag { if (exportName != null) { nameAppend = ": " + Helper.escapePCodeString(exportName); } - if (className != null) { - nameAppend = ": " + Helper.escapePCodeString(className); + if (!classNames.isEmpty()) { + nameAppend = ": " + Helper.joinEscapePCodeString(", ", classNames); } return tagName + " (" + getCharacterId() + nameAppend + ")"; } @@ -57,11 +62,11 @@ public abstract class CharacterTag extends Tag implements CharacterIdTag { @Override public String getExportFileName() { String result = super.getExportFileName(); - return result + "_" + getCharacterId() + (exportName != null ? "_" + exportName : "") + (className != null ? "_" + className : ""); + return result + "_" + getCharacterId() + (exportName != null ? "_" + exportName : "") + (!classNames.isEmpty() ? "_" + String.join("___",classNames) : ""); } public String getCharacterExportFileName() { - return getCharacterId() + (exportName != null ? "_" + exportName : "") + (className != null ? "_" + className : ""); + return getCharacterId() + (exportName != null ? "_" + exportName : "") + (!classNames.isEmpty() ? "_" + String.join("___",classNames) : ""); } protected String exportName; diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/base/FontTag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/base/FontTag.java index 8bb0db7aa..efea03a1e 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/base/FontTag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/base/FontTag.java @@ -211,8 +211,8 @@ public abstract class FontTag extends DrawableTag implements AloneTag { if (exportName != null) { nameAppendList.add(exportName); } - if (className != null) { - nameAppendList.add(Helper.escapePCodeString(className)); + if (!classNames.isEmpty()) { + nameAppendList.add(Helper.joinEscapePCodeString(", ", classNames)); } String fontName = getFontNameIntag(); if (fontName != null) { diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/timeline/Timeline.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/timeline/Timeline.java index fadb155f9..b8aacbf71 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/timeline/Timeline.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/timeline/Timeline.java @@ -1288,7 +1288,7 @@ public class Timeline { exporter.endGroup(); } Matrix mat = Matrix.getTranslateInstance(rect.xMin, rect.yMin).preConcatenate(new Matrix(layer.matrix)); - exporter.addUse(mat, boundRect, assetName, layer.instanceName, scalingGrid == null ? null : scalingGrid.splitter, String.valueOf(drawable.getCharacterId()), drawable.getClassName()); + exporter.addUse(mat, boundRect, assetName, layer.instanceName, scalingGrid == null ? null : scalingGrid.splitter, String.valueOf(drawable.getCharacterId()), String.join("___", drawable.getClassNames())); } } } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/xfl/XFLConverter.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/xfl/XFLConverter.java index 0c2c03c73..e30f4d55f 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/xfl/XFLConverter.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/xfl/XFLConverter.java @@ -3308,16 +3308,26 @@ public class XFLConverter { private static Map getCharacterClasses(ReadOnlyTagList tags) { Map ret = new HashMap<>(); + Set multipleClassesCharacters = new HashSet<>(); for (Tag t : tags) { if (t instanceof SymbolClassTag) { SymbolClassTag sc = (SymbolClassTag) t; for (int i = 0; i < sc.tags.size(); i++) { if (!ret.containsKey(sc.tags.get(i)) && !ret.containsValue(sc.names.get(i))) { ret.put(sc.tags.get(i), sc.names.get(i)); + } else if (ret.containsKey(sc.tags.get(i))){ + multipleClassesCharacters.add(sc.tags.get(i)); } } } } + + for (int i: multipleClassesCharacters) { + ret.remove(i); + } + + //TODO: handle multiple classes assigned to same character (Can happen when Embed tag used with identical file) + return ret; } diff --git a/libsrc/ffdec_lib/src/com/jpexs/helpers/Helper.java b/libsrc/ffdec_lib/src/com/jpexs/helpers/Helper.java index 1e322a363..a89437996 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/helpers/Helper.java +++ b/libsrc/ffdec_lib/src/com/jpexs/helpers/Helper.java @@ -241,6 +241,17 @@ public class Helper { return ret.toString(); } + public static String joinEscapePCodeString(String glue, Collection collection) { + StringBuilder sb = new StringBuilder(); + for (String s:collection) { + if (sb.length() > 0) { + sb.append(glue); + } + sb.append(escapePCodeString(s)); + } + return sb.toString(); + } + /** * Escapes string by adding backslashes * diff --git a/src/com/jpexs/decompiler/flash/gui/ImagePanel.java b/src/com/jpexs/decompiler/flash/gui/ImagePanel.java index fd6a49a6a..70c03aeff 100644 --- a/src/com/jpexs/decompiler/flash/gui/ImagePanel.java +++ b/src/com/jpexs/decompiler/flash/gui/ImagePanel.java @@ -3373,7 +3373,7 @@ public final class ImagePanel extends JPanel implements MediaDisplay { if (cls == null) { continue; } - if (cls.equals(c.getClassName())) { + if (c.getClassNames().contains(cls)) { sounds.set(k, cid); } }