File: System\Xml\Core\XmlCharCheckingReaderAsync.cs
Project: ndp\fx\src\Xml\System.Xml.csproj (System.Xml)

using System;
using System.Xml;
using System.Diagnostics;
using System.Collections;
using System.Collections.Generic;
 
using System.Threading.Tasks;
 
namespace System.Xml {
 
    //
    // XmlCharCheckingReaderWithNS
    //
    internal partial class XmlCharCheckingReader : XmlWrappingReader {
 
        public override async Task< bool > ReadAsync() {
            switch ( state ) {
                case State.Initial:
                    state = State.Interactive;
                    if ( base.reader.ReadState == ReadState.Initial ) {
                        goto case State.Interactive;
                    }
                    break;
 
                case State.Error:
                    return false;
 
                case State.InReadBinary:
                    await FinishReadBinaryAsync().ConfigureAwait(false);
                    state = State.Interactive;
                    goto case State.Interactive;
 
                case State.Interactive:
                    if ( !await base.reader.ReadAsync().ConfigureAwait(false) ) {
                        return false;
                    }
                    break;
 
                default:
                    Debug.Assert( false );
                    return false;
            }
 
            XmlNodeType nodeType = base.reader.NodeType;
 
            if ( !checkCharacters ) {
                switch ( nodeType ) {
                    case XmlNodeType.Comment:
                        if ( ignoreComments ) {
                            return await ReadAsync().ConfigureAwait(false);
                        }
                        break;
                    case XmlNodeType.Whitespace:
                        if ( ignoreWhitespace ) {
                            return await ReadAsync().ConfigureAwait(false);
                        }
                        break;
                    case XmlNodeType.ProcessingInstruction:
                        if ( ignorePis ) {
                            return await ReadAsync().ConfigureAwait(false);
                        }
                        break;
                    case XmlNodeType.DocumentType:
                        if ( dtdProcessing == DtdProcessing.Prohibit ) {
                            Throw( Res.Xml_DtdIsProhibitedEx, string.Empty );
                        }
                        else if ( dtdProcessing == DtdProcessing.Ignore ) {
                            return await ReadAsync().ConfigureAwait(false);
                        }
                        break;
                }
                return true;
            }
            else {
                switch ( nodeType ) {
                    case XmlNodeType.Element:
                        if ( checkCharacters ) {
                            // check element name
                            ValidateQName( base.reader.Prefix, base.reader.LocalName );
 
                            // check values of attributes
                            if ( base.reader.MoveToFirstAttribute() ) {
                                do {
                                    ValidateQName( base.reader.Prefix, base.reader.LocalName );
                                    CheckCharacters( base.reader.Value );
                                } while ( base.reader.MoveToNextAttribute() );
 
                                base.reader.MoveToElement();
                            }
                        }
                        break;
 
                    case XmlNodeType.Text:
                    case XmlNodeType.CDATA:
                        if ( checkCharacters ) {
                            CheckCharacters( await base.reader.GetValueAsync().ConfigureAwait(false) );
                        }
                        break;
 
                    case XmlNodeType.EntityReference:
                        if ( checkCharacters ) {
                            // check name
                            ValidateQName( base.reader.Name );
                        }
                        break;
 
                    case XmlNodeType.ProcessingInstruction:
                        if ( ignorePis ) {
                            return await ReadAsync().ConfigureAwait(false);
                        }
                        if ( checkCharacters ) {
                            ValidateQName( base.reader.Name );
                            CheckCharacters( base.reader.Value );
                        }
                        break;
 
                    case XmlNodeType.Comment:
                        if ( ignoreComments ) {
                            return await ReadAsync().ConfigureAwait(false);
                        }
                        if ( checkCharacters ) {
                            CheckCharacters( base.reader.Value );
                        }
                        break;
 
                    case XmlNodeType.DocumentType:
                        if ( dtdProcessing == DtdProcessing.Prohibit ) {
                            Throw( Res.Xml_DtdIsProhibitedEx, string.Empty );
                        }
                        else if ( dtdProcessing == DtdProcessing.Ignore ) {
                            return await ReadAsync().ConfigureAwait(false);
                        }
                        if ( checkCharacters ) {
                            ValidateQName( base.reader.Name );
                            CheckCharacters( base.reader.Value );
                            
                            string str;
                            str = base.reader.GetAttribute( "SYSTEM" );
                            if ( str != null ) {
                                CheckCharacters( str );
                            }
 
                            str = base.reader.GetAttribute( "PUBLIC" );
                            if ( str != null ) {
                                int i;
                                if ( ( i = xmlCharType.IsPublicId( str ) ) >= 0 ) {
                                    Throw( Res.Xml_InvalidCharacter, XmlException.BuildCharExceptionArgs( str, i ) );
                                }
                            }
                        }
                        break;
 
                    case XmlNodeType.Whitespace:
                        if ( ignoreWhitespace ) {
                            return await ReadAsync().ConfigureAwait(false);
                        }
                        if ( checkCharacters ) {
                            CheckWhitespace( await base.reader.GetValueAsync().ConfigureAwait(false) );
                        }
                        break;
 
                    case XmlNodeType.SignificantWhitespace:
                        if ( checkCharacters ) {
                            CheckWhitespace( await base.reader.GetValueAsync().ConfigureAwait(false) );
                        }
                        break;
 
                    case XmlNodeType.EndElement:
                        if ( checkCharacters ) {
                            ValidateQName( base.reader.Prefix, base.reader.LocalName );
                        }
                        break;
 
                    default:
                        break;
                }
                lastNodeType = nodeType;
                return true;
            }
        }
 
