File: System\Xml\Core\XmlValidatingReaderImpl.cs
Web Access
Project: src\src\libraries\System.Private.Xml\src\System.Private.Xml.csproj (System.Private.Xml)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
 
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using System.IO;
using System.Runtime.Versioning;
using System.Text;
using System.Xml.Schema;
 
namespace System.Xml
{
    internal sealed partial class XmlValidatingReaderImpl : XmlReader, IXmlLineInfo, IXmlNamespaceResolver
    {
        //
        // Private helper types
        //
        // ParsingFunction = what should the reader do when the next Read() is called
        private enum ParsingFunction
        {
            Read = 0,
            Init,
            ParseDtdFromContext,
            ResolveEntityInternally,
            InReadBinaryContent,
            ReaderClosed,
            Error,
            None,
        }
 
        internal sealed class ValidationEventHandling : IValidationEventHandling
        {
            // Fields
            private readonly XmlValidatingReaderImpl _reader;
            private ValidationEventHandler? _eventHandler;
 
            // Constructor
            internal ValidationEventHandling(XmlValidatingReaderImpl reader)
            {
                _reader = reader;
            }
 
            // IValidationEventHandling interface
            #region IValidationEventHandling interface
            object? IValidationEventHandling.EventHandler
            {
                get { return _eventHandler; }
            }
 
            void IValidationEventHandling.SendEvent(Exception /*XmlSchemaException*/ exception, XmlSeverityType severity)
            {
                if (_eventHandler != null)
                {
                    _eventHandler(_reader, new ValidationEventArgs((XmlSchemaException)exception, severity));
                }
                else if (_reader._validationType != ValidationType.None && severity == XmlSeverityType.Error)
                {
                    throw exception;
                }
            }
            #endregion
 
            // XmlValidatingReaderImpl helper methods
            internal void AddHandler(ValidationEventHandler handler)
            {
                _eventHandler += handler;
            }
 
            internal void RemoveHandler(ValidationEventHandler handler)
            {
                _eventHandler -= handler;
            }
        }
 
        //
        // Fields
        //
        // core text reader
        private readonly XmlReader _coreReader;
        private readonly XmlTextReaderImpl _coreReaderImpl;
        private readonly IXmlNamespaceResolver? _coreReaderNSResolver;
 
        // validation
        private ValidationType _validationType;
        private BaseValidator _validator;
 
#pragma warning disable 618
        private readonly XmlSchemaCollection _schemaCollection;
#pragma warning restore 618
        private readonly bool _processIdentityConstraints;
 
        // parsing function (state)
        private ParsingFunction _parsingFunction = ParsingFunction.Init;
 
        // event handling
        private readonly ValidationEventHandling _eventHandling;
 
        // misc
        private readonly XmlParserContext? _parserContext;
 
        // helper for Read[Element]ContentAs{Base64,BinHex} methods
        private ReadContentAsBinaryHelper? _readBinaryHelper;
 
        // Outer XmlReader exposed to the user - either XmlValidatingReader or XmlValidatingReaderImpl (when created via XmlReader.Create).
        // Virtual methods called from within XmlValidatingReaderImpl must be called on the outer reader so in case the user overrides
        // some of the XmlValidatingReader methods we will call the overridden version.
        private XmlReader _outerReader;
 
