XmlSubtreeReader.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ 4.0 / 4.0 / untmp / DEVDIV_TFS / Dev10 / Releases / RTMRel / ndp / fx / src / Xml / System / Xml / Core / XmlSubtreeReader.cs / 1305376 / XmlSubtreeReader.cs

                            //------------------------------------------------------------------------------ 
// 
//     Copyright (c) Microsoft Corporation.  All rights reserved.
// 
// [....] 
//-----------------------------------------------------------------------------
 
using System; 
using System.Xml;
using System.Diagnostics; 
using System.Collections;
using System.Globalization;
using System.Collections.Generic;
 
namespace System.Xml {
 
    internal sealed class XmlSubtreeReader : XmlWrappingReader, IXmlLineInfo, IXmlNamespaceResolver { 
//
// Private types 
//
        class NodeData {
            internal XmlNodeType type;
            internal string localName; 
            internal string prefix;
            internal string name; 
            internal string namespaceUri; 
            internal string value;
 
            internal NodeData() {
            }

            internal void Set( XmlNodeType nodeType, string localName, string prefix, string name, string namespaceUri, string value ) { 
                this.type      = nodeType;
                this.localName = localName; 
                this.prefix    = prefix; 
                this.name      = name;
                this.namespaceUri = namespaceUri; 
                this.value     = value;
            }
        }
 
        enum State {
            Initial      = ReadState.Initial, 
            Interactive  = ReadState.Interactive, 
            Error        = ReadState.Error,
            EndOfFile    = ReadState.EndOfFile, 
            Closed       = ReadState.Closed,
            PopNamespaceScope,
            ClearNsAttributes,
            ReadElementContentAsBase64, 
            ReadElementContentAsBinHex,
            ReadContentAsBase64, 
            ReadContentAsBinHex, 
        }
 
        const int AttributeActiveStates = 0x62; // 00001100010 bin
        const int NamespaceActiveStates = 0x7E2; // 11111100010 bin

// 
// Fields
// 
        int              initialDepth; 
        State            state;
 
        // namespace management
        XmlNamespaceManager  nsManager;
        NodeData[]           nsAttributes;
        int                  nsAttrCount; 
        int                  curNsAttr = -1;
 
        string               xmlns; 
        string               xmlnsUri;
 
        // incremental reading of added xmlns nodes (ReadValueChunk, ReadContentAsBase64, ReadContentAsBinHex)
        int                  nsIncReadOffset;
        IncrementalReadDecoder binDecoder;
 
        // cached nodes
        bool                 useCurNode; 
        NodeData             curNode; 
        // node used for a text node of ReadAttributeValue or as Initial or EOF node
        NodeData             tmpNode; 

//
// Constants
// 
        internal int InitialNamespaceAttributeCount = 4;
 
// 
// Constructor
// 
        internal XmlSubtreeReader( XmlReader reader ) : base( reader ) {
            initialDepth = reader.Depth;
            state  = State.Initial;
            nsManager = new XmlNamespaceManager( reader.NameTable ); 
            xmlns = reader.NameTable.Add( "xmlns" );
            xmlnsUri = reader.NameTable.Add(XmlReservedNs.NsXmlNs); 
 
            tmpNode = new NodeData();
            tmpNode.Set( XmlNodeType.None, string.Empty, string.Empty, string.Empty, string.Empty, string.Empty ); 

            SetCurrentNode( tmpNode );
        }
 
//
// XmlReader implementation 
// 
        public override XmlNodeType NodeType {
            get { 
                return ( useCurNode ) ? curNode.type : reader.NodeType;
            }
        }
 
        public override string Name {
            get { 
                return ( useCurNode ) ? curNode.name : reader.Name; 
            }
        } 

        public override string LocalName {
            get {
                return ( useCurNode ) ? curNode.localName : reader.LocalName; 
            }
        } 
 
        public override string NamespaceURI {
            get { 
                return ( useCurNode ) ? curNode.namespaceUri : reader.NamespaceURI;
            }
        }
 
        public override string Prefix {
            get { 
                return ( useCurNode ) ? curNode.prefix : reader.Prefix; 
            }
        } 

        public override string Value {
            get {
                return ( useCurNode ) ? curNode.value : reader.Value; 
            }
        } 
 
        public override int Depth {
            get { 
                int depth = reader.Depth - initialDepth;
                if ( curNsAttr != -1 ) {
                    if ( curNode.type == XmlNodeType.Text ) { // we are on namespace attribute value
                        depth += 2; 
                    }
                    else { 
                        depth++; 
                    }
                } 
                return depth;
            }
        }
 
        public override string BaseURI {
            get { 
                return reader.BaseURI; 
            }
        } 

        public override bool IsEmptyElement {
            get {
                return reader.IsEmptyElement; 
            }
        } 
 
        public override bool EOF {
            get { 
                return state == State.EndOfFile || state == State.Closed;
            }
        }
 
        public override ReadState ReadState {
            get { 
                if ( reader.ReadState == ReadState.Error ) { 
                    return ReadState.Error;
                } 
                else {
                    if ( (int)state <= (int)State.Closed ) {
 	                    return (ReadState)(int)state;
                    } 
                    else {
                        return ReadState.Interactive; 
                    } 
                }
            } 
        }

