/// <summary> /// Locate the nearest common ancestor conainer. /// </summary> /// <remarks> /// To calculate the offset of elem2 from elem1 we need a the /// nearest common ancestor. From that ancestor we can determine /// the offset of the two elements. If the elements do not share /// a common ancestor we cannot calculate the offset. /// </remarks> /// <param name="elem1"></param> /// <param name="elem2"></param> /// <returns></returns> protected DataElementContainer findCommonRoot(DataElement elem1, DataElement elem2) { List <DataElementContainer> parentsElem1 = new List <DataElementContainer>(); if (elem1 is DataElementContainer) { parentsElem1.Add((DataElementContainer)elem1); } DataElementContainer parent = elem1.parent; while (parent != null) { parentsElem1.Add(parent); parent = parent.parent; } parent = elem2.parent; while (parent != null) { if (parentsElem1.Contains(parent)) { return(parent); } parent = parent.parent; } return(null); }
/// <summary> /// Find the first common parent between two DataElements /// </summary> /// <param name="elem1"></param> /// <param name="elem2"></param> /// <returns>Common parent of null</returns> public DataElement FindCommonParent(DataElement elem1, DataElement elem2) { List <DataElement> elem1Parents = new List <DataElement>(); DataElementContainer parent = null; parent = elem1.parent; while (parent != null) { elem1Parents.Add(parent); parent = parent.parent; } parent = elem2.parent; while (parent != null) { if (elem1Parents.Contains(parent)) { return(parent); } parent = parent.parent; } return(null); }
public static DataElement PitParser(PitParser context, XmlNode node, DataElementContainer parent) { if (node.Name != "Padding") { return(null); } var padding = DataElement.Generate <Padding>(node); if (node.hasAttr("alignment")) { padding.alignment = node.getAttrInt("alignment"); } if (node.hasAttr("alignedTo")) { string strTo = node.getAttrString("alignedTo"); padding.alignedTo = parent.find(strTo); if (padding.alignedTo == null) { throw new PeachException("Error, unable to resolve alignedTo '" + strTo + "'."); } } context.handleCommonDataElementAttributes(node, padding); context.handleCommonDataElementChildren(node, padding); return(padding); }
public DataElement MoveAfter(DataElement target) { DataElementContainer parent = target.parent; int offset = parent.IndexOf(target) + 1; return(MoveTo(parent, offset)); }
public static new DataElement PitParser(PitParser context, XmlNode node, DataElementContainer parent) { string name = node.getAttr("name", null); string refName = node.getAttr("ref", null); DataModel dataModel = null; if (refName != null) { var refObj = context.getReference(refName, parent) as DataModel; if (refObj == null) throw new PeachException("Error, DataModel {0}could not resolve ref '{1}'. XML:\n{2}".Fmt( name == null ? "" : "'" + name + "' ", refName, node.OuterXml)); if (string.IsNullOrEmpty(name)) name = refName; dataModel = refObj.Clone(name) as DataModel; dataModel.isReference = true; dataModel.referenceName = refName; } else { if (string.IsNullOrEmpty(name)) throw new PeachException("Error, DataModel missing required 'name' attribute."); dataModel = new DataModel(name); } context.handleCommonDataElementAttributes(node, dataModel); context.handleCommonDataElementChildren(node, dataModel); context.handleDataElementContainer(node, dataModel); return dataModel; }
public DataElement CommonParent(DataElement elem) { List <DataElement> parents = new List <DataElement>(); DataElementContainer parent = null; parents.Add(this); parent = this.parent; while (parent != null) { parents.Add(parent); parent = parent.parent; } if (parents.Contains(elem)) { return(elem); } parent = elem.parent; while (parent != null) { if (parents.Contains(parent)) { return(parent); } parent = parent.parent; } return(null); }
public new static DataElement PitParser(PitParser context, XmlNode node, DataElementContainer parent) { var array = DataElement.Generate <Array>(node); if (node.hasAttr("minOccurs")) { array.minOccurs = node.getAttrInt("minOccurs"); array.maxOccurs = -1; array.occurs = array.minOccurs; } if (node.hasAttr("maxOccurs")) { array.maxOccurs = node.getAttrInt("maxOccurs"); } if (node.hasAttr("occurs")) { array.occurs = node.getAttrInt("occurs"); } if (node.hasAttr("mutable")) { array.isMutable = node.getAttrBool("mutable"); } return(array); }
public static DataElement PitParser(PitParser context, XmlNode node, DataElementContainer parent) { if (node.Name != "Choice") { return(null); } Choice choice = DataElement.Generate <Choice>(node); choice.parent = parent; context.handleCommonDataElementAttributes(node, choice); context.handleCommonDataElementChildren(node, choice); context.handleDataElementContainer(node, choice); // Move children to choiceElements collection foreach (DataElement elem in choice) { choice.choiceElements.Add(elem.name, elem); elem.parent = choice; } choice.Clear(); return(choice); }
public void ClearRelations() { foreach (var r in _relations) { // Remove toasts r.parent, so resolve 'From' and 'Of' 1st var from = r.From; var of = r.Of; if (from != this) { from.relations.Remove(r); } if (of != this) { of.relations.Remove(r); } } _relations.Clear(); DataElementContainer cont = this as DataElementContainer; if (cont == null) { return; } foreach (var child in cont) { child.ClearRelations(); } }
protected static string ContToStr(DataElementContainer cont) { var sb = new StringBuilder(); foreach (var item in cont) { sb.Append(ElemToStr(item)); } return(sb.ToString()); }
public CloneCache(DataElement element, string newName) { parent = element._parent; stream = new MemoryStream(); additional = new CloneContext(element, newName); context = new StreamingContext(StreamingContextStates.All, additional); formatter = new BinaryFormatter(null, context); formatter.AssemblyFormat = System.Runtime.Serialization.Formatters.FormatterAssemblyStyle.Simple; formatter.Binder = new DataElementBinder(); element._parent = null; formatter.Serialize(stream, element); element._parent = parent; }
public static DataElement PitParser(PitParser context, XmlNode node, DataElementContainer parent) { if (node.Name != "Blob") { return(null); } var blob = DataElement.Generate <Blob>(node); context.handleCommonDataElementAttributes(node, blob); context.handleCommonDataElementChildren(node, blob); context.handleCommonDataElementValue(node, blob); if (blob.DefaultValue == null) { blob.DefaultValue = new Variant(new BitStream()); } BitwiseStream bs; if (blob.DefaultValue.GetVariantType() == Variant.VariantType.String) { bs = new BitStream(); new BitWriter(bs).WriteString((string)blob.DefaultValue); } else { System.Diagnostics.Debug.Assert(blob.DefaultValue.GetVariantType() == Variant.VariantType.BitStream); bs = (BitwiseStream)blob.DefaultValue; } bs.Seek(0, SeekOrigin.Begin); blob.DefaultValue = new Variant(bs); if (blob.hasLength) { if (bs.LengthBits > blob.lengthAsBits) { throw new PeachException("Error, value of " + blob.debugName + " is longer than specified length."); } if (bs.LengthBits < blob.lengthAsBits) { bs.SetLengthBits(blob.lengthAsBits); } } return(blob); }
public static DataElement PitParser(PitParser context, XmlNode node, DataElementContainer parent) { if (node.Name != "Block") { return(null); } Block block = null; if (node.hasAttr("ref")) { string name = node.getAttr("name", null); string refName = node.getAttrString("ref"); DataElement refObj = context.getReference(refName, parent); if (refObj == null) { throw new PeachException("Error, Block {0}could not resolve ref '{1}'. XML:\n{2}".Fmt( name == null ? "" : "'" + name + "' ", refName, node.OuterXml)); } if (!(refObj is Block)) { throw new PeachException("Error, Block {0}resolved ref '{1}' to unsupported element {2}. XML:\n{3}".Fmt( name == null ? "" : "'" + name + "' ", refName, refObj.debugName, node.OuterXml)); } if (string.IsNullOrEmpty(name)) { name = new Block().name; } block = refObj.Clone(name) as Block; block.parent = parent; block.isReference = true; block.referenceName = refName; } else { block = DataElement.Generate <Block>(node); block.parent = parent; } context.handleCommonDataElementAttributes(node, block); context.handleCommonDataElementChildren(node, block); context.handleDataElementContainer(node, block); return(block); }
public DataElement MoveTo(DataElementContainer newParent, int index) { // Locate any fixups so we can update them // Move element DataElement newElem; DataElementContainer oldParent = this.parent; string newName = this.name; for (int i = 0; newParent.ContainsKey(newName); i++) { newName = this.name + "_" + i; } oldParent.RemoveAt(oldParent.IndexOf(this)); if (newName == this.name) { newElem = this; } else { newElem = this.Clone(newName); this.ClearRelations(); } newParent.Insert(index, newElem); foreach (Relation relation in newElem.relations) { if (relation.Of == newElem) { relation.OfName = newElem.fullName; } if (relation.From == newElem) { relation.FromName = newElem.fullName; } } return(newElem); }
public void VerifyRelations() { #if DEBUG foreach (var r in _relations) { IsFromRelation(r); } DataElementContainer cont = this as DataElementContainer; if (cont == null) { return; } foreach (var c in cont) { c.VerifyRelations(); } #endif }
public static DataElement PitParser(PitParser context, XmlNode node, DataElementContainer parent) { if (node.Name != "XmlAttribute" || !(parent is XmlElement)) { return(null); } var xmlAttribute = DataElement.Generate <XmlAttribute>(node); xmlAttribute.attributeName = node.getAttrString("attributeName"); if (node.hasAttr("ns")) { xmlAttribute.ns = node.getAttrString("ns"); } context.handleCommonDataElementAttributes(node, xmlAttribute); context.handleCommonDataElementChildren(node, xmlAttribute); context.handleDataElementContainer(node, xmlAttribute); return(xmlAttribute); }
public static DataElement PitParser(PitParser context, XmlNode node, DataElementContainer parent) { if (node.Name != "Blob") { return(null); } var blob = DataElement.Generate <Blob>(node); context.handleCommonDataElementAttributes(node, blob); context.handleCommonDataElementChildren(node, blob); context.handleCommonDataElementValue(node, blob); if (blob.DefaultValue == null) { blob.DefaultValue = new Variant(new byte[0]); } if (blob.DefaultValue.GetVariantType() == Variant.VariantType.String) { blob.DefaultValue = new Variant(ASCIIEncoding.ASCII.GetBytes((string)blob.DefaultValue)); } if (blob.hasLength) { BitStream bs = (BitStream)blob.DefaultValue; if (bs.LengthBits > blob.lengthAsBits) { throw new PeachException("Error, value of " + blob.debugName + " is longer than specified length."); } else if (bs.LengthBits < blob.lengthAsBits) { ExpandDefaultValue(blob, bs); } } return(blob); }
public static DataElement PitParser(PitParser context, XmlNode node, DataElementContainer parent) { if (node.Name != "Number") { return(null); } var num = DataElement.Generate <Number>(node); if (node.hasAttr("signed")) { num.Signed = node.getAttrBool("signed"); } else { num.Signed = context.getDefaultAttr(typeof(Number), "signed", num.Signed); } if (node.hasAttr("size")) { int size = node.getAttrInt("size"); if (size < 1 || size > 64) { throw new PeachException(string.Format("Error, unsupported size '{0}' for {1}.", size, num.debugName)); } num.lengthType = LengthType.Bits; num.length = size; } string strEndian = null; if (node.hasAttr("endian")) { strEndian = node.getAttrString("endian"); } if (strEndian == null) { strEndian = context.getDefaultAttr(typeof(Number), "endian", null); } if (strEndian != null) { switch (strEndian.ToLower()) { case "little": num.LittleEndian = true; break; case "big": num.LittleEndian = false; break; case "network": num.LittleEndian = false; break; default: throw new PeachException( string.Format("Error, unsupported value '{0}' for 'endian' attribute on {1}.", strEndian, num.debugName)); } } context.handleCommonDataElementAttributes(node, num); context.handleCommonDataElementChildren(node, num); context.handleCommonDataElementValue(node, num); return(num); }
/// <summary> /// Caluclate the offset in bytes between two data elements. /// </summary> /// <param name="from"></param> /// <param name="to"></param> /// <returns>Returns the offset in bits between two elements. Return can be negative.</returns> protected long calculateOffset(DataElement from, DataElement to) { DataElementContainer commonAncestor = null; long fromPosition = 0; long toPosition = 0; if (isRelativeOffset) { if (!string.IsNullOrEmpty(relativeTo)) { DataElement relative = from.find(relativeTo); if (relative == null) { throw new PeachException(string.Format("Error, offset relation from element '{0}' couldn't locate relative to element '{1}'.", from.fullName, relativeTo)); } from = relative; } commonAncestor = findCommonRoot(from, to); if (commonAncestor == null) { throw new PeachException("Error, unable to calculate offset between '" + from.fullName + "' and '" + to.fullName + "'."); } BitStream stream = commonAncestor.Value; if (from != commonAncestor) { if (!stream.HasDataElement(from.fullName)) { throw new PeachException("Error, unable to calculate offset between '" + from.fullName + "' and '" + to.fullName + "'."); } fromPosition = stream.DataElementPosition(from); } if (!stream.HasDataElement(to.fullName)) { throw new PeachException("Error, unable to calculate offset between '" + from.fullName + "' and '" + to.fullName + "'."); } toPosition = stream.DataElementPosition(to); } else { commonAncestor = findCommonRoot(from, to); if (commonAncestor == null) { throw new PeachException("Error, unable to calculate offset between '" + from.fullName + "' and '" + to.fullName + "'."); } BitStream stream = commonAncestor.Value; fromPosition = 0; if (!stream.HasDataElement(to.fullName)) { throw new PeachException("Error, unable to calculate offset between '" + from.fullName + "' and '" + to.fullName + "'."); } toPosition = stream.DataElementPosition(to); } return(toPosition - fromPosition); }
static void ApplyField(DataElementContainer model, string field, Variant value) { DataElement elem = model; DataElementContainer container = model; var names = field.Split('.'); for (int i = 0; i < names.Length; i++) { string name = names[i]; Match m = Regex.Match(name, @"(.*)\[(-?\d+)\]$"); if (m.Success) { name = m.Groups[1].Value; int index = int.Parse(m.Groups[2].Value); if (!container.ContainsKey(name)) { throw new PeachException("Error, unable to resolve field \"" + field + "\" against \"" + model.fullName + "\"."); } var array = container[name] as Array; if (array == null) { throw new PeachException("Error, cannot use array index syntax on field name unless target element is an array. Field: " + field); } // Are we disabling this array? if (index == -1) { if (array.minOccurs > 0) { throw new PeachException("Error, cannot set array to zero elements when minOccurs > 0. Field: " + field + " Element: " + array.fullName); } // Remove all children array.Clear(); return; } if (array.maxOccurs != -1 && index > array.maxOccurs) { throw new PeachException("Error, index larger that maxOccurs. Field: " + field + " Element: " + array.fullName); } if (!array.hasExpanded && array.origionalElement == null) { array.origionalElement = array[0]; array.RemoveAt(0); } // Add elements upto our index for (int x = array.Count; x <= index; x++) { string itemName = array.origionalElement.name + "_" + x; var item = array.origionalElement.Clone(itemName); array.Add(item); } array.hasExpanded = true; elem = array[index]; container = elem as DataElementContainer; } else if (container is Choice) { elem = null; var choice = container as Choice; if (!choice.choiceElements.TryGetValue(name, out elem)) { throw new PeachException("Error, unable to resolve field \"" + field + "\" against \"" + model.fullName + "\"."); } container = elem as DataElementContainer; choice.SelectedElement = elem; } else { if (!container.ContainsKey(name)) { throw new PeachException("Error, unable to resolve field \"" + field + "\" against \"" + model.fullName + "\"."); } elem = container[name]; container = elem as DataElementContainer; } } if (!(elem is DataElementContainer)) { elem.DefaultValue = value; } }
private DataElement MoveTo(DataElementContainer newParent, int index) { DataElementContainer oldParent = this.parent; if (oldParent == newParent) { int oldIdx = oldParent.IndexOf(this); oldParent.RemoveAt(oldIdx); if (oldIdx < index) { --index; } newParent.Insert(index, this); return(this); } string newName = this.name; for (int i = 0; newParent.ContainsKey(newName); i++) { newName = this.name + "_" + i; } DataElement newElem; if (newName == this.name) { newElem = this; } else { newElem = this.Clone(newName); // We are "moving" the element, but doing so by cloning // into a new element. The clone will duplicate relations // that reach outside of the element tree, so we need to // clean up all old relations that were inside // the old element tree. ClearBindings(true); } // Save off relations var relations = newElem.relations.Of <Binding>().ToArray(); oldParent.RemoveAt(oldParent.IndexOf(this)); newParent.Insert(index, newElem); // When an element is moved, the name can change. // Additionally, the resolution algorithm might not // be able to locate the proper element, so set // the 'OfName' to the full name of the new element. foreach (var rel in relations) { rel.OfName = newElem.fullName; rel.Resolve(); } return(newElem); }
public static DataElement PitParser(PitParser context, XmlNode node, DataElementContainer parent) { if (node.Name != "Flags") { return(null); } var flags = DataElement.Generate <Flags>(node); string strSize = null; if (node.hasAttr("size")) { strSize = node.getAttrString("size"); } if (strSize == null) { strSize = context.getDefaultAttr(typeof(Flags), "size", null); } if (strSize == null) { throw new PeachException("Error, Flags elements must have 'size' attribute!"); } int size; if (!int.TryParse(strSize, out size)) { throw new PeachException("Error, " + flags.name + " size attribute is not valid number."); } if (size < 1 || size > 64) { throw new PeachException(string.Format("Error, unsupported size '{0}' for {1}.", size, flags.debugName)); } flags.lengthType = LengthType.Bits; flags.length = size; string strEndian = null; if (node.hasAttr("endian")) { strEndian = node.getAttrString("endian"); } if (strEndian == null) { strEndian = context.getDefaultAttr(typeof(Flags), "endian", null); } if (strEndian != null) { switch (strEndian.ToLower()) { case "little": flags.LittleEndian = true; break; case "big": flags.LittleEndian = false; break; case "network": flags.LittleEndian = false; break; default: throw new PeachException( string.Format("Error, unsupported value '{0}' for 'endian' attribute on {1}.", strEndian, flags.debugName)); } } context.handleCommonDataElementAttributes(node, flags); context.handleCommonDataElementChildren(node, flags); foreach (XmlNode child in node.ChildNodes) { // Looking for "Flag" element if (child.Name == "Flag") { flags.Add(Flag.PitParser(context, child, flags)); } } return(flags); }
public void GenerateBoundaryFile(string filename) { long pos = 0; Stack <DataElement> stack = new Stack <DataElement>(); using (System.IO.StreamWriter outputFile = new System.IO.StreamWriter(filename)) { DataElement root = this; stack.Push(this); // Execute the loop until all data elements (nodes) are traversed while (stack.Count > 0) { DataElement node = stack.Pop(); // If the current node is a DataElementContainer, get all child nodes and push // them on top of the stack if (node is DataElementContainer) { // Output the name of the current node and its boundary string strName = node.name; DataElement ancestor = node.parent; while (ancestor != null) { strName = ancestor.name + "~" + strName; ancestor = ancestor.parent; } if (node.isMutable) { outputFile.WriteLine("{0},{1},{2},{3}", pos, pos + node.Value.LengthBytes - 1, strName, "Enabled"); } else { outputFile.WriteLine("{0},{1},{2},{3}", pos, pos + node.Value.LengthBytes - 1, strName, "Disabled"); } //Console.WriteLine ("Processing node: {0}", node.name); DataElementContainer container = (DataElementContainer)node; if (container.Count > 0) { for (int i = container.Count - 1; i >= 0; i--) { //Console.WriteLine ("Pushing to stack: {0}", container [i].name); stack.Push(container [i]); } } } else { // Output the name of the current node and its boundary // in case the node is mutable if (node.Value.LengthBytes > 0) { if (node.isMutable) { string strName = node.name; DataElement ancestor = node.parent; while (ancestor != null) { strName = ancestor.name + "~" + strName; ancestor = ancestor.parent; } outputFile.WriteLine("{0},{1},{2},{3}", pos, pos + node.Value.LengthBytes - 1, strName, "Enabled"); pos += node.Value.LengthBytes; } else { // If the Data Element is not mutable, just update the position //Console.WriteLine ("DataElement: {0} is not mutable", node.name); string strName = node.name; DataElement ancestor = node.parent; while (ancestor != null) { strName = ancestor.name + "~" + strName; ancestor = ancestor.parent; } outputFile.WriteLine("{0},{1},{2},{3}", pos, pos + node.Value.LengthBytes - 1, strName, "Disabled"); pos += node.Value.LengthBytes; } } } } } }
public static DataElement PitParser(PitParser context, XmlNode node, DataElementContainer parent) { if (node.Name != "String") { return(null); } var str = DataElement.Generate <String>(node); if (node.hasAttr("nullTerminated")) { str.nullTerminated = node.getAttrBool("nullTerminated"); } else { str.nullTerminated = context.getDefaultAttr(typeof(String), "nullTerminated", str.nullTerminated); } string type = "ascii"; if (node.hasAttr("type")) { type = node.getAttrString("type"); } else { type = context.getDefaultAttr(typeof(String), "type", type); } StringType stringType; if (!Enum.TryParse <StringType>(type, true, out stringType)) { throw new PeachException("Error, unknown String type '" + type + "' on element '" + str.name + "'."); } str.stringType = stringType; if (node.hasAttr("padCharacter")) { str.padCharacter = node.getAttrChar("padCharacter"); } else { str.padCharacter = context.getDefaultAttr(typeof(String), "padCharacter", str.padCharacter); } if (node.hasAttr("tokens")) // This item has a default! { throw new NotSupportedException("Tokens attribute is depricated in Peach 3. Use parameter to StringToken analyzer isntead."); } if (node.hasAttr("analyzer")) // this should be passed via a child element me things! { throw new NotSupportedException("Analyzer attribute is depricated in Peach 3. Use a child element instead."); } context.handleCommonDataElementAttributes(node, str); context.handleCommonDataElementChildren(node, str); context.handleCommonDataElementValue(node, str); if (!node.hasAttr("value")) { str.DefaultValue = new Variant(""); } return(str); }