        //
        // Constructors
        //
        // Initializes a new instance of XmlValidatingReaderImpl class with the specified XmlReader.
        // This constructor is used when creating XmlValidatingReaderImpl for V1 XmlValidatingReader
        internal XmlValidatingReaderImpl(XmlReader reader)
        {
            XmlAsyncCheckReader? asyncCheckReader = reader as XmlAsyncCheckReader;
            if (asyncCheckReader != null)
            {
                reader = asyncCheckReader.CoreReader;
            }
 
            _outerReader = this;
            _coreReader = reader;
            _coreReaderNSResolver = reader as IXmlNamespaceResolver;
            _coreReaderImpl = (reader as XmlTextReaderImpl)!;
            if (_coreReaderImpl == null)
            {
                XmlTextReader? tr = reader as XmlTextReader;
                if (tr != null)
                {
                    _coreReaderImpl = tr.Impl;
                }
            }
 
            if (_coreReaderImpl == null)
            {
                throw new ArgumentException(SR.Arg_ExpectingXmlTextReader, nameof(reader));
            }
 
            _coreReaderImpl.EntityHandling = EntityHandling.ExpandEntities;
            _coreReaderImpl.XmlValidatingReaderCompatibilityMode = true;
            _processIdentityConstraints = true;
 
#pragma warning disable 618
            _schemaCollection = new XmlSchemaCollection(_coreReader.NameTable);
            _schemaCollection.XmlResolver = GetResolver();
 
            _eventHandling = new ValidationEventHandling(this);
            _coreReaderImpl.ValidationEventHandling = _eventHandling;
            _coreReaderImpl.OnDefaultAttributeUse = new XmlTextReaderImpl.OnDefaultAttributeUseDelegate(ValidateDefaultAttributeOnUse);
 
            _validationType = ValidationType.Auto;
            SetupValidation(ValidationType.Auto);
#pragma warning restore 618
        }
 
        // Initializes a new instance of XmlValidatingReaderImpl class for parsing fragments with the specified string, fragment type and parser context
        // This constructor is used when creating XmlValidatingReaderImpl for V1 XmlValidatingReader
        // SxS: This method resolves an Uri but does not expose it to the caller. It's OK to suppress the SxS warning.
        internal XmlValidatingReaderImpl(string xmlFragment, XmlNodeType fragType, XmlParserContext? context)
            : this(new XmlTextReader(xmlFragment, fragType, context))
        {
            if (_coreReader.BaseURI!.Length > 0)
            {
                _validator.BaseUri = GetResolver()!.ResolveUri(null, _coreReader.BaseURI);
            }
 
            if (context != null)
            {
                _parsingFunction = ParsingFunction.ParseDtdFromContext;
                _parserContext = context;
            }
        }
 
        // Initializes a new instance of XmlValidatingReaderImpl class for parsing fragments with the specified stream, fragment type and parser context
        // This constructor is used when creating XmlValidatingReaderImpl for V1 XmlValidatingReader
        // SxS: This method resolves an Uri but does not expose it to the caller. It's OK to suppress the SxS warning.
        internal XmlValidatingReaderImpl(Stream xmlFragment, XmlNodeType fragType, XmlParserContext? context)
            : this(new XmlTextReader(xmlFragment, fragType, context))
        {
            if (_coreReader.BaseURI!.Length > 0)
            {
                _validator.BaseUri = GetResolver()!.ResolveUri(null, _coreReader.BaseURI);
            }
 
            if (context != null)
            {
                _parsingFunction = ParsingFunction.ParseDtdFromContext;
                _parserContext = context;
            }
        }
 
        // Initializes a new instance of XmlValidatingReaderImpl class with the specified arguments.
        // This constructor is used when creating XmlValidatingReaderImpl reader via "XmlReader.Create(..)"
        internal XmlValidatingReaderImpl(XmlReader reader, ValidationEventHandler? settingsEventHandler, bool processIdentityConstraints)
        {
            XmlAsyncCheckReader? asyncCheckReader = reader as XmlAsyncCheckReader;
            if (asyncCheckReader != null)
            {
                reader = asyncCheckReader.CoreReader;
            }
 
            _outerReader = this;
            _coreReader = reader;
            _coreReaderImpl = (reader as XmlTextReaderImpl)!;
            if (_coreReaderImpl == null)
            {
                XmlTextReader? tr = reader as XmlTextReader;
                if (tr != null)
                {
                    _coreReaderImpl = tr.Impl;
                }
            }
 
            if (_coreReaderImpl == null)
            {
                throw new ArgumentException(SR.Arg_ExpectingXmlTextReader, nameof(reader));
            }
 
            _coreReaderImpl.XmlValidatingReaderCompatibilityMode = true;
            _coreReaderNSResolver = reader as IXmlNamespaceResolver;
            _processIdentityConstraints = processIdentityConstraints;
 
#pragma warning disable 618
 
            _schemaCollection = new XmlSchemaCollection(_coreReader.NameTable);
 
#pragma warning restore 618
 
            _schemaCollection.XmlResolver = GetResolver();
 
            _eventHandling = new ValidationEventHandling(this);
            if (settingsEventHandler != null)
            {
                _eventHandling.AddHandler(settingsEventHandler);
            }
            _coreReaderImpl.ValidationEventHandling = _eventHandling;
            _coreReaderImpl.OnDefaultAttributeUse = new XmlTextReaderImpl.OnDefaultAttributeUseDelegate(ValidateDefaultAttributeOnUse);
 
            _validationType = ValidationType.DTD;
            SetupValidation(ValidationType.DTD);
        }
 
