diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/model/MBStringExtractActionItem.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/model/MBStringExtractActionItem.java index cbe0f1705..22616b035 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/model/MBStringExtractActionItem.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/model/MBStringExtractActionItem.java @@ -46,7 +46,7 @@ public class MBStringExtractActionItem extends ActionItem { } public MBStringExtractActionItem(GraphSourceItem instruction, GraphSourceItem lineStartIns, GraphTargetItem value, GraphTargetItem index, GraphTargetItem count) { - super(instruction, lineStartIns, PRECEDENCE_PRIMARY, value); + super(instruction, lineStartIns, PRECEDENCE_PRIMARY, value); this.index = index; this.count = count; } @@ -80,10 +80,10 @@ public class MBStringExtractActionItem extends ActionItem { public static String getResult(Object count, Object index, Object value) { String str = EcmaScript.toString(value); - int idx = (int) (double) EcmaScript.toNumberAs2(index); + int idx = EcmaScript.toInt32(index); idx--; // index seems to be 1 based - int cnt = (int) (double) EcmaScript.toNumberAs2(count); + int cnt = EcmaScript.toInt32(count); /*if (idx < 0) { idx = str.length() + idx; diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/model/StringExtractActionItem.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/model/StringExtractActionItem.java index 5669b31b1..675d1ab96 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/model/StringExtractActionItem.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/model/StringExtractActionItem.java @@ -36,7 +36,7 @@ public class StringExtractActionItem extends ActionItem { public GraphTargetItem count; public StringExtractActionItem(GraphSourceItem instruction, GraphSourceItem lineStartIns, GraphTargetItem value, GraphTargetItem index, GraphTargetItem count) { - super(instruction, lineStartIns, PRECEDENCE_PRIMARY, value); + super(instruction, lineStartIns, PRECEDENCE_PRIMARY, value); this.index = index; this.count = count; } @@ -69,10 +69,10 @@ public class StringExtractActionItem extends ActionItem { public static String getResult(Object count, Object index, Object value) { String str = EcmaScript.toString(value); - int idx = (int) (double) EcmaScript.toNumberAs2(index); + int idx = EcmaScript.toInt32(index); idx--; // index seems to be 1 based - int cnt = (int) (double) EcmaScript.toNumberAs2(count); + int cnt = EcmaScript.toInt32(count); /*if (idx < 0) { idx = str.length() + idx; diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/model/operations/GtActionItem.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/model/operations/GtActionItem.java index dad04f9db..f67c82e2a 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/model/operations/GtActionItem.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/model/operations/GtActionItem.java @@ -44,13 +44,13 @@ public class GtActionItem extends BinaryOpItem implements LogicalOpItem { } public static Object getResult(Object rightResult, Object leftResult) { - Object ret = EcmaScript.compare(rightResult, leftResult, true); + Object ret = EcmaScript.compare(leftResult, rightResult, true); if (ret == Undefined.INSTANCE) { return ret; } int reti = (int) ret; - return reti == -1; + return reti == 1; } @Override diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/model/operations/LeActionItem.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/model/operations/LeActionItem.java index b7cd57e95..cb420be83 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/model/operations/LeActionItem.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/model/operations/LeActionItem.java @@ -41,13 +41,13 @@ public class LeActionItem extends BinaryOpItem implements LogicalOpItem, Inverte @Override public Object getResult() { - Object ret = EcmaScript.compare(rightSide.getResult(), leftSide.getResult(), true); + Object ret = EcmaScript.compare(leftSide.getResult(), rightSide.getResult(), true); if (ret == Undefined.INSTANCE) { return ret; } int reti = (int) ret; - return reti != -1; + return reti != 1; } @Override diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/model/operations/ModuloActionItem.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/model/operations/ModuloActionItem.java index ac746bcc8..55e418ee6 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/model/operations/ModuloActionItem.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/model/operations/ModuloActionItem.java @@ -38,10 +38,10 @@ public class ModuloActionItem extends BinaryOpItem { } public static Number getResult(Double rightResult, Double leftResult) { - if (Double.isNaN(rightResult) || Double.compare(rightResult, 0) == 0) { + if (Double.isNaN(leftResult) || Double.isNaN(rightResult) || Double.compare(rightResult, 0) == 0) { return Double.NaN; } - return ((long) (double) leftResult) % ((long) (double) rightResult); + return ((double) leftResult) % ((double) rightResult); } @Override diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/ecma/EcmaScript.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/ecma/EcmaScript.java index 68fa59b86..47a8531f6 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/ecma/EcmaScript.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/ecma/EcmaScript.java @@ -188,6 +188,15 @@ public class EcmaScript { if (sx.equals(sy)) { return 0; } + if (as2) { + // in AS2 an empty string is greater than a non-empty string... + if (sx.isEmpty()) { + return 1; + } + if (sy.isEmpty()) { + return -1; + } + } if (sx.startsWith(sy)) { return 1; } diff --git a/libsrc/ffdec_lib/test/com/jpexs/decompiler/flash/ActionScript3ExecuteTest.java b/libsrc/ffdec_lib/test/com/jpexs/decompiler/flash/ActionScript3ExecuteTest.java new file mode 100644 index 000000000..7127b1678 --- /dev/null +++ b/libsrc/ffdec_lib/test/com/jpexs/decompiler/flash/ActionScript3ExecuteTest.java @@ -0,0 +1,142 @@ +/* + * Copyright (C) 2010-2015 JPEXS, All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3.0 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. */ +package com.jpexs.decompiler.flash; + +import com.jpexs.decompiler.flash.abc.ABC; +import com.jpexs.decompiler.flash.abc.avm2.AVM2Code; +import com.jpexs.decompiler.flash.abc.avm2.AVM2Runtime; +import com.jpexs.decompiler.flash.abc.avm2.AVM2RuntimeInfo; +import com.jpexs.decompiler.flash.abc.avm2.exceptions.AVM2ExecutionException; +import com.jpexs.decompiler.flash.abc.avm2.instructions.AVM2Instruction; +import com.jpexs.decompiler.flash.abc.avm2.instructions.AVM2Instructions; +import com.jpexs.decompiler.flash.abc.types.MethodBody; +import com.jpexs.decompiler.flash.abc.types.MethodInfo; +import com.jpexs.decompiler.flash.abc.types.traits.TraitMethodGetterSetter; +import com.jpexs.decompiler.flash.configuration.Configuration; +import com.jpexs.decompiler.flash.tags.DoABC2Tag; +import com.jpexs.decompiler.flash.tags.Tag; +import java.io.BufferedInputStream; +import java.io.FileInputStream; +import java.io.IOException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertNotNull; +import static org.testng.Assert.fail; +import org.testng.annotations.BeforeClass; +import org.testng.annotations.Test; + +/** + * + * @author JPEXS + */ +public class ActionScript3ExecuteTest { + + private SWF swf; + + private ABC abc; + + @BeforeClass + public void init() throws IOException, InterruptedException { + //Main.initLogging(false); + swf = new SWF(new BufferedInputStream(new FileInputStream("testdata/run_as3/run.swf")), false); + /*try (InputStream is = new BufferedInputStream(new FileInputStream("testdata/run_as3/run.swf"))) { + swf = new SWF(is, false); + }*/ + DoABC2Tag tag = null; + for (Tag t : swf.tags) { + if (t instanceof DoABC2Tag) { + tag = (DoABC2Tag) t; + break; + } + } + assertNotNull(tag); + this.abc = tag.getABC(); + Configuration.autoDeobfuscate.set(false); + Configuration.decompile.set(true); + Configuration.registerNameFormat.set("_loc%d_"); + Configuration.showMethodBodyId.set(false); + } + + //@Test + public void testRun() throws IOException, InterruptedException { + MethodBody body = abc.findBodyByClassAndName("Run", "run"); + Object result; + try { + result = body.getCode().execute(new HashMap<>(), abc.constants, new AVM2RuntimeInfo(AVM2Runtime.ADOBE_FLASH, 19, true)); + assertEquals(result, "Test"); + } catch (AVM2ExecutionException ex) { + fail(); + } + } + + @Test + public void testAddMethod() throws IOException, InterruptedException { + int classId = abc.findClassByName("Run"); + MethodBody runBody = abc.findBodyByClassAndName("Run", "runInstance"); + runBody.max_stack = 10; + + AVM2Code ccode = new AVM2Code(); + ccode.code = new ArrayList<>(); + List code = ccode.code; + code.add(new AVM2Instruction(0, AVM2Instructions.GetLocal0, null)); + code.add(new AVM2Instruction(0, AVM2Instructions.PushScope, null)); + code.add(new AVM2Instruction(0, AVM2Instructions.PushString, new int[]{abc.constants.getStringId("", true)})); + + for (int testMethodId = 1; testMethodId < 10; testMethodId++) { + AVM2Code ccode2 = new AVM2Code(); + ccode2.code = new ArrayList<>(); + List code2 = ccode2.code; + code2.add(new AVM2Instruction(0, AVM2Instructions.GetLocal0, null)); + code2.add(new AVM2Instruction(0, AVM2Instructions.PushScope, null)); + code2.add(new AVM2Instruction(0, AVM2Instructions.PushString, new int[]{abc.constants.getStringId(testMethodId + ""/* + "\r\n"*/, true)})); + code2.add(new AVM2Instruction(0, AVM2Instructions.ReturnValue, null)); + + boolean isStatic = testMethodId % 2 == 0; + int multinameId = addMethod(classId, "test" + testMethodId, isStatic, ccode2); + if (isStatic) { + code.add(new AVM2Instruction(0, AVM2Instructions.FindPropertyStrict, new int[]{multinameId})); + } else { + code.add(new AVM2Instruction(0, AVM2Instructions.GetLocal0, null)); + } + + code.add(new AVM2Instruction(0, AVM2Instructions.CallProperty, new int[]{multinameId, 0})); + code.add(new AVM2Instruction(0, AVM2Instructions.Add, null)); + code.add(new AVM2Instruction(0, AVM2Instructions.PushString, new int[]{abc.constants.getStringId("\r\n", true)})); + code.add(new AVM2Instruction(0, AVM2Instructions.Add, null)); + } + + code.add(new AVM2Instruction(0, AVM2Instructions.ReturnValue, null)); + runBody.setCode(ccode); + runBody.markOffsets(); + } + + private int addMethod(int classId, String name, boolean isStatic, AVM2Code code) { + TraitMethodGetterSetter methodTrait = abc.addMethod(classId, name, isStatic); + MethodInfo methodInfo = abc.method_info.get(methodTrait.method_info); + MethodBody methodBody = methodInfo.getBody(); + methodBody.max_stack = 10; + methodBody.max_regs = 10; + methodBody.init_scope_depth = 3; + methodBody.max_scope_depth = 10; + + methodBody.setCode(code); + methodBody.markOffsets(); + + return methodTrait.name_index; + } +} diff --git a/libsrc/ffdec_lib/testdata/run_as2/run_as2.fla b/libsrc/ffdec_lib/testdata/run_as2/run_as2.fla new file mode 100644 index 000000000..610d7e796 Binary files /dev/null and b/libsrc/ffdec_lib/testdata/run_as2/run_as2.fla differ diff --git a/libsrc/ffdec_lib/testdata/run_as2/run_as2.html b/libsrc/ffdec_lib/testdata/run_as2/run_as2.html new file mode 100644 index 000000000..6a7b1dcbe --- /dev/null +++ b/libsrc/ffdec_lib/testdata/run_as2/run_as2.html @@ -0,0 +1,49 @@ + + + + run_as2 + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + Get Adobe Flash player + + + + + +
+ + diff --git a/test/com/jpexs/decompiler/flash/gui/FlashPlayerTest.java b/test/com/jpexs/decompiler/flash/gui/FlashPlayerTest.java index 975a21e3e..42703010a 100644 --- a/test/com/jpexs/decompiler/flash/gui/FlashPlayerTest.java +++ b/test/com/jpexs/decompiler/flash/gui/FlashPlayerTest.java @@ -76,7 +76,6 @@ import com.jpexs.decompiler.graph.Graph; import com.jpexs.decompiler.graph.GraphTargetItem; import com.jpexs.decompiler.graph.TranslateStack; import com.jpexs.helpers.Helper; -import com.jpexs.helpers.utf8.Utf8Helper; import java.io.IOException; import java.util.ArrayList; import java.util.HashMap; @@ -278,10 +277,10 @@ public class FlashPlayerTest { StringBuilder expeced = new StringBuilder(); StringBuilder current = new StringBuilder(); for (AS3ExecuteTask task : tasks) { - /*System.out.println("Flash result (" + task.description + "): " + task.flashResult); - System.out.println("FFDec execte result: " + task.ffdecResult); + System.out.println("Flash result (" + task.description + "): " + task.flashResult); + System.out.println("FFDec execte result: " + task.ffdecResult); - if (!task.ffdecResult.equals(task.flashResult)) { + /*if (!task.ffdecResult.equals(task.flashResult)) { String ffdecExecuteResult; try { Object res = task.code.execute(new HashMap<>(), abc.constants, adobeRuntime); @@ -289,15 +288,16 @@ public class FlashPlayerTest { } catch (AVM2ExecutionException ex) { ffdecExecuteResult = "Error:" + ex.getMessage(); } - } - - assertEquals(task.ffdecResult, task.flashResult);*/ - expeced.append(task.flashResult).append(Helper.newLine); - current.append(task.ffdecResult).append(Helper.newLine); + }*/ + assertEquals(task.ffdecResult, task.flashResult); + if (!task.flashResult.equals(task.ffdecResult)) { + expeced.append(task.flashResult).append(Helper.newLine); + current.append(task.ffdecResult).append(Helper.newLine); + } } - Helper.writeFile("c:\\1\\expected\\" + i + ".txt", Utf8Helper.getBytes(expeced.toString())); - Helper.writeFile("c:\\1\\current\\" + i + ".txt", Utf8Helper.getBytes(current.toString())); + //Helper.writeFile("expected\\" + i + ".txt", Utf8Helper.getBytes(expeced.toString())); + //Helper.writeFile("current\\" + i + ".txt", Utf8Helper.getBytes(current.toString())); } } @@ -322,6 +322,8 @@ public class FlashPlayerTest { new AVM2Instruction(0, AVM2Instructions.PushString, new int[]{abc.constants.getStringId("4294967296", true)}), // 16 new AVM2Instruction(0, AVM2Instructions.PushString, new int[]{abc.constants.getStringId("1test", true)}), // 17 new AVM2Instruction(0, AVM2Instructions.PushString, new int[]{abc.constants.getStringId("test", true)}), // 18 + new AVM2Instruction(0, AVM2Instructions.PushString, new int[]{abc.constants.getStringId("test2", true)}), // 18 + new AVM2Instruction(0, AVM2Instructions.PushString, new int[]{abc.constants.getStringId("test3", true)}), // 18 new AVM2Instruction(0, AVM2Instructions.PushDouble, new int[]{0}), // 19 new AVM2Instruction(0, AVM2Instructions.PushDouble, new int[]{abc.constants.getDoubleId(-1, true)}), // 20 new AVM2Instruction(0, AVM2Instructions.PushDouble, new int[]{abc.constants.getDoubleId(-0.5, true)}), // 21 @@ -465,7 +467,10 @@ public class FlashPlayerTest { newActions.add(new ActionStringAdd()); AS2ExecuteTask task = new AS2ExecuteTask(); - task.description = i + " " + opAction.toString() + " p1:" + p1o + " p2:" + p2o + " r3:" + "mystring"; + String desc = i + " " + opAction.toString() + " p1:" + + (p1o instanceof String ? "'" + p1o + "'" : p1o) + " p2:" + + (p2o instanceof String ? "'" + p2o + "'" : p2o) + " r3:" + "mystring"; + task.description = desc; task.actions = newActions; List output = new ArrayList<>(); @@ -533,34 +538,30 @@ public class FlashPlayerTest { } }*/ - if (flashResult.equals("Result:number-0.00390625000090949 Type:string")) { - flashResult = "Result:number-0.0039062500009095 Type:string"; - } else if (flashResult.equals("Result:number-0.0000610349234335671 Type:string")) { - flashResult = "Result:number-0.0000610349234335672 Type:string"; - } - - if (!ffdecResult.equals(flashResult)) { - LocalDataArea lda = new LocalDataArea(); - for (Action a : task.actions) { - if (!a.execute(lda)) { - fail(); - } - } - - Object res = lda.stack.pop(); - } + /*if (!ffdecResult.equals(flashResult)) { + LocalDataArea lda = new LocalDataArea(); + for (Action a : task.actions) { + if (!a.execute(lda)) { + fail(); + } + } + Object res = lda.stack.pop(); + }*/ if (checkOnlyStart) { assertTrue(((String) ffdecResult).startsWith(flashResult)); } else { assertEquals(ffdecResult, flashResult); } - expeced.append(task.description).append(task.flashResult).append(Helper.newLine); - current.append(task.description).append(task.ffdecResult).append(Helper.newLine); + + if (!task.flashResult.equals(task.ffdecResult)) { + expeced.append(task.description).append(task.flashResult).append(Helper.newLine); + current.append(task.description).append(task.ffdecResult).append(Helper.newLine); + } } - Helper.writeFile("c:\\1\\expected.txt", Utf8Helper.getBytes(expeced.toString())); - Helper.writeFile("c:\\1\\current.txt", Utf8Helper.getBytes(current.toString())); + //Helper.writeFile("expected.txt", Utf8Helper.getBytes(expeced.toString())); + //Helper.writeFile("current.txt", Utf8Helper.getBytes(current.toString())); } private Object[] getAs2Pushes() { @@ -570,7 +571,7 @@ public class FlashPlayerTest { Undefined.INSTANCE, Null.INSTANCE, false, true, Double.NaN, - "", "-2147483649", "-2147483648", "-2147483647", "-1", "0", "1", "2147483647", "2147483648", "4294967295", "4294967296", "1test", "test", "0.0", "1.0", "-1.0", + "", "-2147483649", "-2147483648", "-2147483647", "-1", "0", "1", "2147483647", "2147483648", "4294967295", "4294967296", "1test", "test", "test2", "test3", "0.0", "1.0", "-1.0", -1.0, -0.5, 0, 0.5, 1.0, -2147483648, -2147483647, -1073741824, -1073741823, -536870912, -536870911, -268435456, -134217728, -134217727, -67108864, -67108863, -33554432, -33554431, -16777216, -16777215, -8388608, -8388607, -4194304, -4194303, -2097152, -2097151, -1048576, -1048575, -524288, -524287, -262144, -262143, -131072, -131071, -65536, -65535, -32768, -32767, -1, 0, 1, 32767, 32768, 268435455,