diff --git a/CHANGELOG.md b/CHANGELOG.md index 7dbc98345..4950670a8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,9 @@ All notable changes to this project will be documented in this file. resizing, adding frames, adding objects to stage. Instance property editation. Undo / redo feature. Double click movie clips to edit sub-objects. +### Fixed +- [#2357] AS3 instance var/const initialization + ## [21.1.3] - 2024-10-29 ### Fixed - Java 8 compatibility @@ -3636,6 +3639,7 @@ Major version of SWF to XML export changed to 2. [alpha 9]: https://github.com/jindrapetrik/jpexs-decompiler/compare/alpha8...alpha9 [alpha 8]: https://github.com/jindrapetrik/jpexs-decompiler/compare/alpha7...alpha8 [alpha 7]: https://github.com/jindrapetrik/jpexs-decompiler/releases/tag/alpha7 +[#2357]: https://www.free-decompiler.com/flash/issues/2357 [#2344]: https://www.free-decompiler.com/flash/issues/2344 [#2348]: https://www.free-decompiler.com/flash/issues/2348 [#2341]: https://www.free-decompiler.com/flash/issues/2341 diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/AVM2Code.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/AVM2Code.java index d20ad5714..9cb4a689e 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/AVM2Code.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/AVM2Code.java @@ -1825,6 +1825,7 @@ public class AVM2Code implements Cloneable { /** * Converts to source output. + * * @param switchParts Switch parts * @param callStack Call stack * @param abcIndex ABC indexing @@ -1910,7 +1911,7 @@ public class AVM2Code implements Cloneable { } } } - + if (ins.definition instanceof KillIns) { int killedReg = ins.operands[0]; if (output.size() >= 2 && !stack.isEmpty()) { @@ -1923,7 +1924,7 @@ public class AVM2Code implements Cloneable { if (insAfter != null && (insAfter.definition instanceof PopIns)) { if (setProp.value instanceof LocalRegAVM2Item) { LocalRegAVM2Item locReg = (LocalRegAVM2Item) setProp.value; - if (locReg.regIndex == killedReg) { + if (locReg.regIndex == killedReg) { setProp.value = setLoc.value; output.remove(output.size() - 2); stack.pop(); @@ -1931,7 +1932,7 @@ public class AVM2Code implements Cloneable { continue; } } - + } } } @@ -1973,7 +1974,7 @@ public class AVM2Code implements Cloneable { } } while (ins.definition instanceof DupIns); } else - */ + */ if ((ins.definition instanceof ReturnValueIns) || (ins.definition instanceof ReturnVoidIns) || (ins.definition instanceof ThrowIns)) { ins.definition.translate(switchParts, callStack, abcIndex, setLocalPosToGetLocalPos, lineStartItem, isStatic, scriptIndex, classIndex, localRegs, stack, scopeStack, localScopeStack, ins, output, body, abc, localRegNames, localRegTypes, fullyQualifiedNames, path, localRegAssignmentIps, ip, this, thisHasDefaultToPrimitive, bottomStackSetLocals); //ip = end + 1; @@ -2016,12 +2017,11 @@ public class AVM2Code implements Cloneable { nft.functionName = functionName; ip++; } else { - try { + try { ins.definition.translate(switchParts, callStack, abcIndex, setLocalPosToGetLocalPos, lineStartItem, isStatic, scriptIndex, classIndex, localRegs, stack, scopeStack, localScopeStack, ins, output, body, abc, localRegNames, localRegTypes, fullyQualifiedNames, path, localRegAssignmentIps, ip, this, thisHasDefaultToPrimitive, bottomStackSetLocals); - - + if (stack.size() == 1 && (stack.peek() instanceof SetLocalAVM2Item)) { - bottomStackSetLocals.add((SetLocalAVM2Item) stack.peek()); + bottomStackSetLocals.add((SetLocalAVM2Item) stack.peek()); } } catch (RuntimeException re) { /*String last=""; @@ -2513,8 +2513,9 @@ public class AVM2Code implements Cloneable { } }*/ } - + private static interface BlockVisitor { + public void visitBlock(List items); } @@ -2561,7 +2562,7 @@ public class AVM2Code implements Cloneable { } catch (SecondPassException spe) { list = AVM2Graph.translateViaGraph(spe.getData(), callStack, abcIndex, path, this, abc, body, isStatic, scriptIndex, classIndex, localRegs, scopeStack, localRegNames, localRegTypes, fullyQualifiedNames, staticOperation, localRegAssignmentIps, thisHasDefaultToPrimitive); } - if (initTraits != null) { + if (initTraits != null) { loopi: for (int i = 0; i < list.size(); i++) { GraphTargetItem ti = list.get(i); @@ -2589,6 +2590,11 @@ public class AVM2Code implements Cloneable { } } } + + /* + TODO: All this requires a better care for instance attributes, + for example using the assigned values only when it is referenced by const. + */ if ((ti instanceof InitPropertyAVM2Item) || (ti instanceof SetPropertyAVM2Item)) { int multinameIndex = 0; GraphTargetItem value = null; @@ -2606,16 +2612,17 @@ public class AVM2Code implements Cloneable { Multiname tm = abc.constants.getMultiname(t.name_index); if (tm != null && tm.equals(m)) { if ((t instanceof TraitSlotConst)) { - if (((TraitSlotConst) t).isConst() || initializerType == GraphTextWriter.TRAIT_CLASS_INITIALIZER || initializerType == GraphTextWriter.TRAIT_SCRIPT_INITIALIZER) { + //if (((TraitSlotConst) t).isConst() || initializerType == GraphTextWriter.TRAIT_CLASS_INITIALIZER || initializerType == GraphTextWriter.TRAIT_SCRIPT_INITIALIZER) + { TraitSlotConst tsc = (TraitSlotConst) t; if (value != null && !convertData.assignedValues.containsKey(tsc)) { - /*if (ti instanceof SetPropertyAVM2Item) { //only for slots + if (!isStatic) { Set subItems = value.getAllSubItemsRecursively(); subItems.add(value); List laterMultinames = new ArrayList<>(); - for (int k = j + 1; k < ts.traits.size(); k++) { - int tMultinameIndex = ts.traits.get(k).name_index; + for (int k = j + 1; k < initTraits.traits.size(); k++) { + int tMultinameIndex = initTraits.traits.get(k).name_index; if (tMultinameIndex > 0) { Multiname tMultiname = abc.constants.getMultiname(tMultinameIndex); laterMultinames.add(tMultiname); @@ -2623,7 +2630,7 @@ public class AVM2Code implements Cloneable { } for (GraphTargetItem item : subItems) { - //if later slot is referenced, we must add it as {} block instead of direct assignment + //if later slot is referenced, we must add it in constructor instead of direct assignment if (item instanceof GetPropertyAVM2Item) { Multiname multiName = abc.constants.getMultiname(((FullMultinameAVM2Item) ((GetPropertyAVM2Item) item).propertyName).multinameIndex); if (laterMultinames.contains(multiName)) { @@ -2637,19 +2644,21 @@ public class AVM2Code implements Cloneable { } } - if (item instanceof LocalRegAVM2Item) { //it is surely in static initializer block, not in slot/const + if (item instanceof LocalRegAVM2Item) { //it is surely in constructor block, not in slot/const continue loopi; } - } - }*/ + } + } if (value instanceof NewFunctionAVM2Item) { NewFunctionAVM2Item f = (NewFunctionAVM2Item) value; f.functionName = tsc.getName(abc).getName(abc.constants, fullyQualifiedNames, true, true); } AssignedValue av = new AssignedValue(ti, value, initializerType, methodIndex); convertData.assignedValues.put(tsc, av); - //list.remove(i); - //i--; + if (!isStatic) { + list.remove(i); + i--; + } continue loopi; } } @@ -2657,14 +2666,14 @@ public class AVM2Code implements Cloneable { } } } - } else { - // In obfuscated code, SetLocal instructions comes first - //break; + } else if (!isStatic) { + //We will ignore the fact, that in obfuscated code, the constructor can + //start with SetLocal in favor of turning on the deobfuscation... + break; } } } - - + int lastPos = list.size() - 1; if (lastPos < 0) { lastPos = 0; @@ -2686,10 +2695,10 @@ public class AVM2Code implements Cloneable { } else { list.set(lastPos, rv.value); } - + } } - + if (initializerType == GraphTextWriter.TRAIT_CLASS_INITIALIZER || initializerType == GraphTextWriter.TRAIT_SCRIPT_INITIALIZER) { Map commandToAssigned = new IdentityHashMap<>(); Map commandToTrait = new IdentityHashMap<>(); @@ -2698,26 +2707,25 @@ public class AVM2Code implements Cloneable { commandToAssigned.put(asv.command, asv); commandToTrait.put(asv.command, tsc); } - + for (int i = 0; i < list.size(); i++) { - GraphTargetItem ti = list.get(i); + GraphTargetItem ti = list.get(i); if (commandToAssigned.containsKey(ti)) { AssignedValue asv = commandToAssigned.get(ti); TraitSlotConst tsc = commandToTrait.get(ti); - + int nsKind = tsc.getName(abc).getSimpleNamespaceKind(abc.constants); if (classIndex == -1 && (nsKind == Namespace.KIND_PACKAGE || nsKind == Namespace.KIND_PACKAGE_INTERNAL)) { list.remove(i); i--; continue; } - - + TraitSlotConstAVM2Item item = new TraitSlotConstAVM2Item( - ti.getSrc(), + ti.getSrc(), ti.getLineStartItem(), - tsc, - asv.value, + tsc, + asv.value, isStatic, scriptIndex, classIndex, @@ -2728,20 +2736,20 @@ public class AVM2Code implements Cloneable { list.set(i, item); } } - + if (initializerType == GraphTextWriter.TRAIT_SCRIPT_INITIALIZER) { - + //Eliminate all setlocals, can sometimes happen BlockVisitor bv = new BlockVisitor() { @Override public void visitBlock(List items) { - + for (int i = 0; i < items.size(); i++) { GraphTargetItem item = items.get(i); if (item instanceof SetLocalAVM2Item) { items.set(i, item.value); } - + if (item instanceof Block) { Block b = (Block) item; for (List list : b.getSubs()) { @@ -2752,7 +2760,7 @@ public class AVM2Code implements Cloneable { } }; bv.visitBlock(list); - + PackageAVM2Item currentPkg = null; for (int i = 0; i < list.size(); i++) { GraphTargetItem ti = list.get(i); @@ -2765,7 +2773,7 @@ public class AVM2Code implements Cloneable { currentPkg = new PackageAVM2Item(new ArrayList<>(), newPkgName); currentPkg.addItem(tsci); list.set(i, currentPkg); - } else if (currentPkg.getPackageName().equals(newPkgName)){ + } else if (currentPkg.getPackageName().equals(newPkgName)) { currentPkg.addItem(tsci); list.remove(i); i--; @@ -2791,14 +2799,10 @@ public class AVM2Code implements Cloneable { TraitSlotConst tsc = (TraitSlotConst) t; if (tsc.slot_id == gs.slotIndex) { int nsKind = tsc.getName(abc).getNamespace(abc.constants).kind; - if ( - ( - nsKind == Namespace.KIND_PACKAGE_INTERNAL - && !currentPkgName.equals(tsc.getName(abc).getNamespace(abc.constants).getRawName(abc.constants)) - ) - || (nsKind == Namespace.KIND_PRIVATE) - ) { - insidePackage.setVal(false); + if ((nsKind == Namespace.KIND_PACKAGE_INTERNAL + && !currentPkgName.equals(tsc.getName(abc).getNamespace(abc.constants).getRawName(abc.constants))) + || (nsKind == Namespace.KIND_PRIVATE)) { + insidePackage.setVal(false); } } } @@ -2819,7 +2823,7 @@ public class AVM2Code implements Cloneable { } } } - + List newList = new ArrayList<>(); for (GraphTargetItem ti : list) { if (!(ti instanceof ReturnVoidAVM2Item)) { @@ -2871,7 +2875,7 @@ public class AVM2Code implements Cloneable { for (int ir = 0; ir < r; ir++) { paramNamesList.add(AVM2Item.localRegName(localRegNames, ir)); } - injectDeclarations(0, paramNamesList, list, 1, d, new ArrayList<>(), new ArrayList<>(), new ArrayList<>(), new ArrayList<>(), abc, body); + injectDeclarations(0, paramNamesList, list, 1, d, new ArrayList<>(), new ArrayList<>(), new ArrayList<>(), new ArrayList<>(), abc, body); return list; } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/types/traits/Traits.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/types/traits/Traits.java index b8658a184..a532d63a8 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/types/traits/Traits.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/types/traits/Traits.java @@ -333,7 +333,7 @@ public class Traits implements Cloneable, Serializable { continue; } - if ((trait instanceof TraitSlotConst) && convertData.assignedValues.containsKey((TraitSlotConst) trait)) { + if ((trait instanceof TraitSlotConst) && convertData.assignedValues.containsKey((TraitSlotConst) trait) && isStatic) { continue; } diff --git a/libsrc/ffdec_lib/test/com/jpexs/decompiler/flash/as3decompile/ActionScript3ClassTest.java b/libsrc/ffdec_lib/test/com/jpexs/decompiler/flash/as3decompile/ActionScript3ClassTest.java index 80ea0e088..13997b67d 100644 --- a/libsrc/ffdec_lib/test/com/jpexs/decompiler/flash/as3decompile/ActionScript3ClassTest.java +++ b/libsrc/ffdec_lib/test/com/jpexs/decompiler/flash/as3decompile/ActionScript3ClassTest.java @@ -373,24 +373,30 @@ public class ActionScript3ClassTest extends ActionScript3DecompileTestBase { + " public static var s_numbers:RegExp = /[0-9]+/;\n" + " \n" + " public static var s_regs:Array = [s_alpha,s_numbers];\n" - + " \n" + " \n" - + " public var i_email:RegExp;\n" + + " public var i_email:RegExp = /.*@.*\\..*/;\n" + " \n" - + " public var i_link:RegExp;\n" + + " public var i_link:RegExp = //;\n" + " \n" - + " public var i_regs:Array;\n" + + " public var i_regs:Array = [this.i_email,this.i_link];\n" + " \n" - + " public function TestInitializer()\n" + + " public var i_a:int = 1;\n" + + " \n" + + " public var i_b:int = this.i_a + 1;\n" + + " \n" + + " public const i_c:int = this.i_a + this.i_b + 1;\n" + + " \n" + + " public var i_d:int;\n" + + " \n" + + " public function TestInitializer(p:int)\n" + " {\n" - + " this.i_email = /.*@.*\\..*/;\n" - + " this.i_link = //;\n" - + " this.i_regs = [this.i_email,this.i_link];\n" + " super();\n" + " trace(s_regs[1]);\n" + + " this.i_a = 7;\n" + + " this.i_d = p;\n" + " }\n" + " }\n" - + "}"); + + "}\n"); } @Test diff --git a/libsrc/ffdec_lib/testdata/as3_new/bin/as3_new.air.swf b/libsrc/ffdec_lib/testdata/as3_new/bin/as3_new.air.swf index bd64502d2..c876f2556 100644 Binary files a/libsrc/ffdec_lib/testdata/as3_new/bin/as3_new.air.swf and b/libsrc/ffdec_lib/testdata/as3_new/bin/as3_new.air.swf differ diff --git a/libsrc/ffdec_lib/testdata/as3_new/bin/as3_new.flex.swf b/libsrc/ffdec_lib/testdata/as3_new/bin/as3_new.flex.swf index d28f3e2c7..5ced947ef 100644 Binary files a/libsrc/ffdec_lib/testdata/as3_new/bin/as3_new.flex.swf and b/libsrc/ffdec_lib/testdata/as3_new/bin/as3_new.flex.swf differ diff --git a/libsrc/ffdec_lib/testdata/as3_new/src/tests_classes/TestInitializer.as b/libsrc/ffdec_lib/testdata/as3_new/src/tests_classes/TestInitializer.as index fcba561ff..a18927a77 100644 --- a/libsrc/ffdec_lib/testdata/as3_new/src/tests_classes/TestInitializer.as +++ b/libsrc/ffdec_lib/testdata/as3_new/src/tests_classes/TestInitializer.as @@ -5,24 +5,31 @@ package tests_classes * @author JPEXS */ public class TestInitializer - { - public static var s_alpha:RegExp = /[a-z]+/; + { + public static var s_alpha:RegExp = /[a-z]+/; public static var s_regs:Array; public static var s_numbers:RegExp = /[0-9]+/; public var i_email:RegExp = /.*@.*\..*/ public var i_link:RegExp = //; public var i_regs:Array = [i_email,i_link]; - + + public var i_a:int = 1; + public var i_b:int = i_a + 1; + public const i_c:int = i_a + i_b + 1; + public var i_d:int; + { s_regs = [s_alpha, s_numbers]; } - public function TestInitializer() + public function TestInitializer(p:int) { trace(s_regs[1]); + i_a = 7; + i_d = p; } } -} \ No newline at end of file +}