/// <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); } } }
XElement IActionVisitor <XElement, XElement> .Visit(ActionDefineFunction action, XElement param) { var res = new XElement(XActionNames.FromAction(action)); res.Add(new XAttribute("name", action.Name), new XAttribute("argc", action.Args.Count) ); var args = new XElement("args"); foreach (var arg in action.Args) { args.Add(new XElement("String", new XAttribute("value", arg))); } res.Add(args); if (action.Actions.Count > 0) { var xActions = new XElement("actions"); foreach (var subaction in action.Actions) { xActions.Add(XAction.ToXml(subaction)); } res.Add(xActions); } return(res); }
/// <summary> /// Read <see cref="SwfOp.ByteCode.Actions.ActionPushList">ActionDefineFunction</see> from swf. /// including inner actions /// </summary> private ActionDefineFunction ReadActionDefineFunction(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()); string[] parameterList = new string[numParams]; for (int i = 0; i < numParams; i++) { parameterList[i] = BinaryStringRW.ReadString(br); } int blockSize = Convert.ToInt32(br.ReadUInt16()); // read function body ArrayList InnerActions = ReadActions(br.ReadBytes(blockSize)); ActionDefineFunction a = new ActionDefineFunction(name, parameterList, InnerActions); int end = Convert.ToInt32(br.BaseStream.Position); //a.ByteSize = end-start +1; return(a); }
/// <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(ActionDefineFunction action, XElement xAction) { var xArgs = xAction.RequiredElement("args"); var xActions = xAction.Element("actions"); action.Name = xAction.RequiredStringAttribute("name"); foreach (var xArg in xArgs.Elements()) { action.Args.Add(xArg.RequiredStringAttribute("value")); } if (xActions != null) { XAction.FromXml(xActions, action.Actions); } return(action); }
///<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; } }