diff --git a/CHANGELOG.md b/CHANGELOG.md index 331dde9bf..9c13e0dd4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,9 @@ All notable changes to this project will be documented in this file. - [#2424] DefineEditText handling of letterSpacing, font size on incorrect values - [#2391] Double not operator in ternar operator expression - [#2436] PDF export clipping - missing colors / text +- [#2437] AS1 P-code - do not group pushes automatically +- [#2437] AS1 Direct editation - group pushes on FP5+ +- [#2437] AS1 - use Constant pool only on FP5+ ## [22.0.2] - 2025-01-17 ### Added @@ -3699,6 +3702,7 @@ Major version of SWF to XML export changed to 2. [#2424]: https://www.free-decompiler.com/flash/issues/2424 [#2391]: https://www.free-decompiler.com/flash/issues/2391 [#2436]: https://www.free-decompiler.com/flash/issues/2436 +[#2437]: https://www.free-decompiler.com/flash/issues/2437 [#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/action/Action.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/Action.java index 0b89a0242..8fbda4eae 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/Action.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/Action.java @@ -728,20 +728,14 @@ public abstract class Action implements GraphSourceItem { } } else { //if (!(a instanceof ActionNop)) { - String add = ""; - // honfika: commented out the following lines, because it makes no sense - /*if (a instanceof ActionIf) { - add = " change: " + ((ActionIf) a).getJumpOffset(); - } - if (a instanceof ActionJump) { - add = " change: " + ((ActionJump) a).getJumpOffset(); - } - add = "; ofs" + Helper.formatAddress(offset) + add; - add = "";*/ - if ((a instanceof ActionPush) && lastPush) { + String add = ""; + //Flash player 4 does not allow more than 1 item in ActionPush, so I commented this out + /*if ((a instanceof ActionPush) && lastPush) { writer.appendNoHilight(", "); ((ActionPush) a).paramsToStringReplaced(list, importantOffsets, exportMode, writer); - } else { + } else + */ + { if (lastPush) { writer.newLine(); //lastPush = false; diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/parser/pcode/ASMParser.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/parser/pcode/ASMParser.java index 1cf559f44..53bf1207e 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/parser/pcode/ASMParser.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/parser/pcode/ASMParser.java @@ -422,10 +422,12 @@ public class ASMParser { ActionList list = new ActionList(charset); Stack containers = new Stack<>(); - ActionConstantPool cpool = new ActionConstantPool(constantPool, charset); - cpool.setAddress(address); - address += cpool.getTotalActionLength(); - list.add(cpool); + if (!constantPool.isEmpty()) { + ActionConstantPool cpool = new ActionConstantPool(constantPool, charset); + cpool.setAddress(address); + address += cpool.getTotalActionLength(); + list.add(cpool); + } while (true) { ASMParsedSymbol symb = lexer.lex(); diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/parser/script/ActionScript2Parser.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/parser/script/ActionScript2Parser.java index 8f243f6c4..b7c95fe10 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/parser/script/ActionScript2Parser.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/parser/script/ActionScript2Parser.java @@ -2147,6 +2147,12 @@ public class ActionScript2Parser { } private DirectValueActionItem pushConst(String s) throws IOException, ActionParseException { + + //ActionConstantPool was introduced in SWF 5 + if (swfVersion < 5) { + return new DirectValueActionItem(null, null, 0, s, constantPool); + } + int index = constantPool.indexOf(s); if (index == -1) { if (ActionConstantPool.calculateSize(constantPool) + ActionConstantPool.calculateSize(s) <= 0xffff) { @@ -2467,7 +2473,9 @@ public class ActionScript2Parser { ret.add((Action) s); } } - ret.add(0, new ActionConstantPool(constantPool, charset)); + if (!constantPool.isEmpty()) { + ret.add(0, new ActionConstantPool(constantPool, charset)); + } return ret; } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/parser/script/ActionSourceGenerator.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/parser/script/ActionSourceGenerator.java index 05330ace0..631ed6d71 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/parser/script/ActionSourceGenerator.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/parser/script/ActionSourceGenerator.java @@ -135,11 +135,35 @@ public class ActionSourceGenerator implements SourceGenerator { * @return List of Action */ public List toActionList(List items) { + items = groupPushes(items); List ret = new ArrayList<>(); - for (GraphSourceItem s : items) { + for (GraphSourceItem s : items) { if (s instanceof Action) { - ret.add((Action) s); + ret.add((Action) s); } + } + return ret; + } + + private List groupPushes(List items) { + if (swfVersion <= 4) { + return items; + } + List ret = new ArrayList<>(); + ActionPush prevPush = null; + for (GraphSourceItem s : items) { + if (s instanceof ActionPush) { + if (prevPush == null) { + prevPush = (ActionPush) s; + ret.add(prevPush); + } else { + prevPush.values.addAll(((ActionPush) s).values); + ((ActionPush) s).values.clear(); + } + } else { + ret.add(s); + prevPush = null; + } } return ret; } @@ -988,6 +1012,7 @@ public class ActionSourceGenerator implements SourceGenerator { for (GraphTargetItem item : commands) { ret.addAll(item.toSourceIgnoreReturnValue(localData, this)); } + ret = groupPushes(ret); return ret; } diff --git a/libsrc/ffdec_lib/test/com/jpexs/decompiler/flash/ActionScript2CompilerTest.java b/libsrc/ffdec_lib/test/com/jpexs/decompiler/flash/ActionScript2CompilerTest.java index 5712f776a..a5ef22bb7 100644 --- a/libsrc/ffdec_lib/test/com/jpexs/decompiler/flash/ActionScript2CompilerTest.java +++ b/libsrc/ffdec_lib/test/com/jpexs/decompiler/flash/ActionScript2CompilerTest.java @@ -171,8 +171,7 @@ public class ActionScript2CompilerTest extends ActionScript2TestBase { @Test public void stopUndefined() { - testCompilation("trace(stop());", "ConstantPool\n" - + "Stop\n" + testCompilation("trace(stop());", "Stop\n" + "Push undefined, undefined\n" + "Trace"); } diff --git a/libsrc/ffdec_lib/test/com/jpexs/decompiler/flash/ActionScript2ModificationTest.java b/libsrc/ffdec_lib/test/com/jpexs/decompiler/flash/ActionScript2ModificationTest.java index 8e4d300f2..0a78f3c97 100644 --- a/libsrc/ffdec_lib/test/com/jpexs/decompiler/flash/ActionScript2ModificationTest.java +++ b/libsrc/ffdec_lib/test/com/jpexs/decompiler/flash/ActionScript2ModificationTest.java @@ -174,8 +174,7 @@ public class ActionScript2ModificationTest extends ActionScript2TestBase { @Test public void testRemoveJumpAction() { String actionsString - = "ConstantPool\n" - + "DefineFunction \"test\", 1, \"p1\" {\n" + = "DefineFunction \"test\", 1, \"p1\" {\n" + "Push 1\n" + "Return\n" + "}\n" @@ -184,20 +183,19 @@ public class ActionScript2ModificationTest extends ActionScript2TestBase { + // remove this action "label_1:Push 3"; String expectedResult - = "ConstantPool\n" - + "DefineFunction \"test\", 1, \"p1\" {\n" + = "DefineFunction \"test\", 1, \"p1\" {\n" + "Push 1\n" + "Return\n" + "}\n" - + "Push 2, 3"; - testRemoveAction(actionsString, expectedResult, new int[]{5}); + + "Push 2\n" + + "Push 3"; + testRemoveAction(actionsString, expectedResult, new int[]{4}); } @Test public void testRemoveActionFromContainer() { String actionsString - = "ConstantPool\n" - + "DefineFunction \"test\", 1, \"p1\" {\n" + = "DefineFunction \"test\", 1, \"p1\" {\n" + "Push 1\n" // remove this action + "Return\n" + "}\n" @@ -205,43 +203,39 @@ public class ActionScript2ModificationTest extends ActionScript2TestBase { + "Jump label_1\n" + "label_1:Push 3"; String expectedResult - = "ConstantPool\n" - + "DefineFunction \"test\", 1, \"p1\" {\n" + = "DefineFunction \"test\", 1, \"p1\" {\n" + "Return\n" + "}\n" + "Push 2\n" + "Jump label_1\n" + "label_1:Push 3"; + testRemoveAction(actionsString, expectedResult, new int[]{1}); + } + + @Test + public void testRemoveLastActionFromContainer() { + String actionsString + = "DefineFunction \"test\", 1, \"p1\" {\n" + + "Push 1\n" + + "GetVariable\n" // remove this action + + "}\n" + + "Push 2\n" + + "Jump label_1\n" + + "label_1:Push 3"; + String expectedResult + = "DefineFunction \"test\", 1, \"p1\" {\n" + + "Push 1\n" + + "}\n" + + "Push 2\n" + + "Jump label_1\n" + + "label_1:Push 3"; testRemoveAction(actionsString, expectedResult, new int[]{2}); } - @Test - public void testRemoveLastActionFromContainer() { - String actionsString - = "ConstantPool\n" - + "DefineFunction \"test\", 1, \"p1\" {\n" - + "Push 1\n" - + "GetVariable\n" // remove this action - + "}\n" - + "Push 2\n" - + "Jump label_1\n" - + "label_1:Push 3"; - String expectedResult - = "ConstantPool\n" - + "DefineFunction \"test\", 1, \"p1\" {\n" - + "Push 1\n" - + "}\n" - + "Push 2\n" - + "Jump label_1\n" - + "label_1:Push 3"; - testRemoveAction(actionsString, expectedResult, new int[]{3}); - } - @Test public void testRemoveIfTargetAction() { String actionsString - = "ConstantPool\n" - + "DefineFunction \"test\", 1, \"p1\" {\n" + = "DefineFunction \"test\", 1, \"p1\" {\n" + "Push 1\n" + "GetVariable\n" + "}\n" @@ -251,8 +245,7 @@ public class ActionScript2ModificationTest extends ActionScript2TestBase { + "label_1:Push 4\n" // remove this action + "Push 5"; // after removing the previous action the if action should jump here String expectedResult - = "ConstantPool\n" - + "DefineFunction \"test\", 1, \"p1\" {\n" + = "DefineFunction \"test\", 1, \"p1\" {\n" + "Push 1\n" + "GetVariable\n" + "}\n" @@ -260,14 +253,13 @@ public class ActionScript2ModificationTest extends ActionScript2TestBase { + "If label_1\n" + "Push 3\n" + "label_1:Push 5"; - testRemoveAction(actionsString, expectedResult, new int[]{7}); + testRemoveAction(actionsString, expectedResult, new int[]{6}); } @Test public void testRemoveIfTargetLastAction() { String actionsString - = "ConstantPool\n" - + "DefineFunction \"test\", 1, \"p1\" {\n" + = "DefineFunction \"test\", 1, \"p1\" {\n" + "Push 1\n" + "GetVariable\n" + "}\n" @@ -276,8 +268,7 @@ public class ActionScript2ModificationTest extends ActionScript2TestBase { + "Push 3\n" + "label_1:Push 4"; // remove this action String expectedResult - = "ConstantPool\n" - + "DefineFunction \"test\", 1, \"p1\" {\n" + = "DefineFunction \"test\", 1, \"p1\" {\n" + "Push 1\n" + "GetVariable\n" + "}\n" @@ -285,14 +276,13 @@ public class ActionScript2ModificationTest extends ActionScript2TestBase { + "If label_1\n" + "Push 3\n" + "label_1:"; - testRemoveAction(actionsString, expectedResult, new int[]{7}); + testRemoveAction(actionsString, expectedResult, new int[]{6}); } @Test public void testAddActionFirst() { String actionsString - = "ConstantPool\n" - + "DefineFunction \"test\", 1, \"p1\" {\n" + = "DefineFunction \"test\", 1, \"p1\" {\n" + "Push 1\n" + "GetVariable\n" + "}\n" @@ -302,7 +292,6 @@ public class ActionScript2ModificationTest extends ActionScript2TestBase { + "label_1:Push 4"; String expectedResult = "GetMember\n" - + "ConstantPool\n" + "DefineFunction \"test\", 1, \"p1\" {\n" + "Push 1\n" + "GetVariable\n" @@ -318,8 +307,7 @@ public class ActionScript2ModificationTest extends ActionScript2TestBase { @Test public void testAddAction1() { String actionsString - = "ConstantPool\n" - + "DefineFunction \"test\", 1, \"p1\" {\n" + = "DefineFunction \"test\", 1, \"p1\" {\n" + "Push 1\n" + "GetVariable\n" + "}\n" @@ -328,8 +316,7 @@ public class ActionScript2ModificationTest extends ActionScript2TestBase { + "Push 3\n" + "label_1:Push 4"; String expectedResult - = "ConstantPool\n" - + "GetMember\n" + = "GetMember\n" + "DefineFunction \"test\", 1, \"p1\" {\n" + "Push 1\n" + "GetVariable\n" @@ -338,42 +325,39 @@ public class ActionScript2ModificationTest extends ActionScript2TestBase { + "If label_1\n" + "Push 3\n" + "label_1:Push 4"; + testAddActionNormal(actionsString, expectedResult, new ActionGetMember(), 0); + testAddActionFast(actionsString, expectedResult, new ActionGetMember(), 0); + } + + @Test + public void testAddActionToContainer() { + String actionsString + = "DefineFunction \"test\", 1, \"p1\" {\n" + + "Push 1\n" + + "GetVariable\n" + + "}\n" + + "Push 2\n" + + "If label_1\n" + + "Push 3\n" + + "label_1:Push 4"; + String expectedResult + = "DefineFunction \"test\", 1, \"p1\" {\n" + + "GetMember\n" + + "Push 1\n" + + "GetVariable\n" + + "}\n" + + "Push 2\n" + + "If label_1\n" + + "Push 3\n" + + "label_1:Push 4"; testAddActionNormal(actionsString, expectedResult, new ActionGetMember(), 1); testAddActionFast(actionsString, expectedResult, new ActionGetMember(), 1); } - @Test - public void testAddActionToContainer() { - String actionsString - = "ConstantPool\n" - + "DefineFunction \"test\", 1, \"p1\" {\n" - + "Push 1\n" - + "GetVariable\n" - + "}\n" - + "Push 2\n" - + "If label_1\n" - + "Push 3\n" - + "label_1:Push 4"; - String expectedResult - = "ConstantPool\n" - + "DefineFunction \"test\", 1, \"p1\" {\n" - + "GetMember\n" - + "Push 1\n" - + "GetVariable\n" - + "}\n" - + "Push 2\n" - + "If label_1\n" - + "Push 3\n" - + "label_1:Push 4"; - testAddActionNormal(actionsString, expectedResult, new ActionGetMember(), 2); - testAddActionFast(actionsString, expectedResult, new ActionGetMember(), 2); - } - @Test public void testAddActionIf() { String actionsString - = "ConstantPool\n" - + "DefineFunction \"test\", 1, \"p1\" {\n" + = "DefineFunction \"test\", 1, \"p1\" {\n" + "Push 1\n" + "GetVariable\n" + "}\n" @@ -382,8 +366,7 @@ public class ActionScript2ModificationTest extends ActionScript2TestBase { + "Push 3\n" + "label_1:Push 4"; String expectedResult - = "ConstantPool\n" - + "DefineFunction \"test\", 1, \"p1\" {\n" + = "DefineFunction \"test\", 1, \"p1\" {\n" + "Push 1\n" + "GetVariable\n" + "}\n" @@ -392,15 +375,14 @@ public class ActionScript2ModificationTest extends ActionScript2TestBase { + "Push 3\n" + "GetMember\n" + "label_1:Push 4"; - testAddActionNormal(actionsString, expectedResult, new ActionGetMember(), 7); - testAddActionFast(actionsString, expectedResult, new ActionGetMember(), 7); + testAddActionNormal(actionsString, expectedResult, new ActionGetMember(), 6); + testAddActionFast(actionsString, expectedResult, new ActionGetMember(), 6); } @Test public void testAddActionAfterContainer() { String actionsString - = "ConstantPool\n" - + "DefineFunction \"test\", 1, \"p1\" {\n" + = "DefineFunction \"test\", 1, \"p1\" {\n" + "Push 1\n" + "GetVariable\n" + "}\n" @@ -409,8 +391,7 @@ public class ActionScript2ModificationTest extends ActionScript2TestBase { + "Push 3\n" + "label_1:Push 4"; String expectedResult - = "ConstantPool\n" - + "DefineFunction \"test\", 1, \"p1\" {\n" + = "DefineFunction \"test\", 1, \"p1\" {\n" + "Push 1\n" + "GetVariable\n" + "}\n" @@ -419,23 +400,21 @@ public class ActionScript2ModificationTest extends ActionScript2TestBase { + "If label_1\n" + "Push 3\n" + "label_1:Push 4"; - testAddActionNormal(actionsString, expectedResult, new ActionGetMember(), 4); - testAddActionFast(actionsString, expectedResult, new ActionGetMember(), 4); + testAddActionNormal(actionsString, expectedResult, new ActionGetMember(), 3); + testAddActionFast(actionsString, expectedResult, new ActionGetMember(), 3); } @Test public void testAddToJumpTarget() { String actionsString - = "ConstantPool\n" - + "If label_1\n" + = "If label_1\n" + "GetMember\n" - + "label_1:Jump label_2\n" // address 9 + + "label_1:Jump label_2\n" // address 6 + "label_2:Jump label_3\n" + "label_3:Jump labelend\n" - + "labelend:End"; // address 24 + + "labelend:End"; // address 21 String expectedResult - = "ConstantPool\n" - + "If label_1\n" + = "If label_1\n" + "GetMember\n" + "Jump label_4\n" + "label_1:Jump label_2\n" @@ -443,9 +422,9 @@ public class ActionScript2ModificationTest extends ActionScript2TestBase { + "label_3:Jump label_4\n" + "label_4:"; ActionJump jump = new ActionJump(0, Utf8Helper.charsetName); - jump.setAddress(9); - jump.setJumpOffset(24 - 9 - 5); - testAddActionNormal(actionsString, expectedResult, jump, 3); - testAddActionFast(actionsString, expectedResult, jump, 3); + jump.setAddress(6); + jump.setJumpOffset(21 - 6 - 5); + testAddActionNormal(actionsString, expectedResult, jump, 2); + testAddActionFast(actionsString, expectedResult, jump, 2); } }