        public override async Task< int > ReadContentAsBase64Async( byte[] buffer, int index, int count ) {
            if (ReadState != ReadState.Interactive) {
                return 0;
            }
 
            if ( state != State.InReadBinary ) {
                // forward ReadBase64Chunk calls into the base (wrapped) reader if possible, i.e. if it can read binary and we 
                // should not check characters
                if ( base.CanReadBinaryContent && ( !checkCharacters ) ) {
                    readBinaryHelper = null;
                    state = State.InReadBinary;
                    return await base.ReadContentAsBase64Async( buffer, index, count ).ConfigureAwait(false);
                }
                // the wrapped reader cannot read chunks or we are on an element where we should check characters or ignore white spaces
                else {
                    readBinaryHelper = ReadContentAsBinaryHelper.CreateOrReset( readBinaryHelper, this );
                }
            }
            else { 
                // forward calls into wrapped reader 
                if ( readBinaryHelper == null ) {
                    return await base.ReadContentAsBase64Async( buffer, index, count ).ConfigureAwait(false);
                }
            }
 
            // turn off InReadBinary state in order to have a normal Read() behavior when called from readBinaryHelper
            state = State.Interactive;
 
            // call to the helper
            int readCount = await readBinaryHelper.ReadContentAsBase64Async(buffer, index, count).ConfigureAwait(false);
 
            // turn on InReadBinary in again and return
            state = State.InReadBinary;
            return readCount;
        }
 
        public override async Task< int > ReadContentAsBinHexAsync( byte[] buffer, int index, int count ) {
            if (ReadState != ReadState.Interactive) {
                return 0;
            }
 
            if ( state != State.InReadBinary ) {
                // forward ReadBinHexChunk calls into the base (wrapped) reader if possible, i.e. if it can read chunks and we 
                // should not check characters
                if ( base.CanReadBinaryContent && ( !checkCharacters ) ) {
                    readBinaryHelper = null;
                    state = State.InReadBinary;
                    return await base.ReadContentAsBinHexAsync( buffer, index, count ).ConfigureAwait(false);
                }
                // the wrapped reader cannot read chunks or we are on an element where we should check characters or ignore white spaces
                else {
                    readBinaryHelper = ReadContentAsBinaryHelper.CreateOrReset( readBinaryHelper, this );
                }
            }
            else { 
                // forward calls into wrapped reader 
                if ( readBinaryHelper == null ) {
                    return await base.ReadContentAsBinHexAsync( buffer, index, count ).ConfigureAwait(false);
                }
            }
 
            // turn off InReadBinary state in order to have a normal Read() behavior when called from readBinaryHelper
            state = State.Interactive;
 
            // call to the helper
            int readCount = await readBinaryHelper.ReadContentAsBinHexAsync(buffer, index, count).ConfigureAwait(false);
 
            // turn on InReadBinary in again and return
            state = State.InReadBinary;
            return readCount;        
        }
 
