From 4f3bbe732b2ae0a62ad5ba77355451d34c280bf0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jindra=20Pet=C5=99=C3=ADk?= Date: Sat, 19 Nov 2022 22:53:19 +0100 Subject: [PATCH] Added Flattened ActionScript packages (one row per package instead package tree), can be turned off in settings Changes ActionScript packages are by default flattened --- CHANGELOG.md | 2 ++ .../src/com/jpexs/decompiler/flash/SWF.java | 13 +++++++++ .../flash/configuration/Configuration.java | 4 +++ .../decompiler/flash/timeline/AS2Package.java | 9 +++++- .../decompiler/flash/timeline/AS3Package.java | 8 +++++- .../decompiler/flash/timeline/Timeline.java | 28 +++++++++++++++++-- .../decompiler/flash/gui/MainFrameMenu.java | 16 +++++++++++ .../jpexs/decompiler/flash/gui/MainPanel.java | 23 +++++++++++++++ .../flash/gui/abc/ClassesListTreeModel.java | 21 ++++++++++++-- .../locales/AdvancedSettingsDialog.properties | 4 +++ .../AdvancedSettingsDialog_cs.properties | 5 +++- .../flash/gui/locales/MainFrame.properties | 4 ++- .../flash/gui/locales/MainFrame_cs.properties | 4 ++- .../flash/gui/tagtree/TagTreeModel.java | 3 +- 14 files changed, 132 insertions(+), 12 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0aed7ab1a..06b84241d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,7 @@ All notable changes to this project will be documented in this file. - [#1501] Bulk import shapes - [#1680] Pinning items - Indices in brackets for items with same name (like two subsequent DoAction tags) +- Flattened ActionScript packages (one row per package instead package tree), can be turned off in settings ### Fixed - [#1869] Replace references now replaces all references, not just PlaceObject @@ -45,6 +46,7 @@ All notable changes to this project will be documented in this file. - GFX - DefineExternalImage2 no longer handled as character - Raw editor does not show tag name in the tree (it's now in the new pinnable head) - DoInitAction is not shown in resources/sprites section, only in scripts +- ActionScript packages are by default flattened (can be turned off in settings) ## [16.3.1] - 2022-11-14 ### Fixed 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 c876558a0..8d2c59c33 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/SWF.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/SWF.java @@ -1973,6 +1973,19 @@ public final class SWF implements SWFContainerItem, Timelined { } private String getASMPath(boolean exportFileName, TreeItem treeItem) { + + if (treeItem instanceof AS2Package) { + AS2Package pkg = (AS2Package) treeItem; + if (pkg.isFlat()) { + String parts[] = pkg.toString().split("\\."); + for (int i = 0; i < parts.length; i++) { + parts[i] = Helper.makeFileName(parts[i]); + } + return String.join(File.separator, parts); + } + } + + if (!exportFileName) { return treeItem.toString(); } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/configuration/Configuration.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/configuration/Configuration.java index f90a390d8..12e00a956 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/configuration/Configuration.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/configuration/Configuration.java @@ -808,6 +808,10 @@ public final class Configuration { @ConfigurationDefaultString("") public static ConfigurationItem pinnedItemsTagListPaths = null; + @ConfigurationDefaultBoolean(true) + @ConfigurationCategory("script") + public static ConfigurationItem flattenASPackages = null; + private enum OSId { WINDOWS, OSX, UNIX } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/timeline/AS2Package.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/timeline/AS2Package.java index e337d9155..0387b2274 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/timeline/AS2Package.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/timeline/AS2Package.java @@ -39,11 +39,14 @@ public class AS2Package implements TreeItem { public Map subPackages = new TreeMap<>(); public Map scripts = new TreeMap<>(); + + private boolean flat; - public AS2Package(String name, AS2Package parent, SWF swf) { + public AS2Package(String name, AS2Package parent, SWF swf, boolean flat) { this.name = name; this.parent = parent; this.swf = swf; + this.flat = flat; } @Override @@ -133,4 +136,8 @@ public class AS2Package implements TreeItem { } return false; } + + public boolean isFlat() { + return flat; + } } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/timeline/AS3Package.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/timeline/AS3Package.java index 61d4a5806..7e1642574 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/timeline/AS3Package.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/timeline/AS3Package.java @@ -43,9 +43,12 @@ public class AS3Package extends AS3ClassTreeItem { private List sortedPackages; private List sortedScripts; + + private boolean flat; - public AS3Package(String packageName, SWF swf) { + public AS3Package(String packageName, SWF swf, boolean flat) { super(packageName, "", null); + this.flat = flat; this.swf = swf; this.packageName = packageName; } @@ -148,6 +151,9 @@ public class AS3Package extends AS3ClassTreeItem { @Override public String toString() { + if (flat) { + return packageName; + } return IdentifiersDeobfuscation.printIdentifier(true, packageName); } 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 25f9508dc..95041af14 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 @@ -18,6 +18,7 @@ package com.jpexs.decompiler.flash.timeline; import com.jpexs.decompiler.flash.SWF; import com.jpexs.decompiler.flash.TagRemoveListener; +import com.jpexs.decompiler.flash.configuration.Configuration; import com.jpexs.decompiler.flash.exporters.BlendModeSetable; import com.jpexs.decompiler.flash.exporters.FrameExporter; import com.jpexs.decompiler.flash.exporters.commonshape.ExportRectangle; @@ -191,7 +192,7 @@ public class Timeline { this.displayRect = displayRect; this.frameRate = swf.frameRate; this.timelined = timelined; - as2RootPackage = new AS2Package(null, null, swf); + as2RootPackage = new AS2Package(null, null, swf, false); } public final int getMaxDepth() { @@ -256,7 +257,7 @@ public class Timeline { this.displayRect = displayRect; this.frameRate = swf.frameRate; this.timelined = timelined; - as2RootPackage = new AS2Package(null, null, swf); + as2RootPackage = new AS2Package(null, null, swf, false); } public int getFrameWithLabel(String label) { @@ -479,10 +480,31 @@ public class Timeline { String[] pathParts = path.contains(".") ? path.split("\\.") : new String[]{path}; AS2Package pkg = as2RootPackage; for (int pos = 0; pos < pathParts.length - 1; pos++) { + if (Configuration.flattenASPackages.get()) { + boolean isNamedPackages = "__Packages".equals(pathParts[0]); + + if (isNamedPackages && pos == 0) { + //nothing + } else { + String fullPath; + if (isNamedPackages) { + fullPath = path.substring(pathParts[0].length() + 1, path.length() - pathParts[pathParts.length - 1].length() - 1); + } else { + fullPath = path.substring(0, path.length() - pathParts[pathParts.length - 1].length() - 1); + } + AS2Package subPkg = pkg.subPackages.get(fullPath); + if (subPkg == null) { + subPkg = new AS2Package(fullPath, pkg, swf, true); + pkg.subPackages.put(fullPath, subPkg); + } + pkg = subPkg; + break; + } + } String pathPart = pathParts[pos]; AS2Package subPkg = pkg.subPackages.get(pathPart); if (subPkg == null) { - subPkg = new AS2Package(pathPart, pkg, swf); + subPkg = new AS2Package(pathPart, pkg, swf, false); pkg.subPackages.put(pathPart, subPkg); } diff --git a/src/com/jpexs/decompiler/flash/gui/MainFrameMenu.java b/src/com/jpexs/decompiler/flash/gui/MainFrameMenu.java index c18e59b6b..fc750d410 100644 --- a/src/com/jpexs/decompiler/flash/gui/MainFrameMenu.java +++ b/src/com/jpexs/decompiler/flash/gui/MainFrameMenu.java @@ -79,6 +79,9 @@ public abstract class MainFrameMenu implements MenuBuilder { private SWF swf; private ConfigurationItemChangeListener configListenerAutoDeobfuscate; + + private ConfigurationItemChangeListener configListenerFlattenASPackages; + private ConfigurationItemChangeListener configListenerSimplifyExpressions; @@ -651,6 +654,13 @@ public abstract class MainFrameMenu implements MenuBuilder { Configuration.autoOpenLoadedSWFs.set(selected); } + + protected void flattenASPackagesActionPerformed(ActionEvent evt) { + AbstractButton button = (AbstractButton) evt.getSource(); + boolean selected = button.isSelected(); + + Configuration.flattenASPackages.set(selected); + } protected void autoRenameIdentifiersActionPerformed(ActionEvent evt) { AbstractButton button = (AbstractButton) evt.getSource(); @@ -1056,6 +1066,7 @@ public abstract class MainFrameMenu implements MenuBuilder { addToggleMenuItem("/settings/gotoMainClassOnStartup", translate("menu.settings.gotoMainClassOnStartup"), null, null, this::gotoDucumentClassOnStartupActionPerformed, 0, null); addToggleMenuItem("/settings/autoRenameIdentifiers", translate("menu.settings.autoRenameIdentifiers"), null, null, this::autoRenameIdentifiersActionPerformed, 0, null); addToggleMenuItem("/settings/autoOpenLoadedSWFs", translate("menu.settings.autoOpenLoadedSWFs"), null, null, this::autoOpenLoadedSWFsActionPerformed, 0, null); + addToggleMenuItem("/settings/flattenASPackages", translate("menu.settings.flattenASPackages"), null, null, this::flattenASPackagesActionPerformed, 0, null); if (Platform.isWindows()) { addToggleMenuItem("/settings/associate", translate("menu.settings.addtocontextmenu"), null, null, this::associateActionPerformed, 0, null); } @@ -1125,6 +1136,11 @@ public abstract class MainFrameMenu implements MenuBuilder { Configuration.autoOpenLoadedSWFs.addListener(configListenerAutoOpenLoadedSWFs = (Boolean newValue) -> { setMenuChecked("/settings/autoOpenLoadedSWFs", newValue); }); + + setMenuChecked("/settings/flattenASPackages", Configuration.flattenASPackages.get()); + Configuration.flattenASPackages.addListener(configListenerFlattenASPackages = (Boolean newValue) -> { + setMenuChecked("/settings/flattenASPackages", newValue); + }); /* if (externalFlashPlayerUnavailable) { diff --git a/src/com/jpexs/decompiler/flash/gui/MainPanel.java b/src/com/jpexs/decompiler/flash/gui/MainPanel.java index 51eace15b..830b57ac4 100644 --- a/src/com/jpexs/decompiler/flash/gui/MainPanel.java +++ b/src/com/jpexs/decompiler/flash/gui/MainPanel.java @@ -33,6 +33,7 @@ import com.jpexs.decompiler.flash.abc.avm2.deobfuscation.DeobfuscationLevel; import com.jpexs.decompiler.flash.abc.types.traits.Trait; import com.jpexs.decompiler.flash.configuration.Configuration; import com.jpexs.decompiler.flash.configuration.ConfigurationItem; +import com.jpexs.decompiler.flash.configuration.ConfigurationItemChangeListener; import com.jpexs.decompiler.flash.configuration.CustomConfigurationKeys; import com.jpexs.decompiler.flash.configuration.SwfSpecificCustomConfiguration; import com.jpexs.decompiler.flash.dumpview.DumpInfo; @@ -1191,6 +1192,14 @@ public final class MainPanel extends JPanel implements TreeSelectionListener, Se calculateMissingNeededThread = new CalculateMissingNeededThread(); calculateMissingNeededThread.start(); pinsPanel.load(); + + Configuration.flattenASPackages.addListener(new ConfigurationItemChangeListener() { + @Override + public void configurationItemChanged(Boolean newValue) { + resetAllTimelines(); + refreshTree(); + } + }); } public void closeTagTreeSearch() { @@ -1201,6 +1210,20 @@ public final class MainPanel extends JPanel implements TreeSelectionListener, Se searchPanel.setVisible(false); } + public void resetAllTimelines() { + List swfsLists = new ArrayList<>(swfs); + List allSwfs = new ArrayList<>(); + for (SWFList swfList : swfsLists) { + allSwfs.addAll(swfList); + for (SWF swf : swfList) { + Main.populateSwfs(swf, allSwfs); + } + } + for (SWF swf : allSwfs) { + swf.resetTimeline(); + } + } + public void loadSwfAtPos(SWFList newSwfs, int index) { View.checkAccess(); diff --git a/src/com/jpexs/decompiler/flash/gui/abc/ClassesListTreeModel.java b/src/com/jpexs/decompiler/flash/gui/abc/ClassesListTreeModel.java index 2495dd145..78bd30c6f 100644 --- a/src/com/jpexs/decompiler/flash/gui/abc/ClassesListTreeModel.java +++ b/src/com/jpexs/decompiler/flash/gui/abc/ClassesListTreeModel.java @@ -46,14 +46,17 @@ public class ClassesListTreeModel extends AS3ClassTreeItem implements TreeModel private final AS3Package root; private final List listeners = new ArrayList<>(); + + private boolean flat = true; public List getList() { return list; } - public ClassesListTreeModel(SWF swf) { + public ClassesListTreeModel(SWF swf, boolean flat) { super(null, null, null); - root = new AS3Package(null, swf); + this.flat = flat; + root = new AS3Package(null, swf, flat); this.swf = swf; this.list = swf.getAS3Packs(); setFilter(null); @@ -111,12 +114,24 @@ public class ClassesListTreeModel extends AS3ClassTreeItem implements TreeModel } private AS3Package ensurePackage(DottedChain packageStr) { + if (flat) { + String fullName = packageStr.toPrintableString(true); + if (fullName.length() == 0) { + return root; + } + AS3Package pkg = root.getSubPackage(fullName); + if (pkg == null) { + pkg = new AS3Package(fullName, swf, true); + root.addSubPackage(pkg); + } + return pkg; + } AS3Package parent = root; for (int i = 0; i < packageStr.size(); i++) { String pathElement = packageStr.get(i); AS3Package pkg = parent.getSubPackage(pathElement); if (pkg == null) { - pkg = new AS3Package(pathElement, swf); + pkg = new AS3Package(pathElement, swf, false); parent.addSubPackage(pkg); } diff --git a/src/com/jpexs/decompiler/flash/gui/locales/AdvancedSettingsDialog.properties b/src/com/jpexs/decompiler/flash/gui/locales/AdvancedSettingsDialog.properties index 4e049b7e1..921a9899f 100644 --- a/src/com/jpexs/decompiler/flash/gui/locales/AdvancedSettingsDialog.properties +++ b/src/com/jpexs/decompiler/flash/gui/locales/AdvancedSettingsDialog.properties @@ -617,3 +617,7 @@ config.description.pinnedItemsTagTreePaths = Paths of nodes of tag tree which ar config.name.pinnedItemsTagListPaths = Pinned items paths in tag list view tree config.description.pinnedItemsTagListPaths = Paths of nodes of tag list view tree which are pinned. + +config.name.flattenASPackages = Flatten ActionScript packages +config.description.flattenASPackages = Make one item per package instead of package tree. + diff --git a/src/com/jpexs/decompiler/flash/gui/locales/AdvancedSettingsDialog_cs.properties b/src/com/jpexs/decompiler/flash/gui/locales/AdvancedSettingsDialog_cs.properties index 37a0b9ad0..dfad233d0 100644 --- a/src/com/jpexs/decompiler/flash/gui/locales/AdvancedSettingsDialog_cs.properties +++ b/src/com/jpexs/decompiler/flash/gui/locales/AdvancedSettingsDialog_cs.properties @@ -603,4 +603,7 @@ config.name.pinnedItemsTagTreePaths = Cesty p\u0159ipnut\u00fdch polo\u017eek v config.description.pinnedItemsTagTreePaths = Cesty uzl\u016f v stromu tag\u016f, kter\u00e9 jsou p\u0159ipnuty. config.name.pinnedItemsTagListPaths = Cesty p\u0159ipnut\u00fdch polo\u017eek v stromu seznamu tag\u016f -config.description.pinnedItemsTagListPaths = Cesty uzl\u016f v stromu seznamu tag\u016f, kter\u00e9 jsou p\u0159ipnuty. \ No newline at end of file +config.description.pinnedItemsTagListPaths = Cesty uzl\u016f v stromu seznamu tag\u016f, kter\u00e9 jsou p\u0159ipnuty. + +config.name.flattenASPackages = Zplo\u0161tit bal\u00ed\u010dky ActionScriptu +config.description.flattenASPackages = Zobraz\u00ed bal\u00ed\u010dky jako jednu polo\u017eku pro bal\u00ed\u010dek m\u00edsto stromu bal\u00ed\u010dku. \ No newline at end of file diff --git a/src/com/jpexs/decompiler/flash/gui/locales/MainFrame.properties b/src/com/jpexs/decompiler/flash/gui/locales/MainFrame.properties index 72721355a..6c823de20 100644 --- a/src/com/jpexs/decompiler/flash/gui/locales/MainFrame.properties +++ b/src/com/jpexs/decompiler/flash/gui/locales/MainFrame.properties @@ -976,4 +976,6 @@ contextmenu.unpin = Unpin contextmenu.unpin.all = Unpin all contextmenu.unpin.others = Unpin others -menu.tools.otherTools.clearPinnedItems = Clear pinned items \ No newline at end of file +menu.tools.otherTools.clearPinnedItems = Clear pinned items + +menu.settings.flattenASPackages = Flatten ActionScript packages \ No newline at end of file diff --git a/src/com/jpexs/decompiler/flash/gui/locales/MainFrame_cs.properties b/src/com/jpexs/decompiler/flash/gui/locales/MainFrame_cs.properties index 7b7eddd97..00555236c 100644 --- a/src/com/jpexs/decompiler/flash/gui/locales/MainFrame_cs.properties +++ b/src/com/jpexs/decompiler/flash/gui/locales/MainFrame_cs.properties @@ -948,4 +948,6 @@ contextmenu.unpin = Odepnout contextmenu.unpin.all = Odepnout v\u0161e contextmenu.unpin.others = Odepnout ostatn\u00ed -menu.tools.otherTools.clearPinnedItems = Vymazat p\u0159ipnut\u00e9 polo\u017eky \ No newline at end of file +menu.tools.otherTools.clearPinnedItems = Vymazat p\u0159ipnut\u00e9 polo\u017eky + +menu.settings.flattenASPackages = Zplo\u0161tit bal\u00ed\u010dky ActionScriptu \ No newline at end of file diff --git a/src/com/jpexs/decompiler/flash/gui/tagtree/TagTreeModel.java b/src/com/jpexs/decompiler/flash/gui/tagtree/TagTreeModel.java index 5d14c550b..f532cfe23 100644 --- a/src/com/jpexs/decompiler/flash/gui/tagtree/TagTreeModel.java +++ b/src/com/jpexs/decompiler/flash/gui/tagtree/TagTreeModel.java @@ -17,6 +17,7 @@ package com.jpexs.decompiler.flash.gui.tagtree; import com.jpexs.decompiler.flash.SWF; +import com.jpexs.decompiler.flash.configuration.Configuration; import com.jpexs.decompiler.flash.gui.AppStrings; import com.jpexs.decompiler.flash.gui.TreeNodeType; import com.jpexs.decompiler.flash.gui.abc.ClassesListTreeModel; @@ -287,7 +288,7 @@ public class TagTreeModel extends AbstractTagTreeModel { Map currentTagScriptCache = new HashMap<>(); if (swf.isAS3()) { if (!swf.getAbcList().isEmpty()) { - nodeList.add(new ClassesListTreeModel(swf)); + nodeList.add(new ClassesListTreeModel(swf, Configuration.flattenASPackages.get())); } } else { List subNodes = swf.getFirstLevelASMNodes(currentTagScriptCache);