diff --git a/CHANGELOG.md b/CHANGELOG.md index 8727aae08..422cf1814 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -36,6 +36,7 @@ All notable changes to this project will be documented in this file. - PlaceObject tag - do not display export name twice - Loading nested characters when Importassets tag used - Hide various actions for imported tags +- Clone tag ### Changed - Quick search needs minimum of 3 characters 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 d9561f36f..1526238a0 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/SWF.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/SWF.java @@ -1244,7 +1244,7 @@ public final class SWF implements SWFContainerItem, Timelined, Openable { } for (Tag tag : getTags()) { - if (tag.isModified()) { + if (tag.isModified() && !tag.isReadOnly()) { return true; } } @@ -1531,6 +1531,7 @@ public final class SWF implements SWFContainerItem, Timelined, Openable { } int pos = 0; + Set importedCharIds = new HashSet<>(); Set importedTagPos = new HashSet<>(); List importedCharacters = new ArrayList<>(); for (String key : importedMap2.keySet()) { @@ -1542,15 +1543,26 @@ public final class SWF implements SWFContainerItem, Timelined, Openable { int ip = 0; for (Tag cht : iSwf.tags) { if ((cht instanceof CharacterIdTag) && (((CharacterIdTag) cht).getCharacterId() == exportedId) && !(cht instanceof PlaceObjectTypeTag) && !(cht instanceof RemoveTag)) { - CharacterIdTag ch = (CharacterIdTag) cht; - ch.setCharacterId(importedId); - setImportedDeep(cht, false); - tags.add(p + 1 + pos, cht); + + importedCharIds.add(exportedId); + Tag chtCopy = null; + try { + chtCopy = cht.cloneTag(); + CharacterIdTag ch = (CharacterIdTag) chtCopy; + ch.setCharacterId(importedId); + setImportedDeep(cht, false); + + tags.add(p + 1 + pos, chtCopy); + } catch (InterruptedException | IOException ex) { + Logger.getLogger(SWF.class.getName()).log(Level.SEVERE, null, ex); + } + importedTagPos.add(ip); if (cht instanceof CharacterTag) { - importedCharacters.add((CharacterTag)cht); + importedCharacters.add((CharacterTag)chtCopy); } else { - cht.setSwf(this); + chtCopy.setTimelined(this); + chtCopy.setSwf(this); } pos++; } @@ -1566,15 +1578,24 @@ public final class SWF implements SWFContainerItem, Timelined, Openable { int ip = 0; for (Tag cht : iSwf.tags) { if (!importedTagPos.contains(ip) && (cht instanceof CharacterIdTag) && (((CharacterIdTag) cht).getCharacterId() == exportedId) && !(cht instanceof PlaceObjectTypeTag) && !(cht instanceof RemoveTag)) { - CharacterIdTag ch = (CharacterIdTag) cht; + + importedCharIds.add(exportedId); + Tag chtCopy = null; + try { + chtCopy = cht.cloneTag(); + CharacterIdTag ch = (CharacterIdTag) chtCopy; + ch.setCharacterId(importedId); + setImportedDeep(chtCopy, false); - ch.setCharacterId(importedId); - setImportedDeep(cht, false); - tags.add(p + 1 + pos, cht); + tags.add(p + 1 + pos, chtCopy); + } catch (InterruptedException | IOException ex) { + Logger.getLogger(SWF.class.getName()).log(Level.SEVERE, null, ex); + } if (cht instanceof CharacterTag) { - importedCharacters.add((CharacterTag)cht); + importedCharacters.add((CharacterTag)chtCopy); } else { - cht.setSwf(this); + chtCopy.setSwf(this); + chtCopy.setTimelined(this); } pos++; } @@ -1588,16 +1609,22 @@ public final class SWF implements SWFContainerItem, Timelined, Openable { ich.getNeededCharactersDeep(needed); Map replaceCharactersMap = new HashMap<>(); for (int n:needed) { + if (importedCharIds.contains(n)) { + continue; + } CharacterTag cht = iSwf.getCharacter(n); - if (cht.getSwf() != iSwf) { - continue; //already imported - } int importedId = newId++; - cht.setSwf(this); + CharacterTag chtCopy = null; + try { + chtCopy = (CharacterTag)cht.cloneTag(); + } catch (InterruptedException | IOException ex) { + Logger.getLogger(SWF.class.getName()).log(Level.SEVERE, null, ex); + } + chtCopy.setSwf(this); replaceCharactersMap.put(n, importedId); - cht.setCharacterId(importedId); - setImportedDeep(cht, true); - tags.add(p + 1 + pos, cht); + chtCopy.setCharacterId(importedId); + setImportedDeep(chtCopy, true); + tags.add(p + 1 + pos, chtCopy); pos++; } @@ -1615,8 +1642,9 @@ public final class SWF implements SWFContainerItem, Timelined, Openable { int to = replaceCharactersMap2.get(from); ich.replaceCharacter(from, to); } - ich.setModified(false); + //ich.setModified(false); setSwfDeep(ich); + ich.setTimelined(this); } updateCharacters(); } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/Tag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/Tag.java index 58ddbbddd..27208ea60 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/Tag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/Tag.java @@ -442,8 +442,8 @@ public abstract class Tag implements NeedsCharacters, Exportable, Serializable { public Tag cloneTag() throws InterruptedException, IOException { byte[] data = getData(); - SWFInputStream tagDataStream = new SWFInputStream(swf, data, getDataPos(), data.length); - TagStub copy = new TagStub(swf, getId(), "Unresolved", getOriginalRange(), tagDataStream); + SWFInputStream tagDataStream = new SWFInputStream(swf, data, 0, data.length); + TagStub copy = new TagStub(swf, getId(), "Unresolved", new ByteArrayRange(data), tagDataStream); copy.forceWriteAsLong = forceWriteAsLong; return SWFInputStream.resolveTag(copy, 0, false, true, false, false); } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/timeline/Frame.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/timeline/Frame.java index 106ebd7b1..84d623219 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/timeline/Frame.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/timeline/Frame.java @@ -118,7 +118,7 @@ public class Frame implements TreeItem, Exportable { public boolean isAllInnerTagsModified() { for (Tag t : allInnerTags) { - if (t.isModified()) { + if (t.isModified() && !t.isReadOnly()) { return true; } } @@ -128,12 +128,12 @@ public class Frame implements TreeItem, Exportable { @Override public boolean isModified() { for (Tag t : innerTags) { - if (t.isModified()) { + if (t.isModified() && !t.isReadOnly()) { return true; } } for (Tag t : actions) { - if (t.isModified()) { + if (t.isModified() && !t.isReadOnly()) { return true; } } @@ -142,7 +142,7 @@ public class Frame implements TreeItem, Exportable { return true; } } - if (showFrameTag != null && showFrameTag.isModified()) { + if (showFrameTag != null && showFrameTag.isModified() && !showFrameTag.isReadOnly()) { return true; } return false; diff --git a/src/com/jpexs/decompiler/flash/gui/taglistview/TagListTreeCellRenderer.java b/src/com/jpexs/decompiler/flash/gui/taglistview/TagListTreeCellRenderer.java index 3b5b935b5..bd3c9bb05 100644 --- a/src/com/jpexs/decompiler/flash/gui/taglistview/TagListTreeCellRenderer.java +++ b/src/com/jpexs/decompiler/flash/gui/taglistview/TagListTreeCellRenderer.java @@ -105,6 +105,9 @@ public class TagListTreeCellRenderer extends DefaultTreeCellRenderer { } else { isModified = val.isModified(); } + if (isReadOnly) { + isModified = false; + } if (isModified) { if (boldFont == null) { Font font = getFont(); diff --git a/src/com/jpexs/decompiler/flash/gui/tagtree/TagTree.java b/src/com/jpexs/decompiler/flash/gui/tagtree/TagTree.java index 18b9c2288..451a89e08 100644 --- a/src/com/jpexs/decompiler/flash/gui/tagtree/TagTree.java +++ b/src/com/jpexs/decompiler/flash/gui/tagtree/TagTree.java @@ -181,6 +181,11 @@ public class TagTree extends AbstractTagTree { } boolean isModified = val.isModified(); + + if (isReadOnly) { + isModified = false; + } + if (isModified) { if (boldFont == null) { Font font = getFont();