        //
        // XmlReader members
        //
        // Returns the current settings of the reader
        public override XmlReaderSettings? Settings
        {
            get
            {
                XmlReaderSettings? settings;
                if (_coreReaderImpl.V1Compat)
                {
                    settings = null;
                }
                else
                {
                    settings = _coreReader.Settings;
                }
 
                if (settings != null)
                {
                    settings = settings.Clone();
                }
                else
                {
                    settings = new XmlReaderSettings();
                }
 
                settings.ValidationType = ValidationType.DTD;
                if (!_processIdentityConstraints)
                {
                    settings.ValidationFlags &= ~XmlSchemaValidationFlags.ProcessIdentityConstraints;
                }
 
                settings.ReadOnly = true;
                return settings;
            }
        }
 
        // Returns the type of the current node.
        public override XmlNodeType NodeType
        {
            get
            {
                return _coreReader.NodeType;
            }
        }
 
        // Returns the name of the current node, including prefix.
        public override string Name
        {
            get
            {
                return _coreReader.Name;
            }
        }
 
        // Returns local name of the current node (without prefix)
        public override string LocalName
        {
            get
            {
                return _coreReader.LocalName;
            }
        }
 
        // Returns namespace name of the current node.
        public override string NamespaceURI
        {
            get
            {
                return _coreReader.NamespaceURI;
            }
        }
 
        // Returns prefix associated with the current node.
        public override string Prefix
        {
            get
            {
                return _coreReader.Prefix;
            }
        }
 
        // Returns true if the current node can have Value property != string.Empty.
        public override bool HasValue
        {
            get
            {
                return _coreReader.HasValue;
            }
        }
 
        // Returns the text value of the current node.
        public override string Value
        {
            get
            {
                return _coreReader.Value;
            }
        }
 
        // Returns the depth of the current node in the XML element stack
        public override int Depth
        {
            get
            {
                return _coreReader.Depth;
            }
        }
 
        // Returns the base URI of the current node.
        public override string BaseURI
        {
            get
            {
                return _coreReader.BaseURI;
            }
        }
 
        // Returns true if the current node is an empty element (for example, <MyElement/>).
        public override bool IsEmptyElement
        {
            get
            {
                return _coreReader.IsEmptyElement;
            }
        }
 
        // Returns true of the current node is a default attribute declared in DTD.
        public override bool IsDefault
        {
            get
            {
                return _coreReader.IsDefault;
            }
        }
 
        // Returns the quote character used in the current attribute declaration
        public override char QuoteChar
        {
            get
            {
                return _coreReader.QuoteChar;
            }
        }
 
        // Returns the current xml:space scope.
        public override XmlSpace XmlSpace
        {
            get
            {
                return _coreReader.XmlSpace;
            }
        }
 
        // Returns the current xml:lang scope.</para>
        public override string XmlLang
        {
            get
            {
                return _coreReader.XmlLang;
            }
        }
 
        // Returns the current read state of the reader
        public override ReadState ReadState
        {
            get
            {
                return (_parsingFunction == ParsingFunction.Init) ? ReadState.Initial : _coreReader.ReadState;
            }
        }
 
        // Returns true if the reader reached end of the input data
        public override bool EOF
        {
            get
            {
                return _coreReader.EOF;
            }
        }
 
        // Returns the XmlNameTable associated with this XmlReader
        public override XmlNameTable NameTable
        {
            get
            {
                return _coreReader.NameTable;
            }
        }
 
        // Returns encoding of the XML document
        internal Encoding? Encoding
        {
            get
            {
                return _coreReaderImpl.Encoding;
            }
        }
 
