Code:
/ 4.0 / 4.0 / 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 // IDictionaryIXmlNamespaceResolver.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. //------------------------------------------------------------------------------ // // 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 // IDictionaryIXmlNamespaceResolver.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
This book is available now!
Buy at Amazon US or
Buy at Amazon UK
- EllipseGeometry.cs
- CompilerParameters.cs
- Operator.cs
- FrameworkElementFactory.cs
- XmlSchemaSearchPattern.cs
- DatatypeImplementation.cs
- TextContainerHelper.cs
- XmlSchemaObject.cs
- TypeSystemProvider.cs
- ReadOnlyCollectionBase.cs
- NameValuePair.cs
- TextModifierScope.cs
- SmiMetaDataProperty.cs
- ExceptionRoutedEventArgs.cs
- ErrorLog.cs
- NumberFunctions.cs
- HasCopySemanticsAttribute.cs
- WpfKnownType.cs
- AnnotationResourceCollection.cs
- WebConfigurationManager.cs
- URLAttribute.cs
- ProfilePropertySettingsCollection.cs
- BindingsCollection.cs
- MenuCommand.cs
- MouseButtonEventArgs.cs
- SoapAttributeAttribute.cs
- safesecurityhelperavalon.cs
- RelationshipFixer.cs
- GridToolTip.cs
- InfoCardMasterKey.cs
- BindingsSection.cs
- RIPEMD160.cs
- ComboBoxItem.cs
- DoubleStorage.cs
- DrawToolTipEventArgs.cs
- DataDocumentXPathNavigator.cs
- ModelFactory.cs
- ReachPageContentSerializerAsync.cs
- XmlSchemaAttribute.cs
- DataGridViewButtonCell.cs
- PrintControllerWithStatusDialog.cs
- ApplicationGesture.cs
- ReadWriteObjectLock.cs
- EditorPartChrome.cs
- SaveFileDialog.cs
- HMACSHA512.cs
- SpellerInterop.cs
- InkCanvasSelection.cs
- TimerTable.cs
- VisemeEventArgs.cs
- ScrollChrome.cs
- GraphicsState.cs
- ZipPackagePart.cs
- ImageList.cs
- SelectorItemAutomationPeer.cs
- XmlNotation.cs
- CacheOutputQuery.cs
- SimpleMailWebEventProvider.cs
- CompositeFontInfo.cs
- AspNetSynchronizationContext.cs
- IIS7WorkerRequest.cs
- PropertyEmitter.cs
- FilterException.cs
- LinqExpressionNormalizer.cs
- ContainerParaClient.cs
- SubqueryRules.cs
- XmlQualifiedName.cs
- XPathBinder.cs
- OrderedDictionary.cs
- TemplateBindingExpression.cs
- DataServiceQueryOfT.cs
- MembershipValidatePasswordEventArgs.cs
- Environment.cs
- SpnEndpointIdentityExtension.cs
- BrowserDefinitionCollection.cs
- MailMessage.cs
- ResourceDescriptionAttribute.cs
- precedingsibling.cs
- ObjectComplexPropertyMapping.cs
- PersonalizationEntry.cs
- EmptyCollection.cs
- OdbcPermission.cs
- InstalledFontCollection.cs
- ExplicitDiscriminatorMap.cs
- HtmlSelect.cs
- DefaultBindingPropertyAttribute.cs
- Propagator.Evaluator.cs
- HttpPostLocalhostServerProtocol.cs
- ImportedNamespaceContextItem.cs
- IChannel.cs
- DataGridViewCellCollection.cs
- ResourcePermissionBaseEntry.cs
- TypeForwardedToAttribute.cs
- TableCell.cs
- FontNamesConverter.cs
- CookieHandler.cs
- CommandConverter.cs
- WindowsFormsLinkLabel.cs
- ToolBarTray.cs
- ServicePerformanceCounters.cs