diff --git a/CHANGELOG.md b/CHANGELOG.md index 9b536b138..25eb6eba1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -31,6 +31,7 @@ All notable changes to this project will be documented in this file. - [#2183] AS1/2 Direct editation - case sensitive identifiers since SWF version 7 - [#2203] GFX - DefineSubImage with TGA bitmapFormat - [#2207] AS - Index -2 out of bounds for some of the switches +- [#2190] AS1/2 - for..in inside switch before break ### Changed - [#2185] MochiCrypt no longer offered for auto decrypt, user needs to choose variant from "Use unpacker" menu @@ -3384,7 +3385,6 @@ Major version of SWF to XML export changed to 2. [#2176]: https://www.free-decompiler.com/flash/issues/2176 [#2179]: https://www.free-decompiler.com/flash/issues/2179 [#2185]: https://www.free-decompiler.com/flash/issues/2185 -[#2206]: https://www.free-decompiler.com/flash/issues/2206 [#2149]: https://www.free-decompiler.com/flash/issues/2149 [#2172]: https://www.free-decompiler.com/flash/issues/2172 [#2174]: https://www.free-decompiler.com/flash/issues/2174 @@ -3394,6 +3394,8 @@ Major version of SWF to XML export changed to 2. [#2183]: https://www.free-decompiler.com/flash/issues/2183 [#2203]: https://www.free-decompiler.com/flash/issues/2203 [#2207]: https://www.free-decompiler.com/flash/issues/2207 +[#2190]: https://www.free-decompiler.com/flash/issues/2190 +[#2206]: https://www.free-decompiler.com/flash/issues/2206 [#2100]: https://www.free-decompiler.com/flash/issues/2100 [#2123]: https://www.free-decompiler.com/flash/issues/2123 [#2119]: https://www.free-decompiler.com/flash/issues/2119 diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/ActionGraph.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/ActionGraph.java index 49bd650c3..c1c6bd186 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/ActionGraph.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/ActionGraph.java @@ -34,6 +34,7 @@ import com.jpexs.decompiler.flash.action.model.TemporaryRegister; import com.jpexs.decompiler.flash.action.model.TemporaryRegisterMark; import com.jpexs.decompiler.flash.action.model.clauses.ForInActionItem; import com.jpexs.decompiler.flash.action.model.clauses.TellTargetActionItem; +import com.jpexs.decompiler.flash.action.model.operations.EqActionItem; import com.jpexs.decompiler.flash.action.model.operations.NeqActionItem; import com.jpexs.decompiler.flash.action.model.operations.StrictEqActionItem; import com.jpexs.decompiler.flash.action.model.operations.StrictNeqActionItem; @@ -70,6 +71,7 @@ import com.jpexs.decompiler.graph.model.PopItem; import com.jpexs.decompiler.graph.model.PushItem; import com.jpexs.decompiler.graph.model.ScriptEndItem; import com.jpexs.decompiler.graph.model.SwitchItem; +import com.jpexs.decompiler.graph.model.TrueItem; import com.jpexs.decompiler.graph.model.WhileItem; import com.jpexs.helpers.Helper; import com.jpexs.helpers.Reference; @@ -362,59 +364,28 @@ public class ActionGraph extends Graph { checkedLoop = null; } } + + EnumerateActionItem enumerateItem = null; + BinaryOpItem comparisonOp = null; + //for..in inside switch before break + if ((checkedCondition instanceof TrueItem) && checkedBody != null) { + if (!checkedBody.isEmpty() && (checkedBody.get(0) instanceof IfItem)) { + IfItem ifi = (IfItem) checkedBody.get(0); + if (ifi.onFalse.isEmpty()) { + if (!ifi.onTrue.isEmpty() && (ifi.onTrue.get(ifi.onTrue.size() - 1) instanceof BreakItem)) { + checkedCondition = ifi.expression; - if (checkedCondition instanceof NeqActionItem) { - NeqActionItem ne = (NeqActionItem) checkedCondition; - if (ne.rightSide instanceof DirectValueActionItem) { - DirectValueActionItem dv = (DirectValueActionItem) ne.rightSide; - if (dv.value == Null.INSTANCE) { - GraphTargetItem en = list.get(t - 1); - if (en instanceof EnumerateActionItem) { - EnumerateActionItem eti = (EnumerateActionItem) en; - if (checkedCondition instanceof NeqActionItem) { - NeqActionItem neq = (NeqActionItem) checkedCondition; - if (neq.leftSide instanceof StoreRegisterActionItem) { - if (checkedBody != null && (!checkedBody.isEmpty()) && (checkedBody.get(0) instanceof SetTypeActionItem)) { - SetTypeActionItem sti = (SetTypeActionItem) checkedBody.get(0); - - if ((sti.getValue() instanceof DirectValueActionItem) && (((DirectValueActionItem) sti.getValue()).value instanceof RegisterNumber)) { - if ((neq.rightSide instanceof DirectValueActionItem) && (((DirectValueActionItem) neq.rightSide).value instanceof Null)) { - if (neq.leftSide.value instanceof EnumeratedValueActionItem) { - if (((StoreRegisterActionItem) neq.leftSide).register.number == ((RegisterNumber) (((DirectValueActionItem) sti.getValue()).value)).number) { - list.remove(t); - checkedBody.remove(0); - if (checkedLoop == null) { - checkedLoop = new Loop(localData.loops.size(), null, null); - checkedBody.add(new BreakItem(null, null, checkedLoop.id)); - } - sti.setValue(new DirectValueActionItem(Null.INSTANCE)); - list.add(t, new ForInActionItem(null, null, checkedLoop, (GraphTargetItem) sti, eti.object, checkedBody)); - //sti.getObject() - list.remove(t - 1); - t--; - continue; - } - } - } - } - } - - if (checkedBody != null) { - list.remove(t); - if (checkedLoop == null) { - checkedLoop = new Loop(localData.loops.size(), null, null); - checkedBody.add(new BreakItem(null, null, checkedLoop.id)); - } - list.remove(t - 1); - t--; - if (eti.object instanceof SetTypeActionItem) { - list.add(t++, eti.object); - eti.object = ((SetTypeActionItem) eti.object).getObject(); - } - list.add(t, new ForInActionItem(null, null, checkedLoop, (GraphTargetItem) neq.leftSide, eti.object, checkedBody)); - if (t + 1 < list.size()) { - if (list.get(t + 1) instanceof EnumeratedValueActionItem) { - list.remove(t + 1); + if (checkedCondition instanceof EqActionItem) { + EqActionItem eq = (EqActionItem) checkedCondition; + if (eq.rightSide instanceof DirectValueActionItem) { + DirectValueActionItem dv = (DirectValueActionItem) eq.rightSide; + if (dv.value == Null.INSTANCE) { + GraphTargetItem en = list.get(t - 1); + if (en instanceof EnumerateActionItem) { + enumerateItem = (EnumerateActionItem) en; + if (eq.leftSide instanceof StoreRegisterActionItem) { + comparisonOp = eq; + checkedBody.remove(0); } } } @@ -425,6 +396,68 @@ public class ActionGraph extends Graph { } } + if (checkedCondition instanceof NeqActionItem) { + NeqActionItem ne = (NeqActionItem) checkedCondition; + if (ne.rightSide instanceof DirectValueActionItem) { + DirectValueActionItem dv = (DirectValueActionItem) ne.rightSide; + if (dv.value == Null.INSTANCE) { + GraphTargetItem en = list.get(t - 1); + if (en instanceof EnumerateActionItem) { + enumerateItem = (EnumerateActionItem) en; + if (ne.leftSide instanceof StoreRegisterActionItem) { + comparisonOp = ne; + } + } + } + } + } + if (comparisonOp != null) { + + if (checkedBody != null && (!checkedBody.isEmpty()) && (checkedBody.get(0) instanceof SetTypeActionItem)) { + SetTypeActionItem sti = (SetTypeActionItem) checkedBody.get(0); + + if ((sti.getValue() instanceof DirectValueActionItem) && (((DirectValueActionItem) sti.getValue()).value instanceof RegisterNumber)) { + if ((comparisonOp.rightSide instanceof DirectValueActionItem) && (((DirectValueActionItem) comparisonOp.rightSide).value instanceof Null)) { + if (comparisonOp.leftSide.value instanceof EnumeratedValueActionItem) { + if (((StoreRegisterActionItem) comparisonOp.leftSide).register.number == ((RegisterNumber) (((DirectValueActionItem) sti.getValue()).value)).number) { + list.remove(t); + checkedBody.remove(0); + if (checkedLoop == null) { + checkedLoop = new Loop(localData.loops.size(), null, null); + checkedBody.add(new BreakItem(null, null, checkedLoop.id)); + } + sti.setValue(new DirectValueActionItem(Null.INSTANCE)); + list.add(t, new ForInActionItem(null, null, checkedLoop, (GraphTargetItem) sti, enumerateItem.object, checkedBody)); + //sti.getObject() + list.remove(t - 1); + t--; + continue; + } + } + } + } + } + + if (checkedBody != null) { + list.remove(t); + if (checkedLoop == null) { + checkedLoop = new Loop(localData.loops.size(), null, null); + checkedBody.add(new BreakItem(null, null, checkedLoop.id)); + } + list.remove(t - 1); + t--; + if (enumerateItem.object instanceof SetTypeActionItem) { + list.add(t++, enumerateItem.object); + enumerateItem.object = ((SetTypeActionItem) enumerateItem.object).getObject(); + } + list.add(t, new ForInActionItem(null, null, checkedLoop, (GraphTargetItem) comparisonOp.leftSide, enumerateItem.object, checkedBody)); + if (t + 1 < list.size()) { + if (list.get(t + 1) instanceof EnumeratedValueActionItem) { + list.remove(t + 1); + } + } + } + } } //Handle for loops at the end: super.finalProcess(list, level, localData, path); diff --git a/libsrc/ffdec_lib/test/com/jpexs/decompiler/flash/ActionScript2Test.java b/libsrc/ffdec_lib/test/com/jpexs/decompiler/flash/ActionScript2Test.java index 92f092f65..597241def 100644 --- a/libsrc/ffdec_lib/test/com/jpexs/decompiler/flash/ActionScript2Test.java +++ b/libsrc/ffdec_lib/test/com/jpexs/decompiler/flash/ActionScript2Test.java @@ -2410,13 +2410,13 @@ public class ActionScript2Test extends ActionScript2TestBase { } @Test - public void frame87_CallRegisterTest() { + public void frame87_callRegisterTest() { compareSrc(87, "function tst(o)\r\n" + "{\r\n" + "var _loc1_ = \"a\";\r\n" + "o[_loc1_]();\r\n" + "}\r\n" - + "trace(\"CallRegisterTest\");\r\n" + + "trace(\"callRegisterTest\");\r\n" + "var f = function()\r\n" + "{\r\n" + "trace(\"A\");\r\n" @@ -2429,4 +2429,27 @@ public class ActionScript2Test extends ActionScript2TestBase { + "tst(obj);\r\n" ); } + + @Test + public void frame88_switchForInTest() { + compareSrc(88, "trace(\"switchForInTest\");\r\n" + + "var t = 5;\r\n" + + "var a = [\"x\",\"y\",\"z\"];\r\n" + + "switch(t)\r\n" + + "{\r\n" + + "case 0:\r\n" + + "trace(\"A\");\r\n" + + "break;\r\n" + + "case 1:\r\n" + + "trace(\"B\");\r\n" + + "break;\r\n" + + "case 2:\r\n" + + "for(var k in a)\r\n" + + "{\r\n" + + "trace(k);\r\n" + + "}\r\n" + + "}\r\n" + + "trace(\"finish\");\r\n" + ); + } } diff --git a/libsrc/ffdec_lib/testdata/as2/as2.swf b/libsrc/ffdec_lib/testdata/as2/as2.swf index 64b420e58..4791355d1 100644 Binary files a/libsrc/ffdec_lib/testdata/as2/as2.swf and b/libsrc/ffdec_lib/testdata/as2/as2.swf differ diff --git a/libsrc/ffdec_lib/testdata/as2/as2/DOMDocument.xml b/libsrc/ffdec_lib/testdata/as2/as2/DOMDocument.xml index 903014524..07bbf7558 100644 --- a/libsrc/ffdec_lib/testdata/as2/as2/DOMDocument.xml +++ b/libsrc/ffdec_lib/testdata/as2/as2/DOMDocument.xml @@ -1,4 +1,4 @@ - + @@ -31,7 +31,7 @@ - + @@ -761,9 +761,9 @@ +!3054 7490[3050 7494 3050 7457!3050 7457[3050 7441 3159 7239!3159 7239[3270 7033 3327 6947!3327 6947[3353 6908 3412 6794!3412 6794[3470 6682 3500 6639!3500 6639[3602 6491 3649 6692!3649 6692|3713 6670!3713 6670[3760 6655 3782 6655!3782 + 6655[3942 6655 3985 6781!3985 6781[4007 6844 3996 6914!3996 6914[3996 6948 3999 6995!3999 6995[4000 7031 3993 7054!3993 7054[3976 7106 3860 7224!3860 7224[3847 7237 3741 7292!3741 7292[3638 7346 3616 7372!3616 7372[3594 7396 3511 7442 +!3511 7442[3435 7483 3427 7483!3427 7483[3409 7483 3407 7468!3407 7468[3405 7453 3386 7453!3386 7453[3361 7468 3330 7483!3330 7483[3270 7512 3235 7512!3235 7512[3220 7512 3156 7501!3156 7501[3091 7490 3054 7490"/> - + + + + + + @@ -3348,6 +3371,10 @@ tst(obj);]]> + + + + @@ -3364,9 +3391,5 @@ tst(obj);]]> - - - - \ No newline at end of file diff --git a/libsrc/ffdec_lib/testdata/as2/as2/LIBRARY/NineSlice.xml b/libsrc/ffdec_lib/testdata/as2/as2/LIBRARY/NineSlice.xml index 5c2332e03..bd9a31d14 100644 --- a/libsrc/ffdec_lib/testdata/as2/as2/LIBRARY/NineSlice.xml +++ b/libsrc/ffdec_lib/testdata/as2/as2/LIBRARY/NineSlice.xml @@ -37,26 +37,23 @@ - - - - - + + + + + + + + + + + + - - - - - +!0 1000|0 3000"/> diff --git a/libsrc/ffdec_lib/testdata/as2/as2/LIBRARY/blue.xml b/libsrc/ffdec_lib/testdata/as2/as2/LIBRARY/blue.xml index 7aa0f1c9f..56636e13c 100644 --- a/libsrc/ffdec_lib/testdata/as2/as2/LIBRARY/blue.xml +++ b/libsrc/ffdec_lib/testdata/as2/as2/LIBRARY/blue.xml @@ -36,8 +36,8 @@ trace("init_blue"); - + diff --git a/libsrc/ffdec_lib/testdata/as2/as2/META-INF/metadata.xml b/libsrc/ffdec_lib/testdata/as2/as2/META-INF/metadata.xml index a5dd95f75..16c34fecc 100644 --- a/libsrc/ffdec_lib/testdata/as2/as2/META-INF/metadata.xml +++ b/libsrc/ffdec_lib/testdata/as2/as2/META-INF/metadata.xml @@ -5,8 +5,8 @@ xmlns:xmp="http://ns.adobe.com/xap/1.0/"> Adobe Flash CS4 Professional 2010-08-03T10:48:58+02:00 - 2023-12-10T13:27:42-08:00 - 2023-12-10T13:27:42-08:00 + 2024-03-17T00:50:46-07:00 + 2024-03-17T00:50:46-07:00 @@ -22,7 +22,7 @@ xmp.did:8DD71700DC9EDF1194ADAC9B23608190 xmp.did:F0EB4FF7CAC3ED11AC9DC078F41E1AA7 - xmp.iid:37EB8B269097EE11BB10B6D1BEF0E058 + xmp.iid:7B15281033E4EE1187F5B2EA9E0AA389 xmp.did:8DD71700DC9EDF1194ADAC9B23608190 @@ -452,6 +452,12 @@ 2010-08-03T10:48:58+02:00 Adobe Flash Professional CS6 - build 481 + + created + xmp.iid:7B15281033E4EE1187F5B2EA9E0AA389 + 2010-08-03T10:48:58+02:00 + Adobe Flash Professional CS6 - build 481 + diff --git a/libsrc/ffdec_lib/testdata/as2/as2/bin/SymDepend.cache b/libsrc/ffdec_lib/testdata/as2/as2/bin/SymDepend.cache index 5b211b31d..4210680dc 100644 Binary files a/libsrc/ffdec_lib/testdata/as2/as2/bin/SymDepend.cache and b/libsrc/ffdec_lib/testdata/as2/as2/bin/SymDepend.cache differ