        public override XmlNameTable NameTable {
            get { 
                return reader.NameTable;
            } 
        } 

        public override int AttributeCount { 
            get {
                return InAttributeActiveState ? reader.AttributeCount + nsAttrCount : 0;
            }
        } 

        public override string GetAttribute( string name ) { 
            if (!InAttributeActiveState) { 
                return null;
            } 
            string attr = reader.GetAttribute( name );
            if ( attr != null ) {
                return attr;
            } 
            for ( int i = 0; i < nsAttrCount; i++ ) {
                if ( name == nsAttributes[i].name ) { 
                    return nsAttributes[i].value; 
                }
            } 
            return null;
        }

        public override string GetAttribute( string name, string namespaceURI ) { 
            if (!InAttributeActiveState) {
                return null; 
            } 
            string attr = reader.GetAttribute( name, namespaceURI );
            if ( attr != null ) { 
                return attr;
            }
            for ( int i = 0; i < nsAttrCount; i++ ) {
                if ( name == nsAttributes[i].localName && namespaceURI == xmlnsUri ) { 
                    return nsAttributes[i].value;
                } 
            } 
            return null;
        } 

        public override string GetAttribute( int i ) {
            if ( !InAttributeActiveState ) {
                throw new ArgumentOutOfRangeException("i"); 
            }
            int n = reader.AttributeCount; 
            if ( i < n ) { 
                return reader.GetAttribute( i );
            } 
            else if ( i - n < nsAttrCount ) {
                return nsAttributes[i-n].value;
            }
            else { 
                throw new ArgumentOutOfRangeException( "i" );
            } 
        } 

        public override bool MoveToAttribute( string name ) { 
            if ( !InAttributeActiveState ) {
                return false;
            }
            if ( reader.MoveToAttribute( name ) ) { 
                curNsAttr = -1;
                useCurNode = false; 
                return true; 
            }
            for ( int i = 0; i < nsAttrCount; i++ ) { 
                if ( name == nsAttributes[i].name ) {
                    MoveToNsAttribute( i );
                    return true;
                } 
            }
            return false; 
        } 

        public override bool MoveToAttribute( string name, string ns ) { 
            if ( !InAttributeActiveState ) {
                return false;
            }
            if ( reader.MoveToAttribute( name, ns ) ) { 
                curNsAttr = -1;
                useCurNode = false; 
                return true; 
            }
            for ( int i = 0; i < nsAttrCount; i++ ) { 
                if ( name == nsAttributes[i].localName && ns == xmlnsUri ) {
                    MoveToNsAttribute( i );
                    return true;
                } 
            }
            return false; 
        } 

        public override void MoveToAttribute( int i ) { 
            if ( !InAttributeActiveState ) {
                throw new ArgumentOutOfRangeException("i");
            }
            int n = reader.AttributeCount; 
            if ( i < n ) {
                reader.MoveToAttribute( i ); 
                curNsAttr = -1; 
                useCurNode = false;
            } 
            else if ( i - n < nsAttrCount ) {
                MoveToNsAttribute( i - n );
            }
            else { 
                throw new ArgumentOutOfRangeException( "i" );
            } 
        } 

        public override bool MoveToFirstAttribute() { 
            if ( !InAttributeActiveState ) {
                return false;
            }
            if ( reader.MoveToFirstAttribute() ) { 
                useCurNode = false;
                return true; 
            } 
            if ( nsAttrCount > 0 ) {
                MoveToNsAttribute( 0 ); 
                return true;
            }
            return false;
        } 

        public override bool MoveToNextAttribute() { 
            if ( !InAttributeActiveState ) { 
                return false;
            } 
            if ( curNsAttr == -1 && reader.MoveToNextAttribute() ) {
                return true;
            }
            if ( curNsAttr + 1 < nsAttrCount ) { 
                MoveToNsAttribute( curNsAttr + 1 );
                return true; 
            } 
            return false;
        } 

        public override bool MoveToElement() {
            if ( !InAttributeActiveState ) {
                return false; 
            }
            curNsAttr = -1; 
            useCurNode = false; 
            return reader.MoveToElement();
        } 

        public override bool ReadAttributeValue() {
            if ( !InAttributeActiveState ) {
                return false; 
            }
            if ( curNsAttr == -1 ) { 
                return reader.ReadAttributeValue(); 
            }
            else if ( curNode.type == XmlNodeType.Text ) { // we are on namespace attribute value 
                return false;
            }
            else {
                Debug.Assert( curNode.type == XmlNodeType.Attribute ); 
                tmpNode.type = XmlNodeType.Text;
                tmpNode.value = curNode.value; 
                SetCurrentNode( tmpNode ); 
                return true;
            } 
        }

