From 6d656228a24f6ca429e913cdae0d230b4669255e Mon Sep 17 00:00:00 2001 From: Exund Date: Sun, 28 Nov 2021 22:55:22 +0100 Subject: [PATCH] Frame dependencies Show needed characters for a frame and frames depending on a character in the "Basic tag info" box --- .../src/com/jpexs/decompiler/flash/SWF.java | 63 ++++++++++++++----- .../com/jpexs/decompiler/flash/tags/Tag.java | 5 ++ .../decompiler/flash/timeline/Frame.java | 11 ++++ .../jpexs/decompiler/flash/gui/MainPanel.java | 16 ++++- .../decompiler/flash/gui/TagInfoPanel.java | 55 +++++++++++----- .../flash/gui/locales/MainFrame.properties | 4 +- 6 files changed, 121 insertions(+), 33 deletions(-) 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 05bcdf14b..c6fc16021 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/SWF.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/SWF.java @@ -304,6 +304,9 @@ public final class SWF implements SWFContainerItem, Timelined { @Internal private volatile Map> dependentCharacters; + @Internal + private volatile Map> dependentFrames; + @Internal private volatile List abcList; @@ -488,21 +491,21 @@ public final class SWF implements SWFContainerItem, Timelined { Map> dep = new HashMap<>(); for (Tag tag : getTags()) { if (tag instanceof CharacterTag) { - int characterId = ((CharacterTag) tag).getCharacterId(); - Set needed = new HashSet<>(); - tag.getNeededCharacters(needed); - for (Integer needed1 : needed) { - Set s = dep.get(needed1); - if (s == null) { - s = new HashSet<>(); - dep.put(needed1, s); - } - - s.add(characterId); - } - } + int characterId = ((CharacterTag) tag).getCharacterId(); + Set needed = new HashSet<>(); + tag.getNeededCharacters(needed); + for (Integer needed1 : needed) { + Set s = dep.get(needed1); + if (s == null) { + s = new HashSet<>(); + dep.put(needed1, s); } + s.add(characterId); + } + } + } + dependentCharacters = dep; } } @@ -545,6 +548,38 @@ public final class SWF implements SWFContainerItem, Timelined { return dependents; } + + public void computeDependentFrames() { + Map> dep = new HashMap<>(); + for (int i = 0; i < timeline.getFrameCount(); i++) { + Frame frame = timeline.getFrame(i); + Set needed = new HashSet<>(); + frame.getNeededCharacters(needed); + for (Integer needed1 : needed) { + Set s = dep.get(needed1); + if (s == null) { + s = new HashSet<>(); + dep.put(needed1, s); + } + + s.add(i); + } + } + + dependentFrames = dep; + } + + public Set getDependentFrames(int characterId) { + if (dependentFrames == null) { + synchronized (this) { + if (dependentFrames == null) { + computeDependentFrames(); + } + } + } + + return dependentFrames.get(characterId); + } public CharacterTag getCharacter(int characterId) { return getCharacters().get(characterId); @@ -1446,7 +1481,7 @@ public final class SWF implements SWFContainerItem, Timelined { } } - public void assignExportNamesToSymbols() { + public void assignExportNamesToSymbols() { HashMap exportNames = new HashMap<>(); for (Tag t : getTags()) { if (t instanceof ExportAssetsTag) { 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 620c40e52..4918bd5cc 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 @@ -684,6 +684,11 @@ public abstract class Tag implements NeedsCharacters, Exportable, Serializable { tagInfo.addInfo("general", "dependentCharacters", Helper.joinStrings(dependent, ", ")); } } + + Set dependent2 = swf.getDependentFrames(characterId); + if(dependent2 != null && dependent2.size() > 0) { + tagInfo.addInfo("general", "dependentFrames", Helper.joinStrings(dependent2, ", ")); + } } } } 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 386b21041..2d50e89bf 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 @@ -22,6 +22,7 @@ import com.jpexs.decompiler.flash.tags.ShowFrameTag; import com.jpexs.decompiler.flash.tags.Tag; import com.jpexs.decompiler.flash.tags.base.ASMSourceContainer; import com.jpexs.decompiler.flash.tags.base.Exportable; +import com.jpexs.decompiler.flash.tags.base.PlaceObjectTypeTag; import com.jpexs.decompiler.flash.treeitems.TreeItem; import com.jpexs.decompiler.flash.types.RGB; import com.jpexs.decompiler.flash.types.RGBA; @@ -29,6 +30,7 @@ import com.jpexs.decompiler.flash.types.SOUNDINFO; import java.util.ArrayList; import java.util.List; import java.util.Objects; +import java.util.Set; import java.util.TreeMap; /** @@ -133,4 +135,13 @@ public class Frame implements TreeItem, Exportable { } return false; } + + public void getNeededCharacters(Set needed) { + for (Tag t : innerTags) { + if(t instanceof PlaceObjectTypeTag) { + needed.add(((PlaceObjectTypeTag)t).getCharacterId()); + } + } + needed.remove(-1); + } } diff --git a/src/com/jpexs/decompiler/flash/gui/MainPanel.java b/src/com/jpexs/decompiler/flash/gui/MainPanel.java index 843a8a478..21ed803ff 100644 --- a/src/com/jpexs/decompiler/flash/gui/MainPanel.java +++ b/src/com/jpexs/decompiler/flash/gui/MainPanel.java @@ -1120,7 +1120,7 @@ public final class MainPanel extends JPanel implements TreeSelectionListener, Se tagTree.clearSelection(); for (TreeItem n : nodes) { if (n instanceof ClassesListTreeModel) { - String filterText = filterField.getText(); + String filterText = filterField.getText(); ((ClassesListTreeModel) n).setFilter(filterText); TagTreeModel tm = tagTree.getModel(); TreePath path = tm.getTreePath(n); @@ -3723,6 +3723,20 @@ public final class MainPanel extends JPanel implements TreeSelectionListener, Se } else { showDetail(DETAILCARDEMPTYPANEL); } + } else if (treeItem instanceof Frame) { + Frame frame = (Frame) treeItem; + Set needed = new LinkedHashSet<>(); + + frame.getNeededCharacters(needed); + + if (!needed.isEmpty()) { + TagInfo tagInfo = new TagInfo(); + tagInfo.addInfo("general", "neededCharacters", Helper.joinStrings(needed, ", ")); + tagInfoPanel.setTagInfos(tagInfo); + showDetail(DETAILCARDTAGINFO); + } else { + showDetail(DETAILCARDEMPTYPANEL); + } } else { showDetail(DETAILCARDEMPTYPANEL); } diff --git a/src/com/jpexs/decompiler/flash/gui/TagInfoPanel.java b/src/com/jpexs/decompiler/flash/gui/TagInfoPanel.java index c0e86fdc1..7afe5b73b 100644 --- a/src/com/jpexs/decompiler/flash/gui/TagInfoPanel.java +++ b/src/com/jpexs/decompiler/flash/gui/TagInfoPanel.java @@ -16,11 +16,14 @@ */ package com.jpexs.decompiler.flash.gui; +import com.jpexs.decompiler.flash.SWF; import com.jpexs.decompiler.flash.configuration.Configuration; import com.jpexs.decompiler.flash.tags.TagInfo; +import com.jpexs.decompiler.flash.treeitems.TreeItem; import java.awt.BorderLayout; import java.awt.Color; import java.awt.Font; +import java.net.URI; import java.util.ArrayList; import java.util.Collections; import java.util.List; @@ -62,11 +65,25 @@ public class TagInfoPanel extends JPanel { public void hyperlinkUpdate(HyperlinkEvent hyperLink) { if (HyperlinkEvent.EventType.ACTIVATED.equals(hyperLink.getEventType())) { - String url = hyperLink.getDescription(); - String strId = url.substring(7); - Integer id = Integer.parseInt(strId); + URI url; + try { + url = new URI(hyperLink.getDescription()); + } catch (Exception ex) { + return; + } - mainPanel.setTagTreeSelectedNode(mainPanel.getCurrentSwf().getCharacter(id)); + String scheme = url.getScheme(); + String strId = url.getHost(); + Integer id = Integer.parseInt(strId); + SWF swf = mainPanel.getCurrentSwf(); + + TreeItem item = null; + if ("char".equals(scheme)) { + item = swf.getCharacter(id); + } else if ("frame".equals(scheme)) { + item = swf.getTimeline().getFrame(id); + } + mainPanel.setTagTreeSelectedNode(item); } } @@ -92,16 +109,17 @@ public class TagInfoPanel extends JPanel { } else { result += ""; } - result += ""; - result += mainPanel.translate("tagInfo.header.name"); - result += ""; - result += ""; - result += mainPanel.translate("tagInfo.header.value"); - result += ""; + result += String.format( + "%s", + mainPanel.translate("tagInfo.header.name") + ); + result += String.format( + "%s", + mainPanel.translate("tagInfo.header.value") + ); result += ""; for (TagInfo.TagInfoItem item : items) { - Boolean convertToCharacterList; flipFlop = !flipFlop; @@ -114,7 +132,8 @@ public class TagInfoPanel extends JPanel { String name = item.getName(); String key = "tagInfo." + name; - convertToCharacterList = name.equals("dependentCharacters") || name.equals("neededCharacters"); + boolean frameList = name.equals("dependentFrames"); + boolean convertToLinkList = name.equals("dependentCharacters") || name.equals("neededCharacters") || frameList; try { name = mainPanel.translate(key); @@ -130,11 +149,10 @@ public class TagInfoPanel extends JPanel { if (value instanceof Boolean) { boolean boolValue = (boolean) value; value = boolValue ? AppStrings.translate("yes") : AppStrings.translate("no"); - } else if (convertToCharacterList) { - String strValue = (String) value; - String[] strIds = strValue.split(", "); + } else if (convertToLinkList) { + String[] strIds = ((String) value).split(", "); List sortedIds = new ArrayList<>(); - strValue = ""; + String strValue = ""; for (String strId : strIds) { sortedIds.add(Integer.parseInt(strId)); @@ -142,8 +160,11 @@ public class TagInfoPanel extends JPanel { Collections.sort(sortedIds); + String scheme = frameList ? "frame" : "char"; + for (int id : sortedIds) { - strValue += "" + id + ", "; + int displayId = frameList ? id + 1 : id; + strValue += String.format("%d, ", scheme, id, displayId); } value = strValue.substring(0, strValue.length() - 2); diff --git a/src/com/jpexs/decompiler/flash/gui/locales/MainFrame.properties b/src/com/jpexs/decompiler/flash/gui/locales/MainFrame.properties index 239a9bc61..37929ff55 100644 --- a/src/com/jpexs/decompiler/flash/gui/locales/MainFrame.properties +++ b/src/com/jpexs/decompiler/flash/gui/locales/MainFrame.properties @@ -844,4 +844,6 @@ message.info.importSymbolClass = During importing Symbol-Class, you need to sele This is the same filename as it is used when exported. message.info.importXml = For XML importing, you need a XML file in special format - the format in which FFDec exports.\r\n \ - The best way to create such XML file is to export XML from existing SWF first. \ No newline at end of file + The best way to create such XML file is to export XML from existing SWF first. + +tagInfo.dependentFrames = Dependent Frames \ No newline at end of file