/// <summary> /// Fills an event signature object from an XML fragment. /// </summary> /// <param name="reader">The XML reader containing the fragment to read.</param> /// <exception cref="ArgumentNullException">If <paramref name="reader" /> is <c>null</c>.</exception> /// <exception cref="LSLLibraryDataXmlSyntaxException"> /// On missing or unknown attributes. /// If a parameter 'Name' is used more than once. /// If a parameter 'Name' is whitespace. /// If a parameter 'Type' is <see cref="LSLType.Void" />. /// If a parameter 'Type' does not correspond to an <see cref="LSLType" /> enumeration member. /// If a 'Properties' node 'Name' is <c>null</c> or whitespace. /// If a 'Properties' node 'Name' is used more than once. /// If a 'Properties' node 'Value' is <c>null</c> or whitespace. /// </exception> /// <exception cref="LSLInvalidSymbolNameException"> /// Thrown if the event signatures name or any of its parameters names do /// not abide by LSL symbol naming conventions. /// </exception> /// <exception cref="XmlException">Incorrect XML encountered in the input stream. </exception> /// <exception cref="LSLInvalidSubsetNameException"> /// Thrown if any of the given subset names in the 'Subsets' CSV string do /// not match the pattern ([a-zA-Z]+[a-zA-Z_0-9\\-]*). /// </exception> void IXmlSerializable.ReadXml(XmlReader reader) { if (reader == null) { throw new ArgumentNullException("reader"); } var parameterNames = new HashSet <string>(); reader.MoveToContent(); var hasSubsets = false; var hasName = false; var lineNumberInfo = (IXmlLineInfo)reader; while (reader.MoveToNextAttribute()) { if (reader.Name == "Subsets") { Subsets.SetSubsets(reader.Value); hasSubsets = true; } else if (reader.Name == "Name") { hasName = true; Name = reader.Value; } else { throw new LSLLibraryDataXmlSyntaxException(lineNumberInfo.LineNumber, string.Format("EventHandler{0}: Unknown attribute '{1}'.", hasName ? (" '" + Name + "'") : "", reader.Name)); } } if (!hasName) { throw new LSLLibraryDataXmlSyntaxException(lineNumberInfo.LineNumber, "EventHandler: Missing Name attribute."); } if (!hasSubsets) { throw new LSLLibraryDataXmlSyntaxException(lineNumberInfo.LineNumber, string.Format("EventHandler '{0}': Missing Subsets attribute.", Name)); } var canRead = reader.Read(); while (canRead) { if ((reader.Name == "Parameter") && reader.IsStartElement()) { var pName = reader.GetAttribute("Name"); if (string.IsNullOrWhiteSpace(pName)) { throw new LSLLibraryDataXmlSyntaxException(lineNumberInfo.LineNumber, string.Format( "EventHandler '{0}': Parameter Name attribute invalid, cannot be empty or whitespace.", Name)); } LSLType pType; if (!Enum.TryParse(reader.GetAttribute("Type"), out pType)) { throw new LSLLibraryDataXmlSyntaxException(lineNumberInfo.LineNumber, string.Format("EventHandler '{0}': Parameter named '{1}' has an invalid Type attribute.", pName, Name)); } if (pType == LSLType.Void) { throw new LSLLibraryDataXmlSyntaxException(lineNumberInfo.LineNumber, string.Format( "EventHandler '{0}': Parameter named '{1}' has an invalid Type, event parameters cannot be Void.", Name, pName)); } if (parameterNames.Contains(pName)) { throw new LSLLibraryDataXmlSyntaxException(lineNumberInfo.LineNumber, string.Format("EventHandler '{0}': Parameter Name '{1}' already used.", Name, pName)); } parameterNames.Add(pName); AddParameter(new LSLParameterSignature(pType, pName, false)); canRead = reader.Read(); } else if ((reader.Name == "DocumentationString") && reader.IsStartElement()) { DocumentationString = reader.ReadElementContentAsString(); canRead = reader.Read(); } else if ((reader.Name == "Property") && reader.IsStartElement()) { var pName = reader.GetAttribute("Name"); if (string.IsNullOrWhiteSpace(pName)) { throw new LSLLibraryDataXmlSyntaxException(lineNumberInfo.LineNumber, string.Format("EventHandler '{0}': Property element's Name attribute cannot be empty.", pName)); } var value = reader.GetAttribute("Value"); if (string.IsNullOrWhiteSpace(value)) { throw new LSLLibraryDataXmlSyntaxException(lineNumberInfo.LineNumber, string.Format("EventHandler '{0}': Property element's Value attribute cannot be empty.", pName)); } if (_properties.ContainsKey(pName)) { throw new LSLLibraryDataXmlSyntaxException(lineNumberInfo.LineNumber, string.Format( "EventHandler '{0}': Property name '{1}' has already been used.", Name, pName)); } _properties.Add(pName, value); canRead = reader.Read(); } else if (reader.NodeType == XmlNodeType.EndElement && reader.Name == "EventHandler") { break; } else { canRead = reader.Read(); } } }
/// <summary> /// Fills a constant signature object from an XML fragment. /// </summary> /// <param name="reader">The XML reader containing the fragment to read.</param> /// <exception cref="LSLInvalidSymbolNameException"> /// Thrown if the constants name does not abide by LSL symbol naming /// conventions. /// </exception> /// <exception cref="LSLInvalidSubsetNameException"> /// Thrown if any of the given subset names in the CSV 'Subsets' string do /// not match the pattern ([a-zA-Z]+[a-zA-Z_0-9\\-]*). /// </exception> /// <exception cref="LSLInvalidConstantTypeException">if 'Type' is <see cref="LSLType.Void" />.</exception> /// <exception cref="LSLLibraryDataXmlSyntaxException"> /// On missing or unknown attributes. /// If the constant 'Type' is <see cref="LSLType.Void" />. /// If the constant 'Type' does not correspond to an <see cref="LSLType" /> enumeration member. /// If a 'Properties' node 'Name' is <c>null</c> or whitespace. /// If a 'Properties' node 'Name' is used more than once. /// If a 'Properties' node 'Value' is <c>null</c> or whitespace. /// </exception> /// <exception cref="LSLInvalidConstantValueStringException"> /// If 'Value' is an invalid value for a float and <see cref="LSLConstantSignature.Type" /> is set to <see cref="LSLType.Float" /> /// or /// If 'Value' is an invalid value for an integer and <see cref="LSLConstantSignature.Type" /> is set to <see cref="LSLType.Integer" /> /// or /// If 'Value' is an invalid value for a vector and <see cref="LSLConstantSignature.Type" /> is set to <see cref="LSLType.Vector" /> /// or /// If 'Value' is an invalid value for a rotation and <see cref="LSLConstantSignature.Type" /> is set to <see cref="LSLType.Rotation" /> /// </exception> /// <exception cref="XmlException">Incorrect XML encountered in the input stream. </exception> /// <exception cref="ArgumentNullException"><paramref name="reader" /> is <c>null</c>.</exception> void IXmlSerializable.ReadXml(XmlReader reader) { if (reader == null) { throw new ArgumentNullException("reader"); } reader.MoveToContent(); var hasSubsets = false; var hasType = false; var hasName = false; var hasValue = false; string valueString = null; var lineNumberInfo = (IXmlLineInfo)reader; while (reader.MoveToNextAttribute()) { if (reader.Name == "Value") { var val = reader.Value; //The value is only truly missing if its entirely devoid of character data //some LSL constants like EOF are nothing but whitespace characters if (val.Length != 0) { hasValue = true; } //need to set the type first, defer this until later. valueString = val; } else if (reader.Name == "Subsets") { Subsets.SetSubsets(reader.Value); hasSubsets = true; } else if (reader.Name == "Type") { LSLType type; if (Enum.TryParse(reader.Value, out type)) { Type = type; hasType = true; } else { throw new LSLLibraryDataXmlSyntaxException(lineNumberInfo.LineNumber, string.Format("LibraryConstantSignature{0}: Type attribute invalid.", hasName ? (" '" + Name + "'") : "")); } } else if (reader.Name == "Name") { Name = reader.Value; hasName = true; } else { throw new LSLLibraryDataXmlSyntaxException(lineNumberInfo.LineNumber, string.Format("LibraryConstantSignature{0}: Unknown attribute '{1}'.", hasName ? (" '" + Name + "'") : "", reader.Name)); } } if (!hasName) { throw new LSLLibraryDataXmlSyntaxException(lineNumberInfo.LineNumber, "LibraryConstantSignature: Missing Name attribute."); } if (!hasType) { throw new LSLLibraryDataXmlSyntaxException(lineNumberInfo.LineNumber, string.Format("LibraryConstantSignature '{0}': Missing Type attribute.", Name)); } if (!hasValue) { throw new LSLLibraryDataXmlSyntaxException(lineNumberInfo.LineNumber, string.Format("LibraryConstantSignature '{0}': Missing Value attribute.", Name)); } if (!hasSubsets) { throw new LSLLibraryDataXmlSyntaxException(lineNumberInfo.LineNumber, string.Format("LibraryConstantSignature '{0}': Missing Subsets attribute.", Name)); } //Set the value string, this can possibly throw an LSLInvalidConstantValueStringException //The Type property needs to be set first above for validation to occur. ValueString = valueString; var canRead = reader.Read(); while (canRead) { if ((reader.Name == "DocumentationString") && reader.IsStartElement()) { DocumentationString = reader.ReadElementContentAsString(); canRead = reader.Read(); } else if ((reader.Name == "Property") && reader.IsStartElement()) { var pName = reader.GetAttribute("Name"); if (string.IsNullOrWhiteSpace(pName)) { throw new LSLLibraryDataXmlSyntaxException(lineNumberInfo.LineNumber, string.Format( "LibraryConstantSignature '{0}': Property element's Name attribute cannot be empty.", Name)); } var value = reader.GetAttribute("Value"); if (string.IsNullOrWhiteSpace(value)) { throw new LSLLibraryDataXmlSyntaxException(lineNumberInfo.LineNumber, string.Format( "LibraryConstantSignature '{0}': Property element's Value attribute cannot be empty.", Name)); } if (_properties.ContainsKey(pName)) { throw new LSLLibraryDataXmlSyntaxException(lineNumberInfo.LineNumber, string.Format( "LibraryConstantSignature '{0}': Property name '{1}' has already been used.", Name, pName)); } _properties.Add(pName, value); canRead = reader.Read(); } else if (reader.NodeType == XmlNodeType.EndElement && reader.Name == "LibraryConstant") { break; } else { canRead = reader.Read(); } } }
/// <summary> /// Fills a function signature object from an XML fragment. /// </summary> /// <param name="reader">The XML reader containing the fragment to read.</param> /// <exception cref="ArgumentNullException">If <paramref name="reader" /> is <c>null</c>.</exception> /// <exception cref="LSLLibraryDataXmlSyntaxException"> /// On missing or unknown attributes. /// If a parameter 'Name' is used more than once. /// If a parameter 'Name' is whitespace. /// If a parameter 'Type' is <see cref="LSLType.Void" /> and not Variadic. /// If a parameter 'Type' does not correspond to an <see cref="LSLType" /> enumeration member. /// If a 'Properties' node 'Name' is <c>null</c> or whitespace. /// If a 'Properties' node 'Name' is used more than once. /// If a 'Properties' node 'Value' is <c>null</c> or whitespace. /// </exception> /// <exception cref="LSLInvalidSymbolNameException"> /// Thrown if the function signatures name or any of its parameters names /// do not abide by LSL symbol naming conventions. /// </exception> /// <exception cref="XmlException">Incorrect XML encountered in the input stream. </exception> /// <exception cref="LSLInvalidSubsetNameException"> /// Thrown if any of the given subset names in the 'Subsets' CSV string do /// not match the pattern ([a-zA-Z]+[a-zA-Z_0-9\\-]*). /// </exception> void IXmlSerializable.ReadXml(XmlReader reader) { if (reader == null) { throw new ArgumentNullException("reader"); } var parameterNames = new HashSet <string>(); var lineNumberInfo = (IXmlLineInfo)reader; reader.MoveToContent(); var hasReturnType = false; var hasSubsets = false; var hasName = false; while (reader.MoveToNextAttribute()) { if (reader.Name == "Subsets") { Subsets.SetSubsets(reader.Value); hasSubsets = true; } else if (reader.Name == "ReturnType") { LSLType type; if (Enum.TryParse(reader.Value, out type)) { ReturnType = type; hasReturnType = true; } else { throw new LSLLibraryDataXmlSyntaxException(lineNumberInfo.LineNumber, string.Format("LibraryFunction{0}: ReturnType attribute Value '{1}' invalid.", hasName ? (" '" + Name + "'") : "", reader.Value)); } } else if (reader.Name == "Name") { hasName = true; Name = reader.Value; } else { throw new LSLLibraryDataXmlSyntaxException(lineNumberInfo.LineNumber, string.Format("LibraryFunction{0}: Unknown attribute '{1}'.", hasName ? (" '" + Name + "'") : "", reader.Name)); } } if (!hasName) { throw new LSLLibraryDataXmlSyntaxException(lineNumberInfo.LineNumber, "LibraryFunction: Missing Name attribute."); } if (!hasReturnType) { throw new LSLLibraryDataXmlSyntaxException(lineNumberInfo.LineNumber, string.Format("LibraryFunction '{0}': Missing ReturnType attribute.", Name)); } if (!hasSubsets) { throw new LSLLibraryDataXmlSyntaxException(lineNumberInfo.LineNumber, string.Format("LibraryFunction '{0}': Missing Subsets attribute.", Name)); } var isVariadic = false; var canRead = reader.Read(); while (canRead) { if ((reader.Name == "Parameter") && reader.IsStartElement()) { if (isVariadic) { throw new LSLLibraryDataXmlSyntaxException(lineNumberInfo.LineNumber, string.Format("LibraryFunction '{0}': More than one variadic parameter was defined.", Name)); } var pName = reader.GetAttribute("Name"); if (string.IsNullOrWhiteSpace(pName)) { throw new LSLLibraryDataXmlSyntaxException(lineNumberInfo.LineNumber, string.Format( "LibraryFunction '{0}': Parameter Name attribute invalid, cannot be empty or whitespace.", Name)); } LSLType pType; if (!Enum.TryParse(reader.GetAttribute("Type"), out pType)) { throw new LSLLibraryDataXmlSyntaxException(lineNumberInfo.LineNumber, string.Format( "LibraryFunction '{0}': Parameter named '{1}' has an invalid Type attribute.", Name, pName)); } if (parameterNames.Contains(pName)) { throw new LSLLibraryDataXmlSyntaxException(lineNumberInfo.LineNumber, string.Format("LibraryFunction '{0}': Parameter Name '{1}' already used.", Name, pName)); } var variadic = reader.GetAttribute("Variadic"); if (!string.IsNullOrWhiteSpace(variadic)) { if (variadic.ToLower() == "true") { isVariadic = true; } else if (variadic.ToLower() != "false") { throw new LSLLibraryDataXmlSyntaxException(lineNumberInfo.LineNumber, string.Format( "LibraryFunction '{0}': Variadic attribute in parameter #{1} of Function '{2}' must equal True or False (Case Insensitive).", Name, pName, Name)); } } if (pType == LSLType.Void && !isVariadic) { throw new LSLLibraryDataXmlSyntaxException(lineNumberInfo.LineNumber, string.Format( "LibraryFunction '{0}': Parameter Type invalid, function parameters cannot be Void unless they are declared variadic.", Name)); } parameterNames.Add(pName); AddParameter(new LSLParameterSignature(pType, pName, isVariadic)); canRead = reader.Read(); } else if ((reader.Name == "DocumentationString") && reader.IsStartElement()) { DocumentationString = reader.ReadElementContentAsString(); canRead = reader.Read(); } else if ((reader.Name == "Property") && reader.IsStartElement()) { var pName = reader.GetAttribute("Name"); if (string.IsNullOrWhiteSpace(pName)) { throw new LSLLibraryDataXmlSyntaxException(lineNumberInfo.LineNumber, string.Format("LibraryFunction '{0}': Property element's Name attribute cannot be empty.", Name)); } var value = reader.GetAttribute("Value"); if (string.IsNullOrWhiteSpace(value)) { throw new LSLLibraryDataXmlSyntaxException(lineNumberInfo.LineNumber, string.Format("LibraryFunction '{0}': Property element's Value attribute cannot be empty.", Name)); } if (_properties.ContainsKey(pName)) { throw new LSLLibraryDataXmlSyntaxException(lineNumberInfo.LineNumber, string.Format("LibraryFunction '{0}': Property name '{1}' has already been used.", Name, pName)); } _properties.Add(pName, value); canRead = reader.Read(); } else if (reader.NodeType == XmlNodeType.EndElement && reader.Name == "LibraryFunction") { break; } else { canRead = reader.Read(); } } }