        public override bool Read() {
 
            switch ( state ) {
                case State.Initial: 
                    useCurNode = false; 
                    state = State.Interactive;
                    ProcessNamespaces(); 
                    return true;

                case State.Interactive:
                    curNsAttr = -1; 
                    useCurNode = false;
                    reader.MoveToElement(); 
                    Debug.Assert( reader.Depth >= initialDepth ); 
                    if ( reader.Depth == initialDepth ) {
                        if ( reader.NodeType == XmlNodeType.EndElement || 
                            ( reader.NodeType == XmlNodeType.Element && reader.IsEmptyElement ) ) {
                            state = State.EndOfFile;
                            SetEmptyNode();
                            return false; 
                        }
                        Debug.Assert( reader.NodeType == XmlNodeType.Element && !reader.IsEmptyElement ); 
                    } 
                    if ( reader.Read() ) {
                        ProcessNamespaces(); 
                        return true;
                    }
                    else {
                        SetEmptyNode(); 
                        return false;
                    } 
 
                case State.EndOfFile:
                case State.Closed: 
                case State.Error:
                    return false;

                case State.PopNamespaceScope: 
                    nsManager.PopScope();
                    goto case State.ClearNsAttributes; 
 
                case State.ClearNsAttributes:
                    nsAttrCount = 0; 
                    state = State.Interactive;
                    goto case State.Interactive;

                case State.ReadElementContentAsBase64: 
                case State.ReadElementContentAsBinHex:
                    if ( !FinishReadElementContentAsBinary() ) { 
                        return false; 
                    }
                    return Read(); 

                case State.ReadContentAsBase64:
                case State.ReadContentAsBinHex:
                    if ( !FinishReadContentAsBinary() ) { 
                        return false;
                    } 
                    return Read(); 

                default: 
                    Debug.Assert( false );
                    return false;
            }
        } 

        public override void Close() { 
            if ( state == State.Closed) { 
                return;
            } 
            try {
                // move the underlying reader to the next sibling
                if (state != State.EndOfFile) {
                    reader.MoveToElement(); 
                    Debug.Assert( reader.Depth >= initialDepth );
                    // move off the root of the subtree 
                    if (reader.Depth == initialDepth && reader.NodeType == XmlNodeType.Element && !reader.IsEmptyElement) { 
                        reader.Read();
                    } 
                    // move to the end of the subtree, do nothing if on empty root element
                    while (reader.Depth > initialDepth && reader.Read()) {
                        /* intentionally empty */
                    } 
                }
            } 
            catch { // never fail... 
            }
            finally { 
                curNsAttr = -1;
                useCurNode = false;
                state = State.Closed;
                SetEmptyNode(); 
            }
        } 
 
        public override void Skip() {
 
            switch ( state ) {
                case State.Initial:
                    Read();
                    return; 

                case State.Interactive: 
                    curNsAttr = -1; 
                    useCurNode = false;
                    reader.MoveToElement(); 
                    Debug.Assert( reader.Depth >= initialDepth );
                    if ( reader.Depth == initialDepth ) {
                        if ( reader.NodeType == XmlNodeType.Element && !reader.IsEmptyElement ) {
                            // we are on root of the subtree -> skip to the end element and set to Eof state 
                            if ( reader.Read() ) {
                                while ( reader.NodeType != XmlNodeType.EndElement && reader.Depth > initialDepth ) { 
                                    reader.Skip(); 
                                }
                            } 
                        }
                        Debug.Assert( reader.NodeType == XmlNodeType.EndElement ||
                                      reader.NodeType == XmlNodeType.Element && reader.IsEmptyElement ||
                                      reader.ReadState != ReadState.Interactive ); 
                        state = State.EndOfFile;
                        SetEmptyNode(); 
                        return; 
                    }
 
                    if ( reader.NodeType == XmlNodeType.Element && !reader.IsEmptyElement ) {
                        nsManager.PopScope();
                    }
                    reader.Skip(); 
                    ProcessNamespaces();
 
                    Debug.Assert( reader.Depth >= initialDepth ); 
                    return;
 
                case State.Closed:
                case State.EndOfFile:
                    return;
 
                case State.PopNamespaceScope:
                    nsManager.PopScope(); 
                    goto case State.ClearNsAttributes; 

                case State.ClearNsAttributes: 
                    nsAttrCount = 0;
                    state = State.Interactive;
                    goto case State.Interactive;
 
                case State.ReadElementContentAsBase64:
                case State.ReadElementContentAsBinHex: 
                    if ( FinishReadElementContentAsBinary() ) { 
                        Skip();
                    } 
                    break;

                case State.ReadContentAsBase64:
                case State.ReadContentAsBinHex: 
                    if ( FinishReadContentAsBinary() ) {
                        Skip(); 
                    } 
                    break;
 
                case State.Error:
                    return;

                default: 
                    Debug.Assert( false );
                    return; 
            } 
        }
 
        public override object ReadContentAsObject() {
            try {
                InitReadContentAsType( "ReadContentAsObject" );
                object value = reader.ReadContentAsObject(); 
                FinishReadContentAsType();
                return value; 
            } 
            catch {
                state = State.Error; 
                throw;
            }
        }
 
        public override bool ReadContentAsBoolean() {
            try { 
                InitReadContentAsType( "ReadContentAsBoolean" ); 
                bool value = reader.ReadContentAsBoolean();
                FinishReadContentAsType(); 
                return value;
            }
            catch {
                state = State.Error; 
                throw;
            } 
        } 

        public override DateTime ReadContentAsDateTime() { 
            try {
                InitReadContentAsType( "ReadContentAsDateTime" );
                DateTime value = reader.ReadContentAsDateTime();
                FinishReadContentAsType(); 
                return value;
            } 
            catch { 
                state = State.Error;
                throw; 
            }
        }