        public override async Task< int > ReadElementContentAsBase64Async( byte[] buffer, int index, int count ) {
            // check arguments
            if (buffer == null) {
                throw new ArgumentNullException("buffer");
            }
            if (count < 0) {
                throw new ArgumentOutOfRangeException("count");
            }
            if (index < 0) {
                throw new ArgumentOutOfRangeException("index");
            }
            if (buffer.Length - index < count) {
                throw new ArgumentOutOfRangeException("count");
            }
 
            if (ReadState != ReadState.Interactive) {
                return 0;
            }
 
            if ( state != State.InReadBinary ) {
                // forward ReadBase64Chunk calls into the base (wrapped) reader if possible, i.e. if it can read binary and we 
                // should not check characters
                if ( base.CanReadBinaryContent && ( !checkCharacters ) ) {
                    readBinaryHelper = null;
                    state = State.InReadBinary;
                    return await base.ReadElementContentAsBase64Async( buffer, index, count ).ConfigureAwait(false);
                }
                // the wrapped reader cannot read chunks or we are on an element where we should check characters or ignore white spaces
                else {
                    readBinaryHelper = ReadContentAsBinaryHelper.CreateOrReset( readBinaryHelper, this );
                }
            }
            else { 
                // forward calls into wrapped reader 
                if ( readBinaryHelper == null ) {
                    return await base.ReadElementContentAsBase64Async( buffer, index, count ).ConfigureAwait(false);
                }
            }
 
            // turn off InReadBinary state in order to have a normal Read() behavior when called from readBinaryHelper
            state = State.Interactive;
 
            // call to the helper
            int readCount = await readBinaryHelper.ReadElementContentAsBase64Async(buffer, index, count).ConfigureAwait(false);
 
            // turn on InReadBinary in again and return
            state = State.InReadBinary;
            return readCount;
        }
 
        public override async Task< int > ReadElementContentAsBinHexAsync( byte[] buffer, int index, int count ) {
            // check arguments
            if (buffer == null) {
                throw new ArgumentNullException("buffer");
            }
            if (count < 0) {
                throw new ArgumentOutOfRangeException("count");
            }
            if (index < 0) {
                throw new ArgumentOutOfRangeException("index");
            }
            if (buffer.Length - index < count) {
                throw new ArgumentOutOfRangeException("count");
            }
            if (ReadState != ReadState.Interactive) {
                return 0;
            }
 
            if ( state != State.InReadBinary ) {
                // forward ReadBinHexChunk calls into the base (wrapped) reader if possible, i.e. if it can read chunks and we 
                // should not check characters
                if ( base.CanReadBinaryContent && ( !checkCharacters ) ) {
                    readBinaryHelper = null;
                    state = State.InReadBinary;
                    return await base.ReadElementContentAsBinHexAsync( buffer, index, count ).ConfigureAwait(false);
                }
                // the wrapped reader cannot read chunks or we are on an element where we should check characters or ignore white spaces
                else {
                    readBinaryHelper = ReadContentAsBinaryHelper.CreateOrReset( readBinaryHelper, this );
                }
            }
            else { 
                // forward calls into wrapped reader 
                if ( readBinaryHelper == null ) {
                    return await base.ReadElementContentAsBinHexAsync( buffer, index, count ).ConfigureAwait(false);
                }
            }
 
            // turn off InReadBinary state in order to have a normal Read() behavior when called from readBinaryHelper
            state = State.Interactive;
 
            // call to the helper
            int readCount = await readBinaryHelper.ReadElementContentAsBinHexAsync(buffer, index, count).ConfigureAwait(false);
 
            // turn on InReadBinary in again and return
            state = State.InReadBinary;
            return readCount;        
        }
 
        private async Task FinishReadBinaryAsync() {
            state = State.Interactive;
            if ( readBinaryHelper != null ) {
                await readBinaryHelper.FinishAsync().ConfigureAwait(false);
            }
        }
 
    }
}