From d360c61ed8653b5eda92286bc51249e905d6dcb7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jindra=20Pet=C5=99=C3=ADk?= Date: Mon, 21 Apr 2025 21:42:44 +0200 Subject: [PATCH] Fixed: #2415 AS3 direct editation - nested functions - prefer callstack variables over prototype chain --- CHANGELOG.md | 2 + .../avm2/parser/script/PropertyAVM2Item.java | 298 +++++++++--------- 2 files changed, 154 insertions(+), 146 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 87f4664e9..db80d3c03 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -34,6 +34,7 @@ All notable changes to this project will be documented in this file. - [#2443] SVG importer - converting cubic bezier curves to quadratic - [#2444] SVG importer - improper stroke width when using width/height with viewBox - [#2444] SVG importer - stroke width not respecting transforms +- [#2415] AS3 direct editation - nested functions - prefer callstack variables over prototype chain ## [22.0.2] - 2025-01-17 ### Added @@ -3738,6 +3739,7 @@ Major version of SWF to XML export changed to 2. [#2386]: https://www.free-decompiler.com/flash/issues/2386 [#2443]: https://www.free-decompiler.com/flash/issues/2443 [#2444]: https://www.free-decompiler.com/flash/issues/2444 +[#2415]: https://www.free-decompiler.com/flash/issues/2415 [#2375]: https://www.free-decompiler.com/flash/issues/2375 [#2374]: https://www.free-decompiler.com/flash/issues/2374 [#2389]: https://www.free-decompiler.com/flash/issues/2389 diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/parser/script/PropertyAVM2Item.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/parser/script/PropertyAVM2Item.java index bcc804cf9..f7367e823 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/parser/script/PropertyAVM2Item.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/parser/script/PropertyAVM2Item.java @@ -209,60 +209,12 @@ public class PropertyAVM2Item extends AssignableAVM2Item { default: ttype = new TypeItem(InitVectorAVM2Item.VECTOR_OBJECT); } - } - - if (ttype instanceof TypeItem) { - DottedChain ftn = ((TypeItem) ttype).fullTypeName; - Reference outName = new Reference<>(""); - Reference outNs = new Reference<>(DottedChain.EMPTY); - Reference outPropNs = new Reference<>(DottedChain.EMPTY); - Reference outPropNsKind = new Reference<>(1); - Reference outPropNsIndex = new Reference<>(0); - Reference outPropType = new Reference<>(null); - Reference outPropValue = new Reference<>(null); - Reference outPropValueAbc = new Reference<>(null); - Reference outPropTrait = new Reference<>(null); - List otherNs = new ArrayList<>(); - for (NamespaceItem n : openedNamespaces) { - if (n.isResolved()) { - otherNs.add(n.getCpoolIndex(abcIndex)); - } - } - if ((object instanceof NameAVM2Item) && "super".equals(((NameAVM2Item) object).getVariableName())) { - // super is special cause its static type is the super class, but it still allows access to protected members - // so for super to work we need to also allow the protected namespace of the super class - // however this namespace is in the ABC of the super class and not in abcIndex.getSelectedAbc() - AbcIndexing.ClassIndex ci = abcIndex.findClass(objType, null, null/*FIXME?*/); - int superProtectedNs = ci.abc.instance_info.get(ci.index).protectedNS; - AbcIndexing.TraitIndex sp = abcIndex.findProperty(new AbcIndexing.PropertyDef(propertyName, objType, ci.abc, superProtectedNs), false, true, true); - if (sp != null) { - objType = sp.objType; - Namespace ns = sp.trait.getName(sp.abc).getNamespace(sp.abc.constants); - propIndex = constants.getMultinameId(Multiname.createQName(false, - constants.getStringId(propertyName, true), - constants.getNamespaceId(ns.kind, ns.getName(sp.abc.constants), sp.abc == abc ? abc.constants.getNamespaceSubIndex(sp.trait.getName(sp.abc).namespace_index) : 0, true)), true - ); - propType = sp.returnType; - propValue = sp.value; - propValueAbc = sp.abc; - propTrait = sp.trait; - } - } - if (propType == null && AVM2SourceGenerator.searchPrototypeChain(namespaceSuffixInt, otherNs, localData.privateNs, localData.protectedNs, false, abcIndex, ftn.getWithoutLast(), ftn.getLast(), propertyName, outName, outNs, outPropNs, outPropNsKind, outPropNsIndex, outPropType, outPropValue, outPropValueAbc, isType, outPropTrait)) { - objType = new TypeItem(outNs.getVal().addWithSuffix(outName.getVal())); - propType = outPropType.getVal(); - propIndex = constants.getMultinameId(Multiname.createQName(false, - constants.getStringId(propertyName, true), - namespaceSuffixInt != null ? namespaceSuffixInt : constants.getNamespaceId(outPropNsKind.getVal(), outPropNs.getVal(), outPropNsIndex.getVal(), true)), true - ); - propValue = outPropValue.getVal(); - propValueAbc = outPropValueAbc.getVal(); - propTrait = outPropTrait.getVal(); - } - } - + } + + boolean foundInCallStack = false; + if (objType == null) { - for (MethodBody b : callStack) { + loopcallstack: for (MethodBody b : callStack) { for (int i = 0; i < b.traits.traits.size(); i++) { Trait t = b.traits.traits.get(i); if (t.getName(abc).getName(constants, null, true, true).equals(propertyName)) { @@ -275,128 +227,182 @@ public class PropertyAVM2Item extends AssignableAVM2Item { localData.traitUsages.put(b, new ArrayList<>()); } localData.traitUsages.get(b).add(i); + foundInCallStack = true; } } } } - if (objType == null) { - loopobjType: - for (int i = 0; i < openedNamespaces.size(); i++) { - if (!openedNamespaces.get(i).isResolved()) { - continue; + } + + if (!foundInCallStack) { + if (ttype instanceof TypeItem) { + DottedChain ftn = ((TypeItem) ttype).fullTypeName; + Reference outName = new Reference<>(""); + Reference outNs = new Reference<>(DottedChain.EMPTY); + Reference outPropNs = new Reference<>(DottedChain.EMPTY); + Reference outPropNsKind = new Reference<>(1); + Reference outPropNsIndex = new Reference<>(0); + Reference outPropType = new Reference<>(null); + Reference outPropValue = new Reference<>(null); + Reference outPropValueAbc = new Reference<>(null); + Reference outPropTrait = new Reference<>(null); + List otherNs = new ArrayList<>(); + for (NamespaceItem n : openedNamespaces) { + if (n.isResolved()) { + otherNs.add(n.getCpoolIndex(abcIndex)); } - int nsindex = openedNamespaces.get(i).getCpoolIndex(abcIndex); - - int nsKind = openedNamespaces.get(i).kind; - DottedChain nsname = openedNamespaces.get(i).name; - - if (nsname.isTopLevel()) { - continue; + } + if ((object instanceof NameAVM2Item) && "super".equals(((NameAVM2Item) object).getVariableName())) { + // super is special cause its static type is the super class, but it still allows access to protected members + // so for super to work we need to also allow the protected namespace of the super class + // however this namespace is in the ABC of the super class and not in abcIndex.getSelectedAbc() + AbcIndexing.ClassIndex ci = abcIndex.findClass(objType, null, null/*FIXME?*/); + int superProtectedNs = ci.abc.instance_info.get(ci.index).protectedNS; + AbcIndexing.TraitIndex sp = abcIndex.findProperty(new AbcIndexing.PropertyDef(propertyName, objType, ci.abc, superProtectedNs), false, true, true); + if (sp != null) { + objType = sp.objType; + Namespace ns = sp.trait.getName(sp.abc).getNamespace(sp.abc.constants); + propIndex = constants.getMultinameId(Multiname.createQName(false, + constants.getStringId(propertyName, true), + constants.getNamespaceId(ns.kind, ns.getName(sp.abc.constants), sp.abc == abc ? abc.constants.getNamespaceSubIndex(sp.trait.getName(sp.abc).namespace_index) : 0, true)), true + ); + propType = sp.returnType; + propValue = sp.value; + propValueAbc = sp.abc; + propTrait = sp.trait; } + } + if (propType == null && AVM2SourceGenerator.searchPrototypeChain(namespaceSuffixInt, otherNs, localData.privateNs, localData.protectedNs, false, abcIndex, ftn.getWithoutLast(), ftn.getLast(), propertyName, outName, outNs, outPropNs, outPropNsKind, outPropNsIndex, outPropType, outPropValue, outPropValueAbc, isType, outPropTrait)) { + objType = new TypeItem(outNs.getVal().addWithSuffix(outName.getVal())); + propType = outPropType.getVal(); + propIndex = constants.getMultinameId(Multiname.createQName(false, + constants.getStringId(propertyName, true), + namespaceSuffixInt != null ? namespaceSuffixInt : constants.getNamespaceId(outPropNsKind.getVal(), outPropNs.getVal(), outPropNsIndex.getVal(), true)), true + ); + propValue = outPropValue.getVal(); + propValueAbc = outPropValueAbc.getVal(); + propTrait = outPropTrait.getVal(); + } + } + } - int name_index = 0; - int string_property_index = constants.getStringId(propertyName, false); - if (string_property_index > -1) { - for (int m = 1; m < constants.getMultinameCount(); m++) { - Multiname mname = constants.getMultiname(m); - if (mname.kind == Multiname.QNAME - && mname.name_index == string_property_index - && mname.namespace_index == nsindex) { - name_index = m; - break; - } + if (objType == null) { + loopobjType: + for (int i = 0; i < openedNamespaces.size(); i++) { + if (!openedNamespaces.get(i).isResolved()) { + continue; + } + int nsindex = openedNamespaces.get(i).getCpoolIndex(abcIndex); + + int nsKind = openedNamespaces.get(i).kind; + DottedChain nsname = openedNamespaces.get(i).name; + + if (nsname.isTopLevel()) { + continue; + } + + int name_index = 0; + int string_property_index = constants.getStringId(propertyName, false); + if (string_property_index > -1) { + for (int m = 1; m < constants.getMultinameCount(); m++) { + Multiname mname = constants.getMultiname(m); + if (mname.kind == Multiname.QNAME + && mname.name_index == string_property_index + && mname.namespace_index == nsindex) { + name_index = m; + break; } } - if (name_index > 0) { - //I believe these can be commented out... as it breaks #1840 - /*for (int c = 0; c < abc.instance_info.size(); c++) { - if (abc.instance_info.get(c).deleted) { - continue; - } - for (Trait t : abc.instance_info.get(c).instance_traits.traits) { - if (t.name_index == name_index) { - objType = multinameToType(abc.instance_info.get(c).name_index, constants); - propType = AVM2SourceGenerator.getTraitReturnType(abcIndex, t); - propIndex = t.name_index; - if (t instanceof TraitSlotConst) { - TraitSlotConst tsc = (TraitSlotConst) t; - propValue = new ValueKind(tsc.value_index, tsc.value_kind); - propValueAbc = abc; - } - break loopobjType; - } - } - for (Trait t : abc.class_info.get(c).static_traits.traits) { - if (t.name_index == name_index) { - objType = multinameToType(abc.instance_info.get(c).name_index, constants); - propType = AVM2SourceGenerator.getTraitReturnType(abcIndex, t); - propIndex = t.name_index; - if (t instanceof TraitSlotConst) { - TraitSlotConst tsc = (TraitSlotConst) t; - propValue = new ValueKind(tsc.value_index, tsc.value_kind); - propValueAbc = abc; - } - break loopobjType; - } - } - }*/ - - for (ScriptInfo si : abc.script_info) { - if (si.deleted) { + } + if (name_index > 0) { + //I believe these can be commented out... as it breaks #1840 + /*for (int c = 0; c < abc.instance_info.size(); c++) { + if (abc.instance_info.get(c).deleted) { continue; } - for (Trait t : si.traits.traits) { + for (Trait t : abc.instance_info.get(c).instance_traits.traits) { if (t.name_index == name_index) { - isType.setVal(t instanceof TraitClass); - objType = new TypeItem(DottedChain.OBJECT); + objType = multinameToType(abc.instance_info.get(c).name_index, constants); propType = AVM2SourceGenerator.getTraitReturnType(abcIndex, t); propIndex = t.name_index; if (t instanceof TraitSlotConst) { TraitSlotConst tsc = (TraitSlotConst) t; propValue = new ValueKind(tsc.value_index, tsc.value_kind); propValueAbc = abc; - propTrait = t; } break loopobjType; } } - } - } - if (nsKind == Namespace.KIND_PACKAGE && propertyName != null) { - AbcIndexing.TraitIndex p = abcIndex.findNsProperty(new AbcIndexing.PropertyNsDef(propertyName, nsname, abc, openedNamespaces.get(i).getCpoolIndex(abcIndex)), true, true); - - Reference outName = new Reference<>(""); - Reference outNs = new Reference<>(DottedChain.EMPTY); - Reference outPropNs = new Reference<>(DottedChain.EMPTY); - Reference outPropNsKind = new Reference<>(1); - Reference outPropNsIndex = new Reference<>(0); - Reference outPropType = new Reference<>(null); - Reference outPropValue = new Reference<>(null); - Reference outPropValueAbc = new Reference<>(null); - Reference outPropTrait = new Reference<>(null); - if (p != null && (p.objType instanceof TypeItem)) { - List otherns = new ArrayList<>(); - for (NamespaceItem n : openedNamespaces) { - if (n.isResolved()) { - otherns.add(n.getCpoolIndex(abcIndex)); + for (Trait t : abc.class_info.get(c).static_traits.traits) { + if (t.name_index == name_index) { + objType = multinameToType(abc.instance_info.get(c).name_index, constants); + propType = AVM2SourceGenerator.getTraitReturnType(abcIndex, t); + propIndex = t.name_index; + if (t instanceof TraitSlotConst) { + TraitSlotConst tsc = (TraitSlotConst) t; + propValue = new ValueKind(tsc.value_index, tsc.value_kind); + propValueAbc = abc; + } + break loopobjType; } } - if (AVM2SourceGenerator.searchPrototypeChain(namespaceSuffixInt, otherns, localData.privateNs, localData.protectedNs, false, abcIndex, nsname, (((TypeItem) p.objType).fullTypeName.getLast()), propertyName, outName, outNs, outPropNs, outPropNsKind, outPropNsIndex, outPropType, outPropValue, outPropValueAbc, isType, outPropTrait)) { - objType = new TypeItem(outNs.getVal().addWithSuffix(outName.getVal())); - propType = p.returnType; - propIndex = constants.getMultinameId(Multiname.createQName(false, - constants.getStringId(propertyName, true), - namespaceSuffixInt != null ? namespaceSuffixInt : constants.getNamespaceId(outPropNsKind.getVal(), outPropNs.getVal(), outPropNsIndex.getVal(), true)), true - ); - propValue = p.value; - propValueAbc = outPropValueAbc.getVal(); - propTrait = outPropTrait.getVal(); + }*/ + + for (ScriptInfo si : abc.script_info) { + if (si.deleted) { + continue; + } + for (Trait t : si.traits.traits) { + if (t.name_index == name_index) { + isType.setVal(t instanceof TraitClass); + objType = new TypeItem(DottedChain.OBJECT); + propType = AVM2SourceGenerator.getTraitReturnType(abcIndex, t); + propIndex = t.name_index; + if (t instanceof TraitSlotConst) { + TraitSlotConst tsc = (TraitSlotConst) t; + propValue = new ValueKind(tsc.value_index, tsc.value_kind); + propValueAbc = abc; + propTrait = t; + } break loopobjType; } } } } - } + if (nsKind == Namespace.KIND_PACKAGE && propertyName != null) { + AbcIndexing.TraitIndex p = abcIndex.findNsProperty(new AbcIndexing.PropertyNsDef(propertyName, nsname, abc, openedNamespaces.get(i).getCpoolIndex(abcIndex)), true, true); + + Reference outName = new Reference<>(""); + Reference outNs = new Reference<>(DottedChain.EMPTY); + Reference outPropNs = new Reference<>(DottedChain.EMPTY); + Reference outPropNsKind = new Reference<>(1); + Reference outPropNsIndex = new Reference<>(0); + Reference outPropType = new Reference<>(null); + Reference outPropValue = new Reference<>(null); + Reference outPropValueAbc = new Reference<>(null); + Reference outPropTrait = new Reference<>(null); + if (p != null && (p.objType instanceof TypeItem)) { + List otherns = new ArrayList<>(); + for (NamespaceItem n : openedNamespaces) { + if (n.isResolved()) { + otherns.add(n.getCpoolIndex(abcIndex)); + } + } + if (AVM2SourceGenerator.searchPrototypeChain(namespaceSuffixInt, otherns, localData.privateNs, localData.protectedNs, false, abcIndex, nsname, (((TypeItem) p.objType).fullTypeName.getLast()), propertyName, outName, outNs, outPropNs, outPropNsKind, outPropNsIndex, outPropType, outPropValue, outPropValueAbc, isType, outPropTrait)) { + objType = new TypeItem(outNs.getVal().addWithSuffix(outName.getVal())); + propType = p.returnType; + propIndex = constants.getMultinameId(Multiname.createQName(false, + constants.getStringId(propertyName, true), + namespaceSuffixInt != null ? namespaceSuffixInt : constants.getNamespaceId(outPropNsKind.getVal(), outPropNs.getVal(), outPropNsIndex.getVal(), true)), true + ); + propValue = p.value; + propValueAbc = outPropValueAbc.getVal(); + propTrait = outPropTrait.getVal(); + break loopobjType; + } + } + } + } } } }