        public override double ReadContentAsDouble() { 
            try {
                InitReadContentAsType( "ReadContentAsDouble" ); 
                double value = reader.ReadContentAsDouble(); 
                FinishReadContentAsType();
                return value; 
            }
            catch {
                state = State.Error;
                throw; 
            }
        } 
 
        public override float ReadContentAsFloat() {
            try { 
                InitReadContentAsType( "ReadContentAsFloat" );
                float value = reader.ReadContentAsFloat();
                FinishReadContentAsType();
                return value; 
            }
            catch { 
                state = State.Error; 
                throw;
            } 
        }

        public override decimal ReadContentAsDecimal() {
            try { 
                InitReadContentAsType( "ReadContentAsDecimal" );
                decimal value = reader.ReadContentAsDecimal(); 
                FinishReadContentAsType(); 
                return value;
            } 
            catch {
                state = State.Error;
                throw;
            } 
        }
 
        public override int ReadContentAsInt() { 
            try {
                InitReadContentAsType( "ReadContentAsInt" ); 
                int value = reader.ReadContentAsInt();
                FinishReadContentAsType();
                return value;
            } 
            catch {
                state = State.Error; 
                throw; 
            }
        } 

        public override long ReadContentAsLong() {
            try {
                InitReadContentAsType( "ReadContentAsLong" ); 
                long value = reader.ReadContentAsLong();
                FinishReadContentAsType(); 
                return value; 
            }
            catch { 
                state = State.Error;
                throw;
            }
        } 

        public override string ReadContentAsString() { 
            try { 
                InitReadContentAsType( "ReadContentAsString" );
                string value = reader.ReadContentAsString(); 
                FinishReadContentAsType();
                return value;
            }
            catch { 
                state = State.Error;
                throw; 
            } 
        }
 
        public override object ReadContentAs( Type returnType, IXmlNamespaceResolver namespaceResolver ) {
            try {
                InitReadContentAsType( "ReadContentAs" );
                object value = reader.ReadContentAs( returnType, namespaceResolver ); 
                FinishReadContentAsType();
                return value; 
            } 
            catch {
                state = State.Error; 
                throw;
            }
        }
 
        public override bool CanReadBinaryContent {
            get { 
                return reader.CanReadBinaryContent; 
            }
        } 

        public override int ReadContentAsBase64( byte[] buffer, int index, int count ) {

            switch ( state ) { 
                case State.Initial:
                case State.EndOfFile: 
                case State.Closed: 
                case State.Error:
                    return 0; 

                case State.ClearNsAttributes:
                case State.PopNamespaceScope:
                    switch ( NodeType ) { 
                        case XmlNodeType.Element:
                            throw CreateReadContentAsException( "ReadContentAsBase64" ); 
                        case XmlNodeType.EndElement: 
                            return 0;
                        case XmlNodeType.Attribute: 
                            if ( curNsAttr != -1 && reader.CanReadBinaryContent ) {
                                CheckBuffer( buffer, index, count );
                                if ( count == 0 ) {
                                    return 0; 
                                }
                                if ( nsIncReadOffset == 0 ) { 
                                    // called first time on this ns attribute 
                                    if ( binDecoder != null && binDecoder is Base64Decoder ) {
                                        binDecoder.Reset(); 
                                    }
                                    else {
                                        binDecoder = new Base64Decoder();
                                    } 
                                }
                                if ( nsIncReadOffset == curNode.value.Length ) { 
                                    return 0; 
                                }
                                binDecoder.SetNextOutputBuffer( buffer, index, count ); 
                                nsIncReadOffset += binDecoder.Decode( curNode.value, nsIncReadOffset, curNode.value.Length - nsIncReadOffset );
                                return binDecoder.DecodedCount;
                            }
                            goto case XmlNodeType.Text; 
                        case XmlNodeType.Text:
                            Debug.Assert( AttributeCount > 0 ); 
                            return reader.ReadContentAsBase64( buffer, index, count ); 
                        default:
                            Debug.Assert( false ); 
                            return 0;
                    }

                case State.Interactive: 
                    state = State.ReadContentAsBase64;
                    goto case State.ReadContentAsBase64; 
 
                case State.ReadContentAsBase64:
                    int read = reader.ReadContentAsBase64( buffer, index, count ); 
                    if ( read == 0 ) {
                        state = State.Interactive;
                        ProcessNamespaces();
                    } 
                    return read;
 
                case State.ReadContentAsBinHex: 
                case State.ReadElementContentAsBase64:
                case State.ReadElementContentAsBinHex: 
                    throw new InvalidOperationException( Res.GetString( Res.Xml_MixingBinaryContentMethods ) );

                default:
                    Debug.Assert( false ); 
                    return 0;
            } 
        } 

