From a30bc9136ffdfe81f00775657a872d651ab3de50 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jindra=20Pet=C5=99=C3=ADk?= Date: Wed, 27 Sep 2023 23:28:13 +0200 Subject: [PATCH] Display compound scripts in separate folders, display script initializer separately. Show imported classes. --- .../decompiler/flash/abc/ScriptPack.java | 20 +++++++--- .../flash/abc/types/ScriptInfo.java | 28 +++++++++++--- .../decompiler/flash/timeline/AS3Package.java | 37 ++++++++++++++++-- .../jpexs/decompiler/graph/DottedChain.java | 13 +++++++ .../jpexs/decompiler/flash/gui/MainPanel.java | 21 +++++++++- .../flash/gui/abc/ClassesListTreeModel.java | 38 ++++++++++++++----- .../flash/gui/tagtree/AbstractTagTree.java | 4 ++ 7 files changed, 135 insertions(+), 26 deletions(-) diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/ScriptPack.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/ScriptPack.java index 3f2e7ad83..6bd55376b 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/ScriptPack.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/ScriptPack.java @@ -112,7 +112,7 @@ public class ScriptPack extends AS3ClassTreeItem { this.path = path; this.allABCs = allAbcs; } - + public DottedChain getPathPackage() { DottedChain packageName = DottedChain.TOPLEVEL; for (int t : traitIndices) { @@ -182,8 +182,8 @@ public class ScriptPack extends AS3ClassTreeItem { List callStack = new ArrayList<>(); callStack.add(abc.bodies.get(sinit_bodyIndex)); abc.bodies.get(sinit_bodyIndex).convert(callStack, abcIndex, convertData, path +/*packageName +*/ "/.scriptinitializer", exportMode, true, sinit_index, scriptIndex, -1, abc, null, new ScopeStack(), GraphTextWriter.TRAIT_SCRIPT_INITIALIZER, writer, new ArrayList<>(), ts, true, new HashSet<>()); - scriptInitializerIsEmpty = !writer.getMark(); - + scriptInitializerIsEmpty = !writer.getMark(); + } ScopeStack scopeStack = new ScopeStack(); scopeStack.push(new GlobalAVM2Item(null, null)); @@ -206,7 +206,17 @@ public class ScriptPack extends AS3ClassTreeItem { //script initializer int script_init = abc.script_info.get(scriptIndex).init_index; int bodyIndex = abc.findBodyIndex(script_init); - if (bodyIndex != -1 && Configuration.enableScriptInitializerDisplay.get()) { + + + if (!isSimple && traitIndices.isEmpty()) { + for (Trait t : abc.script_info.get(scriptIndex).traits.traits) { + String fullName = t.getName(abc).getNameWithNamespace(abc.constants, false).toPrintableString(true); + writer.appendNoHilight("include(\"" + fullName.replace(".", "/") + ".as\");").newLine(); + } + writer.newLine(); + } + + if (bodyIndex != -1 && (isSimple || traitIndices.isEmpty())) { // && Configuration.enableScriptInitializerDisplay.get()) { //Note: There must be trait/method highlight even if the initializer is empty to TraitList in GUI to work correctly //TODO: handle this better in GUI(?) writer.startTrait(GraphTextWriter.TRAIT_SCRIPT_INITIALIZER); @@ -228,8 +238,6 @@ public class ScriptPack extends AS3ClassTreeItem { writer.newLine(); } first = false; - } else { - //"/*classInitializer*/"; } for (int t : traitIndices) { diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/types/ScriptInfo.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/types/ScriptInfo.java index 36947ba31..b69ee5c4c 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/types/ScriptInfo.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/types/ScriptInfo.java @@ -103,6 +103,21 @@ public class ScriptInfo { otherTraits.add(j); } } + + int publicTraitsCount = 0; + for (int j = 0; j < traits.traits.size(); j++) { + Trait t = traits.traits.get(j); + Multiname name = t.getName(abc); + int nskind = name.getSimpleNamespaceKind(abc.constants); + if ((nskind == Namespace.KIND_PACKAGE_INTERNAL) + || (nskind == Namespace.KIND_PACKAGE)) { + publicTraitsCount++; + } + } + + boolean isSimple = publicTraitsCount == 1; + + for (int j = 0; j < traits.traits.size(); j++) { Trait t = traits.traits.get(j); Multiname name = t.getName(abc); @@ -121,14 +136,14 @@ public class ScriptInfo { } if (packagePrefix == null || packageName.toPrintableString(true).startsWith(packagePrefix)) { + ClassPath cp = new ClassPath(packageName, objectName, namespaceSuffix); - ret.add(new ScriptPack(cp, abc, allAbcs, scriptIndex, traitIndices)); + ScriptPack pack = new ScriptPack(cp, abc, allAbcs, scriptIndex, traitIndices); + pack.isSimple = isSimple; + ret.add(pack); } } - } - if (ret.size() == 1) { - ret.get(0).isSimple = true; - } + } if (ret.isEmpty() && !otherTraits.isEmpty()) { //no public/package internal traits to determine common pack name //make each trait separate pack for (int traitIndex : otherTraits) { @@ -145,6 +160,9 @@ public class ScriptInfo { ClassPath cp = new ClassPath(packageName, objectName, namespaceSuffix); ret.add(new ScriptPack(cp, abc, allAbcs, scriptIndex, traitIndices)); } + } + if (!isSimple) { + ret.add(new ScriptPack(new ClassPath(DottedChain.EMPTY, "script_"+scriptIndex, ""), abc, allAbcs, scriptIndex, new ArrayList<>())); } if (packagePrefix == null) { cachedPacks = new ArrayList<>(ret); 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 322d95bc3..a9cf87db8 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 @@ -17,6 +17,7 @@ package com.jpexs.decompiler.flash.timeline; import com.jpexs.decompiler.flash.IdentifiersDeobfuscation; +import com.jpexs.decompiler.flash.abc.ABC; import com.jpexs.decompiler.flash.abc.ClassPath; import com.jpexs.decompiler.flash.abc.ScriptPack; import com.jpexs.decompiler.flash.treeitems.AS3ClassTreeItem; @@ -47,15 +48,33 @@ public class AS3Package extends AS3ClassTreeItem { private boolean flat; private boolean defaultPackage; + + private Integer compoundScriptIndex; + + private ABC abc; + + private ScriptPack compoundInitializerPack = null; - public AS3Package(String packageName, Openable openable, boolean flat, boolean defaultPackage) { + public AS3Package(String packageName, Openable openable, boolean flat, boolean defaultPackage, ABC abc, Integer compoundScriptIndex) { super(packageName, "", null); this.flat = flat; this.openable = openable; this.packageName = packageName; this.defaultPackage = defaultPackage; + this.compoundScriptIndex = compoundScriptIndex; + this.abc = abc; } + public void setCompoundInitializerPack(ScriptPack compoundInitializerPack) { + this.compoundInitializerPack = compoundInitializerPack; + } + + public ScriptPack getCompoundInitializerPack() { + return compoundInitializerPack; + } + + + public boolean isDefaultPackage() { return defaultPackage; } @@ -63,9 +82,21 @@ public class AS3Package extends AS3ClassTreeItem { public boolean isFlat() { return flat; } - - + public boolean isCompoundScript() { + return compoundScriptIndex != null; + } + + public Integer getCompoundScriptIndex() { + return compoundScriptIndex; + } + + public ABC getAbc() { + return abc; + } + + + @Override public Openable getOpenable() { return openable; diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/graph/DottedChain.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/graph/DottedChain.java index 291d25f11..cae98bc75 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/graph/DottedChain.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/graph/DottedChain.java @@ -248,6 +248,19 @@ public class DottedChain implements Serializable, Comparable { newParts.add(new PathPart(name, attribute, namespaceSuffix)); return new DottedChain(newParts, false); } + + public DottedChain preAdd(String name, String namespaceSuffix) { + return preAdd(false, name, namespaceSuffix); + } + + public DottedChain preAdd(boolean attribute, String name, String namespaceSuffix) { + if (name == null) { + return new DottedChain(this); + } + List newParts = new ArrayList<>(parts); + newParts.add(0, new PathPart(name, attribute, namespaceSuffix)); + return new DottedChain(newParts, false); + } protected String toString(boolean as3, boolean raw, boolean withSuffix) { if (isNull) { diff --git a/src/com/jpexs/decompiler/flash/gui/MainPanel.java b/src/com/jpexs/decompiler/flash/gui/MainPanel.java index 707033b26..b6a34dba7 100644 --- a/src/com/jpexs/decompiler/flash/gui/MainPanel.java +++ b/src/com/jpexs/decompiler/flash/gui/MainPanel.java @@ -189,6 +189,7 @@ import com.jpexs.decompiler.flash.tags.gfx.DefineExternalImage2; import com.jpexs.decompiler.flash.tags.gfx.DefineExternalStreamSound; import com.jpexs.decompiler.flash.tags.gfx.DefineSubImage; import com.jpexs.decompiler.flash.tags.text.TextParseException; +import com.jpexs.decompiler.flash.timeline.AS3Package; import com.jpexs.decompiler.flash.timeline.DepthState; import com.jpexs.decompiler.flash.timeline.Frame; import com.jpexs.decompiler.flash.timeline.TagScript; @@ -5131,7 +5132,23 @@ public final class MainPanel extends JPanel implements TreeSelectionListener, Se boolean internalViewer = !isAdobeFlashPlayerEnabled(); - if (treeItem instanceof ScriptPack) { + if ((treeItem instanceof AS3Package) && ((AS3Package)treeItem).isCompoundScript()) { + final ScriptPack scriptLeaf = ((AS3Package)treeItem).getCompoundInitializerPack(); + if (!Main.isInited() || !Main.isWorking() || Main.isDebugging()) { + ABCPanel abcPanel = getABCPanel(); + abcPanel.detailPanel.methodTraitPanel.methodCodePanel.clear(); + abcPanel.setAbc(scriptLeaf.abc); + abcPanel.decompiledTextArea.setScript(scriptLeaf, true); + abcPanel.decompiledTextArea.setNoTrait(); + } + + if (Configuration.displayAs3TraitsListAndConstantsPanel.get()) { + showDetail(DETAILCARDAS3NAVIGATOR); + } else { + showDetail(DETAILCARDEMPTYPANEL); + } + showCard(CARDACTIONSCRIPT3PANEL); + } else if (treeItem instanceof ScriptPack) { final ScriptPack scriptLeaf = (ScriptPack) treeItem; if (!Main.isInited() || !Main.isWorking() || Main.isDebugging()) { ABCPanel abcPanel = getABCPanel(); @@ -5274,7 +5291,7 @@ public final class MainPanel extends JPanel implements TreeSelectionListener, Se } else if (treeItem instanceof BUTTONRECORD) { showPreview(treeItem, previewPanel, -1, null); showCard(CARDPREVIEWPANEL); - } else if (!(treeItem instanceof ScriptPack)) { + } else if (!((treeItem instanceof ScriptPack) || ((treeItem instanceof AS3Package) &&((AS3Package)treeItem).isCompoundScript()))) { if (treePath == null) { showCard(CARDEMPTYPANEL); } else { diff --git a/src/com/jpexs/decompiler/flash/gui/abc/ClassesListTreeModel.java b/src/com/jpexs/decompiler/flash/gui/abc/ClassesListTreeModel.java index 580d72604..92f495a1f 100644 --- a/src/com/jpexs/decompiler/flash/gui/abc/ClassesListTreeModel.java +++ b/src/com/jpexs/decompiler/flash/gui/abc/ClassesListTreeModel.java @@ -59,7 +59,7 @@ public class ClassesListTreeModel extends AS3ClassTreeItem implements TreeModel public ClassesListTreeModel(SWF swf, boolean flat) { super(null, null, null); this.flat = flat; - root = new AS3Package(null, swf, flat, false); + root = new AS3Package(null, swf, flat, false, null, null); this.targetItem = swf; this.list = swf.getAS3Packs(); setFilter(null); @@ -68,7 +68,7 @@ public class ClassesListTreeModel extends AS3ClassTreeItem implements TreeModel public ClassesListTreeModel(ABC abc, boolean flat) { super(null, null, null); this.flat = flat; - root = new AS3Package(null, abc.getOpenable(), flat, false); + root = new AS3Package(null, abc.getOpenable(), flat, false, null, null); this.targetItem = abc; List allAbcs = new ArrayList<>(); allAbcs.add(abc); @@ -131,12 +131,30 @@ public class ClassesListTreeModel extends AS3ClassTreeItem implements TreeModel } DottedChain packageStr = item.getClassPath().packageStr; - AS3Package pkg = ensurePackage(packageStr); - pkg.addScriptPack(item); + AS3Package pkg = ensurePackage(packageStr, item.abc, item.isSimple ? null : item.scriptIndex, item); + if (pkg != null) { + pkg.addScriptPack(item); + } } } - private AS3Package ensurePackage(DottedChain packageStr) { + private AS3Package ensurePackage(DottedChain packageStr, ABC abc, Integer scriptIndex, ScriptPack pack) { + AS3Package parent = root; + + if (scriptIndex != null) { + String pathElement = "script_" + scriptIndex; + AS3Package pkg = parent.getSubPackage(pathElement); + if (pkg == null) { + pkg = new AS3Package(pathElement, getOpenable(), false, false, abc, scriptIndex); + parent.addSubPackage(pkg); + } + if (pack.traitIndices.isEmpty()) { + pkg.setCompoundInitializerPack(pack); + return null; + } + parent = pkg; + } + if (flat) { String fullName = packageStr.toPrintableString(true); boolean defaultPackage = false; @@ -144,19 +162,19 @@ public class ClassesListTreeModel extends AS3ClassTreeItem implements TreeModel fullName = AppResources.translate("package.default"); defaultPackage = true; } - AS3Package pkg = root.getSubPackage(fullName); + AS3Package pkg = parent.getSubPackage(fullName); if (pkg == null) { - pkg = new AS3Package(fullName, getOpenable(), true, defaultPackage); - root.addSubPackage(pkg); + pkg = new AS3Package(fullName, getOpenable(), true, defaultPackage, null, null); + parent.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, getOpenable(), false, false); + pkg = new AS3Package(pathElement, getOpenable(), false, false, null, null); parent.addSubPackage(pkg); } diff --git a/src/com/jpexs/decompiler/flash/gui/tagtree/AbstractTagTree.java b/src/com/jpexs/decompiler/flash/gui/tagtree/AbstractTagTree.java index f888c7c8d..5a9ee5838 100644 --- a/src/com/jpexs/decompiler/flash/gui/tagtree/AbstractTagTree.java +++ b/src/com/jpexs/decompiler/flash/gui/tagtree/AbstractTagTree.java @@ -358,6 +358,10 @@ public abstract class AbstractTagTree extends JTree { } if (t instanceof AS3Package) { + AS3Package pkg = (AS3Package)t; + if (pkg.isCompoundScript()) { + return TreeNodeType.AS; + } return TreeNodeType.PACKAGE; }