void handleConstraint(DataElement element, BitStream data) { logger.Debug("Running constraint [" + element.constraint + "]"); Dictionary <string, object> scope = new Dictionary <string, object>(); scope["element"] = element; var iv = element.InternalValue; if (iv.GetVariantType() == Variant.VariantType.ByteString || iv.GetVariantType() == Variant.VariantType.BitStream) { scope["value"] = (byte[])iv; logger.Debug("Constraint, value=byte array."); } else { scope["value"] = (string)iv; logger.Debug("Constraint, value=[" + (string)iv + "]."); } object oReturn = Scripting.EvalExpression(element.constraint, scope); if (!((bool)oReturn)) { throw new CrackingFailure("Constraint failed.", element, data); } }
public override long GetValue() { if (_isRecursing) { return(0); } try { _isRecursing = true; long size = (long)From.DefaultValue; if (_expressionGet != null) { Dictionary <string, object> state = new Dictionary <string, object>(); state["size"] = size; state["value"] = size; state["self"] = From; object value = Scripting.EvalExpression(_expressionGet, state); size = Convert.ToInt64(value); } if (lengthType == LengthType.Bytes) { size = size * 8; } return(size); } finally { _isRecursing = false; } }
protected override Variant fixupImpl() { if (_pythonFixup == null) { Dictionary <string, object> state = new Dictionary <string, object>(); state["fixupSelf"] = this; _pythonFixup = Scripting.EvalExpression( string.Format("{0}(fixupSelf)", (string)args["class"]), state); } var from = elements["ref"]; logger.Debug("fixupImpl(): ref: " + from.GetHashCode().ToString()); object data = _pythonFixup.fixup(from); if (data is byte[]) { return(new Variant((byte[])data)); } else if (data is string) { return(new Variant((string)data)); } else if (data is int) { return(new Variant((int)data)); } logger.Error("Error, unknown type [" + data.GetType().ToString() + "]."); throw new ApplicationException("Error, unknown type [" + data.GetType().ToString() + "]."); }
public ScriptFixup(DataElement parent, Dictionary <string, Variant> args) : base(parent, args, "ref") { try { Dictionary <string, object> state = new Dictionary <string, object>(); state["fixupSelf"] = this; _pythonFixup = Scripting.EvalExpression( string.Format("{0}(fixupSelf)", (string)args["class"]), state); if (_pythonFixup == null) { throw new PeachException("Error, unable to create an instance of the \"" + (string)args["class"] + "\" script class."); } logger.Debug("ScriptFixup(): _pythonFixup != null"); } catch (Exception ex) { logger.Debug("class: " + (string)args["class"]); logger.Error(ex.Message); throw; } }
public override long GetValue() { if (_isRecursing) { return(0); } try { _isRecursing = true; long offset = (long)From.DefaultValue; if (_expressionGet != null) { Dictionary <string, object> state = new Dictionary <string, object>(); state["offset"] = offset; state["value"] = offset; state["self"] = this._parent; object value = Scripting.EvalExpression(_expressionGet, state); offset = Convert.ToInt64(value); } return(offset); } finally { _isRecursing = false; } }
public object CallMethod(string method, object[] args) { if (comObject == null) { throw new Exception("Error, please call Initalize first!"); } Dictionary <string, object> state = new Dictionary <string, object>(); state["ComObject"] = comObject; string cmd = "ComObject." + method + "("; int count = 0; foreach (object arg in args) { state["ComArgs_" + count] = arg; cmd += "ComArgs_" + count + ","; count++; } if (count > 0) { // Remove that last comma :) cmd = cmd.Substring(0, cmd.Length - 1); } cmd += ")"; return(Scripting.EvalExpression(cmd, state)); }
public override Variant CalculateFromValue() { if (_isRecursing) { return(new Variant(0)); } try { if (Of == null) { logger.Error("Error, Of returned null"); return(null); } _isRecursing = true; long size = Of.Value.LengthBits; if (lengthType == LengthType.Bytes) { if (_expressionSet != null) { Dictionary <string, object> state = new Dictionary <string, object>(); state["size"] = size / 8; state["value"] = size / 8; state["self"] = From; object newValue = Scripting.EvalExpression(_expressionSet, state); size = Convert.ToInt64(newValue) * 8; } size = size / 8; } else { if (_expressionSet != null) { Dictionary <string, object> state = new Dictionary <string, object>(); state["size"] = size; state["value"] = size; state["self"] = From; object newValue = Scripting.EvalExpression(_expressionSet, state); size = Convert.ToInt64(newValue); } } return(new Variant(size)); } finally { _isRecursing = false; } }
public override Variant CalculateFromValue() { if (_isRecursing) { return(new Variant(0)); } try { _isRecursing = true; if (Of == null) { logger.Error("Error, Of returned null"); return(null); } Array OfArray = Of as Array; if (OfArray == null) { logger.Error( string.Format("Count Relation requires '{0}' to be an array. Set the minOccurs and maxOccurs properties.", OfName)); return(null); } int count = OfArray.Count; // Allow us to override the count of the array if (OfArray.overrideCount.HasValue) { count = (int)OfArray.overrideCount; } if (_expressionSet != null) { Dictionary <string, object> state = new Dictionary <string, object>(); state["count"] = count; state["value"] = count; state["self"] = this._parent; object value = Scripting.EvalExpression(_expressionSet, state); count = Convert.ToInt32(value); } return(new Variant(count)); } finally { _isRecursing = false; } }
public void SetProperty(string property, object value) { if (comObject == null) { throw new Exception("Error, please call Initalize first!"); } Dictionary <string, object> state = new Dictionary <string, object>(); state["ComObject"] = comObject; state["ComArg"] = value; string cmd = "setattr(ComObject, '" + property + "', ComArg)"; Scripting.EvalExpression(cmd, state); }
protected virtual void OnStarting() { if (!string.IsNullOrEmpty(onStart)) { Dictionary <string, object> state = new Dictionary <string, object>(); state["action"] = this; state["state"] = this.parent; state["self"] = this; Scripting.EvalExpression(onStart, state); } if (Starting != null) { Starting(this); } }
protected virtual void OnFinished() { if (!string.IsNullOrEmpty(onComplete)) { Dictionary <string, object> state = new Dictionary <string, object>(); state["action"] = this; state["state"] = this.parent; state["self"] = this; Scripting.EvalExpression(onComplete, state); } if (Finished != null) { Finished(this); } }
public override void SetValue(Variant value) { int size = (int)value; if (_expressionSet != null) { Dictionary <string, object> state = new Dictionary <string, object>(); state["size"] = size / 8; state["value"] = size / 8; state["self"] = From; object newValue = Scripting.EvalExpression(_expressionSet, state); size = Convert.ToInt32(newValue); } From.DefaultValue = new Variant(size); }
public override void SetValue(Variant value) { int offset = (int)value; if (_expressionSet != null) { Dictionary <string, object> state = new Dictionary <string, object>(); state["offset"] = offset; state["value"] = offset; state["self"] = this._parent; object newValue = Scripting.EvalExpression(_expressionGet, state); offset = Convert.ToInt32(newValue); } _from.DefaultValue = new Variant(offset); }
protected override Variant fixupImpl() { var from = elements["ref"]; string expression = (string)args["expression"]; byte[] data = from.Value.Value; Dictionary <string, object> state = new Dictionary <string, object>(); state["self"] = this; state["ref"] = from; state["data"] = data; try { object value = Scripting.EvalExpression(expression, state); if (value is string) { string str = value as string; byte[] strbytes = new byte[str.Length]; for (int i = 0; i < strbytes.Length; ++i) { strbytes[i] = (byte)str[i]; } return(new Variant(strbytes)); } else if (value is int) { return(new Variant(Convert.ToInt32(value))); } else { throw new PeachException( string.Format("ExpressionFixup expected a return value of string or int but got '{0}'", value.GetType().Name)); } } catch (System.Exception ex) { throw new PeachException( string.Format("ExpressionFixup expression threw an exception!\nExpression: {0}\n Exception: {1}", expression, ex.ToString()), ex); } }
public override Variant CalculateFromValue() { if (_isRecursing) { return(new Variant(0)); } try { if (Of == null) { logger.Error("Error, Of returned null"); return(null); } _isRecursing = true; // calculateOffset can throw PeachException during mutations // we will catch and return null; long offset = calculateOffset(From, Of) / 8; if (_expressionGet != null) { Dictionary <string, object> state = new Dictionary <string, object>(); state["offset"] = offset; state["value"] = offset; state["self"] = this._parent; object value = Scripting.EvalExpression(_expressionSet, state); offset = Convert.ToInt32(value); } return(new Variant(offset)); } catch (PeachException ex) { logger.Error(ex.Message); return(null); } finally { _isRecursing = false; } }
void addElements(DataElement de, BitStream data, Dictionary <DataElement, Position> positions, long offset) { Position pos; if (!positions.TryGetValue(de, out pos)) { pos = new Position() { begin = -offset, end = -offset } } ; OnEnterHandleNodeEvent(de, offset + pos.begin, data); var cont = de as DataElementContainer; if (cont != null) { foreach (var child in cont) { addElements(child, data, positions, offset); } } OnExitHandleNodeEvent(de, offset + pos.end, data); } #endregion #region Handlers #region Top Level Handlers void handleRoot(DataElement element, BitStream data) { _sizedElements = new Dictionary <DataElement, SizedPosition>(); _sizeRelations = new List <SizeRelation>(); _elementsWithAnalyzer = new List <DataElement>(); // We want at least 1 byte before we begin data.WantBytes(1); // Crack the model handleNode(element, data); // Handle any analyzers foreach (DataElement elem in _elementsWithAnalyzer) { OnAnalyzerEvent(elem, data); var positions = new Dictionary <DataElement, Position>(); var parent = elem.parent; try { elem.analyzer.asDataElement(elem, positions); } catch (Exception ex) { throw new CrackingFailure("Exception in analyzer on '" + elem.fullName + "': " + ex.Message, elem, data, ex); } var de = parent[elem.name]; var pos = _sizedElements[elem]; positions[elem] = new Position() { begin = 0, end = pos.end - pos.begin }; addElements(de, data, positions, pos.begin); } } /// <summary> /// Called to crack a DataElement based on an input stream. This method /// will hand cracking off to a more specific method after performing /// some common tasks. /// </summary> /// <param name="elem">DataElement to crack</param> /// <param name="data">Input stream to use for data</param> void handleNode(DataElement elem, BitStream data) { List <BitStream> oldStack = null; try { if (elem == null) { throw new ArgumentNullException("elem"); } if (data == null) { throw new ArgumentNullException("data"); } logger.Debug("------------------------------------"); logger.Debug("{0} {1}", elem.debugName, data.Progress); var pos = handleNodeBegin(elem, data); if (elem.transformer != null) { long startPos = data.PositionBits; var sizedData = elem.ReadSizedData(data, pos.size); var decodedData = elem.transformer.decode(sizedData); // Make a new stack of data for the decoded data oldStack = _dataStack; _dataStack = new List <BitStream>(); _dataStack.Add(decodedData); // Use the size of the transformed data as the new size of the element handleCrack(elem, decodedData, decodedData.LengthBits); // Make sure the non-decoded data is at the right place if (data == decodedData) { data.SeekBits(startPos + decodedData.LengthBits, System.IO.SeekOrigin.Begin); } } else { handleCrack(elem, data, pos.size); } if (elem.constraint != null) { handleConstraint(elem, data); } if (elem.analyzer != null) { _elementsWithAnalyzer.Add(elem); } handleNodeEnd(elem, data, pos); } catch (Exception e) { handleException(elem, data, e); throw; } finally { if (oldStack != null) { _dataStack = oldStack; } } } void handlePlacelemt(DataElement element, BitStream data) { var fixups = new List <Tuple <Fixup, string, string> >(); DataElementContainer oldParent = element.parent; // Ensure relations are resolved foreach (var relation in element.relations) { if (relation.Of != element && relation.From != element) { throw new CrackingFailure("Error, unable to resolve Relations of/from to match current element.", element, data); } } // Locate relevant fixups DataElementContainer root = element.getRoot() as DataElementContainer; foreach (DataElement child in root.EnumerateAllElements()) { if (child.fixup == null) { continue; } foreach (var item in child.fixup.references) { var refElem = child.find(item.Item2); if (refElem == null) { throw new CrackingFailure("Error, unable to resolve Fixup reference to match current element.", element, data); } if (refElem == element) { fixups.Add(new Tuple <Fixup, string, string>(child.fixup, item.Item1, null)); } else if (!refElem.isChildOf(element)) { fixups.Add(new Tuple <Fixup, string, string>(child.fixup, item.Item1, refElem.fullName)); } } } // Update fixups foreach (var fixup in fixups) { if (fixup.Item3 != null) { fixup.Item1.updateRef(fixup.Item2, fixup.Item3); } } string debugName = element.debugName; DataElement newElem = null; if (element.placement.after != null) { var after = element.find(element.placement.after); if (after == null) { throw new CrackingFailure("Error, unable to resolve Placement on element '" + element.fullName + "' with 'after' == '" + element.placement.after + "'.", element, data); } newElem = element.MoveAfter(after); } else if (element.placement.before != null) { DataElement before = element.find(element.placement.before); if (before == null) { throw new CrackingFailure("Error, unable to resolve Placement on element '" + element.fullName + "' with 'after' == '" + element.placement.after + "'.", element, data); } newElem = element.MoveBefore(before); } // Update fixups foreach (var fixup in fixups) { if (fixup.Item3 == null) { fixup.Item1.updateRef(fixup.Item2, newElem.fullName); } } // Clear placement now that it has occured newElem.placement = null; logger.Debug("handlePlacement: {0} -> {1}", debugName, newElem.fullName); OnPlacementEvent(element, newElem, oldParent); } #endregion #region Helpers void handleOffsetRelation(DataElement element, BitStream data) { long?offset = getRelativeOffset(element, data, 0); if (!offset.HasValue) { return; } offset += data.PositionBits; if (offset > data.LengthBits) { data.WantBytes((offset.Value + 7 - data.LengthBits) / 8); } if (offset > data.LengthBits) { string msg = "{0} has offset of {1} bits but buffer only has {2} bits.".Fmt( element.debugName, offset, data.LengthBits); throw new CrackingFailure(msg, element, data); } data.SeekBits(offset.Value, System.IO.SeekOrigin.Begin); } void handleException(DataElement elem, BitStream data, Exception e) { _sizedElements.Remove(elem); _sizeRelations.RemoveAll(r => r.Of == elem); CrackingFailure ex = e as CrackingFailure; if (ex != null) { logger.Debug("{0} failed to crack.", elem.debugName); if (!ex.logged) { logger.Debug(ex.Message); } ex.logged = true; } else { logger.Debug("Exception occured: {0}", e.ToString()); } OnExceptionHandleNodeEvent(elem, data.PositionBits, data, e); } void handleConstraint(DataElement element, BitStream data) { logger.Debug("Running constraint [" + element.constraint + "]"); Dictionary <string, object> scope = new Dictionary <string, object>(); scope["element"] = element; // Use DefaultValue for constraint, it is the actual cracked value. // InternalValue will have relations/fixups applied var iv = element.DefaultValue; if (iv == null) { scope["value"] = null; logger.Debug("Constraint, value=None."); } else if (iv.GetVariantType() == Variant.VariantType.ByteString || iv.GetVariantType() == Variant.VariantType.BitStream) { scope["value"] = (BitwiseStream)iv; logger.Debug("Constraint, value=byte array."); } else { scope["value"] = (string)iv; logger.Debug("Constraint, value=[" + (string)iv + "]."); } object oReturn = Scripting.EvalExpression(element.constraint, scope); if (!((bool)oReturn)) { throw new CrackingFailure("Constraint failed.", element, data); } } SizedPosition handleNodeBegin(DataElement elem, BitStream data) { handleOffsetRelation(elem, data); System.Diagnostics.Debug.Assert(!_sizedElements.ContainsKey(elem)); long?size = getSize(elem, data); var pos = new SizedPosition(); pos.begin = data.PositionBits + getDataOffset(); pos.size = size; _sizedElements.Add(elem, pos); // If this element does not have a size but has a size relation, // keep track of the relation for evaluation in the future if (!size.HasValue) { var rel = elem.relations.Of <SizeRelation>(); _sizeRelations.AddRange(rel); } OnEnterHandleNodeEvent(elem, pos.begin, data); return(pos); } void handleNodeEnd(DataElement elem, BitStream data, Position pos) { // Completing this element might allow us to evaluate // outstanding size reation computations. for (int i = _sizeRelations.Count - 1; i >= 0; --i) { var rel = _sizeRelations[i]; if (elem == rel.From) { var other = _sizedElements[rel.Of]; long size = rel.GetValue(); if (other.size.HasValue) { logger.Debug("Size relation of {0} cracked again. Updating size from: {1} to: {2}", rel.Of.debugName, other.size, size); } else { logger.Debug("Size relation of {0} cracked. Updating size to: {1}", rel.Of.debugName, size); } other.size = size; _sizeRelations.RemoveAt(i); } var cont = elem as DataElementContainer; if (cont != null && cont.isParentOf(rel.From)) { // If we have finished cracking the parent of the From half of // an outstanding size relation, this means we never cracked // the From element. This can happen when the From half is in // a choice. Just stop tracking the incomplete relation and // keep going. _sizeRelations.RemoveAt(i); } } // Mark the end position of this element pos.end = data.PositionBits + getDataOffset(); OnExitHandleNodeEvent(elem, pos.end, data); } void handleCrack(DataElement elem, BitStream data, long?size) { logger.Debug("Crack: {0} Size: {1}, {2}", elem.debugName, size.HasValue ? size.ToString() : "<null>", data.Progress); elem.Crack(this, data, size); } #endregion #endregion #region Calculate Element Size long?getRelativeOffset(DataElement elem, BitStream data, long minOffset = 0) { var relations = elem.relations.Of <OffsetRelation>(); if (!relations.Any()) { return(null); } // Ensure we have cracked the from half of the relation var rel = relations.Where(HasCracked).FirstOrDefault(); if (rel == null) { return(null); } // Offset is in bytes long offset = (long)rel.GetValue() * 8; if (rel.isRelativeOffset) { DataElement from = rel.From; if (rel.relativeTo != null) { from = from.find(rel.relativeTo); } if (from == null) { throw new CrackingFailure("Unable to locate 'relativeTo' element in relation attached to " + elem.debugName + "'.", elem, data); } // Get the position we are related to SizedPosition pos; if (!_sizedElements.TryGetValue(from, out pos)) { return(null); } // If relativeTo, offset is from beginning of relativeTo element // Otherwise, offset is after the From element offset += rel.relativeTo != null ? pos.begin : pos.end; } // Adjust offset to be relative to the current BitStream offset -= getDataOffset(); // Ensure the offset is not before our current position if (offset < data.PositionBits) { string msg = "{0} has offset of {1} bits but already read {2} bits.".Fmt( elem.debugName, offset, data.PositionBits); throw new CrackingFailure(msg, elem, data); } // Make offset relative to current position offset -= data.PositionBits; // Ensure the offset satisfies the minimum if (offset < minOffset) { string msg = "{0} has offset of {1} bits but must be at least {2} bits.".Fmt( elem.debugName, offset, minOffset); throw new CrackingFailure(msg, elem, data); } return(offset); } /// <summary> /// Searches data for the first occurance of token starting at offset. /// </summary> /// <param name="data">BitStream to search in.</param> /// <param name="token">BitStream to search for.</param> /// <param name="offset">How many bits after the current position of data to start searching.</param> /// <returns>The location of the token in data from the current position or null.</returns> long?findToken(BitStream data, BitwiseStream token, long offset) { while (true) { long start = data.PositionBits; long end = data.IndexOf(token, start + offset); if (end >= 0) { return(end - start); } long dataLen = data.Length; data.WantBytes(token.Length); if (dataLen == data.Length) { return(null); } } } bool?scanArray(Dom.Array array, ref long pos, List <Mark> tokens, Until until) { logger.Debug("scanArray: {0}", array.debugName); int tokenCount = tokens.Count; long arrayPos = 0; var ret = scan(array.origionalElement, ref arrayPos, tokens, null, until); for (int i = tokenCount; i < tokens.Count; ++i) { tokens[i].Optional = array.Count >= array.minOccurs; tokens[i].Position += pos; } if (ret.HasValue && ret.Value) { if (until == Until.FirstSized) { ret = false; } var relations = array.relations.Of <CountRelation>(); if (relations.Any()) { var rel = relations.Where(HasCracked).FirstOrDefault(); if (rel != null) { arrayPos *= rel.GetValue(); pos += arrayPos; logger.Debug("scanArray: {0} -> Count Relation: {1}, Size: {2}", array.debugName, rel.GetValue(), arrayPos); return(ret); } else { logger.Debug("scanArray: {0} -> Count Relation: ???", array.debugName); return(null); } } else if (array.minOccurs == 1 && array.maxOccurs == 1) { arrayPos *= array.occurs; pos += arrayPos; logger.Debug("scanArray: {0} -> Occurs: {1}, Size: {2}", array.debugName, array.occurs, arrayPos); return(ret); } else { // If the count is unknown, treat the array unsized ret = null; // If no tokens were found in the array, we are done if (tokenCount == tokens.Count) { logger.Debug("scanArray: {0} -> Count Unknown", array.debugName); return(ret); } } } // If we are looking for the first sized element, try cracking our first element if (until == Until.FirstSized) { logger.Debug("scanArray: {0} -> FirstSized", array.debugName); return(false); } if (tokenCount == tokens.Count) { logger.Debug("scanArray: {0} -> No Tokens", array.debugName); //ret.HasValue ? "Deterministic" : "Unsized"); return(false); } // If we have tokens, keep scanning thru the dom. logger.Debug("scanArray: {0} -> Tokens", array.debugName); return(true); }
public void Run(RunContext context) { logger.Trace("Run({0}): {1}", name, type); if (when != null) { Dictionary <string, object> state = new Dictionary <string, object>(); state["context"] = context; state["Context"] = context; state["action"] = this; state["Action"] = this; state["state"] = this.parent; state["State"] = this.parent; state["StateModel"] = this.parent.parent; state["Test"] = this.parent.parent.parent; state["self"] = this; object value = Scripting.EvalExpression(when, state); if (!(value is bool)) { logger.Debug("Run: action '{0}' when return is not boolean, returned: {1}", name, value); return; } if (!(bool)value) { logger.Debug("Run: action '{0}' when returned false", name); return; } } try { Publisher publisher = null; if (this.publisher != null && this.publisher != "Peach.Agent") { if (!context.test.publishers.ContainsKey(this.publisher)) { logger.Debug("Run: Publisher '" + this.publisher + "' not found!"); throw new PeachException("Error, Action '" + name + "' publisher value '" + this.publisher + "' was not found!"); } publisher = context.test.publishers[this.publisher]; } else { publisher = context.test.publishers[0]; } if (context.controlIteration && context.controlRecordingIteration) { logger.Debug("Run: Adding action to controlRecordingActionsExecuted"); context.controlRecordingActionsExecuted.Add(this); } else if (context.controlIteration) { logger.Debug("Run: Adding action to controlActionsExecuted"); context.controlActionsExecuted.Add(this); } started = true; finished = false; error = false; OnStarting(); logger.Debug("ActionType.{0}", type.ToString()); switch (type) { case ActionType.Start: publisher.start(); break; case ActionType.Stop: publisher.close(); publisher.stop(); break; case ActionType.Open: case ActionType.Connect: publisher.start(); publisher.open(); break; case ActionType.Close: publisher.start(); publisher.close(); break; case ActionType.Accept: publisher.start(); publisher.open(); publisher.accept(); break; case ActionType.Input: publisher.start(); publisher.open(); publisher.input(); handleInput(publisher); parent.parent.dataActions.Add(this); break; case ActionType.Output: publisher.start(); if (publisher is FilePublisher) { if (context.config.outputFilePath != null) { FilePublisher filePublisher = (FilePublisher)publisher; filePublisher.FileName = context.config.outputFilePath; } if (context.config.inputFilePath != null) { if (File.Exists(context.config.inputFilePath)) { fileLengthBytes = (int)new FileInfo(context.config.inputFilePath).Length; } } } publisher.open(); handleOutput(publisher); parent.parent.dataActions.Add(this); break; case ActionType.Call: publisher.start(); handleCall(publisher, context); parent.parent.dataActions.Add(this); break; case ActionType.GetProperty: publisher.start(); handleGetProperty(publisher); parent.parent.dataActions.Add(this); break; case ActionType.SetProperty: publisher.start(); handleSetProperty(publisher); parent.parent.dataActions.Add(this); break; case ActionType.ChangeState: handleChangeState(); break; case ActionType.Slurp: handleSlurp(context); break; default: throw new ApplicationException("Error, Action.Run fell into unknown Action type handler!"); } finished = true; } catch { error = true; finished = true; throw; } finally { OnFinished(); } }
public void Run(RunContext context) { logger.Trace("Run({0}): {1}", name, GetType().Name); // Setup scope for any scripting expressions scope["context"] = context; scope["Context"] = context; scope["action"] = this; scope["Action"] = this; scope["state"] = parent; scope["State"] = parent; scope["StateModel"] = parent.parent; scope["stateModel"] = parent.parent; scope["Test"] = parent.parent.parent; scope["test"] = parent.parent.parent; scope["self"] = this; if (when != null) { object value = Scripting.EvalExpression(when, scope); if (!(value is bool)) { logger.Debug("Run: action '{0}' when return is not boolean, returned: {1}", name, value); return; } if (!(bool)value) { logger.Debug("Run: action '{0}' when returned false", name); return; } } try { Publisher publisher = null; if (this.publisher != null && this.publisher != "Peach.Agent") { if (!context.test.publishers.ContainsKey(this.publisher)) { logger.Debug("Run: Publisher '" + this.publisher + "' not found!"); throw new PeachException("Error, Action '" + name + "' couldn't find publisher named '" + this.publisher + "'."); } publisher = context.test.publishers[this.publisher]; } else { publisher = context.test.publishers[0]; } if (context.controlIteration && context.controlRecordingIteration) { logger.Debug("Run: Adding action to controlRecordingActionsExecuted"); context.controlRecordingActionsExecuted.Add(this); } else if (context.controlIteration) { logger.Debug("Run: Adding action to controlActionsExecuted"); context.controlActionsExecuted.Add(this); } started = true; finished = false; error = false; OnStarting(); logger.Debug("ActionType.{0}", GetType().Name.ToString()); RunScript(onStart); // Save output data foreach (var item in outputData) { parent.parent.SaveData(item.outputName, item.dataModel.Value); } OnRun(publisher, context); // Save input data foreach (var item in inputData) { parent.parent.SaveData(item.inputName, item.dataModel.Value); } RunScript(onComplete); finished = true; } catch (ActionChangeStateException) { // this is not an error throw; } catch { error = true; throw; } finally { finished = true; OnFinished(); } }