        public override int ReadElementContentAsBase64( byte[] buffer, int index, int count ) { 

            switch (state) {
                case State.Initial:
                case State.EndOfFile: 
                case State.Closed:
                case State.Error: 
                    return 0; 

                case State.Interactive: 
                case State.PopNamespaceScope:
                case State.ClearNsAttributes:
                    if ( !InitReadElementContentAsBinary( State.ReadElementContentAsBase64 ) ) {
                        return 0; 
                    }
                    goto case State.ReadElementContentAsBase64; 
 
                case State.ReadElementContentAsBase64:
                    int read = reader.ReadContentAsBase64( buffer, index, count ); 
                    if ( read > 0 || count == 0 ) {
                        return read;
                    }
                    if ( NodeType != XmlNodeType.EndElement ) { 
                        throw new XmlException(Res.Xml_InvalidNodeType, reader.NodeType.ToString(), reader as IXmlLineInfo);
                    } 
 
                    // pop namespace scope
                    state = State.Interactive; 
                    ProcessNamespaces();

                    // set eof state or move off the end element
                    if ( reader.Depth == initialDepth ) { 
                        state = State.EndOfFile;
                        SetEmptyNode(); 
                    } 
                    else {
                        Read(); 
                    }
                    return 0;

                case State.ReadContentAsBase64: 
                case State.ReadContentAsBinHex:
                case State.ReadElementContentAsBinHex: 
                    throw new InvalidOperationException( Res.GetString( Res.Xml_MixingBinaryContentMethods ) ); 

                default: 
                    Debug.Assert( false );
                    return 0;
            }
        } 

        public override int ReadContentAsBinHex( byte[] buffer, int index, int count ) { 
 
            switch (state) {
                case State.Initial: 
                case State.EndOfFile:
                case State.Closed:
                case State.Error:
                    return 0; 

                case State.ClearNsAttributes: 
                case State.PopNamespaceScope: 
                    switch ( NodeType ) {
                        case XmlNodeType.Element: 
                            throw CreateReadContentAsException( "ReadContentAsBinHex" );
                        case XmlNodeType.EndElement:
                            return 0;
                        case XmlNodeType.Attribute: 
                            if (curNsAttr != -1 && reader.CanReadBinaryContent) {
                                CheckBuffer( buffer, index, count ); 
                                if ( count == 0 ) { 
                                    return 0;
                                } 
                                if ( nsIncReadOffset == 0 ) {
                                    // called first time on this ns attribute
                                    if ( binDecoder != null && binDecoder is BinHexDecoder ) {
                                        binDecoder.Reset(); 
                                    }
                                    else { 
                                        binDecoder = new BinHexDecoder(); 
                                    }
                                } 
                                if ( nsIncReadOffset == curNode.value.Length ) {
                                    return 0;
                                }
                                binDecoder.SetNextOutputBuffer( buffer, index, count ); 
                                nsIncReadOffset += binDecoder.Decode( curNode.value, nsIncReadOffset, curNode.value.Length - nsIncReadOffset );
                                return binDecoder.DecodedCount;                            } 
                            goto case XmlNodeType.Text; 
                        case XmlNodeType.Text:
                            Debug.Assert( AttributeCount > 0 ); 
                            return reader.ReadContentAsBinHex( buffer, index, count );
                        default:
                            Debug.Assert( false );
                            return 0; 
                    }
 
                case State.Interactive: 
                    state = State.ReadContentAsBinHex;
                    goto case State.ReadContentAsBinHex; 

                case State.ReadContentAsBinHex:
                    int read = reader.ReadContentAsBinHex( buffer, index, count );
                    if ( read == 0 ) { 
                        state = State.Interactive;
                        ProcessNamespaces(); 
                    } 
                    return read;
 
                case State.ReadContentAsBase64:
                case State.ReadElementContentAsBase64:
                case State.ReadElementContentAsBinHex:
                    throw new InvalidOperationException( Res.GetString( Res.Xml_MixingBinaryContentMethods ) ); 

                default: 
                    Debug.Assert( false ); 
                    return 0;
            } 
        }

        public override int ReadElementContentAsBinHex( byte[] buffer, int index, int count ) {
 
            switch (state) {
                case State.Initial: 
                case State.EndOfFile: 
                case State.Closed:
                case State.Error: 
                    return 0;

                case State.Interactive:
                case State.PopNamespaceScope: 
                case State.ClearNsAttributes:
                    if ( !InitReadElementContentAsBinary( State.ReadElementContentAsBinHex ) ) { 
                        return 0; 
                    }
                    goto case State.ReadElementContentAsBinHex; 
                case State.ReadElementContentAsBinHex:
                    int read = reader.ReadContentAsBinHex( buffer, index, count );
                    if ( read > 0  || count == 0 ) {
                        return read; 
                    }
                    if ( NodeType != XmlNodeType.EndElement ) { 
                        throw new XmlException(Res.Xml_InvalidNodeType, reader.NodeType.ToString(), reader as IXmlLineInfo); 
                    }
 
                    // pop namespace scope
                    state = State.Interactive;
                    ProcessNamespaces();
 
                    // set eof state or move off the end element
                    if ( reader.Depth == initialDepth ) { 
                        state = State.EndOfFile; 
                        SetEmptyNode();
                    } 
                    else {
                        Read();
                    }
                    return 0; 

                case State.ReadContentAsBase64: 
                case State.ReadContentAsBinHex: 
                case State.ReadElementContentAsBase64:
                    throw new InvalidOperationException( Res.GetString( Res.Xml_MixingBinaryContentMethods ) ); 

                default:
                    Debug.Assert( false );
                    return 0; 
            }
        } 
 
