//------------------------------------------------------------------------------ // // Copyright (c) Microsoft Corporation. All rights reserved. // // [....] //------------------------------------------------------------------------------ using System.IO; using System.Text; using System.Xml.Schema; using System.Xml.XPath; using System.Diagnostics; using System.Globalization; using System.Collections; using System.Security.Policy; using System.Collections.Generic; using System.Runtime.Versioning; namespace System.Xml { internal delegate void CachingEventHandler(XsdCachingReader cachingReader); internal class AttributePSVIInfo { internal string localName; internal string namespaceUri; internal object typedAttributeValue; internal XmlSchemaInfo attributeSchemaInfo; internal AttributePSVIInfo() { attributeSchemaInfo = new XmlSchemaInfo(); } internal void Reset() { typedAttributeValue = null; localName = string.Empty; namespaceUri = string.Empty; attributeSchemaInfo.Clear(); } } internal partial class XsdValidatingReader : XmlReader, IXmlSchemaInfo, IXmlLineInfo, IXmlNamespaceResolver { private enum ValidatingReaderState { None = 0, Init = 1, Read = 2, OnDefaultAttribute = -1, OnReadAttributeValue = -2, OnAttribute = 3, ClearAttributes = 4, ParseInlineSchema = 5, ReadAhead = 6, OnReadBinaryContent = 7, ReaderClosed = 8, EOF = 9, Error = 10, } //Validation private XmlReader coreReader; private IXmlNamespaceResolver coreReaderNSResolver; private IXmlNamespaceResolver thisNSResolver; private XmlSchemaValidator validator; private XmlResolver xmlResolver; private ValidationEventHandler validationEvent; private ValidatingReaderState validationState; private XmlValueGetter valueGetter; // namespace management XmlNamespaceManager nsManager; bool manageNamespaces; bool processInlineSchema; bool replayCache; //Current Node handling private ValidatingReaderNodeData cachedNode; //Used to cache current node when looking ahead or default attributes private AttributePSVIInfo attributePSVI; //Attributes int attributeCount; //Total count of attributes including default int coreReaderAttributeCount; int currentAttrIndex; AttributePSVIInfo[] attributePSVINodes; ArrayList defaultAttributes; //Inline Schema private Parser inlineSchemaParser = null; //Typed Value & PSVI private object atomicValue; private XmlSchemaInfo xmlSchemaInfo; // original string of the atomic value private string originalAtomicValueString; //cached coreReader information private XmlNameTable coreReaderNameTable; private XsdCachingReader cachingReader; //ReadAttributeValue TextNode private ValidatingReaderNodeData textNode; //To avoid SchemaNames creation private string NsXmlNs; private string NsXs; private string NsXsi; private string XsiType; private string XsiNil; private string XsdSchema; private string XsiSchemaLocation; private string XsiNoNamespaceSchemaLocation; //XmlCharType instance private XmlCharType xmlCharType = XmlCharType.Instance; //Underlying reader's IXmlLineInfo IXmlLineInfo lineInfo; // helpers for Read[Element]ContentAs{Base64,BinHex} methods ReadContentAsBinaryHelper readBinaryHelper; ValidatingReaderState savedState; //Constants private const int InitialAttributeCount = 8; static volatile Type TypeOfString; //Constructor internal XsdValidatingReader(XmlReader reader, XmlResolver xmlResolver, XmlReaderSettings readerSettings, XmlSchemaObject partialValidationType) { this.coreReader = reader; this.coreReaderNSResolver = reader as IXmlNamespaceResolver; this.lineInfo = reader as IXmlLineInfo; coreReaderNameTable = coreReader.NameTable; if (coreReaderNSResolver == null) { nsManager = new XmlNamespaceManager(coreReaderNameTable); manageNamespaces = true; } thisNSResolver = this as IXmlNamespaceResolver; this.xmlResolver = xmlResolver; this.processInlineSchema = (readerSettings.ValidationFlags & XmlSchemaValidationFlags.ProcessInlineSchema) != 0; Init(); SetupValidator(readerSettings, reader, partialValidationType); validationEvent = readerSettings.GetEventHandler(); } internal XsdValidatingReader(XmlReader reader, XmlResolver xmlResolver, XmlReaderSettings readerSettings) : this(reader, xmlResolver, readerSettings, null) { } private void Init() { validationState = ValidatingReaderState.Init; defaultAttributes = new ArrayList(); currentAttrIndex = -1; attributePSVINodes = new AttributePSVIInfo[InitialAttributeCount]; valueGetter = new XmlValueGetter(GetStringValue); TypeOfString = typeof(System.String); xmlSchemaInfo = new XmlSchemaInfo(); //Add common strings to be compared to NameTable NsXmlNs = coreReaderNameTable.Add(XmlReservedNs.NsXmlNs); NsXs = coreReaderNameTable.Add(XmlReservedNs.NsXs); NsXsi = coreReaderNameTable.Add(XmlReservedNs.NsXsi); XsiType = coreReaderNameTable.Add("type"); XsiNil = coreReaderNameTable.Add("nil"); XsiSchemaLocation = coreReaderNameTable.Add("schemaLocation"); XsiNoNamespaceSchemaLocation = coreReaderNameTable.Add("noNamespaceSchemaLocation"); XsdSchema = coreReaderNameTable.Add("schema"); } private void SetupValidator(XmlReaderSettings readerSettings, XmlReader reader, XmlSchemaObject partialValidationType) { validator = new XmlSchemaValidator(coreReaderNameTable, readerSettings.Schemas, thisNSResolver, readerSettings.ValidationFlags); validator.XmlResolver = this.xmlResolver; validator.SourceUri = XmlConvert.ToUri(reader.BaseURI); //Not using XmlResolver.ResolveUri as it checks for relative Uris,reader.BaseURI will be absolute file paths or string.Empty validator.ValidationEventSender = this; validator.ValidationEventHandler += readerSettings.GetEventHandler(); validator.LineInfoProvider = this.lineInfo; if (validator.ProcessSchemaHints) { validator.SchemaSet.ReaderSettings.DtdProcessing = readerSettings.DtdProcessing; } validator.SetDtdSchemaInfo(reader.DtdInfo); if (partialValidationType != null) { validator.Initialize(partialValidationType); } else { validator.Initialize(); } } // Settings public override XmlReaderSettings Settings { get { XmlReaderSettings settings = coreReader.Settings; if (null != settings) settings = settings.Clone(); if (settings == null) { settings = new XmlReaderSettings(); } settings.Schemas = validator.SchemaSet; settings.ValidationType = ValidationType.Schema; settings.ValidationFlags = validator.ValidationFlags; settings.ReadOnly = true; return settings; } } // Node Properties // Gets the type of the current node. public override XmlNodeType NodeType { get { if ((int)validationState < 0) { return cachedNode.NodeType; } else { XmlNodeType nodeType = coreReader.NodeType; //Check for significant whitespace if (nodeType == XmlNodeType.Whitespace && (validator.CurrentContentType == XmlSchemaContentType.TextOnly || validator.CurrentContentType == XmlSchemaContentType.Mixed)) { return XmlNodeType.SignificantWhitespace; } return nodeType; } } } // Gets the name of the current node, including the namespace prefix. public override string Name { get { if (validationState == ValidatingReaderState.OnDefaultAttribute) { string prefix = validator.GetDefaultAttributePrefix(cachedNode.Namespace); if (prefix != null && prefix.Length != 0) { return string.Concat(prefix + ":" + cachedNode.LocalName); } return cachedNode.LocalName; } return coreReader.Name; } } // Gets the name of the current node without the namespace prefix. public override string LocalName { get { if ((int)validationState < 0) { return cachedNode.LocalName; } return coreReader.LocalName; } } // Gets the namespace URN (as defined in the W3C Namespace Specification) of the current namespace scope. public override string NamespaceURI { get { if ((int)validationState < 0) { return cachedNode.Namespace; } return coreReader.NamespaceURI; } } // Gets the namespace prefix associated with the current node. public override string Prefix { get { if ((int)validationState < 0) { return cachedNode.Prefix; } return coreReader.Prefix; } } // Gets a value indicating whether the current node can have a non-empty Value public override bool HasValue { get { if ((int)validationState < 0) { return true; } return coreReader.HasValue; } } // Gets the text value of the current node. public override string Value { get { if ((int)validationState < 0) { return cachedNode.RawValue; } return coreReader.Value; } } // Gets the depth of the current node in the XML element stack. public override int Depth { get { if ((int)validationState < 0) { return cachedNode.Depth; } return coreReader.Depth; } } // Gets the base URI of the current node. public override string BaseURI { get { return coreReader.BaseURI; } } // Gets a value indicating whether the current node is an empty element (for example, ). public override bool IsEmptyElement { get { return coreReader.IsEmptyElement; } } // Gets a value indicating whether the current node is an attribute that was generated from the default value defined // in the DTD or schema. public override bool IsDefault { get { if (validationState == ValidatingReaderState.OnDefaultAttribute) { //XSD default attributes return true; } return coreReader.IsDefault; //This is DTD Default attribute } } // Gets the quotation mark character used to enclose the value of an attribute node. public override char QuoteChar { get { return coreReader.QuoteChar; } } // Gets the current xml:space scope. public override XmlSpace XmlSpace { get { return coreReader.XmlSpace; } } // Gets the current xml:lang scope. public override string XmlLang { get { return coreReader.XmlLang; } } public override IXmlSchemaInfo SchemaInfo { get { return this as IXmlSchemaInfo; } } public override System.Type ValueType { get { switch (NodeType) { case XmlNodeType.Element: case XmlNodeType.EndElement: // if (xmlSchemaInfo.ContentType == XmlSchemaContentType.TextOnly) { return xmlSchemaInfo.SchemaType.Datatype.ValueType; } goto default; case XmlNodeType.Attribute: if (attributePSVI != null && AttributeSchemaInfo.ContentType == XmlSchemaContentType.TextOnly) { return AttributeSchemaInfo.SchemaType.Datatype.ValueType; } goto default; default: return TypeOfString; } } } public override object ReadContentAsObject() { if (!CanReadContentAs(this.NodeType)) { throw CreateReadContentAsException("ReadContentAsObject"); } return InternalReadContentAsObject(true); } public override bool ReadContentAsBoolean() { if (!CanReadContentAs(this.NodeType)) { throw CreateReadContentAsException("ReadContentAsBoolean"); } object typedValue = InternalReadContentAsObject(); XmlSchemaType xmlType = NodeType == XmlNodeType.Attribute ? AttributeXmlType : ElementXmlType; try { if (xmlType != null) { return xmlType.ValueConverter.ToBoolean(typedValue); } else { return XmlUntypedConverter.Untyped.ToBoolean(typedValue); } } catch (InvalidCastException e) { throw new XmlException(Res.Xml_ReadContentAsFormatException, "Boolean", e, this as IXmlLineInfo); } catch (FormatException e) { throw new XmlException(Res.Xml_ReadContentAsFormatException, "Boolean", e, this as IXmlLineInfo); } catch (OverflowException e) { throw new XmlException(Res.Xml_ReadContentAsFormatException, "Boolean", e, this as IXmlLineInfo); } } public override DateTime ReadContentAsDateTime() { if (!CanReadContentAs(this.NodeType)) { throw CreateReadContentAsException("ReadContentAsDateTime"); } object typedValue = InternalReadContentAsObject(); XmlSchemaType xmlType = NodeType == XmlNodeType.Attribute ? AttributeXmlType : ElementXmlType; try { if (xmlType != null) { return xmlType.ValueConverter.ToDateTime(typedValue); } else { return XmlUntypedConverter.Untyped.ToDateTime(typedValue); } } catch (InvalidCastException e) { throw new XmlException(Res.Xml_ReadContentAsFormatException, "DateTime", e, this as IXmlLineInfo); } catch (FormatException e) { throw new XmlException(Res.Xml_ReadContentAsFormatException, "DateTime", e, this as IXmlLineInfo); } catch (OverflowException e) { throw new XmlException(Res.Xml_ReadContentAsFormatException, "DateTime", e, this as IXmlLineInfo); } } public override double ReadContentAsDouble() { if (!CanReadContentAs(this.NodeType)) { throw CreateReadContentAsException("ReadContentAsDouble"); } object typedValue = InternalReadContentAsObject(); XmlSchemaType xmlType = NodeType == XmlNodeType.Attribute ? AttributeXmlType : ElementXmlType; try { if (xmlType != null) { return xmlType.ValueConverter.ToDouble(typedValue); } else { return XmlUntypedConverter.Untyped.ToDouble(typedValue); } } catch (InvalidCastException e) { throw new XmlException(Res.Xml_ReadContentAsFormatException, "Double", e, this as IXmlLineInfo); } catch (FormatException e) { throw new XmlException(Res.Xml_ReadContentAsFormatException, "Double", e, this as IXmlLineInfo); } catch (OverflowException e) { throw new XmlException(Res.Xml_ReadContentAsFormatException, "Double", e, this as IXmlLineInfo); } } public override float ReadContentAsFloat() { if (!CanReadContentAs(this.NodeType)) { throw CreateReadContentAsException("ReadContentAsFloat"); } object typedValue = InternalReadContentAsObject(); XmlSchemaType xmlType = NodeType == XmlNodeType.Attribute ? AttributeXmlType : ElementXmlType; try { if (xmlType != null) { return xmlType.ValueConverter.ToSingle(typedValue); } else { return XmlUntypedConverter.Untyped.ToSingle(typedValue); } } catch (InvalidCastException e) { throw new XmlException(Res.Xml_ReadContentAsFormatException, "Float", e, this as IXmlLineInfo); } catch (FormatException e) { throw new XmlException(Res.Xml_ReadContentAsFormatException, "Float", e, this as IXmlLineInfo); } catch (OverflowException e) { throw new XmlException(Res.Xml_ReadContentAsFormatException, "Float", e, this as IXmlLineInfo); } } public override decimal ReadContentAsDecimal() { if (!CanReadContentAs(this.NodeType)) { throw CreateReadContentAsException("ReadContentAsDecimal"); } object typedValue = InternalReadContentAsObject(); XmlSchemaType xmlType = NodeType == XmlNodeType.Attribute ? AttributeXmlType : ElementXmlType; try { if (xmlType != null) { return xmlType.ValueConverter.ToDecimal(typedValue); } else { return XmlUntypedConverter.Untyped.ToDecimal(typedValue); } } catch (InvalidCastException e) { throw new XmlException(Res.Xml_ReadContentAsFormatException, "Decimal", e, this as IXmlLineInfo); } catch (FormatException e) { throw new XmlException(Res.Xml_ReadContentAsFormatException, "Decimal", e, this as IXmlLineInfo); } catch (OverflowException e) { throw new XmlException(Res.Xml_ReadContentAsFormatException, "Decimal", e, this as IXmlLineInfo); } } public override int ReadContentAsInt() { if (!CanReadContentAs(this.NodeType)) { throw CreateReadContentAsException("ReadContentAsInt"); } object typedValue = InternalReadContentAsObject(); XmlSchemaType xmlType = NodeType == XmlNodeType.Attribute ? AttributeXmlType : ElementXmlType; try { if (xmlType != null) { return xmlType.ValueConverter.ToInt32(typedValue); } else { return XmlUntypedConverter.Untyped.ToInt32(typedValue); } } catch (InvalidCastException e) { throw new XmlException(Res.Xml_ReadContentAsFormatException, "Int", e, this as IXmlLineInfo); } catch (FormatException e) { throw new XmlException(Res.Xml_ReadContentAsFormatException, "Int", e, this as IXmlLineInfo); } catch (OverflowException e) { throw new XmlException(Res.Xml_ReadContentAsFormatException, "Int", e, this as IXmlLineInfo); } } public override long ReadContentAsLong() { if (!CanReadContentAs(this.NodeType)) { throw CreateReadContentAsException("ReadContentAsLong"); } object typedValue = InternalReadContentAsObject(); XmlSchemaType xmlType = NodeType == XmlNodeType.Attribute ? AttributeXmlType : ElementXmlType; try { if (xmlType != null) { return xmlType.ValueConverter.ToInt64(typedValue); } else { return XmlUntypedConverter.Untyped.ToInt64(typedValue); } } catch (InvalidCastException e) { throw new XmlException(Res.Xml_ReadContentAsFormatException, "Long", e, this as IXmlLineInfo); } catch (FormatException e) { throw new XmlException(Res.Xml_ReadContentAsFormatException, "Long", e, this as IXmlLineInfo); } catch (OverflowException e) { throw new XmlException(Res.Xml_ReadContentAsFormatException, "Long", e, this as IXmlLineInfo); } } public override string ReadContentAsString() { if (!CanReadContentAs(this.NodeType)) { throw CreateReadContentAsException("ReadContentAsString"); } object typedValue = InternalReadContentAsObject(); XmlSchemaType xmlType = NodeType == XmlNodeType.Attribute ? AttributeXmlType : ElementXmlType; try { if (xmlType != null) { return xmlType.ValueConverter.ToString(typedValue); } else { return typedValue as string; } } catch (InvalidCastException e) { throw new XmlException(Res.Xml_ReadContentAsFormatException, "String", e, this as IXmlLineInfo); } catch (FormatException e) { throw new XmlException(Res.Xml_ReadContentAsFormatException, "String", e, this as IXmlLineInfo); } catch (OverflowException e) { throw new XmlException(Res.Xml_ReadContentAsFormatException, "String", e, this as IXmlLineInfo); } } public override object ReadContentAs(Type returnType, IXmlNamespaceResolver namespaceResolver) { if (!CanReadContentAs(this.NodeType)) { throw CreateReadContentAsException("ReadContentAs"); } string originalStringValue; object typedValue = InternalReadContentAsObject(false, out originalStringValue); XmlSchemaType xmlType = NodeType == XmlNodeType.Attribute ? AttributeXmlType : ElementXmlType; // try { if (xmlType != null) { // special-case convertions to DateTimeOffset; typedValue is by default a DateTime // which cannot preserve time zone, so we need to convert from the original string if (returnType == typeof(DateTimeOffset) && xmlType.Datatype is Datatype_dateTimeBase) { typedValue = originalStringValue; } return xmlType.ValueConverter.ChangeType(typedValue, returnType); } else { return XmlUntypedConverter.Untyped.ChangeType(typedValue, returnType, namespaceResolver); } } catch (FormatException e) { throw new XmlException(Res.Xml_ReadContentAsFormatException, returnType.ToString(), e, this as IXmlLineInfo); } catch (InvalidCastException e) { throw new XmlException(Res.Xml_ReadContentAsFormatException, returnType.ToString(), e, this as IXmlLineInfo); } catch (OverflowException e) { throw new XmlException(Res.Xml_ReadContentAsFormatException, returnType.ToString(), e, this as IXmlLineInfo); } } public override object ReadElementContentAsObject() { if (this.NodeType != XmlNodeType.Element) { throw CreateReadElementContentAsException("ReadElementContentAsObject"); } XmlSchemaType xmlType; return InternalReadElementContentAsObject(out xmlType, true); } public override bool ReadElementContentAsBoolean() { if (this.NodeType != XmlNodeType.Element) { throw CreateReadElementContentAsException("ReadElementContentAsBoolean"); } XmlSchemaType xmlType; object typedValue = InternalReadElementContentAsObject(out xmlType); try { if (xmlType != null) { return xmlType.ValueConverter.ToBoolean(typedValue); } else { return XmlUntypedConverter.Untyped.ToBoolean(typedValue); } } catch (FormatException e) { throw new XmlException(Res.Xml_ReadContentAsFormatException, "Boolean", e, this as IXmlLineInfo); } catch (InvalidCastException e) { throw new XmlException(Res.Xml_ReadContentAsFormatException, "Boolean", e, this as IXmlLineInfo); } catch (OverflowException e) { throw new XmlException(Res.Xml_ReadContentAsFormatException, "Boolean", e, this as IXmlLineInfo); } } public override DateTime ReadElementContentAsDateTime() { if (this.NodeType != XmlNodeType.Element) { throw CreateReadElementContentAsException("ReadElementContentAsDateTime"); } XmlSchemaType xmlType; object typedValue = InternalReadElementContentAsObject(out xmlType); try { if (xmlType != null) { return xmlType.ValueConverter.ToDateTime(typedValue); } else { return XmlUntypedConverter.Untyped.ToDateTime(typedValue); } } catch (FormatException e) { throw new XmlException(Res.Xml_ReadContentAsFormatException, "DateTime", e, this as IXmlLineInfo); } catch (InvalidCastException e) { throw new XmlException(Res.Xml_ReadContentAsFormatException, "DateTime", e, this as IXmlLineInfo); } catch (OverflowException e) { throw new XmlException(Res.Xml_ReadContentAsFormatException, "DateTime", e, this as IXmlLineInfo); } } public override double ReadElementContentAsDouble() { if (this.NodeType != XmlNodeType.Element) { throw CreateReadElementContentAsException("ReadElementContentAsDouble"); } XmlSchemaType xmlType; object typedValue = InternalReadElementContentAsObject(out xmlType); try { if (xmlType != null) { return xmlType.ValueConverter.ToDouble(typedValue); } else { return XmlUntypedConverter.Untyped.ToDouble(typedValue); } } catch (FormatException e) { throw new XmlException(Res.Xml_ReadContentAsFormatException, "Double", e, this as IXmlLineInfo); } catch (InvalidCastException e) { throw new XmlException(Res.Xml_ReadContentAsFormatException, "Double", e, this as IXmlLineInfo); } catch (OverflowException e) { throw new XmlException(Res.Xml_ReadContentAsFormatException, "Double", e, this as IXmlLineInfo); } } public override float ReadElementContentAsFloat() { if (this.NodeType != XmlNodeType.Element) { throw CreateReadElementContentAsException("ReadElementContentAsFloat"); } XmlSchemaType xmlType; object typedValue = InternalReadElementContentAsObject(out xmlType); try { if (xmlType != null) { return xmlType.ValueConverter.ToSingle(typedValue); } else { return XmlUntypedConverter.Untyped.ToSingle(typedValue); } } catch (FormatException e) { throw new XmlException(Res.Xml_ReadContentAsFormatException, "Float", e, this as IXmlLineInfo); } catch (InvalidCastException e) { throw new XmlException(Res.Xml_ReadContentAsFormatException, "Float", e, this as IXmlLineInfo); } catch (OverflowException e) { throw new XmlException(Res.Xml_ReadContentAsFormatException, "Float", e, this as IXmlLineInfo); } } public override Decimal ReadElementContentAsDecimal() { if (this.NodeType != XmlNodeType.Element) { throw CreateReadElementContentAsException("ReadElementContentAsDecimal"); } XmlSchemaType xmlType; object typedValue = InternalReadElementContentAsObject(out xmlType); try { if (xmlType != null) { return xmlType.ValueConverter.ToDecimal(typedValue); } else { return XmlUntypedConverter.Untyped.ToDecimal(typedValue); } } catch (FormatException e) { throw new XmlException(Res.Xml_ReadContentAsFormatException, "Decimal", e, this as IXmlLineInfo); } catch (InvalidCastException e) { throw new XmlException(Res.Xml_ReadContentAsFormatException, "Decimal", e, this as IXmlLineInfo); } catch (OverflowException e) { throw new XmlException(Res.Xml_ReadContentAsFormatException, "Decimal", e, this as IXmlLineInfo); } } public override int ReadElementContentAsInt() { if (this.NodeType != XmlNodeType.Element) { throw CreateReadElementContentAsException("ReadElementContentAsInt"); } XmlSchemaType xmlType; object typedValue = InternalReadElementContentAsObject(out xmlType); try { if (xmlType != null) { return xmlType.ValueConverter.ToInt32(typedValue); } else { return XmlUntypedConverter.Untyped.ToInt32(typedValue); } } catch (FormatException e) { throw new XmlException(Res.Xml_ReadContentAsFormatException, "Int", e, this as IXmlLineInfo); } catch (InvalidCastException e) { throw new XmlException(Res.Xml_ReadContentAsFormatException, "Int", e, this as IXmlLineInfo); } catch (OverflowException e) { throw new XmlException(Res.Xml_ReadContentAsFormatException, "Int", e, this as IXmlLineInfo); } } public override long ReadElementContentAsLong() { if (this.NodeType != XmlNodeType.Element) { throw CreateReadElementContentAsException("ReadElementContentAsLong"); } XmlSchemaType xmlType; object typedValue = InternalReadElementContentAsObject(out xmlType); try { if (xmlType != null) { return xmlType.ValueConverter.ToInt64(typedValue); } else { return XmlUntypedConverter.Untyped.ToInt64(typedValue); } } catch (FormatException e) { throw new XmlException(Res.Xml_ReadContentAsFormatException, "Long", e, this as IXmlLineInfo); } catch (InvalidCastException e) { throw new XmlException(Res.Xml_ReadContentAsFormatException, "Long", e, this as IXmlLineInfo); } catch (OverflowException e) { throw new XmlException(Res.Xml_ReadContentAsFormatException, "Long", e, this as IXmlLineInfo); } } public override string ReadElementContentAsString() { if (this.NodeType != XmlNodeType.Element) { throw CreateReadElementContentAsException("ReadElementContentAsString"); } XmlSchemaType xmlType; object typedValue = InternalReadElementContentAsObject(out xmlType); try { if (xmlType != null) { return xmlType.ValueConverter.ToString(typedValue); } else { return typedValue as string; } } catch (InvalidCastException e) { throw new XmlException(Res.Xml_ReadContentAsFormatException, "String", e, this as IXmlLineInfo); } catch (FormatException e) { throw new XmlException(Res.Xml_ReadContentAsFormatException, "String", e, this as IXmlLineInfo); } catch (OverflowException e) { throw new XmlException(Res.Xml_ReadContentAsFormatException, "String", e, this as IXmlLineInfo); } } public override object ReadElementContentAs(Type returnType, IXmlNamespaceResolver namespaceResolver) { if (this.NodeType != XmlNodeType.Element) { throw CreateReadElementContentAsException("ReadElementContentAs"); } XmlSchemaType xmlType; string originalStringValue; object typedValue = InternalReadElementContentAsObject(out xmlType, false, out originalStringValue); try { if (xmlType != null) { // special-case convertions to DateTimeOffset; typedValue is by default a DateTime // which cannot preserve time zone, so we need to convert from the original string if (returnType == typeof(DateTimeOffset) && xmlType.Datatype is Datatype_dateTimeBase) { typedValue = originalStringValue; } return xmlType.ValueConverter.ChangeType(typedValue, returnType, namespaceResolver); } else { return XmlUntypedConverter.Untyped.ChangeType(typedValue, returnType, namespaceResolver); } } catch (FormatException e) { throw new XmlException(Res.Xml_ReadContentAsFormatException, returnType.ToString(), e, this as IXmlLineInfo); } catch (InvalidCastException e) { throw new XmlException(Res.Xml_ReadContentAsFormatException, returnType.ToString(), e, this as IXmlLineInfo); } catch (OverflowException e) { throw new XmlException(Res.Xml_ReadContentAsFormatException, returnType.ToString(), e, this as IXmlLineInfo); } } // Attribute Accessors // The number of attributes on the current node. public override int AttributeCount { get { return attributeCount; } } // Gets the value of the attribute with the specified Name. public override string GetAttribute(string name) { string attValue = coreReader.GetAttribute(name); if (attValue == null && attributeCount > 0) { //Could be default attribute ValidatingReaderNodeData defaultNode = GetDefaultAttribute(name, false); if (defaultNode != null) { //Default found attValue = defaultNode.RawValue; } } return attValue; } // Gets the value of the attribute with the specified LocalName and NamespaceURI. public override string GetAttribute(string name, string namespaceURI) { string attValue = coreReader.GetAttribute(name, namespaceURI); if (attValue == null && attributeCount > 0) { //Could be default attribute namespaceURI = (namespaceURI == null) ? string.Empty : coreReaderNameTable.Get(namespaceURI); name = coreReaderNameTable.Get(name); if (name == null || namespaceURI == null) { //Attribute not present since we did not see it return null; } ValidatingReaderNodeData attNode = GetDefaultAttribute(name, namespaceURI, false); if (attNode != null) { return attNode.RawValue; } } return attValue; } // Gets the value of the attribute with the specified index. public override string GetAttribute(int i) { if (attributeCount == 0) { return null; } if (i < coreReaderAttributeCount) { return coreReader.GetAttribute(i); } else { int defaultIndex = i - coreReaderAttributeCount; ValidatingReaderNodeData attNode = (ValidatingReaderNodeData)defaultAttributes[defaultIndex]; Debug.Assert(attNode != null); return attNode.RawValue; } } // Moves to the attribute with the specified Name public override bool MoveToAttribute(string name) { if (coreReader.MoveToAttribute(name)) { validationState = ValidatingReaderState.OnAttribute; attributePSVI = GetAttributePSVI(name); goto Found; } else if (attributeCount > 0) { //Default attribute ValidatingReaderNodeData defaultNode = GetDefaultAttribute(name, true); if (defaultNode != null) { validationState = ValidatingReaderState.OnDefaultAttribute; attributePSVI = defaultNode.AttInfo; cachedNode = defaultNode; goto Found; } } return false; Found: if (validationState == ValidatingReaderState.OnReadBinaryContent) { readBinaryHelper.Finish(); validationState = savedState; } return true; } // Moves to the attribute with the specified LocalName and NamespaceURI public override bool MoveToAttribute(string name, string ns) { //Check atomized local name and ns name = coreReaderNameTable.Get(name); ns = ns != null ? coreReaderNameTable.Get(ns) : string.Empty; if (name == null || ns == null) { //Name or ns not found in the nameTable, then attribute is not found return false; } if (coreReader.MoveToAttribute(name, ns)) { validationState = ValidatingReaderState.OnAttribute; if (inlineSchemaParser == null) { attributePSVI = GetAttributePSVI(name, ns); Debug.Assert(attributePSVI != null); } else { //Parsing inline schema, no PSVI for schema attributes attributePSVI = null; } goto Found; } else { //Default attribute ValidatingReaderNodeData defaultNode = GetDefaultAttribute(name, ns, true); if (defaultNode != null) { attributePSVI = defaultNode.AttInfo; cachedNode = defaultNode; validationState = ValidatingReaderState.OnDefaultAttribute; goto Found; } } return false; Found: if (validationState == ValidatingReaderState.OnReadBinaryContent) { readBinaryHelper.Finish(); validationState = savedState; } return true; } // Moves to the attribute with the specified index public override void MoveToAttribute(int i) { if (i < 0 || i >= attributeCount) { throw new ArgumentOutOfRangeException("i"); } currentAttrIndex = i; if (i < coreReaderAttributeCount) { //reader attribute coreReader.MoveToAttribute(i); if (inlineSchemaParser == null) { attributePSVI = attributePSVINodes[i]; } else { attributePSVI = null; } validationState = ValidatingReaderState.OnAttribute; } else { //default attribute int defaultIndex = i - coreReaderAttributeCount; cachedNode = (ValidatingReaderNodeData)defaultAttributes[defaultIndex]; attributePSVI = cachedNode.AttInfo; validationState = ValidatingReaderState.OnDefaultAttribute; } if (validationState == ValidatingReaderState.OnReadBinaryContent) { readBinaryHelper.Finish(); validationState = savedState; } } // Moves to the first attribute. public override bool MoveToFirstAttribute() { if (coreReader.MoveToFirstAttribute()) { currentAttrIndex = 0; if (inlineSchemaParser == null) { attributePSVI = attributePSVINodes[0]; } else { attributePSVI = null; } validationState = ValidatingReaderState.OnAttribute; goto Found; } else if (defaultAttributes.Count > 0) { //check for default cachedNode = (ValidatingReaderNodeData)defaultAttributes[0]; attributePSVI = cachedNode.AttInfo; currentAttrIndex = 0; validationState = ValidatingReaderState.OnDefaultAttribute; goto Found; } return false; Found: if (validationState == ValidatingReaderState.OnReadBinaryContent) { readBinaryHelper.Finish(); validationState = savedState; } return true; } // Moves to the next attribute. public override bool MoveToNextAttribute() { if (currentAttrIndex + 1 < coreReaderAttributeCount) { bool moveTo = coreReader.MoveToNextAttribute(); Debug.Assert(moveTo); currentAttrIndex++; if (inlineSchemaParser == null) { attributePSVI = attributePSVINodes[currentAttrIndex]; } else { attributePSVI = null; } validationState = ValidatingReaderState.OnAttribute; goto Found; } else if (currentAttrIndex + 1 < attributeCount) { //default attribute int defaultIndex = ++currentAttrIndex - coreReaderAttributeCount; cachedNode = (ValidatingReaderNodeData)defaultAttributes[defaultIndex]; attributePSVI = cachedNode.AttInfo; validationState = ValidatingReaderState.OnDefaultAttribute; goto Found; } return false; Found: if (validationState == ValidatingReaderState.OnReadBinaryContent) { readBinaryHelper.Finish(); validationState = savedState; } return true; } // Moves to the element that contains the current attribute node. public override bool MoveToElement() { if (coreReader.MoveToElement() || (int)validationState < 0) { //states OnDefaultAttribute or OnReadAttributeValue currentAttrIndex = -1; validationState = ValidatingReaderState.ClearAttributes; return true; } return false; } // Reads the next node from the stream/TextReader. public override bool Read() { switch (validationState) { case ValidatingReaderState.Read: if (coreReader.Read()) { ProcessReaderEvent(); return true; } else { validator.EndValidation(); if (coreReader.EOF) { validationState = ValidatingReaderState.EOF; } return false; } case ValidatingReaderState.ParseInlineSchema: ProcessInlineSchema(); return true; case ValidatingReaderState.OnAttribute: case ValidatingReaderState.OnDefaultAttribute: case ValidatingReaderState.ClearAttributes: case ValidatingReaderState.OnReadAttributeValue: ClearAttributesInfo(); if (inlineSchemaParser != null) { validationState = ValidatingReaderState.ParseInlineSchema; goto case ValidatingReaderState.ParseInlineSchema; } else { validationState = ValidatingReaderState.Read; goto case ValidatingReaderState.Read; } case ValidatingReaderState.ReadAhead: //Will enter here on calling Skip() ClearAttributesInfo(); ProcessReaderEvent(); validationState = ValidatingReaderState.Read; return true; case ValidatingReaderState.OnReadBinaryContent: validationState = savedState; readBinaryHelper.Finish(); return Read(); case ValidatingReaderState.Init: validationState = ValidatingReaderState.Read; if (coreReader.ReadState == ReadState.Interactive) { //If the underlying reader is already positioned on a ndoe, process it ProcessReaderEvent(); return true; } else { goto case ValidatingReaderState.Read; } case ValidatingReaderState.ReaderClosed: case ValidatingReaderState.EOF: return false; default: return false; } } // Gets a value indicating whether XmlReader is positioned at the end of the stream/TextReader. public override bool EOF { get { return coreReader.EOF; } } // Closes the stream, changes the ReadState to Closed, and sets all the properties back to zero. public override void Close() { coreReader.Close(); validationState = ValidatingReaderState.ReaderClosed; } // Returns the read state of the XmlReader. public override ReadState ReadState { get { return (validationState == ValidatingReaderState.Init) ? ReadState.Initial : coreReader.ReadState; } } // Skips to the end tag of the current element. public override void Skip() { int startDepth = Depth; switch (NodeType) { case XmlNodeType.Element: if (coreReader.IsEmptyElement) { break; } bool callSkipToEndElem = true; //If union and unionValue has been parsed till EndElement, then validator.ValidateEndElement has been called //Hence should not call SkipToEndElement as the current context has already been popped in the validator if ((xmlSchemaInfo.IsUnionType || xmlSchemaInfo.IsDefault) && coreReader is XsdCachingReader) { callSkipToEndElem = false; } coreReader.Skip(); validationState = ValidatingReaderState.ReadAhead; if (callSkipToEndElem) { validator.SkipToEndElement(xmlSchemaInfo); } break; case XmlNodeType.Attribute: MoveToElement(); goto case XmlNodeType.Element; } //For all other NodeTypes Skip() same as Read() Read(); return; } // Gets the XmlNameTable associated with this implementation. public override XmlNameTable NameTable { get { return coreReaderNameTable; } } // Resolves a namespace prefix in the current element's scope. public override string LookupNamespace(string prefix) { return thisNSResolver.LookupNamespace(prefix); } // Resolves the entity reference for nodes of NodeType EntityReference. public override void ResolveEntity() { throw new InvalidOperationException(); } // Parses the attribute value into one or more Text and/or EntityReference node types. public override bool ReadAttributeValue() { if (validationState == ValidatingReaderState.OnReadBinaryContent) { readBinaryHelper.Finish(); validationState = savedState; } if (NodeType == XmlNodeType.Attribute) { if (validationState == ValidatingReaderState.OnDefaultAttribute) { cachedNode = CreateDummyTextNode(cachedNode.RawValue, cachedNode.Depth + 1); validationState = ValidatingReaderState.OnReadAttributeValue; return true; } return coreReader.ReadAttributeValue(); } return false; } public override bool CanReadBinaryContent { get { return true; } } public override int ReadContentAsBase64(byte[] buffer, int index, int count) { if (ReadState != ReadState.Interactive) { return 0; } // init ReadContentAsBinaryHelper when called first time if (validationState != ValidatingReaderState.OnReadBinaryContent) { readBinaryHelper = ReadContentAsBinaryHelper.CreateOrReset(readBinaryHelper, this); savedState = validationState; } // restore original state in order to have a normal Read() behavior when called from readBinaryHelper validationState = savedState; // call to the helper int readCount = readBinaryHelper.ReadContentAsBase64(buffer, index, count); // set OnReadBinaryContent state again and return savedState = validationState; validationState = ValidatingReaderState.OnReadBinaryContent; return readCount; } public override int ReadContentAsBinHex(byte[] buffer, int index, int count) { if (ReadState != ReadState.Interactive) { return 0; } // init ReadContentAsBinaryHelper when called first time if (validationState != ValidatingReaderState.OnReadBinaryContent) { readBinaryHelper = ReadContentAsBinaryHelper.CreateOrReset(readBinaryHelper, this); savedState = validationState; } // restore original state in order to have a normal Read() behavior when called from readBinaryHelper validationState = savedState; // call to the helper int readCount = readBinaryHelper.ReadContentAsBinHex(buffer, index, count); // set OnReadBinaryContent state again and return savedState = validationState; validationState = ValidatingReaderState.OnReadBinaryContent; return readCount; } public override int ReadElementContentAsBase64(byte[] buffer, int index, int count) { if (ReadState != ReadState.Interactive) { return 0; } // init ReadContentAsBinaryHelper when called first time if (validationState != ValidatingReaderState.OnReadBinaryContent) { readBinaryHelper = ReadContentAsBinaryHelper.CreateOrReset(readBinaryHelper, this); savedState = validationState; } // restore original state in order to have a normal Read() behavior when called from readBinaryHelper validationState = savedState; // call to the helper int readCount = readBinaryHelper.ReadElementContentAsBase64(buffer, index, count); // set OnReadBinaryContent state again and return savedState = validationState; validationState = ValidatingReaderState.OnReadBinaryContent; return readCount; } public override int ReadElementContentAsBinHex(byte[] buffer, int index, int count) { if (ReadState != ReadState.Interactive) { return 0; } // init ReadContentAsBinaryHelper when called first time if (validationState != ValidatingReaderState.OnReadBinaryContent) { readBinaryHelper = ReadContentAsBinaryHelper.CreateOrReset(readBinaryHelper, this); savedState = validationState; } // restore original state in order to have a normal Read() behavior when called from readBinaryHelper validationState = savedState; // call to the helper int readCount = readBinaryHelper.ReadElementContentAsBinHex(buffer, index, count); // set OnReadBinaryContent state again and return savedState = validationState; validationState = ValidatingReaderState.OnReadBinaryContent; return readCount; } // // IXmlSchemaInfo interface // bool IXmlSchemaInfo.IsDefault { get { switch (NodeType) { case XmlNodeType.Element: if (!coreReader.IsEmptyElement) { GetIsDefault(); } return xmlSchemaInfo.IsDefault; case XmlNodeType.EndElement: return xmlSchemaInfo.IsDefault; case XmlNodeType.Attribute: if (attributePSVI != null) { return AttributeSchemaInfo.IsDefault; } break; default: break; } return false; } } bool IXmlSchemaInfo.IsNil { get { switch (NodeType) { case XmlNodeType.Element: case XmlNodeType.EndElement: return xmlSchemaInfo.IsNil; default: break; } return false; } } XmlSchemaValidity IXmlSchemaInfo.Validity { get { switch (NodeType) { case XmlNodeType.Element: if (coreReader.IsEmptyElement) { return xmlSchemaInfo.Validity; } if (xmlSchemaInfo.Validity == XmlSchemaValidity.Valid) { //It might be valid for unions since we read ahead, but report notknown for consistency return XmlSchemaValidity.NotKnown; } return xmlSchemaInfo.Validity; case XmlNodeType.EndElement: return xmlSchemaInfo.Validity; case XmlNodeType.Attribute: if (attributePSVI != null) { return AttributeSchemaInfo.Validity; } break; } return XmlSchemaValidity.NotKnown; } } XmlSchemaSimpleType IXmlSchemaInfo.MemberType { get { switch (NodeType) { case XmlNodeType.Element: if (!coreReader.IsEmptyElement) { GetMemberType(); } return xmlSchemaInfo.MemberType; case XmlNodeType.EndElement: return xmlSchemaInfo.MemberType; case XmlNodeType.Attribute: if (attributePSVI != null) { return AttributeSchemaInfo.MemberType; } return null; default: return null; //Text, PI, Comment etc } } } XmlSchemaType IXmlSchemaInfo.SchemaType { get { switch (NodeType) { case XmlNodeType.Element: case XmlNodeType.EndElement: return xmlSchemaInfo.SchemaType; case XmlNodeType.Attribute: if (attributePSVI != null) { return AttributeSchemaInfo.SchemaType; } return null; default: return null; //Text, PI, Comment etc } } } XmlSchemaElement IXmlSchemaInfo.SchemaElement { get { if (NodeType == XmlNodeType.Element || NodeType == XmlNodeType.EndElement) { return xmlSchemaInfo.SchemaElement; } return null; } } XmlSchemaAttribute IXmlSchemaInfo.SchemaAttribute { get { if (NodeType == XmlNodeType.Attribute) { if (attributePSVI != null) { return AttributeSchemaInfo.SchemaAttribute; } } return null; } } // // IXmlLineInfo members // public bool HasLineInfo() { return true; } public int LineNumber { get { if (lineInfo != null) { return lineInfo.LineNumber; } return 0; } } public int LinePosition { get { if (lineInfo != null) { return lineInfo.LinePosition; } return 0; } } // // IXmlNamespaceResolver members // IDictionary IXmlNamespaceResolver.GetNamespacesInScope(XmlNamespaceScope scope) { if (coreReaderNSResolver != null) { return coreReaderNSResolver.GetNamespacesInScope(scope); } else { return nsManager.GetNamespacesInScope(scope); } } string IXmlNamespaceResolver.LookupNamespace(string prefix) { if (coreReaderNSResolver != null) { return coreReaderNSResolver.LookupNamespace(prefix); } else { return nsManager.LookupNamespace(prefix); } } string IXmlNamespaceResolver.LookupPrefix(string namespaceName) { if (coreReaderNSResolver != null) { return coreReaderNSResolver.LookupPrefix(namespaceName); } else { return nsManager.LookupPrefix(namespaceName); } } //Internal / Private methods private object GetStringValue() { return coreReader.Value; } private XmlSchemaType ElementXmlType { get { return xmlSchemaInfo.XmlType; } } private XmlSchemaType AttributeXmlType { get { if (attributePSVI != null) { return AttributeSchemaInfo.XmlType; } return null; } } private XmlSchemaInfo AttributeSchemaInfo { get { Debug.Assert(attributePSVI != null); return attributePSVI.attributeSchemaInfo; } } private void ProcessReaderEvent() { if (replayCache) { //if in replay mode, do nothing since nodes have been validated already //If NodeType == XmlNodeType.EndElement && if manageNamespaces, may need to pop namespace scope, since scope is not popped in ReadAheadForMemberType return; } switch (coreReader.NodeType) { case XmlNodeType.Element: ProcessElementEvent(); break; case XmlNodeType.Whitespace: case XmlNodeType.SignificantWhitespace: validator.ValidateWhitespace(GetStringValue); break; case XmlNodeType.Text: // text inside a node case XmlNodeType.CDATA: // validator.ValidateText(GetStringValue); break; case XmlNodeType.EndElement: ProcessEndElementEvent(); break; case XmlNodeType.EntityReference: throw new InvalidOperationException(); case XmlNodeType.DocumentType: #if TEMP_HACK_FOR_SCHEMA_INFO validator.SetDtdSchemaInfo((SchemaInfo)coreReader.DtdInfo); #else validator.SetDtdSchemaInfo(coreReader.DtdInfo); #endif break; default: break; } } // SxS: This function calls ValidateElement on XmlSchemaValidator which is annotated with ResourceExposure attribute. // Since the resource names (namespace location) are not provided directly by the user (they are read from the source // document) and the function does not expose any resources it is fine to suppress the SxS warning. [ResourceConsumption(ResourceScope.Machine, ResourceScope.Machine)] [ResourceExposure(ResourceScope.None)] private void ProcessElementEvent() { if (this.processInlineSchema && IsXSDRoot(coreReader.LocalName, coreReader.NamespaceURI) && coreReader.Depth > 0) { xmlSchemaInfo.Clear(); attributeCount = coreReaderAttributeCount = coreReader.AttributeCount; if (!coreReader.IsEmptyElement) { //If its not empty schema, then parse else ignore inlineSchemaParser = new Parser(SchemaType.XSD, coreReaderNameTable, validator.SchemaSet.GetSchemaNames(coreReaderNameTable), validationEvent); inlineSchemaParser.StartParsing(coreReader, null); inlineSchemaParser.ParseReaderNode(); validationState = ValidatingReaderState.ParseInlineSchema; } else { validationState = ValidatingReaderState.ClearAttributes; } } else { //Validate element //Clear previous data atomicValue = null; originalAtomicValueString = null; xmlSchemaInfo.Clear(); if (manageNamespaces) { nsManager.PushScope(); } //Find Xsi attributes that need to be processed before validating the element string xsiSchemaLocation = null; string xsiNoNamespaceSL = null; string xsiNil = null; string xsiType = null; if (coreReader.MoveToFirstAttribute()) { do { string objectNs = coreReader.NamespaceURI; string objectName = coreReader.LocalName; if (Ref.Equal(objectNs, NsXsi)) { if (Ref.Equal(objectName, XsiSchemaLocation)) { xsiSchemaLocation = coreReader.Value; } else if (Ref.Equal(objectName, XsiNoNamespaceSchemaLocation)) { xsiNoNamespaceSL = coreReader.Value; } else if (Ref.Equal(objectName, XsiType)) { xsiType = coreReader.Value; } else if (Ref.Equal(objectName, XsiNil)) { xsiNil = coreReader.Value; } } if (manageNamespaces && Ref.Equal(coreReader.NamespaceURI, NsXmlNs)) { nsManager.AddNamespace(coreReader.Prefix.Length == 0 ? string.Empty : coreReader.LocalName, coreReader.Value); } } while (coreReader.MoveToNextAttribute()); coreReader.MoveToElement(); } validator.ValidateElement(coreReader.LocalName, coreReader.NamespaceURI, xmlSchemaInfo, xsiType, xsiNil, xsiSchemaLocation, xsiNoNamespaceSL); ValidateAttributes(); validator.ValidateEndOfAttributes(xmlSchemaInfo); if (coreReader.IsEmptyElement) { ProcessEndElementEvent(); } validationState = ValidatingReaderState.ClearAttributes; } } private void ProcessEndElementEvent() { atomicValue = validator.ValidateEndElement(xmlSchemaInfo); originalAtomicValueString = GetOriginalAtomicValueStringOfElement(); if (xmlSchemaInfo.IsDefault) { //The atomicValue returned is a default value Debug.Assert(atomicValue != null); int depth = coreReader.Depth; coreReader = GetCachingReader(); cachingReader.RecordTextNode( xmlSchemaInfo.XmlType.ValueConverter.ToString( atomicValue ), originalAtomicValueString, depth + 1, 0, 0 ); cachingReader.RecordEndElementNode(); cachingReader.SetToReplayMode(); replayCache = true; } else if (manageNamespaces) { nsManager.PopScope(); } } private void ValidateAttributes() { attributeCount = coreReaderAttributeCount = coreReader.AttributeCount; AttributePSVIInfo attributePSVI; int attIndex = 0; bool attributeInvalid = false; if (coreReader.MoveToFirstAttribute()) { do { string localName = coreReader.LocalName; string ns = coreReader.NamespaceURI; attributePSVI = AddAttributePSVI(attIndex); attributePSVI.localName = localName; attributePSVI.namespaceUri = ns; if ((object)ns == (object)NsXmlNs) { attIndex++; continue; } attributePSVI.typedAttributeValue = validator.ValidateAttribute(localName, ns, valueGetter, attributePSVI.attributeSchemaInfo); if (!attributeInvalid) { attributeInvalid = attributePSVI.attributeSchemaInfo.Validity == XmlSchemaValidity.Invalid; } attIndex++; } while (coreReader.MoveToNextAttribute()); } coreReader.MoveToElement(); if (attributeInvalid) { //If any of the attributes are invalid, Need to report element's validity as invalid xmlSchemaInfo.Validity = XmlSchemaValidity.Invalid; } validator.GetUnspecifiedDefaultAttributes(defaultAttributes, true); attributeCount += defaultAttributes.Count; } private void ClearAttributesInfo() { attributeCount = 0; coreReaderAttributeCount = 0; currentAttrIndex = -1; defaultAttributes.Clear(); attributePSVI = null; } private AttributePSVIInfo GetAttributePSVI(string name) { if (inlineSchemaParser != null) { //Parsing inline schema, no PSVI for schema attributes return null; } string attrLocalName; string attrPrefix; string ns; ValidateNames.SplitQName(name, out attrPrefix, out attrLocalName); attrPrefix = coreReaderNameTable.Add(attrPrefix); attrLocalName = coreReaderNameTable.Add(attrLocalName); if (attrPrefix.Length == 0) { //empty prefix, not qualified ns = string.Empty; } else { ns = thisNSResolver.LookupNamespace(attrPrefix); } return GetAttributePSVI(attrLocalName, ns); } private AttributePSVIInfo GetAttributePSVI(string localName, string ns) { Debug.Assert(coreReaderNameTable.Get(localName) != null); Debug.Assert(coreReaderNameTable.Get(ns) != null); AttributePSVIInfo attInfo = null; for (int i = 0; i < coreReaderAttributeCount; i++) { attInfo = attributePSVINodes[i]; if (attInfo != null) { //Will be null for invalid attributes if (Ref.Equal(localName, attInfo.localName) && Ref.Equal(ns, attInfo.namespaceUri)) { currentAttrIndex = i; return attInfo; } } } return null; } private ValidatingReaderNodeData GetDefaultAttribute(string name, bool updatePosition) { string attrLocalName; string attrPrefix; ValidateNames.SplitQName(name, out attrPrefix, out attrLocalName); //Atomize attrPrefix = coreReaderNameTable.Add(attrPrefix); attrLocalName = coreReaderNameTable.Add(attrLocalName); string ns; if (attrPrefix.Length == 0) { ns = string.Empty; } else { ns = thisNSResolver.LookupNamespace(attrPrefix); } return GetDefaultAttribute(attrLocalName, ns, updatePosition); } private ValidatingReaderNodeData GetDefaultAttribute(string attrLocalName, string ns, bool updatePosition) { Debug.Assert(coreReaderNameTable.Get(attrLocalName) != null); Debug.Assert(coreReaderNameTable.Get(ns) != null); ValidatingReaderNodeData defaultNode = null; for (int i = 0; i < defaultAttributes.Count; i++) { defaultNode = (ValidatingReaderNodeData)defaultAttributes[i]; if (Ref.Equal(defaultNode.LocalName, attrLocalName) && Ref.Equal(defaultNode.Namespace, ns)) { if (updatePosition) { currentAttrIndex = coreReader.AttributeCount + i; } return defaultNode; } } return null; } private AttributePSVIInfo AddAttributePSVI(int attIndex) { Debug.Assert(attIndex <= attributePSVINodes.Length); AttributePSVIInfo attInfo = attributePSVINodes[attIndex]; if (attInfo != null) { attInfo.Reset(); return attInfo; } if (attIndex >= attributePSVINodes.Length - 1) { //reached capacity of PSVIInfo array, Need to increase capacity to twice the initial AttributePSVIInfo[] newPSVINodes = new AttributePSVIInfo[attributePSVINodes.Length * 2]; Array.Copy(attributePSVINodes, 0, newPSVINodes, 0, attributePSVINodes.Length); attributePSVINodes = newPSVINodes; } attInfo = attributePSVINodes[attIndex]; if (attInfo == null) { attInfo = new AttributePSVIInfo(); attributePSVINodes[attIndex] = attInfo; } return attInfo; } private bool IsXSDRoot(string localName, string ns) { return Ref.Equal(ns, NsXs) && Ref.Equal(localName, XsdSchema); } private void ProcessInlineSchema() { Debug.Assert(inlineSchemaParser != null); if (coreReader.Read()) { if (coreReader.NodeType == XmlNodeType.Element) { attributeCount = coreReaderAttributeCount = coreReader.AttributeCount; } else { //Clear attributes info if nodeType is not element ClearAttributesInfo(); } if (!inlineSchemaParser.ParseReaderNode()) { inlineSchemaParser.FinishParsing(); XmlSchema schema = inlineSchemaParser.XmlSchema; validator.AddSchema(schema); inlineSchemaParser = null; validationState = ValidatingReaderState.Read; } } } private object InternalReadContentAsObject() { return InternalReadContentAsObject(false); } private object InternalReadContentAsObject(bool unwrapTypedValue) { string str; return InternalReadContentAsObject(unwrapTypedValue, out str); } private object InternalReadContentAsObject(bool unwrapTypedValue, out string originalStringValue) { XmlNodeType nodeType = this.NodeType; if (nodeType == XmlNodeType.Attribute) { originalStringValue = this.Value; if ( attributePSVI != null && attributePSVI.typedAttributeValue != null ) { if ( validationState == ValidatingReaderState.OnDefaultAttribute) { XmlSchemaAttribute schemaAttr = attributePSVI.attributeSchemaInfo.SchemaAttribute; originalStringValue = ( schemaAttr.DefaultValue != null ) ? schemaAttr.DefaultValue : schemaAttr.FixedValue; } return ReturnBoxedValue( attributePSVI.typedAttributeValue, AttributeSchemaInfo.XmlType, unwrapTypedValue ); } else { //return string value return this.Value; } } else if (nodeType == XmlNodeType.EndElement) { if (atomicValue != null) { originalStringValue = originalAtomicValueString; return atomicValue; } else { originalStringValue = string.Empty; return string.Empty; } } else { //Positioned on text, CDATA, PI, Comment etc if (validator.CurrentContentType == XmlSchemaContentType.TextOnly) { //if current element is of simple type object value = ReturnBoxedValue(ReadTillEndElement(), xmlSchemaInfo.XmlType, unwrapTypedValue); originalStringValue = originalAtomicValueString; return value; } else { XsdCachingReader cachingReader = this.coreReader as XsdCachingReader; if ( cachingReader != null ) { originalStringValue = cachingReader.ReadOriginalContentAsString(); } else { originalStringValue = InternalReadContentAsString(); } return originalStringValue; } } } private object InternalReadElementContentAsObject(out XmlSchemaType xmlType) { return InternalReadElementContentAsObject(out xmlType, false); } private object InternalReadElementContentAsObject(out XmlSchemaType xmlType, bool unwrapTypedValue) { string tmpString; return InternalReadElementContentAsObject(out xmlType, unwrapTypedValue, out tmpString); } private object InternalReadElementContentAsObject(out XmlSchemaType xmlType, bool unwrapTypedValue, out string originalString) { Debug.Assert(this.NodeType == XmlNodeType.Element); object typedValue = null; xmlType = null; //If its an empty element, can have default/fixed value if (this.IsEmptyElement) { if (xmlSchemaInfo.ContentType == XmlSchemaContentType.TextOnly) { typedValue = ReturnBoxedValue(atomicValue, xmlSchemaInfo.XmlType, unwrapTypedValue); } else { typedValue = atomicValue; } originalString = originalAtomicValueString; xmlType = ElementXmlType; //Set this for default values this.Read(); return typedValue; } // move to content and read typed value this.Read(); if (this.NodeType == XmlNodeType.EndElement) { //If IsDefault is true, the next node will be EndElement if (xmlSchemaInfo.IsDefault) { if (xmlSchemaInfo.ContentType == XmlSchemaContentType.TextOnly) { typedValue = ReturnBoxedValue(atomicValue, xmlSchemaInfo.XmlType, unwrapTypedValue); } else { //anyType has default value typedValue = atomicValue; } originalString = originalAtomicValueString; } else { //Empty content typedValue = string.Empty; originalString = string.Empty; } } else if (this.NodeType == XmlNodeType.Element) { //the first child is again element node throw new XmlException(Res.Xml_MixedReadElementContentAs, string.Empty, this as IXmlLineInfo); } else { typedValue = InternalReadContentAsObject(unwrapTypedValue, out originalString); // ReadElementContentAsXXX cannot be called on mixed content, if positioned on node other than EndElement, Error if (this.NodeType != XmlNodeType.EndElement) { throw new XmlException(Res.Xml_MixedReadElementContentAs, string.Empty, this as IXmlLineInfo); } } xmlType = ElementXmlType; //Set this as we are moving ahead to the next node // move to next node this.Read(); return typedValue; } private object ReadTillEndElement() { if (atomicValue == null) { while (coreReader.Read()) { if (replayCache) { //If replaying nodes in the cache, they have already been validated continue; } switch (coreReader.NodeType) { case XmlNodeType.Element: ProcessReaderEvent(); goto breakWhile; case XmlNodeType.Text: case XmlNodeType.CDATA: validator.ValidateText(GetStringValue); break; case XmlNodeType.Whitespace: case XmlNodeType.SignificantWhitespace: validator.ValidateWhitespace(GetStringValue); break; case XmlNodeType.Comment: case XmlNodeType.ProcessingInstruction: break; case XmlNodeType.EndElement: atomicValue = validator.ValidateEndElement(xmlSchemaInfo); originalAtomicValueString = GetOriginalAtomicValueStringOfElement(); if (manageNamespaces) { nsManager.PopScope(); } goto breakWhile; } continue; breakWhile: break; } } else { //atomicValue != null, meaning already read ahead - Switch reader if (atomicValue == this) { //switch back invalid marker; dont need it since coreReader moved to endElement atomicValue = null; } SwitchReader(); } return atomicValue; } private void SwitchReader() { XsdCachingReader cachingReader = this.coreReader as XsdCachingReader; if (cachingReader != null) { //Switch back without going over the cached contents again. this.coreReader = cachingReader.GetCoreReader(); } Debug.Assert(coreReader.NodeType == XmlNodeType.EndElement); replayCache = false; } private void ReadAheadForMemberType() { while (coreReader.Read()) { switch (coreReader.NodeType) { case XmlNodeType.Element: Debug.Assert(false); //Should not happen as the caching reader does not cache elements in simple content break; case XmlNodeType.Text: case XmlNodeType.CDATA: validator.ValidateText(GetStringValue); break; case XmlNodeType.Whitespace: case XmlNodeType.SignificantWhitespace: validator.ValidateWhitespace(GetStringValue); break; case XmlNodeType.Comment: case XmlNodeType.ProcessingInstruction: break; case XmlNodeType.EndElement: atomicValue = validator.ValidateEndElement(xmlSchemaInfo); //?? pop namespaceManager scope originalAtomicValueString = GetOriginalAtomicValueStringOfElement(); if (atomicValue == null) { //Invalid marker atomicValue = this; } else if (xmlSchemaInfo.IsDefault) { //The atomicValue returned is a default value cachingReader.SwitchTextNodeAndEndElement(xmlSchemaInfo.XmlType.ValueConverter.ToString(atomicValue), originalAtomicValueString); } goto breakWhile; } continue; breakWhile: break; } } private void GetIsDefault() { XsdCachingReader cachedReader = coreReader as XsdCachingReader; if (cachedReader == null && xmlSchemaInfo.HasDefaultValue) { //Get Isdefault coreReader = GetCachingReader(); if (xmlSchemaInfo.IsUnionType && !xmlSchemaInfo.IsNil) { //If it also union, get the memberType as well ReadAheadForMemberType(); } else { if (coreReader.Read()) { switch (coreReader.NodeType) { case XmlNodeType.Element: Debug.Assert(false); //Should not happen as the caching reader does not cache elements in simple content break; case XmlNodeType.Text: case XmlNodeType.CDATA: validator.ValidateText(GetStringValue); break; case XmlNodeType.Whitespace: case XmlNodeType.SignificantWhitespace: validator.ValidateWhitespace(GetStringValue); break; case XmlNodeType.Comment: case XmlNodeType.ProcessingInstruction: break; case XmlNodeType.EndElement: atomicValue = validator.ValidateEndElement(xmlSchemaInfo); //?? pop namespaceManager scope originalAtomicValueString = GetOriginalAtomicValueStringOfElement(); if (xmlSchemaInfo.IsDefault) { //The atomicValue returned is a default value cachingReader.SwitchTextNodeAndEndElement(xmlSchemaInfo.XmlType.ValueConverter.ToString(atomicValue), originalAtomicValueString); } break; default: break; } } } cachingReader.SetToReplayMode(); replayCache = true; } } private void GetMemberType() { if (xmlSchemaInfo.MemberType != null || atomicValue == this) { return; } XsdCachingReader cachedReader = coreReader as XsdCachingReader; if (cachedReader == null && xmlSchemaInfo.IsUnionType && !xmlSchemaInfo.IsNil) { coreReader = GetCachingReader(); ReadAheadForMemberType(); cachingReader.SetToReplayMode(); replayCache = true; } } private object ReturnBoxedValue(object typedValue, XmlSchemaType xmlType, bool unWrap) { if (typedValue != null) { if (unWrap) { //convert XmlAtomicValue[] to object[] for list of unions; The other cases return typed value of the valueType anyway Debug.Assert(xmlType != null && xmlType.Datatype != null); if (xmlType.Datatype.Variety == XmlSchemaDatatypeVariety.List) { Datatype_List listType = xmlType.Datatype as Datatype_List; if (listType.ItemType.Variety == XmlSchemaDatatypeVariety.Union) { typedValue = xmlType.ValueConverter.ChangeType(typedValue, xmlType.Datatype.ValueType, thisNSResolver); } } } return typedValue; } else { //return the original string value of the element or attribute Debug.Assert(NodeType != XmlNodeType.Attribute); typedValue = validator.GetConcatenatedValue(); } return typedValue; } private XsdCachingReader GetCachingReader() { if (cachingReader == null) { cachingReader = new XsdCachingReader(coreReader, lineInfo, new CachingEventHandler(CachingCallBack)); } else { cachingReader.Reset(coreReader); } this.lineInfo = cachingReader as IXmlLineInfo; return cachingReader; } internal ValidatingReaderNodeData CreateDummyTextNode(string attributeValue, int depth) { if (textNode == null) { textNode = new ValidatingReaderNodeData(XmlNodeType.Text); } textNode.Depth = depth; textNode.RawValue = attributeValue; return textNode; } internal void CachingCallBack(XsdCachingReader cachingReader) { this.coreReader = cachingReader.GetCoreReader(); //re-switch the core-reader after caching reader is done this.lineInfo = cachingReader.GetLineInfo(); replayCache = false; } private string GetOriginalAtomicValueStringOfElement() { if ( xmlSchemaInfo.IsDefault ) { XmlSchemaElement schemaElem = xmlSchemaInfo.SchemaElement; if ( schemaElem != null ) { return ( schemaElem.DefaultValue != null ) ? schemaElem.DefaultValue : schemaElem.FixedValue; } } else { return validator.GetConcatenatedValue(); } return string.Empty; } } }