        // Returns the number of attributes on the current node.
        public override int AttributeCount
        {
            get
            {
                return _coreReader.AttributeCount;
            }
        }
 
        // Returns value of an attribute with the specified Name
        public override string? GetAttribute(string name)
        {
            return _coreReader.GetAttribute(name);
        }
 
        // Returns value of an attribute with the specified LocalName and NamespaceURI
        public override string? GetAttribute(string localName, string? namespaceURI)
        {
            return _coreReader.GetAttribute(localName, namespaceURI);
        }
 
        // Returns value of an attribute at the specified index (position)
        public override string GetAttribute(int i)
        {
            return _coreReader.GetAttribute(i);
        }
 
        // Moves to an attribute with the specified Name
        public override bool MoveToAttribute(string name)
        {
            if (!_coreReader.MoveToAttribute(name))
            {
                return false;
            }
            _parsingFunction = ParsingFunction.Read;
            return true;
        }
 
        // Moves to an attribute with the specified LocalName and NamespceURI
        public override bool MoveToAttribute(string localName, string? namespaceURI)
        {
            if (!_coreReader.MoveToAttribute(localName, namespaceURI))
            {
                return false;
            }
            _parsingFunction = ParsingFunction.Read;
            return true;
        }
 
        // Moves to an attribute at the specified index (position)
        public override void MoveToAttribute(int i)
        {
            _coreReader.MoveToAttribute(i);
            _parsingFunction = ParsingFunction.Read;
        }
 
        // Moves to the first attribute of the current node
        public override bool MoveToFirstAttribute()
        {
            if (!_coreReader.MoveToFirstAttribute())
            {
                return false;
            }
            _parsingFunction = ParsingFunction.Read;
            return true;
        }
 
        // Moves to the next attribute of the current node
        public override bool MoveToNextAttribute()
        {
            if (!_coreReader.MoveToNextAttribute())
            {
                return false;
            }
            _parsingFunction = ParsingFunction.Read;
            return true;
        }
 
        // If on attribute, moves to the element that contains the attribute node
        public override bool MoveToElement()
        {
            if (!_coreReader.MoveToElement())
            {
                return false;
            }
            _parsingFunction = ParsingFunction.Read;
            return true;
        }
 
        // Reads and validated next node from the input data
        public override bool Read()
        {
            switch (_parsingFunction)
            {
                case ParsingFunction.Read:
                    if (_coreReader.Read())
                    {
                        ProcessCoreReaderEvent();
                        return true;
                    }
                    else
                    {
                        _validator.CompleteValidation();
                        return false;
                    }
                case ParsingFunction.ParseDtdFromContext:
                    _parsingFunction = ParsingFunction.Read;
                    ParseDtdFromParserContext();
                    goto case ParsingFunction.Read;
                case ParsingFunction.Error:
                case ParsingFunction.ReaderClosed:
                    return false;
                case ParsingFunction.Init:
                    _parsingFunction = ParsingFunction.Read; // this changes the value returned by ReadState
                    if (_coreReader.ReadState == ReadState.Interactive)
                    {
                        ProcessCoreReaderEvent();
                        return true;
                    }
                    else
                    {
                        goto case ParsingFunction.Read;
                    }
                case ParsingFunction.ResolveEntityInternally:
                    _parsingFunction = ParsingFunction.Read;
                    ResolveEntityInternally();
                    goto case ParsingFunction.Read;
                case ParsingFunction.InReadBinaryContent:
                    _parsingFunction = ParsingFunction.Read;
                    _readBinaryHelper!.Finish();
                    goto case ParsingFunction.Read;
                default:
                    Debug.Fail($"Unexpected parsing function {_parsingFunction}");
                    return false;
            }
        }
 
        // Closes the input stream ot TextReader, changes the ReadState to Closed and sets all properties to zero/string.Empty
        public override void Close()
        {
            _coreReader.Close();
            _parsingFunction = ParsingFunction.ReaderClosed;
        }
 
        // Returns NamespaceURI associated with the specified prefix in the current namespace scope.
        public override string? LookupNamespace(string prefix)
        {
            return _coreReaderImpl.LookupNamespace(prefix);
        }
 