        public override bool CanReadValueChunk {
            get { 
                return reader.CanReadValueChunk;
            }
        }
 
        public override int ReadValueChunk( char[] buffer, int index, int count ) {
 
            switch (state) { 
                case State.Initial:
                case State.EndOfFile: 
                case State.Closed:
                case State.Error:
                    return 0;
 
                case State.ClearNsAttributes:
                case State.PopNamespaceScope: 
                    // ReadValueChunk implementation on added xmlns attributes 
                    if (curNsAttr != -1 && reader.CanReadValueChunk) {
                        CheckBuffer( buffer, index, count ); 
                        int copyCount = curNode.value.Length - nsIncReadOffset;
                        if ( copyCount > count ) {
                            copyCount = count;
                        } 
                        if ( copyCount > 0 ) {
                            curNode.value.CopyTo( nsIncReadOffset, buffer, index, copyCount ); 
                        } 
                        nsIncReadOffset += copyCount;
                        return copyCount; 
                    }
                    // Otherwise fall back to the case State.Interactive.
                    // No need to clean ns attributes or pop scope because the reader when ReadValueChunk is called
                    // - on Element errors 
                    // - on EndElement errors
                    // - on Attribute does not move 
                    // and that's all where State.ClearNsAttributes or State.PopnamespaceScope can be set 
                    goto case State.Interactive;
 
                case State.Interactive:
                    return reader.ReadValueChunk( buffer, index, count );

                case State.ReadElementContentAsBase64: 
                case State.ReadElementContentAsBinHex:
                case State.ReadContentAsBase64: 
                case State.ReadContentAsBinHex: 
                    throw new InvalidOperationException( Res.GetString( Res.Xml_MixingReadValueChunkWithBinary ) );
 
                default:
                    Debug.Assert( false );
                    return 0;
            } 
        }
 
        public override string LookupNamespace(string prefix) { 
            return ((IXmlNamespaceResolver)this).LookupNamespace(prefix);
        } 


//
// IDisposable interface 
//
        protected override void Dispose( bool disposing ) { 
            // note: we do not want to dispose the underlying reader 
            this.Close();
        } 

//
// IXmlLineInfo implementation
// 
        int IXmlLineInfo.LineNumber {
            get { 
                if ( !useCurNode ) { 
                    IXmlLineInfo lineInfo = reader as IXmlLineInfo;
                    if ( lineInfo != null ) { 
                        return lineInfo.LineNumber;
                    }
                }
                return 0; 
            }
        } 
 
        int IXmlLineInfo.LinePosition {
            get { 
                if ( !useCurNode ) {
                    IXmlLineInfo lineInfo = reader as IXmlLineInfo;
                    if ( lineInfo != null ) {
                        return lineInfo.LinePosition; 
                    }
                } 
                return 0; 
            }
        } 

        bool IXmlLineInfo.HasLineInfo() {
            return reader is IXmlLineInfo;
        } 

// 
// IXmlNamespaceResolver implementation 
//
        IDictionary IXmlNamespaceResolver.GetNamespacesInScope( XmlNamespaceScope scope ) { 
            if (!InNamespaceActiveState) {
                return new Dictionary();
            }
            return nsManager.GetNamespacesInScope(scope); 
        }
 
        string IXmlNamespaceResolver.LookupNamespace( string prefix ) { 
            if (!InNamespaceActiveState) {
                return null; 
            }
            return nsManager.LookupNamespace(prefix);
        }
 
        string IXmlNamespaceResolver.LookupPrefix( string namespaceName ) {
            if (!InNamespaceActiveState) { 
                return null; 
            }
            return nsManager.LookupPrefix(namespaceName); 
        }

//
// Private methods 
//
        private void ProcessNamespaces() { 
            switch ( reader.NodeType ) { 
                case XmlNodeType.Element:
                    nsManager.PushScope(); 

                    string prefix = reader.Prefix;
                    string ns = reader.NamespaceURI;
                    if ( nsManager.LookupNamespace( prefix ) != ns ) { 
                        AddNamespace( prefix, ns );
                    } 
 
                    if ( reader.MoveToFirstAttribute() ) {
                        do { 
                            prefix = reader.Prefix;
                            ns = reader.NamespaceURI;

                            if ( Ref.Equal( ns, xmlnsUri ) ) { 
                                if ( prefix.Length == 0 ) {
                                    nsManager.AddNamespace( string.Empty, reader.Value ); 
                                    RemoveNamespace( string.Empty, xmlns ); 
                                }
                                else { 
                                    prefix = reader.LocalName;
                                    nsManager.AddNamespace( prefix, reader.Value );
                                    RemoveNamespace( xmlns, prefix );
                                } 
                            }
                            else if ( prefix.Length != 0 && nsManager.LookupNamespace( prefix ) != ns ) { 
                                AddNamespace( prefix, ns ); 
                            }
                        } while ( reader.MoveToNextAttribute() ); 
                        reader.MoveToElement();
                    }

                    if ( reader.IsEmptyElement ) { 
                        state = State.PopNamespaceScope;
                    } 
                    break; 
                case XmlNodeType.EndElement:
                    state = State.PopNamespaceScope; 
                    break;
            }
        }
 
