|
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System.IO;
using System.Text;
using Microsoft.Xml.Schema;
using Microsoft.Xml.XPath;
using System.Diagnostics;
using System.Globalization;
using System.Collections;
// using System.Security.Policy;
using System.Collections.Generic;
using System.Runtime.Versioning;
namespace Microsoft.Xml
{
using System;
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
private XmlNamespaceManager _nsManager;
private bool _manageNamespaces;
private bool _processInlineSchema;
private bool _replayCache;
//Current Node handling
private ValidatingReaderNodeData _cachedNode; //Used to cache current node when looking ahead or default attributes
private AttributePSVIInfo _attributePSVI;
//Attributes
private int _attributeCount; //Total count of attributes including default
private int _coreReaderAttributeCount;
private int _currentAttrIndex;
private AttributePSVIInfo[] _attributePSVINodes;
private 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
private IXmlLineInfo _lineInfo;
// helpers for Read[Element]ContentAs{Base64,BinHex} methods
private ReadContentAsBinaryHelper _readBinaryHelper;
private ValidatingReaderState _savedState;
//Constants
private const int InitialAttributeCount = 8;
private static volatile Type s_typeOfString;
//Constructor
internal XsdValidatingReader(XmlReader reader, XmlResolver xmlResolver, XmlReaderSettings readerSettings, XmlSchemaObject partialValidationType)
{
_coreReader = reader;
_coreReaderNSResolver = reader as IXmlNamespaceResolver;
_lineInfo = reader as IXmlLineInfo;
_coreReaderNameTable = _coreReader.NameTable;
if (_coreReaderNSResolver == null)
{
_nsManager = new XmlNamespaceManager(_coreReaderNameTable);
_manageNamespaces = true;
}
_thisNSResolver = this as IXmlNamespaceResolver;
_xmlResolver = xmlResolver;
_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);
s_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 = _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 = _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, <MyElement/>).
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: //TODO Check that context is not popped to parents in the validator
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 s_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(ResXml.Xml_ReadContentAsFormatException, "Boolean", e, this as IXmlLineInfo);
}
catch (FormatException e)
{
throw new XmlException(ResXml.Xml_ReadContentAsFormatException, "Boolean", e, this as IXmlLineInfo);
}
catch (OverflowException e)
{
throw new XmlException(ResXml.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(ResXml.Xml_ReadContentAsFormatException, "DateTime", e, this as IXmlLineInfo);
}
catch (FormatException e)
{
throw new XmlException(ResXml.Xml_ReadContentAsFormatException, "DateTime", e, this as IXmlLineInfo);
}
catch (OverflowException e)
{
throw new XmlException(ResXml.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(ResXml.Xml_ReadContentAsFormatException, "Double", e, this as IXmlLineInfo);
}
catch (FormatException e)
{
throw new XmlException(ResXml.Xml_ReadContentAsFormatException, "Double", e, this as IXmlLineInfo);
}
catch (OverflowException e)
{
throw new XmlException(ResXml.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(ResXml.Xml_ReadContentAsFormatException, "Float", e, this as IXmlLineInfo);
}
catch (FormatException e)
{
throw new XmlException(ResXml.Xml_ReadContentAsFormatException, "Float", e, this as IXmlLineInfo);
}
catch (OverflowException e)
{
throw new XmlException(ResXml.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(ResXml.Xml_ReadContentAsFormatException, "Decimal", e, this as IXmlLineInfo);
}
catch (FormatException e)
{
throw new XmlException(ResXml.Xml_ReadContentAsFormatException, "Decimal", e, this as IXmlLineInfo);
}
catch (OverflowException e)
{
throw new XmlException(ResXml.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(ResXml.Xml_ReadContentAsFormatException, "Int", e, this as IXmlLineInfo);
}
catch (FormatException e)
{
throw new XmlException(ResXml.Xml_ReadContentAsFormatException, "Int", e, this as IXmlLineInfo);
}
catch (OverflowException e)
{
throw new XmlException(ResXml.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(ResXml.Xml_ReadContentAsFormatException, "Long", e, this as IXmlLineInfo);
}
catch (FormatException e)
{
throw new XmlException(ResXml.Xml_ReadContentAsFormatException, "Long", e, this as IXmlLineInfo);
}
catch (OverflowException e)
{
throw new XmlException(ResXml.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(ResXml.Xml_ReadContentAsFormatException, "String", e, this as IXmlLineInfo);
}
catch (FormatException e)
{
throw new XmlException(ResXml.Xml_ReadContentAsFormatException, "String", e, this as IXmlLineInfo);
}
catch (OverflowException e)
{
throw new XmlException(ResXml.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; //TODO special case for xsd:duration and xsd:dateTime
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(ResXml.Xml_ReadContentAsFormatException, returnType.ToString(), e, this as IXmlLineInfo);
}
catch (InvalidCastException e)
{
throw new XmlException(ResXml.Xml_ReadContentAsFormatException, returnType.ToString(), e, this as IXmlLineInfo);
}
catch (OverflowException e)
{
throw new XmlException(ResXml.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(ResXml.Xml_ReadContentAsFormatException, "Boolean", e, this as IXmlLineInfo);
}
catch (InvalidCastException e)
{
throw new XmlException(ResXml.Xml_ReadContentAsFormatException, "Boolean", e, this as IXmlLineInfo);
}
catch (OverflowException e)
{
throw new XmlException(ResXml.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(ResXml.Xml_ReadContentAsFormatException, "DateTime", e, this as IXmlLineInfo);
}
catch (InvalidCastException e)
{
throw new XmlException(ResXml.Xml_ReadContentAsFormatException, "DateTime", e, this as IXmlLineInfo);
}
catch (OverflowException e)
{
throw new XmlException(ResXml.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(ResXml.Xml_ReadContentAsFormatException, "Double", e, this as IXmlLineInfo);
}
catch (InvalidCastException e)
{
throw new XmlException(ResXml.Xml_ReadContentAsFormatException, "Double", e, this as IXmlLineInfo);
}
catch (OverflowException e)
{
throw new XmlException(ResXml.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(ResXml.Xml_ReadContentAsFormatException, "Float", e, this as IXmlLineInfo);
}
catch (InvalidCastException e)
{
throw new XmlException(ResXml.Xml_ReadContentAsFormatException, "Float", e, this as IXmlLineInfo);
}
catch (OverflowException e)
{
throw new XmlException(ResXml.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(ResXml.Xml_ReadContentAsFormatException, "Decimal", e, this as IXmlLineInfo);
}
catch (InvalidCastException e)
{
throw new XmlException(ResXml.Xml_ReadContentAsFormatException, "Decimal", e, this as IXmlLineInfo);
}
catch (OverflowException e)
{
throw new XmlException(ResXml.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(ResXml.Xml_ReadContentAsFormatException, "Int", e, this as IXmlLineInfo);
}
catch (InvalidCastException e)
{
throw new XmlException(ResXml.Xml_ReadContentAsFormatException, "Int", e, this as IXmlLineInfo);
}
catch (OverflowException e)
{
throw new XmlException(ResXml.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(ResXml.Xml_ReadContentAsFormatException, "Long", e, this as IXmlLineInfo);
}
catch (InvalidCastException e)
{
throw new XmlException(ResXml.Xml_ReadContentAsFormatException, "Long", e, this as IXmlLineInfo);
}
catch (OverflowException e)
{
throw new XmlException(ResXml.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(ResXml.Xml_ReadContentAsFormatException, "String", e, this as IXmlLineInfo);
}
catch (FormatException e)
{
throw new XmlException(ResXml.Xml_ReadContentAsFormatException, "String", e, this as IXmlLineInfo);
}
catch (OverflowException e)
{
throw new XmlException(ResXml.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(ResXml.Xml_ReadContentAsFormatException, returnType.ToString(), e, this as IXmlLineInfo);
}
catch (InvalidCastException e)
{
throw new XmlException(ResXml.Xml_ReadContentAsFormatException, returnType.ToString(), e, this as IXmlLineInfo);
}
catch (OverflowException e)
{
throw new XmlException(ResXml.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<string, string> 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: // <![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 disable the SxS warning.
private void ProcessElementEvent()
{
if (_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 = _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(ResXml.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(ResXml.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 = _coreReader as XsdCachingReader;
if (cachingReader != null)
{ //Switch back without going over the cached contents again.
_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);
}
_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)
{
_coreReader = cachingReader.GetCoreReader(); //re-switch the core-reader after caching reader is done
_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;
}
}
}
|