        // Iterates through the current attribute value's text and entity references chunks.
        public override bool ReadAttributeValue()
        {
            if (_parsingFunction == ParsingFunction.InReadBinaryContent)
            {
                _parsingFunction = ParsingFunction.Read;
                _readBinaryHelper!.Finish();
            }
            if (!_coreReader.ReadAttributeValue())
            {
                return false;
            }
            _parsingFunction = ParsingFunction.Read;
            return true;
        }
 
        public override bool CanReadBinaryContent
        {
            get
            {
                return true;
            }
        }
 
        public override int ReadContentAsBase64(byte[] buffer, int index, int count)
        {
            if (ReadState != ReadState.Interactive)
            {
                return 0;
            }
 
            // init ReadChunkHelper if called the first time
            if (_parsingFunction != ParsingFunction.InReadBinaryContent)
            {
                _readBinaryHelper = ReadContentAsBinaryHelper.CreateOrReset(_readBinaryHelper, _outerReader);
            }
 
            // set parsingFunction to Read state in order to have a normal Read() behavior when called from readBinaryHelper
            _parsingFunction = ParsingFunction.Read;
 
            // call to the helper
            int readCount = _readBinaryHelper!.ReadContentAsBase64(buffer, index, count);
 
            // setup parsingFunction
            _parsingFunction = ParsingFunction.InReadBinaryContent;
            return readCount;
        }
 
        public override int ReadContentAsBinHex(byte[] buffer, int index, int count)
        {
            if (ReadState != ReadState.Interactive)
            {
                return 0;
            }
 
            // init ReadChunkHelper when called first time
            if (_parsingFunction != ParsingFunction.InReadBinaryContent)
            {
                _readBinaryHelper = ReadContentAsBinaryHelper.CreateOrReset(_readBinaryHelper, _outerReader);
            }
 
            // set parsingFunction to Read state in order to have a normal Read() behavior when called from readBinaryHelper
            _parsingFunction = ParsingFunction.Read;
 
            // call to the helper
            int readCount = _readBinaryHelper!.ReadContentAsBinHex(buffer, index, count);
 
            // setup parsingFunction
            _parsingFunction = ParsingFunction.InReadBinaryContent;
            return readCount;
        }
 
        public override int ReadElementContentAsBase64(byte[] buffer, int index, int count)
        {
            if (ReadState != ReadState.Interactive)
            {
                return 0;
            }
 
            // init ReadChunkHelper if called the first time
            if (_parsingFunction != ParsingFunction.InReadBinaryContent)
            {
                _readBinaryHelper = ReadContentAsBinaryHelper.CreateOrReset(_readBinaryHelper, _outerReader);
            }
 
            // set parsingFunction to Read state in order to have a normal Read() behavior when called from readBinaryHelper
            _parsingFunction = ParsingFunction.Read;
 
            // call to the helper
            int readCount = _readBinaryHelper!.ReadElementContentAsBase64(buffer, index, count);
 
            // setup parsingFunction
            _parsingFunction = ParsingFunction.InReadBinaryContent;
            return readCount;
        }
 
        public override int ReadElementContentAsBinHex(byte[] buffer, int index, int count)
        {
            if (ReadState != ReadState.Interactive)
            {
                return 0;
            }
 
            // init ReadChunkHelper when called first time
            if (_parsingFunction != ParsingFunction.InReadBinaryContent)
            {
                _readBinaryHelper = ReadContentAsBinaryHelper.CreateOrReset(_readBinaryHelper, _outerReader);
            }
 
            // set parsingFunction to Read state in order to have a normal Read() behavior when called from readBinaryHelper
            _parsingFunction = ParsingFunction.Read;
 
            // call to the helper
            int readCount = _readBinaryHelper!.ReadElementContentAsBinHex(buffer, index, count);
 
            // setup parsingFunction
            _parsingFunction = ParsingFunction.InReadBinaryContent;
            return readCount;
        }
 
        // Returns true if the XmlReader knows how to resolve general entities
        public override bool CanResolveEntity
        {
            get
            {
                return true;
            }
        }
 
        // Resolves the current entity reference node
        public override void ResolveEntity()
        {
            if (_parsingFunction == ParsingFunction.ResolveEntityInternally)
            {
                _parsingFunction = ParsingFunction.Read;
            }
            _coreReader.ResolveEntity();
        }
 
