/* * Copyright (C) 2010-2016 JPEXS * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package com.jpexs.decompiler.flash.gui; 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.avm2.instructions.IfTypeIns; import com.jpexs.decompiler.flash.abc.avm2.instructions.InstructionDefinition; import com.jpexs.decompiler.flash.action.Action; import com.jpexs.decompiler.flash.action.ActionLocalData; import com.jpexs.decompiler.flash.action.LocalDataArea; import com.jpexs.decompiler.flash.action.Stage; import com.jpexs.decompiler.flash.action.swf4.ActionAdd; import com.jpexs.decompiler.flash.action.swf4.ActionAnd; import com.jpexs.decompiler.flash.action.swf4.ActionAsciiToChar; import com.jpexs.decompiler.flash.action.swf4.ActionCharToAscii; import com.jpexs.decompiler.flash.action.swf4.ActionDivide; import com.jpexs.decompiler.flash.action.swf4.ActionEquals; import com.jpexs.decompiler.flash.action.swf4.ActionLess; import com.jpexs.decompiler.flash.action.swf4.ActionMBAsciiToChar; import com.jpexs.decompiler.flash.action.swf4.ActionMBCharToAscii; import com.jpexs.decompiler.flash.action.swf4.ActionMBStringExtract; import com.jpexs.decompiler.flash.action.swf4.ActionMBStringLength; import com.jpexs.decompiler.flash.action.swf4.ActionMultiply; import com.jpexs.decompiler.flash.action.swf4.ActionNot; import com.jpexs.decompiler.flash.action.swf4.ActionOr; import com.jpexs.decompiler.flash.action.swf4.ActionPush; import com.jpexs.decompiler.flash.action.swf4.ActionStringAdd; import com.jpexs.decompiler.flash.action.swf4.ActionStringExtract; import com.jpexs.decompiler.flash.action.swf4.ActionStringLength; import com.jpexs.decompiler.flash.action.swf4.ActionStringLess; import com.jpexs.decompiler.flash.action.swf4.ActionSubtract; import com.jpexs.decompiler.flash.action.swf4.ActionToInteger; import com.jpexs.decompiler.flash.action.swf5.ActionAdd2; import com.jpexs.decompiler.flash.action.swf5.ActionBitAnd; import com.jpexs.decompiler.flash.action.swf5.ActionBitLShift; import com.jpexs.decompiler.flash.action.swf5.ActionBitOr; import com.jpexs.decompiler.flash.action.swf5.ActionBitRShift; import com.jpexs.decompiler.flash.action.swf5.ActionBitURShift; import com.jpexs.decompiler.flash.action.swf5.ActionBitXor; import com.jpexs.decompiler.flash.action.swf5.ActionDecrement; import com.jpexs.decompiler.flash.action.swf5.ActionEquals2; import com.jpexs.decompiler.flash.action.swf5.ActionIncrement; import com.jpexs.decompiler.flash.action.swf5.ActionLess2; import com.jpexs.decompiler.flash.action.swf5.ActionModulo; import com.jpexs.decompiler.flash.action.swf5.ActionPushDuplicate; import com.jpexs.decompiler.flash.action.swf5.ActionStackSwap; import com.jpexs.decompiler.flash.action.swf5.ActionToNumber; import com.jpexs.decompiler.flash.action.swf5.ActionToString; import com.jpexs.decompiler.flash.action.swf5.ActionTypeOf; import com.jpexs.decompiler.flash.action.swf6.ActionGreater; import com.jpexs.decompiler.flash.action.swf6.ActionStrictEquals; import com.jpexs.decompiler.flash.action.swf6.ActionStringGreater; import com.jpexs.decompiler.flash.ecma.EcmaScript; import com.jpexs.decompiler.flash.ecma.Null; import com.jpexs.decompiler.flash.ecma.Undefined; import com.jpexs.decompiler.graph.Graph; import com.jpexs.decompiler.graph.GraphTargetItem; import com.jpexs.decompiler.graph.TranslateStack; import com.jpexs.helpers.Helper; import java.io.IOException; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Random; import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertTrue; import static org.testng.Assert.fail; /** * * @author JPEXS */ public class FlashPlayerTest { private final Random random = new Random(); private final AVM2RuntimeInfo adobeRuntime = new AVM2RuntimeInfo(AVM2Runtime.ADOBE_FLASH, 19, false); //@Test public void testAs3Pushes() throws IOException, InterruptedException { AdobeFlashExecutor adobeExecutor = new AdobeFlashExecutor(); adobeExecutor.loadTestSwf(); ABC abc = adobeExecutor.as3TestSwfAbcTag.getABC(); abc.constants.ensureStringCapacity(1000000); abc.constants.ensureMultinameCapacity(1000000); AVM2Instruction[] pushes = getAs3Pushes(abc); List<AS3ExecuteTask> tasks = new ArrayList<>(); for (int p1 = 0; p1 < pushes.length; p1++) { AVM2Code ccode = new AVM2Code(); List<AVM2Instruction> code = ccode.code; code.add(new AVM2Instruction(0, AVM2Instructions.GetLocal0, null)); code.add(new AVM2Instruction(0, AVM2Instructions.PushScope, null)); code.add(pushes[p1].clone()); code.add(new AVM2Instruction(0, AVM2Instructions.ReturnValue, null)); ccode.markOffsets(); AS3ExecuteTask task = new AS3ExecuteTask(); task.description = p1 + ", " + pushes[p1].definition.instructionName; task.code = ccode; String ffdecExecuteResult; try { Object res = ccode.execute(new HashMap<>(), abc.constants, adobeRuntime); ffdecExecuteResult = "Result:" + EcmaScript.toString(res) + " Type:" + EcmaScript.typeString(res); } catch (AVM2ExecutionException ex) { ffdecExecuteResult = "Error:" + ex.getMessage(); } task.ffdecResult = ffdecExecuteResult; tasks.add(task); } adobeExecutor.executeAvm2(tasks); for (AS3ExecuteTask task : tasks) { System.out.println("Flash result (" + task.description + "): " + task.flashResult); System.out.println("FFDec execte result: " + task.ffdecResult); assertEquals(task.ffdecResult, task.flashResult); } } //@Test public void testAs3() throws IOException, InterruptedException { AdobeFlashExecutor adobeExecutor = new AdobeFlashExecutor(); for (int i = 0; i < 256; i++) { System.out.println("Instruction code: " + Integer.toHexString(i) + " (" + i + ")"); List<AS3ExecuteTask> tasks = new ArrayList<>(); adobeExecutor.loadTestSwf(); ABC abc = adobeExecutor.as3TestSwfAbcTag.getABC(); AVM2Instruction[] pushes = getAs3Pushes(abc); for (int p1 = 0; p1 < pushes.length; p1++) { for (int p2 = 0; p2 < pushes.length; p2++) { // todo: the following instructions are not implemented if (i == AVM2Instructions.GetSuper || i == AVM2Instructions.SetSuper || i == AVM2Instructions.DXNS || i == AVM2Instructions.DXNSLate || i == AVM2Instructions.Kill || i == AVM2Instructions.LookupSwitch || i == AVM2Instructions.PushWith || i == AVM2Instructions.NextName || i == AVM2Instructions.HasNext || i == AVM2Instructions.NextValue || i == AVM2Instructions.PushScope || i == AVM2Instructions.PushNamespace || i == AVM2Instructions.HasNext2 || i == AVM2Instructions.NewFunction || i == AVM2Instructions.Call || i == AVM2Instructions.Construct || i == AVM2Instructions.CallMethod || i == AVM2Instructions.CallStatic || i == AVM2Instructions.CallSuper || i == AVM2Instructions.CallProperty || i == AVM2Instructions.ConstructSuper || i == AVM2Instructions.ConstructProp || i == AVM2Instructions.CallPropLex || i == AVM2Instructions.CallSuperVoid || i == AVM2Instructions.CallPropVoid || i == AVM2Instructions.ApplyType || i == AVM2Instructions.NewObject || i == AVM2Instructions.NewArray || i == AVM2Instructions.NewActivation || i == AVM2Instructions.NewClass || i == AVM2Instructions.GetDescendants || i == AVM2Instructions.NewCatch || i == AVM2Instructions.FindPropGlobal || i == AVM2Instructions.FindPropertyStrict || i == AVM2Instructions.FindProperty || i == AVM2Instructions.FindDef || i == AVM2Instructions.GetLex || i == AVM2Instructions.SetProperty || i == AVM2Instructions.GetGlobalScope || i == AVM2Instructions.GetScopeObject || i == AVM2Instructions.GetProperty || i == AVM2Instructions.GetOuterScope || i == AVM2Instructions.InitProperty || i == AVM2Instructions.DeleteProperty || i == AVM2Instructions.GetSlot || i == AVM2Instructions.SetSlot || i == AVM2Instructions.GetGlobalSlot || i == AVM2Instructions.SetGlobalSlot || i == AVM2Instructions.CheckFilter || i == AVM2Instructions.AsType // todo: fix || i == AVM2Instructions.AsTypeLate || i == AVM2Instructions.InstanceOf || i == AVM2Instructions.IsType || i == AVM2Instructions.IsTypeLate || i == AVM2Instructions.In) { continue; } AVM2Code ccode = new AVM2Code(); List<AVM2Instruction> 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.PushByte, new int[]{10})); code.add(new AVM2Instruction(0, AVM2Instructions.SetLocal0, null)); code.add(new AVM2Instruction(0, AVM2Instructions.PushByte, new int[]{11})); code.add(new AVM2Instruction(0, AVM2Instructions.SetLocal1, null)); code.add(new AVM2Instruction(0, AVM2Instructions.PushByte, new int[]{0})); code.add(pushes[p1].clone()); code.add(pushes[p2].clone()); InstructionDefinition ins = AVM2Code.instructionSet[i]; int[] params = null; boolean ifType = false; if (ins.operands.length > 0) { params = new int[ins.operands.length]; if (!(ins instanceof IfTypeIns)) { for (int param = 0; param < params.length; param++) { params[param] = 1; } } ifType = ins instanceof IfTypeIns; if (ifType) { params[0] = 3; } } code.add(new AVM2Instruction(0, ins, params)); if (ifType) { code.add(new AVM2Instruction(0, AVM2Instructions.PushString, new int[]{1})); code.add(new AVM2Instruction(0, AVM2Instructions.ReturnValue, null)); } code.add(new AVM2Instruction(0, AVM2Instructions.Dup, null)); code.add(new AVM2Instruction(0, AVM2Instructions.TypeOf, null)); code.add(new AVM2Instruction(0, AVM2Instructions.Add, null)); code.add(new AVM2Instruction(0, AVM2Instructions.ReturnValue, null)); ccode.markOffsets(); AS3ExecuteTask task = new AS3ExecuteTask(); task.description = "Instruction code: " + Integer.toHexString(i) + " (" + i + ") " + AVM2Code.instructionSet[i].instructionName + ", " + "p1: " + p1 + ", " + pushes[p1].definition.instructionName + ", " + "p2: " + p2 + ", " + pushes[p2].definition.instructionName; task.code = ccode; String ffdecExecuteResult; try { Object res = ccode.execute(new HashMap<>(), abc.constants, adobeRuntime); ffdecExecuteResult = "Result:" + EcmaScript.toString(res) + " Type:" + EcmaScript.typeString(res); } catch (AVM2ExecutionException ex) { ffdecExecuteResult = "Error:" + ex.getMessage(); } task.ffdecResult = ffdecExecuteResult; tasks.add(task); } } adobeExecutor.executeAvm2(tasks); StringBuilder expeced = new StringBuilder(); StringBuilder current = new StringBuilder(); for (AS3ExecuteTask task : tasks) { if (!task.flashResult.equals(task.ffdecResult)) { System.out.println("Flash result (" + task.description + "): " + task.flashResult); System.out.println("FFDec execte result: " + task.ffdecResult); expeced.append(task.flashResult).append(Helper.newLine); current.append(task.ffdecResult).append(Helper.newLine); } /*if (!task.ffdecResult.equals(task.flashResult)) { String ffdecExecuteResult; try { Object res = task.code.execute(new HashMap<>(), abc.constants, adobeRuntime); ffdecExecuteResult = "Result:" + EcmaScript.toString(res) + " Type:" + EcmaScript.typeString(res); } catch (AVM2ExecutionException ex) { ffdecExecuteResult = "Error:" + ex.getMessage(); } }*/ assertEquals(task.ffdecResult, task.flashResult); } //Helper.writeFile("expected\\" + i + ".txt", Utf8Helper.getBytes(expeced.toString())); //Helper.writeFile("current\\" + i + ".txt", Utf8Helper.getBytes(current.toString())); } } private AVM2Instruction[] getAs3Pushes(ABC abc) { AVM2Instruction[] pushes = new AVM2Instruction[]{ new AVM2Instruction(0, AVM2Instructions.PushUndefined, null), // 0 new AVM2Instruction(0, AVM2Instructions.PushNull, null), // 1 new AVM2Instruction(0, AVM2Instructions.PushTrue, null), // 2 new AVM2Instruction(0, AVM2Instructions.PushFalse, null), // 3 new AVM2Instruction(0, AVM2Instructions.PushNan, null), // 4 new AVM2Instruction(0, AVM2Instructions.PushString, new int[]{0}), // 5 new AVM2Instruction(0, AVM2Instructions.PushString, new int[]{abc.constants.getStringId("", true)}), // 6 new AVM2Instruction(0, AVM2Instructions.PushString, new int[]{abc.constants.getStringId("-2147483649", true)}), // 7 new AVM2Instruction(0, AVM2Instructions.PushString, new int[]{abc.constants.getStringId("-2147483648", true)}), // 8 new AVM2Instruction(0, AVM2Instructions.PushString, new int[]{abc.constants.getStringId("-2147483647", true)}), // 9 new AVM2Instruction(0, AVM2Instructions.PushString, new int[]{abc.constants.getStringId("-1", true)}), // 10 new AVM2Instruction(0, AVM2Instructions.PushString, new int[]{abc.constants.getStringId("0", true)}), // 11 new AVM2Instruction(0, AVM2Instructions.PushString, new int[]{abc.constants.getStringId("1", true)}), // 12 new AVM2Instruction(0, AVM2Instructions.PushString, new int[]{abc.constants.getStringId("2147483647", true)}), // 13 new AVM2Instruction(0, AVM2Instructions.PushString, new int[]{abc.constants.getStringId("2147483648", true)}), // 14 new AVM2Instruction(0, AVM2Instructions.PushString, new int[]{abc.constants.getStringId("4294967295", true)}), // 15 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 new AVM2Instruction(0, AVM2Instructions.PushDouble, new int[]{abc.constants.getDoubleId(0, true)}), // 22 new AVM2Instruction(0, AVM2Instructions.PushDouble, new int[]{abc.constants.getDoubleId(0.5, true)}), // 23 new AVM2Instruction(0, AVM2Instructions.PushDouble, new int[]{abc.constants.getDoubleId(1, true)}), // 24 new AVM2Instruction(0, AVM2Instructions.PushShort, new int[]{-2147483648}), // 25 new AVM2Instruction(0, AVM2Instructions.PushShort, new int[]{-2147483647}), // 26 new AVM2Instruction(0, AVM2Instructions.PushShort, new int[]{-1073741824}), // 27 new AVM2Instruction(0, AVM2Instructions.PushShort, new int[]{-1073741823}), // 28 new AVM2Instruction(0, AVM2Instructions.PushShort, new int[]{-536870912}), // 29 new AVM2Instruction(0, AVM2Instructions.PushShort, new int[]{-536870911}), // 30 new AVM2Instruction(0, AVM2Instructions.PushShort, new int[]{-268435456}), // 31 new AVM2Instruction(0, AVM2Instructions.PushShort, new int[]{-134217728}), // 32 new AVM2Instruction(0, AVM2Instructions.PushShort, new int[]{-134217727}), // 33 new AVM2Instruction(0, AVM2Instructions.PushShort, new int[]{-67108864}), // 34 new AVM2Instruction(0, AVM2Instructions.PushShort, new int[]{-67108863}), // 35 new AVM2Instruction(0, AVM2Instructions.PushShort, new int[]{-33554432}), // 36 new AVM2Instruction(0, AVM2Instructions.PushShort, new int[]{-33554431}), // 37 new AVM2Instruction(0, AVM2Instructions.PushShort, new int[]{-16777216}), // 38 new AVM2Instruction(0, AVM2Instructions.PushShort, new int[]{-16777215}), // 39 new AVM2Instruction(0, AVM2Instructions.PushShort, new int[]{-8388608}), // 40 new AVM2Instruction(0, AVM2Instructions.PushShort, new int[]{-8388607}), // 41 new AVM2Instruction(0, AVM2Instructions.PushShort, new int[]{-4194304}), // 42 new AVM2Instruction(0, AVM2Instructions.PushShort, new int[]{-4194303}), // 43 new AVM2Instruction(0, AVM2Instructions.PushShort, new int[]{-2097152}), // 44 new AVM2Instruction(0, AVM2Instructions.PushShort, new int[]{-2097151}), // 45 new AVM2Instruction(0, AVM2Instructions.PushShort, new int[]{-1048576}), // 46 new AVM2Instruction(0, AVM2Instructions.PushShort, new int[]{-1048575}), // 47 new AVM2Instruction(0, AVM2Instructions.PushShort, new int[]{-524288}), // 48 new AVM2Instruction(0, AVM2Instructions.PushShort, new int[]{-524287}), // 49 new AVM2Instruction(0, AVM2Instructions.PushShort, new int[]{-262144}), // 50 new AVM2Instruction(0, AVM2Instructions.PushShort, new int[]{-262143}), // 51 new AVM2Instruction(0, AVM2Instructions.PushShort, new int[]{-131072}), // 52 new AVM2Instruction(0, AVM2Instructions.PushShort, new int[]{-131071}), // 53 new AVM2Instruction(0, AVM2Instructions.PushShort, new int[]{-65536}), // 54 new AVM2Instruction(0, AVM2Instructions.PushShort, new int[]{-65535}), // 55 new AVM2Instruction(0, AVM2Instructions.PushShort, new int[]{-32768}), // 56 new AVM2Instruction(0, AVM2Instructions.PushShort, new int[]{-32767}), // 57 new AVM2Instruction(0, AVM2Instructions.PushShort, new int[]{-1}), // 58 new AVM2Instruction(0, AVM2Instructions.PushShort, new int[]{0}), // 59 new AVM2Instruction(0, AVM2Instructions.PushShort, new int[]{1}), // 60 /*new AVM2Instruction(0, AVM2Instructions.PushShort, new int[]{127}), // 61 new AVM2Instruction(0, AVM2Instructions.PushShort, new int[]{128}), // 62 new AVM2Instruction(0, AVM2Instructions.PushShort, new int[]{255}), // 61 new AVM2Instruction(0, AVM2Instructions.PushShort, new int[]{256}), // 62 new AVM2Instruction(0, AVM2Instructions.PushShort, new int[]{511}), // 61 new AVM2Instruction(0, AVM2Instructions.PushShort, new int[]{512}), // 62 new AVM2Instruction(0, AVM2Instructions.PushShort, new int[]{1023}), // 61 new AVM2Instruction(0, AVM2Instructions.PushShort, new int[]{1024}), // 62 new AVM2Instruction(0, AVM2Instructions.PushShort, new int[]{2047}), // 61 new AVM2Instruction(0, AVM2Instructions.PushShort, new int[]{2048}), // 62 new AVM2Instruction(0, AVM2Instructions.PushShort, new int[]{4095}), // 61 new AVM2Instruction(0, AVM2Instructions.PushShort, new int[]{4096}), // 62 new AVM2Instruction(0, AVM2Instructions.PushShort, new int[]{8191}), // 61 new AVM2Instruction(0, AVM2Instructions.PushShort, new int[]{8192}), // 62 new AVM2Instruction(0, AVM2Instructions.PushShort, new int[]{16383}), // 61 new AVM2Instruction(0, AVM2Instructions.PushShort, new int[]{16384}), // 62*/ new AVM2Instruction(0, AVM2Instructions.PushShort, new int[]{32767}), // 61 new AVM2Instruction(0, AVM2Instructions.PushShort, new int[]{32768}), // 62 new AVM2Instruction(0, AVM2Instructions.PushShort, new int[]{268435455}), // 63 new AVM2Instruction(0, AVM2Instructions.PushShort, new int[]{268435456}), // 64 new AVM2Instruction(0, AVM2Instructions.PushShort, new int[]{536870911}), // 65 new AVM2Instruction(0, AVM2Instructions.PushShort, new int[]{536870912}), // 66 new AVM2Instruction(0, AVM2Instructions.PushShort, new int[]{1073741823}), // 67 new AVM2Instruction(0, AVM2Instructions.PushShort, new int[]{1073741824}), // 68 new AVM2Instruction(0, AVM2Instructions.PushShort, new int[]{2147483647}), // 69 new AVM2Instruction(0, AVM2Instructions.PushInt, new int[]{0}), // 70 new AVM2Instruction(0, AVM2Instructions.PushInt, new int[]{abc.constants.getIntId(-2147483649L, true)}), // 71 new AVM2Instruction(0, AVM2Instructions.PushInt, new int[]{abc.constants.getIntId(-2147483648, true)}), // 72 new AVM2Instruction(0, AVM2Instructions.PushInt, new int[]{abc.constants.getIntId(-1, true)}), // 73 new AVM2Instruction(0, AVM2Instructions.PushInt, new int[]{abc.constants.getIntId(0, true)}), // 74 new AVM2Instruction(0, AVM2Instructions.PushInt, new int[]{abc.constants.getIntId(1, true)}), // 75 new AVM2Instruction(0, AVM2Instructions.PushInt, new int[]{abc.constants.getIntId(2147483647, true)}), // 76 new AVM2Instruction(0, AVM2Instructions.PushInt, new int[]{abc.constants.getIntId(2147483648L, true)}), // 77 new AVM2Instruction(0, AVM2Instructions.PushUInt, new int[]{abc.constants.getIntId(4294967295L, true)}), // 78 new AVM2Instruction(0, AVM2Instructions.PushUInt, new int[]{abc.constants.getIntId(4294967296L, true)}), // 79 new AVM2Instruction(0, AVM2Instructions.PushUInt, new int[]{0}), // 80 new AVM2Instruction(0, AVM2Instructions.PushUInt, new int[]{abc.constants.getUIntId(-2147483649L, true)}), // 81 new AVM2Instruction(0, AVM2Instructions.PushUInt, new int[]{abc.constants.getUIntId(-2147483648, true)}), // 82 new AVM2Instruction(0, AVM2Instructions.PushUInt, new int[]{abc.constants.getUIntId(-1, true)}), // 83 new AVM2Instruction(0, AVM2Instructions.PushUInt, new int[]{abc.constants.getUIntId(0, true)}), // 84 new AVM2Instruction(0, AVM2Instructions.PushUInt, new int[]{abc.constants.getUIntId(1, true)}), // 85 new AVM2Instruction(0, AVM2Instructions.PushUInt, new int[]{abc.constants.getUIntId(2147483647, true)}), // 86 new AVM2Instruction(0, AVM2Instructions.PushUInt, new int[]{abc.constants.getUIntId(2147483648L, true)}), // 87 new AVM2Instruction(0, AVM2Instructions.PushUInt, new int[]{abc.constants.getUIntId(4294967295L, true)}), // 88 new AVM2Instruction(0, AVM2Instructions.PushUInt, new int[]{abc.constants.getUIntId(4294967296L, true)}), // 89 new AVM2Instruction(0, AVM2Instructions.PushByte, new int[]{-2147483648}), // 90 new AVM2Instruction(0, AVM2Instructions.PushByte, new int[]{-256}), // 91 new AVM2Instruction(0, AVM2Instructions.PushByte, new int[]{-255}), // 92 new AVM2Instruction(0, AVM2Instructions.PushByte, new int[]{-128}), // 93 new AVM2Instruction(0, AVM2Instructions.PushByte, new int[]{-127}), // 94 new AVM2Instruction(0, AVM2Instructions.PushByte, new int[]{-2}), // 95 new AVM2Instruction(0, AVM2Instructions.PushByte, new int[]{-1}), // 96 new AVM2Instruction(0, AVM2Instructions.PushByte, new int[]{0}), // 97 new AVM2Instruction(0, AVM2Instructions.PushByte, new int[]{1}), // 98 new AVM2Instruction(0, AVM2Instructions.PushByte, new int[]{2}), // 99 new AVM2Instruction(0, AVM2Instructions.PushByte, new int[]{127}), // 100 new AVM2Instruction(0, AVM2Instructions.PushByte, new int[]{128}), // 101 new AVM2Instruction(0, AVM2Instructions.PushByte, new int[]{255}), // 102 new AVM2Instruction(0, AVM2Instructions.PushByte, new int[]{256}), // 103 new AVM2Instruction(0, AVM2Instructions.PushByte, new int[]{2147483647}),}; // 104 return pushes; } //@Test public void testAs2() throws InterruptedException { AdobeFlashExecutor adobeExecutor = new AdobeFlashExecutor(); List<AS2ExecuteTask> tasks = new ArrayList<>(); Object[] pushes = getAs2Pushes(); for (int i = 0; i < 13 + 23 + 2; i++) { for (int p1 = 0; p1 < 15; p1++) { int p2Count = 1; if (i >= 13) { p2Count = pushes.length; } for (int p2 = 0; p2 < p2Count; p2++) { List<Action> newActions = new ArrayList<>(); Action opAction = getOpAction(i); if (i >= 13 + 23) { newActions.add(new ActionPush("mystring_\u00E1rv\u00EDzt\u0171r\u0151_t\u00FCk\u00F6rf\u00FAr\u00F3g\u00E9p")); } Object p1o = pushes[p1]; Object p2o = null; if (i >= 13) { p2o = pushes[p2]; newActions.add(new ActionPush(p2o)); } newActions.add(new ActionPush(p1o)); newActions.add(opAction); newActions.add(new ActionPushDuplicate()); newActions.add(new ActionTypeOf()); newActions.add(new ActionStackSwap()); newActions.add(new ActionStringAdd()); AS2ExecuteTask task = new AS2ExecuteTask(); 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<GraphTargetItem> output = new ArrayList<>(); ActionLocalData localData = new ActionLocalData(); TranslateStack stack = new TranslateStack(""); for (Action a : newActions) { a.translate(localData, stack, output, Graph.SOP_USE_STATIC, ""); } String ffdecTranslateResult; try { Object res = stack.pop().getResult(); ffdecTranslateResult = "Result:" + EcmaScript.toString(res) + " Type:" + EcmaScript.typeString(res); } catch (Exception e) { ffdecTranslateResult = "Error:" + e.getMessage(); } String ffdecExecuteResult; try { LocalDataArea lda = new LocalDataArea(new Stage(null)); for (Action a : newActions) { if (!a.execute(lda)) { fail(); } } Object res = lda.stack.pop(); ffdecExecuteResult = "Result:" + EcmaScript.toString(res) + " Type:" + EcmaScript.typeString(res); } catch (Exception e) { ffdecExecuteResult = "Error:" + e.getMessage(); } assertEquals(ffdecTranslateResult, ffdecExecuteResult); task.ffdecResult = ffdecExecuteResult; tasks.add(task); } } } adobeExecutor.executeActionLists(tasks); StringBuilder expeced = new StringBuilder(); StringBuilder current = new StringBuilder(); for (AS2ExecuteTask task : tasks) { if (!task.flashResult.equals(task.ffdecResult)) { System.out.println("Flash result (" + task.description + "): " + task.flashResult); System.out.println("FFDec result: " + task.ffdecResult); expeced.append(task.description).append(task.flashResult).append(Helper.newLine); current.append(task.description).append(task.ffdecResult).append(Helper.newLine); } boolean checkOnlyStart = false; /*if (flashResult.length() > 10) { boolean onlyNumber = true; for (int k = 0; k < 10; k++) { char ch = flashResult.charAt(flashResult.length() - k - 1); if (ch < '0' || ch > '9') { onlyNumber = false; break; } } if (onlyNumber) { flashResult = flashResult.substring(0, flashResult.length() - 1); checkOnlyStart = true; } }*/ /*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) task.ffdecResult).startsWith(task.flashResult)); } else { assertEquals(task.ffdecResult, task.flashResult); } } //Helper.writeFile("expected.txt", Utf8Helper.getBytes(expeced.toString())); //Helper.writeFile("current.txt", Utf8Helper.getBytes(current.toString())); } private Object[] getAs2Pushes() { int r1 = random.nextInt(500) - 255; int r2 = random.nextInt(100); Object[] pushes = new Object[]{ Undefined.INSTANCE, Null.INSTANCE, false, true, Double.NaN, "", "-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, -100, 100, //r1, r2 -225, 66 }; return pushes; } private Action getOpAction(int idx) { Action result; if (idx < 13) { result = getUnaryOpAction(idx); assertEquals(1, result.getStackPopCount(null, null)); assertEquals(1, result.getStackPushCount(null, null)); } else if (idx < 13 + 23) { result = getBinaryOpAction(idx - 13); assertEquals(2, result.getStackPopCount(null, null)); assertEquals(1, result.getStackPushCount(null, null)); } else { result = getTernaryOpAction(idx - 13 - 23); assertEquals(3, result.getStackPopCount(null, null)); assertEquals(1, result.getStackPushCount(null, null)); } return result; } private Action getUnaryOpAction(int idx) { switch (idx) { case 0: return new ActionAsciiToChar(); case 1: return new ActionCharToAscii(); case 2: return new ActionDecrement(); case 3: return new ActionIncrement(); case 4: return new ActionNot(); case 5: return new ActionToInteger(); case 6: return new ActionToNumber(); case 7: return new ActionToString(); case 8: return new ActionTypeOf(); case 9: return new ActionStringLength(); case 10: return new ActionMBAsciiToChar(); case 11: return new ActionMBCharToAscii(); case 12: return new ActionMBStringLength(); } throw new Error("Invalid index"); } private Action getBinaryOpAction(int idx) { switch (idx) { case 0: return new ActionAnd(); case 1: return new ActionAdd(); case 2: return new ActionAdd2(); case 3: return new ActionBitAnd(); case 4: return new ActionBitLShift(); case 5: return new ActionBitOr(); case 6: return new ActionBitRShift(); case 7: return new ActionBitURShift(); case 8: return new ActionBitXor(); case 9: return new ActionDivide(); case 10: return new ActionEquals(); case 11: return new ActionEquals2(); case 12: return new ActionGreater(); case 13: return new ActionLess(); case 14: return new ActionLess2(); case 15: return new ActionModulo(); case 16: return new ActionMultiply(); case 17: return new ActionOr(); case 18: return new ActionStringAdd(); case 19: return new ActionStrictEquals(); case 20: return new ActionStringGreater(); case 21: return new ActionStringLess(); case 22: return new ActionSubtract(); } throw new Error("Invalid index"); } private Action getTernaryOpAction(int idx) { switch (idx) { case 0: return new ActionStringExtract(); case 1: return new ActionMBStringExtract(); } throw new Error("Invalid index"); } }