        private void AddNamespace( string prefix, string ns ) {
            nsManager.AddNamespace( prefix, ns ); 
 
            int index = nsAttrCount++;
            if ( nsAttributes == null ) { 
                nsAttributes = new NodeData[InitialNamespaceAttributeCount];
            }
            if ( index == nsAttributes.Length ) {
                NodeData[] newNsAttrs = new NodeData[nsAttributes.Length * 2]; 
                Array.Copy( nsAttributes, 0, newNsAttrs, 0, index );
                nsAttributes = newNsAttrs; 
            } 

            if ( nsAttributes[index] == null ) { 
                nsAttributes[index] = new NodeData();
            }
            if ( prefix.Length == 0 ) {
                nsAttributes[index].Set( XmlNodeType.Attribute, xmlns, string.Empty, xmlns, xmlnsUri, ns ); 
            }
            else { 
                nsAttributes[index].Set( XmlNodeType.Attribute, prefix, xmlns, reader.NameTable.Add( string.Concat( xmlns, ":", prefix ) ), xmlnsUri, ns ); 
            }
 
            Debug.Assert( state == State.ClearNsAttributes || state == State.Interactive || state == State.PopNamespaceScope );
            state = State.ClearNsAttributes;

            curNsAttr = -1; 
        }
 
        private void RemoveNamespace( string prefix, string localName ) { 
            for ( int i = 0; i < nsAttrCount; i++ ) {
                if ( Ref.Equal( prefix, nsAttributes[i].prefix ) && 
                     Ref.Equal( localName, nsAttributes[i].localName ) ) {
                         if ( i < nsAttrCount - 1 ) {
                             // swap
                             NodeData tmpNodeData = nsAttributes[i]; 
                             nsAttributes[i] = nsAttributes[nsAttrCount - 1];
                             nsAttributes[nsAttrCount - 1] = tmpNodeData; 
                         } 
                         nsAttrCount--;
                         break; 
                 }
            }
        }
 
        private void MoveToNsAttribute( int index ) {
            Debug.Assert( index >= 0 && index <= nsAttrCount ); 
            reader.MoveToElement(); 
            curNsAttr = index;
            nsIncReadOffset = 0; 
            SetCurrentNode( nsAttributes[index] );
        }

        private bool InitReadElementContentAsBinary( State binaryState ) { 
            if ( NodeType != XmlNodeType.Element ) {
                throw reader.CreateReadElementContentAsException( "ReadElementContentAsBase64" ); 
            } 

            bool isEmpty = IsEmptyElement; 

            // move to content or off the empty element
            if ( !Read() || isEmpty ) {
                return false; 
            }
            // special-case child element and end element 
            switch ( NodeType ) { 
                case XmlNodeType.Element:
                    throw new XmlException(Res.Xml_InvalidNodeType, reader.NodeType.ToString(), reader as IXmlLineInfo); 
                case XmlNodeType.EndElement:
                    // pop scope & move off end element
                    ProcessNamespaces();
                    Read(); 
                    return false;
            } 
 
            Debug.Assert( state == State.Interactive );
            state = binaryState; 
            return true;
        }

        private bool FinishReadElementContentAsBinary() { 
            Debug.Assert( state == State.ReadElementContentAsBase64 || state == State.ReadElementContentAsBinHex );
 
            byte[] bytes = new byte[256]; 
            if ( state == State.ReadElementContentAsBase64 ) {
                while ( reader.ReadContentAsBase64( bytes, 0, 256 ) > 0 ) ; 
            }
            else {
                while ( reader.ReadContentAsBinHex( bytes, 0, 256 ) > 0 ) ;
            } 

            if ( NodeType != XmlNodeType.EndElement ) { 
                throw new XmlException(Res.Xml_InvalidNodeType, reader.NodeType.ToString(), reader as IXmlLineInfo); 
            }
 
            // pop namespace scope
            state = State.Interactive;
            ProcessNamespaces();
 
            // check eof
            if ( reader.Depth == initialDepth ) { 
                 state = State.EndOfFile; 
                 SetEmptyNode();
                 return false; 
            }
            // move off end element
            return Read();
        } 

        private bool FinishReadContentAsBinary() { 
            Debug.Assert( state == State.ReadContentAsBase64 || state == State.ReadContentAsBinHex ); 

            byte[] bytes = new byte[256]; 
            if ( state == State.ReadContentAsBase64 ) {
                while ( reader.ReadContentAsBase64( bytes, 0, 256 ) > 0 ) ;
            }
            else { 
                while ( reader.ReadContentAsBinHex( bytes, 0, 256 ) > 0 ) ;
            } 
 
            state = State.Interactive;
            ProcessNamespaces(); 

            // check eof
            if ( reader.Depth == initialDepth ) {
                 state = State.EndOfFile; 
                 SetEmptyNode();
                 return false; 
            } 
            return true;
        } 