        internal XmlReader OuterReader
        {
            get
            {
                return _outerReader;
            }
            set
            {
#pragma warning disable 618
                Debug.Assert(value is XmlValidatingReader);
#pragma warning restore 618
                _outerReader = value;
            }
        }
 
        internal void MoveOffEntityReference()
        {
            if (_outerReader.NodeType == XmlNodeType.EntityReference && _parsingFunction != ParsingFunction.ResolveEntityInternally)
            {
                if (!_outerReader.Read())
                {
                    throw new InvalidOperationException(SR.Xml_InvalidOperation);
                }
            }
        }
 
        public override string ReadString()
        {
            MoveOffEntityReference();
            return base.ReadString();
        }
 
        //
        // IXmlLineInfo members
        //
        public bool HasLineInfo()
        {
            return true;
        }
 
        // Returns the line number of the current node
        public int LineNumber
        {
            get
            {
                return ((IXmlLineInfo)_coreReader).LineNumber;
            }
        }
 
        // Returns the line number of the current node
        public int LinePosition
        {
            get
            {
                return ((IXmlLineInfo)_coreReader).LinePosition;
            }
        }
 
        //
        // IXmlNamespaceResolver members
        //
        IDictionary<string, string> IXmlNamespaceResolver.GetNamespacesInScope(XmlNamespaceScope scope)
        {
            return this.GetNamespacesInScope(scope);
        }
 
        string? IXmlNamespaceResolver.LookupNamespace(string prefix)
        {
            return this.LookupNamespace(prefix);
        }
 
        string? IXmlNamespaceResolver.LookupPrefix(string namespaceName)
        {
            return this.LookupPrefix(namespaceName);
        }
 
        // Internal IXmlNamespaceResolver methods
        internal IDictionary<string, string> GetNamespacesInScope(XmlNamespaceScope scope)
        {
            return _coreReaderNSResolver!.GetNamespacesInScope(scope);
        }
 
        internal string? LookupPrefix(string namespaceName)
        {
            return _coreReaderNSResolver!.LookupPrefix(namespaceName);
        }
 
        //
        // XmlValidatingReader members
        //
        // Specufies the validation event handler that wil get warnings and errors related to validation
        internal event ValidationEventHandler ValidationEventHandler
        {
            add
            {
                _eventHandling.AddHandler(value);
            }
            remove
            {
                _eventHandling.RemoveHandler(value);
            }
        }
 
        // returns the schema type of the current node
        internal object? SchemaType
        {
            get
            {
                if (_validationType != ValidationType.None)
                {
                    XmlSchemaType? schemaTypeObj = _coreReaderImpl.InternalSchemaType as XmlSchemaType;
                    if (schemaTypeObj != null && schemaTypeObj.QualifiedName.Namespace == XmlReservedNs.NsXs)
                    {
                        return schemaTypeObj.Datatype;
                    }
 
                    return _coreReaderImpl.InternalSchemaType;
                }
                else
                    return null;
            }
        }
 
        // returns the underlying XmlTextReader or XmlTextReaderImpl
        internal XmlReader Reader
        {
            get
            {
                return (XmlReader)_coreReader;
            }
        }
 
        // returns the underlying XmlTextReaderImpl
        internal XmlTextReaderImpl ReaderImpl
        {
            get
            {
                return _coreReaderImpl;
            }
        }
 
        // specifies the validation type (None, DDT, XSD, XDR, Auto)
        internal ValidationType ValidationType
        {
            get
            {
                return _validationType;
            }
            set
            {
                if (ReadState != ReadState.Initial)
                {
                    throw new InvalidOperationException(SR.Xml_InvalidOperation);
                }
                _validationType = value;
                SetupValidation(value);
            }
        }
 
        // current schema collection used for validationg
#pragma warning disable 618
        internal XmlSchemaCollection Schemas
        {
            get
            {
                return _schemaCollection;
            }
        }
#pragma warning restore 618
 
