/// <summary> /// convert <see cref="SwfOp.ByteCode.Actions.ActionPushList">push list</see> to sequence of single <see cref="SwfOp.ByteCode.Actions.ActionPush" >push</see> actions /// </summary> private void ExplodePushLists(ArrayList actionRecord) { for (int i = 0; i < actionRecord.Count; i++) { BaseAction a = (BaseAction)actionRecord[i]; // check if action is multiple push ActionPushList pl = actionRecord[i] as ActionPushList; if (pl != null) { // resolve pushs to single push actions for (int j = 0; j < pl.Length; j++) { ActionPush p = pl[j]; actionRecord.Insert(i + 1 + j, p); } actionRecord.RemoveAt(i); } // process inner actionblocks if (a as ActionDefineFunction != null) { ActionDefineFunction f = (ActionDefineFunction)a; ExplodePushLists(f.ActionRecord); } if (a as ActionDefineFunction2 != null) { ActionDefineFunction2 f = (ActionDefineFunction2)a; ExplodePushLists(f.ActionRecord); } } }
public static void AreEqual(ActionDefineFunction2 expected, ActionDefineFunction2 actual, string message) { Assert.AreEqual(expected.Name, actual.Name); Assert.AreEqual(expected.RegisterCount, actual.RegisterCount); Assert.AreEqual(expected.PreloadParent, actual.PreloadParent); Assert.AreEqual(expected.PreloadRoot, actual.PreloadRoot); Assert.AreEqual(expected.SuppressSuper, actual.SuppressSuper); Assert.AreEqual(expected.PreloadSuper, actual.PreloadSuper); Assert.AreEqual(expected.SuppressArguments, actual.SuppressArguments); Assert.AreEqual(expected.PreloadArguments, actual.PreloadArguments); Assert.AreEqual(expected.SuppressThis, actual.SuppressThis); Assert.AreEqual(expected.PreloadThis, actual.PreloadThis); Assert.AreEqual(expected.Reserved, actual.Reserved); Assert.AreEqual(expected.PreloadGlobal, actual.PreloadGlobal); Assert.AreEqual(expected.Parameters.Count, actual.Parameters.Count, message + ".Parameters.Count"); for (var i = 0; i < expected.Parameters.Count; i++) { AreEqual(expected.Parameters[i], actual.Parameters[i], message + ".Parameters[" + i + "]"); } Assert.AreEqual(expected.Actions.Count, actual.Actions.Count, message + ".Actions.Count"); for (var i = 0; i < expected.Actions.Count; i++) { AreEqual(expected.Actions[i], actual.Actions[i], message + ".Parameters[" + i + "]"); } }
public static void AreEqual(ActionDefineFunction2 expected, ActionDefineFunction2 actual, string message) { Assert.AreEqual(expected.Name, actual.Name); Assert.AreEqual(expected.RegisterCount, actual.RegisterCount); Assert.AreEqual(expected.PreloadParent, actual.PreloadParent); Assert.AreEqual(expected.PreloadRoot, actual.PreloadRoot); Assert.AreEqual(expected.SuppressSuper, actual.SuppressSuper); Assert.AreEqual(expected.PreloadSuper, actual.PreloadSuper); Assert.AreEqual(expected.SuppressArguments, actual.SuppressArguments); Assert.AreEqual(expected.PreloadArguments, actual.PreloadArguments); Assert.AreEqual(expected.SuppressThis, actual.SuppressThis); Assert.AreEqual(expected.PreloadThis, actual.PreloadThis); Assert.AreEqual(expected.Reserved, actual.Reserved); Assert.AreEqual(expected.PreloadGlobal, actual.PreloadGlobal); Assert.AreEqual(expected.Parameters.Count, actual.Parameters.Count, message + ".Parameters.Count"); for (var i = 0; i < expected.Parameters.Count; i++) { AreEqual(expected.Parameters[i], actual.Parameters[i], message + ".Parameters[" + i + "]"); } Assert.AreEqual(expected.Actions.Count, actual.Actions.Count, message + ".Actions.Count"); for (var i = 0; i < expected.Actions.Count; i++) { AreEqual(expected.Actions[i], actual.Actions[i], message + ".Parameters[" + i + "]"); } }
/// <summary> /// Collaps sequence of single push actions into one multiple-push action /// </summary> private void CollapsPushActions(ArrayList actionRecord) { int i = 0; bool isPush; while (i < (actionRecord.Count - 1)) { isPush = actionRecord[i] is ActionPush; if (isPush) { int j = i; int count = 1; do { i++; if (i < actionRecord.Count) { isPush = (actionRecord[i] is ActionPush); if (isPush) { count++; } } } while ((isPush) && (i < actionRecord.Count)); if (count > 1) { ActionPush[] pushList = new ActionPush[count]; actionRecord.CopyTo(j, pushList, 0, count); actionRecord.RemoveRange(j, count); ActionPushList pl = new ActionPushList(pushList); actionRecord.Insert(j, pl); i = j + 1; } } else { // recursively step through functions inner actions ActionDefineFunction f = actionRecord[i] as ActionDefineFunction; if (f != null) { CollapsPushActions(f.ActionRecord); } // and function2 of course ActionDefineFunction2 f2 = actionRecord[i] as ActionDefineFunction2; if (f2 != null) { CollapsPushActions(f2.ActionRecord); } i++; } } }
///<summary> /// Calculate branch offsets. ///</summary> private void CalcBranchOffsets(ArrayList actionRecord) { if (actionRecord.Count < 1) { return; } ArrayList jumpList = new ArrayList(); Hashtable labelPos = new Hashtable(); int pos = 0; for (int i = 0; i < actionRecord.Count; i++) { BaseAction action = (BaseAction)actionRecord[i]; ActionLabel label = action as ActionLabel; IJump jump = action as IJump; if (label != null) { labelPos[label.LabelId] = pos; } if (jump != null) { jumpList.Add(new JumpPos(pos, jump)); } // recursively step through function blocks ActionDefineFunction f = actionRecord[i] as ActionDefineFunction; if (f != null) { CalcBranchOffsets(f.ActionRecord); } ActionDefineFunction2 f2 = actionRecord[i] as ActionDefineFunction2; if (f2 != null) { CalcBranchOffsets(f2.ActionRecord); } pos += action.ByteCount; } for (int i = 0; i < jumpList.Count; i++) { JumpPos j = (JumpPos)jumpList[i]; int offset = (int)labelPos[j.Jump.LabelId] - j.Position - 5; j.Jump.Offset = offset; } }
ActionBase IActionVisitor <XElement, ActionBase> .Visit(ActionDefineFunction2 action, XElement xAction) { var xName = xAction.Attribute("name"); var xRegisterCount = xAction.Attribute("regc"); var xPreloadParent = xAction.Attribute("preloadParent"); var xPreloadRoot = xAction.Attribute("preloadRoot"); var xSuppressSuper = xAction.Attribute("suppressSuper"); var xPreloadSuper = xAction.Attribute("preloadSuper"); var xSuppressArguments = xAction.Attribute("suppressArguments"); var xPreloadArguments = xAction.Attribute("preloadArguments"); var xSuppressThis = xAction.Attribute("suppressThis"); var xPreloadThis = xAction.Attribute("preloadThis"); var xReserved = xAction.Attribute("reserved"); var xPreloadGlobal = xAction.Attribute("preloadGlobal"); action.Name = xName != null ? xName.Value : ""; action.RegisterCount = byte.Parse(xRegisterCount.Value); action.PreloadParent = CommonFormatter.ParseBool(xPreloadParent.Value); action.PreloadRoot = CommonFormatter.ParseBool(xPreloadRoot.Value); action.SuppressSuper = CommonFormatter.ParseBool(xSuppressSuper.Value); action.PreloadSuper = CommonFormatter.ParseBool(xPreloadSuper.Value); action.SuppressArguments = CommonFormatter.ParseBool(xSuppressArguments.Value); action.PreloadArguments = CommonFormatter.ParseBool(xPreloadArguments.Value); action.SuppressThis = CommonFormatter.ParseBool(xSuppressThis.Value); action.PreloadThis = CommonFormatter.ParseBool(xPreloadThis.Value); action.Reserved = byte.Parse(xReserved.Value); action.PreloadGlobal = CommonFormatter.ParseBool(xPreloadGlobal.Value); var xArgs = xAction.Element("args"); foreach (var xArg in xArgs.Elements()) { var xReg = xArg.Attribute("reg"); var xArgName = xArg.Attribute("name"); action.Parameters.Add(new RegisterParam { Register = byte.Parse(xReg.Value), Name = xArgName.Value }); } var xActions = xAction.Element("actions"); foreach (var xSubAction in xActions.Elements()) { action.Actions.Add(Deserialize(xSubAction)); } return(action); }
/// <summary> /// Read <see cref="SwfOp.ByteCode.Actions.ActionPushList">ActionDefineFunction2</see> from swf. /// including inner actions /// </summary> private ActionDefineFunction2 ReadActionDefineFunction2(BinaryReader br) { int start = Convert.ToInt32(br.BaseStream.Position); // read block length int len = Convert.ToInt32(br.ReadUInt16()); string name = BinaryStringRW.ReadString(br); int numParams = Convert.ToInt32(br.ReadUInt16()); int numRegs = Convert.ToInt32(br.ReadByte()); byte flags1 = br.ReadByte(); byte flags2 = br.ReadByte(); ActionDefineFunction2.VariableFlagSet f = new ActionDefineFunction2.VariableFlagSet( (flags1 & 0x80) == 0x80, (flags1 & 0x40) == 0x40, (flags1 & 0x20) == 0x20, (flags1 & 0x10) == 0x10, (flags1 & 0x08) == 0x08, (flags1 & 0x04) == 0x04, (flags1 & 0x02) == 0x02, (flags1 & 0x01) == 0x01, (flags2 & 0x01) == 0x01 ); // read parameters ActionDefineFunction2.RegParamPair[] paramList = new ActionDefineFunction2.RegParamPair[numParams]; for (int i = 0; i < numParams; i++) { int r = Convert.ToInt32(br.ReadByte()); string p = BinaryStringRW.ReadString(br); paramList[i] = new ActionDefineFunction2.RegParamPair(r, p); } int blockSize = Convert.ToInt32(br.ReadUInt16()); // read function body ArrayList InnerActions = ReadActions(br.ReadBytes(blockSize)); ActionDefineFunction2 a = new ActionDefineFunction2(name, paramList, numRegs, f, InnerActions); int end = Convert.ToInt32(br.BaseStream.Position); ////a.ByteSize = len+3+blockSize; //a.ByteSize = end-start+1; return(a); }
XElement IActionVisitor <XElement, XElement> .Visit(ActionDefineFunction2 action, XElement res) { res.Add(new XAttribute("name", action.Name ?? "")); res.Add(new XAttribute("argc", action.Parameters.Count)); res.Add(new XAttribute("regc", action.RegisterCount)); res.Add(new XAttribute("preloadParent", CommonFormatter.Format(action.PreloadParent))); res.Add(new XAttribute("preloadRoot", CommonFormatter.Format(action.PreloadRoot))); res.Add(new XAttribute("suppressSuper", CommonFormatter.Format(action.SuppressSuper))); res.Add(new XAttribute("preloadSuper", CommonFormatter.Format(action.PreloadSuper))); res.Add(new XAttribute("suppressArguments", CommonFormatter.Format(action.SuppressArguments))); res.Add(new XAttribute("preloadArguments", CommonFormatter.Format(action.PreloadArguments))); res.Add(new XAttribute("suppressThis", CommonFormatter.Format(action.SuppressThis))); res.Add(new XAttribute("preloadThis", CommonFormatter.Format(action.PreloadThis))); res.Add(new XAttribute("reserved", action.Reserved)); res.Add(new XAttribute("preloadGlobal", CommonFormatter.Format(action.PreloadGlobal))); var xArgs = new XElement("args"); foreach (var arg in action.Parameters) { xArgs.Add(new XElement("Parameter", new XAttribute("reg", arg.Register), new XAttribute("name", arg.Name))); } res.Add(xArgs); var xActions = new XElement("actions"); foreach (var subaction in action.Actions) { xActions.Add(Serialize(subaction)); } res.Add(xActions); return(res); }
///<summary> /// Calculate size or offset for action blocks. ///</summary> private void CalcBlockOffsets(ArrayList actionRecord) { if (actionRecord.Count < 1) { return; } for (int i = 0; i < actionRecord.Count; i++) { BaseAction a = (BaseAction)actionRecord[i]; // action with ActionWith aWith = a as ActionWith; if (aWith != null) { int j = i; int offset = 0; do { j++; offset += ((BaseAction)actionRecord[j]).ByteCount; } while ((actionRecord[j] as ActionEndWith) == null); int oldOffset = aWith.BlockLength; aWith.BlockLength = offset; } // action waitForFrame ActionWaitForFrame aWait = a as ActionWaitForFrame; if (aWait != null) { int j = i; int count = 0; BaseAction ca; do { j++; ca = (BaseAction)actionRecord[j]; if ((ca.Code >= 0) || (ca.Code == (int)ActionCode.PushList)) { count++; } } while ((ca as ActionEndWait) == null); aWait.SkipCount = count; } // action waitForFrame2 ActionWaitForFrame2 aWait2 = a as ActionWaitForFrame2; if (aWait2 != null) { int j = i; int count = 0; BaseAction ca; do { j++; ca = (BaseAction)actionRecord[j]; if ((ca.Code >= 0) || (ca.Code == (int)ActionCode.PushList)) { count++; } } while ((ca as ActionEndWait) == null); aWait2.SkipCount = count; } // action function ActionDefineFunction f = actionRecord[i] as ActionDefineFunction; if (f != null) { CalcBlockOffsets(f.ActionRecord); } // action function2 ActionDefineFunction2 f2 = actionRecord[i] as ActionDefineFunction2; if (f2 != null) { CalcBlockOffsets(f2.ActionRecord); } } }
/// <summary> /// Examine byte code action at index in action record. /// </summary> public void Examine(int index, BaseAction a) { ActionPush p; int args; CodeTraverser trav; switch (a.Code) { case (int)ActionCode.StackSwap: object o1 = stack.Pop(); object o2 = stack.Pop(); stack.Push(o1); stack.Push(o2); break; case (int)ActionCode.PushDuplicate: stack.Push(stack.Peek()); break; case (int)ActionCode.Push: stack.Push(a); break; // -------------------------------------- case (int)ActionCode.CallMethod: ActionCallMethod cm = a as ActionCallMethod; stack.Pop(); // name stack.Pop(); // script object p = stack.Pop() as ActionPush; args = p.GetIntValue(); for (int i = 0; i < args; i++) { stack.Pop(); } if (args > -1) { cm.NumArgs = args; } stack.Push(null); break; case (int)ActionCode.CallFunction: ActionCallFunction cf = a as ActionCallFunction; stack.Pop(); // name p = stack.Pop() as ActionPush; args = p.GetIntValue(); for (int i = 0; i < args; i++) { stack.Pop(); } if (args > -1) { cf.NumArgs = args; } stack.Push(null); break; // -------------------------------------- case (int)ActionCode.InitArray: ActionInitArray ia = a as ActionInitArray; p = stack.Pop() as ActionPush; args = p.GetIntValue(); for (int i = 0; i < args; i++) { stack.Pop(); } ia.NumValues = args; stack.Push(null); break; case (int)ActionCode.InitObject: ActionInitObject io = a as ActionInitObject; p = stack.Pop() as ActionPush; args = p.GetIntValue(); for (int i = 0; i < args; i++) { stack.Pop(); stack.Pop(); } io.NumProps = args; stack.Push(null); break; case (int)ActionCode.NewObject: ActionNewObject n = a as ActionNewObject; stack.Pop(); p = stack.Pop() as ActionPush; args = p.GetIntValue(); for (int i = 0; i < args; i++) { stack.Pop(); } n.NumArgs = args; stack.Push(null); break; case (int)ActionCode.NewMethod: ActionNewMethod nm = a as ActionNewMethod; stack.Pop(); stack.Pop(); p = stack.Pop() as ActionPush; args = p.GetIntValue(); for (int i = 0; i < args; i++) { stack.Pop(); } nm.NumArgs = args; stack.Push(null); break; case (int)ActionCode.Implements: ActionImplements aimpl = a as ActionImplements; stack.Pop(); // constructor function // interface count p = stack.Pop() as ActionPush; args = p.GetIntValue(); // pop interfaces for (int i = 0; i < args; i++) { stack.Pop(); } aimpl.NumInterfaces = args; break; // -------------------------------------- case (int)ActionCode.DefineFunction: ActionDefineFunction f = a as ActionDefineFunction; trav = new CodeTraverser(f.ActionRecord); trav.Traverse(new InvocationExaminer()); stack.Push(null); break; case (int)ActionCode.DefineFunction2: ActionDefineFunction2 f2 = a as ActionDefineFunction2; trav = new CodeTraverser(f2.ActionRecord); trav.Traverse(new InvocationExaminer()); stack.Push(null); break; // -------------------------------------- default: try { for (int i = 0; i < a.PopCount; i++) { stack.Pop(); } for (int i = 0; i < a.PushCount; i++) { stack.Push(null); } } // stack empty catch (InvalidOperationException e) { if (e != null) { } stack.Clear(); } break; } }