        private bool InAttributeActiveState {
            get {
#if DEBUG 
                Debug.Assert( 0 == ( AttributeActiveStates & ( 1 << (int)State.Initial ) ) );
                Debug.Assert( 0 != ( AttributeActiveStates & ( 1 << (int)State.Interactive ) ) ); 
                Debug.Assert( 0 == ( AttributeActiveStates & ( 1 << (int)State.Error ) ) ); 
                Debug.Assert( 0 == ( AttributeActiveStates & ( 1 << (int)State.EndOfFile ) ) );
                Debug.Assert( 0 == ( AttributeActiveStates & ( 1 << (int)State.Closed ) ) ); 
                Debug.Assert( 0 != ( AttributeActiveStates & ( 1 << (int)State.PopNamespaceScope ) ) );
                Debug.Assert( 0 != ( AttributeActiveStates & ( 1 << (int)State.ClearNsAttributes ) ) );
                Debug.Assert( 0 == ( AttributeActiveStates & ( 1 << (int)State.ReadElementContentAsBase64 ) ) );
                Debug.Assert( 0 == ( AttributeActiveStates & ( 1 << (int)State.ReadElementContentAsBinHex ) ) ); 
                Debug.Assert( 0 == ( AttributeActiveStates & ( 1 << (int)State.ReadContentAsBase64 ) ) );
                Debug.Assert( 0 == ( AttributeActiveStates & ( 1 << (int)State.ReadContentAsBinHex ) ) ); 
#endif 
                return 0 != ( AttributeActiveStates & ( 1 << (int)state ) );
            } 
        }

        private bool InNamespaceActiveState {
            get { 
#if DEBUG
                Debug.Assert( 0 == ( NamespaceActiveStates & ( 1 << (int)State.Initial ) ) ); 
                Debug.Assert( 0 != ( NamespaceActiveStates & ( 1 << (int)State.Interactive ) ) ); 
                Debug.Assert( 0 == ( NamespaceActiveStates & ( 1 << (int)State.Error ) ) );
                Debug.Assert( 0 == ( NamespaceActiveStates & ( 1 << (int)State.EndOfFile ) ) ); 
                Debug.Assert( 0 == ( NamespaceActiveStates & ( 1 << (int)State.Closed ) ) );
                Debug.Assert( 0 != ( NamespaceActiveStates & ( 1 << (int)State.PopNamespaceScope ) ) );
                Debug.Assert( 0 != ( NamespaceActiveStates & ( 1 << (int)State.ClearNsAttributes ) ) );
                Debug.Assert( 0 != ( NamespaceActiveStates & ( 1 << (int)State.ReadElementContentAsBase64 ) ) ); 
                Debug.Assert( 0 != ( NamespaceActiveStates & ( 1 << (int)State.ReadElementContentAsBinHex ) ) );
                Debug.Assert( 0 != ( NamespaceActiveStates & ( 1 << (int)State.ReadContentAsBase64 ) ) ); 
                Debug.Assert( 0 != ( NamespaceActiveStates & ( 1 << (int)State.ReadContentAsBinHex ) ) ); 
#endif
                return 0 != ( NamespaceActiveStates & ( 1 << (int)state ) ); 
            }
        }

        void SetEmptyNode() { 
            Debug.Assert( tmpNode.localName == string.Empty && tmpNode.prefix == string.Empty && tmpNode.name == string.Empty && tmpNode.namespaceUri == string.Empty );
            tmpNode.type = XmlNodeType.None; 
            tmpNode.value = string.Empty; 

            curNode = tmpNode; 
            useCurNode = true;
        }

        void SetCurrentNode( NodeData node ) { 
            curNode = node;
            useCurNode = true; 
        } 

        void InitReadContentAsType( string methodName ) { 
            switch ( state ) {
                case State.Initial:
                case State.EndOfFile:
                case State.Closed: 
                case State.Error:
                    throw new InvalidOperationException( Res.GetString( Res.Xml_ClosedOrErrorReader ) ); 
 
                case State.Interactive:
                    return; 

                case State.PopNamespaceScope:
                case State.ClearNsAttributes:
                    // no need to clean ns attributes or pop scope because the reader when ReadContentAs is called 
                    // - on Element errors
                    // - on Attribute does not move 
                    // - on EndElement does not move 
                    // and that's all where State.ClearNsAttributes or State.PopNamespacScope can be set
                    return; 

                case State.ReadElementContentAsBase64:
                case State.ReadElementContentAsBinHex:
                case State.ReadContentAsBase64: 
                case State.ReadContentAsBinHex:
                    throw new InvalidOperationException( Res.GetString( Res.Xml_MixingReadValueChunkWithBinary ) ); 
 
                default:
                    Debug.Assert( false ); 
                    break;
            }
            throw CreateReadContentAsException( methodName );
        } 

        void FinishReadContentAsType() { 
            Debug.Assert( state == State.Interactive || 
                          state == State.PopNamespaceScope ||
                          state == State.ClearNsAttributes ); 

            switch ( NodeType ) {
                case XmlNodeType.Element:
                    // new element we moved to - process namespaces 
                    ProcessNamespaces();
                    break; 
                case XmlNodeType.EndElement: 
                    // end element we've stayed on or have been moved to
                    state = State.PopNamespaceScope; 
                    break;
                case XmlNodeType.Attribute:
                    // stayed on attribute, do nothing
                    break; 
            }
        } 
 
        void CheckBuffer( Array buffer, int index, int count ) {
            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" );
            }
        }
    } 
}

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.


                        

Link Menu

Network programming in C#, Network Programming in VB.NET, Network Programming in .NET
This book is available now!
Buy at Amazon US or
Buy at Amazon UK