        // Spefifies whether general entities should be automatically expanded or not
        internal EntityHandling EntityHandling
        {
            get
            {
                return _coreReaderImpl.EntityHandling;
            }
            set
            {
                _coreReaderImpl.EntityHandling = value;
            }
        }
 
        // Specifies XmlResolver used for opening the XML document and other external references
        internal XmlResolver XmlResolver
        {
            set
            {
                _coreReaderImpl.XmlResolver = value;
                _validator.XmlResolver = value;
                _schemaCollection.XmlResolver = value;
            }
        }
 
        // Disables or enables support of W3C XML 1.0 Namespaces
        internal bool Namespaces
        {
            get
            {
                return _coreReaderImpl.Namespaces;
            }
            set
            {
                _coreReaderImpl.Namespaces = value;
            }
        }
 
        // Returns typed value of the current node (based on the type specified by schema)
        public object? ReadTypedValue()
        {
            if (_validationType == ValidationType.None)
            {
                return null;
            }
 
            switch (_outerReader.NodeType)
            {
                case XmlNodeType.Attribute:
                    return _coreReaderImpl.InternalTypedValue;
                case XmlNodeType.Element:
                    if (SchemaType == null)
                    {
                        return null;
                    }
 
                    XmlSchemaDatatype? dtype = (SchemaType is XmlSchemaDatatype) ? (XmlSchemaDatatype)SchemaType : ((XmlSchemaType)SchemaType).Datatype;
                    if (dtype != null)
                    {
                        if (!_outerReader.IsEmptyElement)
                        {
                            while (true)
                            {
                                if (!_outerReader.Read())
                                {
                                    throw new InvalidOperationException(SR.Xml_InvalidOperation);
                                }
 
                                XmlNodeType type = _outerReader.NodeType;
                                if (type != XmlNodeType.CDATA && type != XmlNodeType.Text &&
                                    type != XmlNodeType.Whitespace && type != XmlNodeType.SignificantWhitespace &&
                                    type != XmlNodeType.Comment && type != XmlNodeType.ProcessingInstruction)
                                {
                                    break;
                                }
                            }
 
                            if (_outerReader.NodeType != XmlNodeType.EndElement)
                            {
                                throw new XmlException(SR.Xml_InvalidNodeType, _outerReader.NodeType.ToString());
                            }
                        }
                        return _coreReaderImpl.InternalTypedValue;
                    }
                    return null;
 
                case XmlNodeType.EndElement:
                    return null;
 
                default:
                    if (_coreReaderImpl.V1Compat)
                    { //If v1 XmlValidatingReader return null
                        return null;
                    }
                    else
                    {
                        return Value;
                    }
            }
        }
 
        //
        // Private implementation methods
        //
 
        private void ParseDtdFromParserContext()
        {
            Debug.Assert(_parserContext != null);
            Debug.Assert(_coreReaderImpl.DtdInfo == null);
 
            if (string.IsNullOrEmpty(_parserContext.DocTypeName))
            {
                return;
            }
 
            IDtdParser dtdParser = DtdParser.Create();
            XmlTextReaderImpl.DtdParserProxy proxy = new XmlTextReaderImpl.DtdParserProxy(_coreReaderImpl);
            IDtdInfo dtdInfo = dtdParser.ParseFreeFloatingDtd(_parserContext.BaseURI, _parserContext.DocTypeName, _parserContext.PublicId,
                                                              _parserContext.SystemId, _parserContext.InternalSubset, proxy);
            _coreReaderImpl.SetDtdInfo(dtdInfo);
 
            ValidateDtd();
        }
 
        private void ValidateDtd()
        {
            IDtdInfo? dtdInfo = _coreReaderImpl.DtdInfo;
            if (dtdInfo != null)
            {
                switch (_validationType)
                {
#pragma warning disable 618
                    case ValidationType.Auto:
                        SetupValidation(ValidationType.DTD);
                        goto case ValidationType.DTD;
#pragma warning restore 618
                    case ValidationType.DTD:
                    case ValidationType.None:
                        _validator.DtdInfo = dtdInfo;
                        break;
                }
            }
        }
 
        private void ResolveEntityInternally()
        {
            Debug.Assert(_coreReader.NodeType == XmlNodeType.EntityReference);
            int initialDepth = _coreReader.Depth;
            _outerReader.ResolveEntity();
            while (_outerReader.Read() && _coreReader.Depth > initialDepth) ;
        }
 
        // SxS: This method resolves an Uri but does not expose it to caller. It's OK to suppress the SxS warning.
        [MemberNotNull(nameof(_validator))]
        private void SetupValidation(ValidationType valType)
        {
            _validator = BaseValidator.CreateInstance(valType, this, _schemaCollection, _eventHandling, _processIdentityConstraints)!;
 
            XmlResolver? resolver = GetResolver();
            _validator.XmlResolver = resolver;
 
            if (_outerReader.BaseURI!.Length > 0)
            {
                _validator.BaseUri = (resolver == null) ? new Uri(_outerReader.BaseURI, UriKind.RelativeOrAbsolute) : resolver.ResolveUri(null, _outerReader.BaseURI);
            }
 
            _coreReaderImpl.ValidationEventHandling = (_validationType == ValidationType.None) ? null : _eventHandling;
        }
 
        private static XmlResolver? s_tempResolver;
 
        // This is needed because we can't have the setter for XmlResolver public and with internal getter.
        private XmlResolver? GetResolver()
        {
            XmlResolver? tempResolver = _coreReaderImpl.GetResolver();
 
            if (tempResolver == null && !_coreReaderImpl.IsResolverSet)
            {
                // it is safe to return valid resolver as it'll be used in the schema validation
                return s_tempResolver ??= XmlReaderSettings.GetDefaultPermissiveResolver();
            }
 
            return tempResolver;
        }
 
        //
        // Internal methods for validators, DOM, XPathDocument etc.
        //
        private void ProcessCoreReaderEvent()
        {
            switch (_coreReader.NodeType)
            {
                case XmlNodeType.Whitespace:
                    if (_coreReader.Depth > 0 || _coreReaderImpl.FragmentType != XmlNodeType.Document)
                    {
                        if (_validator.PreserveWhitespace)
                        {
                            _coreReaderImpl.ChangeCurrentNodeType(XmlNodeType.SignificantWhitespace);
                        }
                    }
                    goto default;
                case XmlNodeType.DocumentType:
                    ValidateDtd();
                    break;
                case XmlNodeType.EntityReference:
                    _parsingFunction = ParsingFunction.ResolveEntityInternally;
                    goto default;
                default:
                    _coreReaderImpl.InternalSchemaType = null;
                    _coreReaderImpl.InternalTypedValue = null;
                    _validator.Validate();
                    break;
            }
        }
 
        internal BaseValidator Validator
        {
            get
            {
                return _validator;
            }
            set
            {
                _validator = value;
            }
        }
 
        internal override XmlNamespaceManager? NamespaceManager
        {
            get
            {
                return _coreReaderImpl.NamespaceManager;
            }
        }
 
        internal bool StandAlone
        {
            get
            {
                return _coreReaderImpl.StandAlone;
            }
        }
 
        internal object? SchemaTypeObject
        {
            set
            {
                _coreReaderImpl.InternalSchemaType = value;
            }
        }
 
        internal object? TypedValueObject
        {
            get
            {
                return _coreReaderImpl.InternalTypedValue;
            }
            set
            {
                _coreReaderImpl.InternalTypedValue = value;
            }
        }
 
        internal bool AddDefaultAttribute(SchemaAttDef attdef)
        {
            return _coreReaderImpl.AddDefaultAttributeNonDtd(attdef);
        }
 
        internal override IDtdInfo? DtdInfo
        {
            get { return _coreReaderImpl.DtdInfo; }
        }
 
        internal void ValidateDefaultAttributeOnUse(IDtdDefaultAttributeInfo defaultAttribute, XmlTextReaderImpl coreReader)
        {
            SchemaAttDef? attdef = defaultAttribute as SchemaAttDef;
            if (attdef == null)
            {
                return;
            }
 
            SchemaInfo? schemaInfo = coreReader.DtdInfo as SchemaInfo;
            if (schemaInfo == null)
            {
                return;
            }
 
            DtdValidator.CheckDefaultValue(attdef, schemaInfo, _eventHandling, coreReader.BaseURI);
        }
    }
}