Updates referencesource to .NET 4.7
[mono.git] / mcs / class / referencesource / System.Xml / System / Xml / XPath / XPathNavigatorReader.cs
1 //------------------------------------------------------------------------------
2 // <copyright file="XmlNavigatorReader.cs" company="Microsoft">
3 //     Copyright (c) Microsoft Corporation.  All rights reserved.
4 // </copyright>
5 // <owner current="true" primary="true">Microsoft</owner>
6 //------------------------------------------------------------------------------
7
8 using System.IO;
9 using System.Xml.Schema;
10 using System.Collections;
11 using System.Diagnostics;
12 using System.Collections.Generic;
13
14
15 namespace System.Xml.XPath {
16
17     /// <summary>
18     /// Reader that traverses the subtree rooted at the current position of the specified navigator.
19     /// </summary>
20     internal class XPathNavigatorReader : XmlReader, IXmlNamespaceResolver {
21         enum State {
22             Initial,
23             Content,
24             EndElement,
25             Attribute,
26             AttrVal,
27             InReadBinary,
28             EOF,
29             Closed,
30             Error,
31         }
32
33         private XPathNavigator nav;
34         private XPathNavigator navToRead;
35         private int depth;
36         private State state;
37         private XmlNodeType nodeType;
38         private int attrCount;
39         private bool readEntireDocument;
40
41         protected IXmlLineInfo lineInfo;
42         protected IXmlSchemaInfo schemaInfo;
43
44         private ReadContentAsBinaryHelper   readBinaryHelper;
45         private State                       savedState;
46
47         internal const string space = "space";
48
49         internal static XmlNodeType[] convertFromXPathNodeType = {
50             XmlNodeType.Document,               // XPathNodeType.Root
51             XmlNodeType.Element,                // XPathNodeType.Element
52             XmlNodeType.Attribute,              // XPathNodeType.Attribute
53             XmlNodeType.Attribute,              // XPathNodeType.Namespace
54             XmlNodeType.Text,                   // XPathNodeType.Text
55             XmlNodeType.SignificantWhitespace,  // XPathNodeType.SignificantWhitespace
56             XmlNodeType.Whitespace,             // XPathNodeType.Whitespace
57             XmlNodeType.ProcessingInstruction,  // XPathNodeType.ProcessingInstruction
58             XmlNodeType.Comment,                // XPathNodeType.Comment
59             XmlNodeType.None                    // XPathNodeType.All
60         };
61
62         /// <summary>
63         /// Translates an XPathNodeType value into the corresponding XmlNodeType value.
64         /// XPathNodeType.Whitespace and XPathNodeType.SignificantWhitespace are mapped into XmlNodeType.Text.
65         /// </summary>
66         internal static XmlNodeType ToXmlNodeType( XPathNodeType typ ) {
67             return XPathNavigatorReader.convertFromXPathNodeType[(int) typ];
68         }
69
70         internal object UnderlyingObject {
71             get {
72                 return this.nav.UnderlyingObject;
73             }
74         }
75
76         static public XPathNavigatorReader Create(XPathNavigator navToRead ) {
77             XPathNavigator nav = navToRead.Clone();
78             IXmlLineInfo xli = nav as IXmlLineInfo;
79             IXmlSchemaInfo xsi = nav as IXmlSchemaInfo;
80 #if NAVREADER_SUPPORTSLINEINFO
81             if (null == xsi) {
82                 if (null == xli) {
83                     return new XPathNavigatorReader(nav, xli, xsi);
84                 }
85                 else {
86                     return new XPathNavigatorReaderWithLI(nav, xli, xsi);
87                 }
88             }
89             else {
90                 if (null == xli) {
91                     return new XPathNavigatorReaderWithSI(nav, xli, xsi);
92                 }
93                 else {
94                     return new XPathNavigatorReaderWithLIAndSI(nav, xli, xsi);
95                 }
96             }
97 #else
98             if (null == xsi) {
99                 return new XPathNavigatorReader(nav, xli, xsi);
100             }
101             else {
102                 return new XPathNavigatorReaderWithSI(nav, xli, xsi);
103             }
104 #endif
105         }
106
107         protected XPathNavigatorReader( XPathNavigator navToRead, IXmlLineInfo xli, IXmlSchemaInfo xsi ) {
108             // Need clone that can be moved independently of original navigator
109             this.navToRead = navToRead;
110             this.lineInfo = xli;
111             this.schemaInfo = xsi;
112             this.nav = XmlEmptyNavigator.Singleton;
113             this.state = State.Initial;
114             this.depth = 0;
115             this.nodeType = XPathNavigatorReader.ToXmlNodeType( this.nav.NodeType );
116         }
117
118         protected bool IsReading { 
119             get { return this.state > State.Initial && this.state < State.EOF; } 
120         }
121
122         internal override XmlNamespaceManager NamespaceManager {
123             get { return XPathNavigator.GetNamespaces( this ); }
124         }
125
126
127         //-----------------------------------------------
128         // IXmlNamespaceResolver -- pass through to Navigator
129         //-----------------------------------------------
130         public override XmlNameTable NameTable {
131             get {
132                 return this.navToRead.NameTable;
133             }
134         }
135
136         IDictionary<string,string> IXmlNamespaceResolver.GetNamespacesInScope(XmlNamespaceScope scope) {
137             return this.nav.GetNamespacesInScope(scope);
138         }
139
140         string IXmlNamespaceResolver.LookupNamespace(string prefix) {
141             return this.nav.LookupNamespace(prefix);
142         }
143
144         string IXmlNamespaceResolver.LookupPrefix(string namespaceName) {
145             return this.nav.LookupPrefix(namespaceName);
146         }
147
148         //-----------------------------------------------
149         // XmlReader -- pass through to Navigator
150         //-----------------------------------------------
151
152         public override XmlReaderSettings Settings {
153             get {
154                 XmlReaderSettings rs = new XmlReaderSettings();
155                 rs.NameTable = this.NameTable;
156                 rs.ConformanceLevel = ConformanceLevel.Fragment;
157                 rs.CheckCharacters = false;
158                 rs.ReadOnly = true;
159                 return rs;
160             }
161         }
162
163         public override IXmlSchemaInfo SchemaInfo {
164             get {
165                 // Special case attribute text (this.nav points to attribute even though current state is Text)
166                 if ( this.nodeType == XmlNodeType.Text )
167                     return null;
168                 return this.nav.SchemaInfo;
169             }
170         }
171
172         public override System.Type ValueType {
173             get { return this.nav.ValueType; }
174         }
175
176         public override XmlNodeType NodeType {
177             get { return this.nodeType; }
178         }
179
180         public override string NamespaceURI {
181             get {
182                 //NamespaceUri for namespace nodes is different in case of XPathNavigator and Reader
183                 if (this.nav.NodeType == XPathNodeType.Namespace)
184                     return this.NameTable.Add(XmlReservedNs.NsXmlNs);
185                 //Special case attribute text node
186                 if (this.NodeType == XmlNodeType.Text)
187                     return string.Empty;
188                 return this.nav.NamespaceURI; 
189             }
190         }
191
192         public override string LocalName {
193             get {
194                 //Default namespace in case of reader has a local name value of 'xmlns'
195                 if (this.nav.NodeType == XPathNodeType.Namespace && this.nav.LocalName.Length == 0)
196                     return this.NameTable.Add("xmlns");
197                 //Special case attribute text node
198                 if (this.NodeType == XmlNodeType.Text)
199                     return string.Empty;
200                 return this.nav.LocalName; 
201             }
202         }
203
204         public override string Prefix {
205             get {
206                 //Prefix for namespace nodes is different in case of XPathNavigator and Reader
207                 if (this.nav.NodeType == XPathNodeType.Namespace && this.nav.LocalName.Length != 0)
208                     return this.NameTable.Add("xmlns");
209                 //Special case attribute text node
210                 if (this.NodeType == XmlNodeType.Text)
211                     return string.Empty;
212                 return this.nav.Prefix; 
213             }
214         }
215
216         public override string BaseURI {
217             get { 
218                 //reader returns BaseUri even before read method is called.
219                 if( this.state == State.Initial )
220                     return this.navToRead.BaseURI; 
221                 return this.nav.BaseURI;
222             }
223         }
224
225         public override bool IsEmptyElement { 
226             get {
227                 return this.nav.IsEmptyElement;
228             }
229         }        
230
231         public override XmlSpace XmlSpace { 
232             get {
233                 XPathNavigator tempNav = this.nav.Clone();
234                 do {
235                     if (tempNav.MoveToAttribute(XPathNavigatorReader.space, XmlReservedNs.NsXml)) {
236                         switch (XmlConvert.TrimString(tempNav.Value)) {
237                             case "default":
238                                 return XmlSpace.Default;
239                             case "preserve":
240                                 return XmlSpace.Preserve;
241                             default:
242                                 break;
243                         }
244                         tempNav.MoveToParent();
245                     }                    
246                 } 
247                 while (tempNav.MoveToParent());
248                 return XmlSpace.None;
249             }        
250         }        
251
252         public override string XmlLang { 
253             get {
254                 return this.nav.XmlLang;
255             }
256         }              
257
258         public override bool HasValue { 
259             get {
260                 if( ( this.nodeType != XmlNodeType.Element ) 
261                     && ( this.nodeType !=XmlNodeType.Document ) 
262                     && ( this.nodeType !=XmlNodeType.EndElement ) 
263                     && ( this.nodeType !=XmlNodeType.None ) )
264                     return true;
265                 return false;
266             }        
267         }
268
269         public override string Value {
270             get {
271                 if( ( this.nodeType != XmlNodeType.Element ) 
272                     && ( this.nodeType !=XmlNodeType.Document ) 
273                     && ( this.nodeType !=XmlNodeType.EndElement ) 
274                     && ( this.nodeType !=XmlNodeType.None ) )
275                     return this.nav.Value;
276                 return string.Empty;
277             }
278         }
279
280         private XPathNavigator GetElemNav() {
281             XPathNavigator tempNav;
282             switch (this.state) {
283                 case State.Content:
284                     return this.nav.Clone();
285                 case State.Attribute:
286                 case State.AttrVal:
287                     tempNav = this.nav.Clone();
288                     if (tempNav.MoveToParent())
289                         return tempNav;
290                     break;
291                 case State.InReadBinary:
292                     state = savedState;
293                     XPathNavigator nav = GetElemNav();
294                     state = State.InReadBinary;
295                     return nav;
296             }
297             return null;
298         }
299
300         private XPathNavigator GetElemNav(out int depth) {
301             XPathNavigator nav = null;
302             switch (this.state) {
303                 case State.Content:
304                     if (this.nodeType == XmlNodeType.Element)
305                         nav = this.nav.Clone();
306                     depth = this.depth;
307                     break;
308                 case State.Attribute:
309                     nav = this.nav.Clone();
310                     nav.MoveToParent();
311                     depth = this.depth - 1;
312                     break;
313                 case State.AttrVal:
314                     nav = this.nav.Clone();
315                     nav.MoveToParent();
316                     depth = this.depth - 2;
317                     break;
318                 case State.InReadBinary:
319                     state = savedState;
320                     nav = GetElemNav(out depth);
321                     state = State.InReadBinary;
322                     break;
323                 default:
324                     depth = this.depth;
325                     break;
326             }
327             return nav;
328         }
329
330         private void MoveToAttr(XPathNavigator nav, int depth) {
331             this.nav.MoveTo( nav );
332             this.depth = depth;
333             this.nodeType = XmlNodeType.Attribute;
334             this.state = State.Attribute;
335         }
336
337         public override int AttributeCount {
338             get {
339                 if ( this.attrCount < 0 ) {
340                     // attribute count works for element, regardless of where you are in start tag
341                     XPathNavigator tempNav = GetElemNav();
342                     int count = 0;
343                     if ( null != tempNav ) {
344                         if( tempNav.MoveToFirstNamespace( XPathNamespaceScope.Local ) ) {
345                             do {
346                                 count++;
347                             } while( tempNav.MoveToNextNamespace( ( XPathNamespaceScope.Local ) ) );
348                             tempNav.MoveToParent();
349                         }                
350                         if( tempNav.MoveToFirstAttribute() ) {
351                             do {
352                                 count++;
353                             } while( tempNav.MoveToNextAttribute() );                                        
354                         }
355                     }
356                     this.attrCount = count;
357                 }
358                 return this.attrCount;
359             }
360         }
361
362         public override string GetAttribute( string name ) {
363             // reader allows calling GetAttribute, even when positioned inside attributes
364             XPathNavigator nav = this.nav;
365             switch (nav.NodeType) {
366                 case XPathNodeType.Element:
367                     break;
368                 case XPathNodeType.Attribute:
369                     nav = nav.Clone();
370                     if (!nav.MoveToParent())
371                         return null;
372                     break;
373                 default:
374                     return null;
375             }
376             string prefix, localname;
377             ValidateNames.SplitQName( name, out prefix, out localname );
378             if ( 0 == prefix.Length ) {
379                 if( localname == "xmlns" )
380                     return nav.GetNamespace( string.Empty );
381                 if ( (object)nav == (object)this.nav )
382                     nav = nav.Clone();
383                 if ( nav.MoveToAttribute( localname, string.Empty ) )
384                     return nav.Value;
385             }
386             else {
387                 if( prefix == "xmlns" )
388                     return nav.GetNamespace( localname );
389                 if ((object)nav == (object)this.nav)
390                     nav = nav.Clone();
391                 if (nav.MoveToFirstAttribute()) {
392                     do {
393                         if (nav.LocalName == localname && nav.Prefix == prefix)
394                             return nav.Value;
395                     } while (nav.MoveToNextAttribute());
396                 }
397             }
398             return null;
399         }
400
401         public override string GetAttribute( string localName, string namespaceURI ) {
402             if ( null == localName )
403                 throw new ArgumentNullException("localName");
404             // reader allows calling GetAttribute, even when positioned inside attributes
405             XPathNavigator nav = this.nav;
406             switch (nav.NodeType) {
407                 case XPathNodeType.Element:
408                     break;
409                 case XPathNodeType.Attribute:
410                     nav = nav.Clone();
411                     if (!nav.MoveToParent())
412                         return null;
413                     break;
414                 default:
415                     return null;
416             }
417             // are they really looking for a namespace-decl?
418             if( namespaceURI == XmlReservedNs.NsXmlNs ) {
419                 if (localName == "xmlns")
420                     localName = string.Empty;
421                 return nav.GetNamespace( localName );
422             }
423             if ( null == namespaceURI )
424                 namespaceURI = string.Empty;
425             // We need to clone the navigator and move the clone to the attribute to see whether the attribute exists, 
426             // because XPathNavigator.GetAttribute return string.Empty for both when the the attribute is not there or when 
427             // it has an empty value. XmlReader.GetAttribute must return null if the attribute does not exist.
428             if ((object)nav == (object)this.nav)
429                 nav = nav.Clone();
430             if ( nav.MoveToAttribute( localName, namespaceURI ) ) {
431                 return nav.Value;
432             }
433             else {
434                 return null;
435             }
436         }
437
438         private static string GetNamespaceByIndex( XPathNavigator nav, int index, out int count ) {
439             string thisValue = nav.Value;
440             string value = null;
441             if ( nav.MoveToNextNamespace( XPathNamespaceScope.Local ) ) {
442                 value = GetNamespaceByIndex( nav, index, out count );
443             }
444             else {
445                 count = 0;
446             }
447             if ( count == index ) {
448                 Debug.Assert( value == null );
449                 value = thisValue;
450             }
451             count++;
452             return value;
453         }
454
455         public override string GetAttribute( int index ) {
456             if (index < 0)
457                 goto Error;
458             XPathNavigator nav = GetElemNav();
459             if (null == nav)
460                 goto Error;
461             if ( nav.MoveToFirstNamespace( XPathNamespaceScope.Local ) ) {
462                 // namespaces are returned in reverse order, 
463                 // but we want to return them in the correct order,
464                 // so first count the namespaces
465                 int nsCount;
466                 string value = GetNamespaceByIndex( nav, index, out nsCount );
467                 if ( null != value ) {
468                     return value;
469                 }
470                 index -= nsCount;
471                 nav.MoveToParent();
472             }
473             if ( nav.MoveToFirstAttribute() ) {
474                 do {
475                     if (index == 0)
476                         return nav.Value;
477                     index--;
478                 } while ( nav.MoveToNextAttribute() );
479             }
480             // can't find it... error
481         Error:
482             throw new ArgumentOutOfRangeException("index");
483         }
484
485
486         public override bool MoveToAttribute( string localName, string namespaceName ) {
487             if ( null == localName )
488                 throw new ArgumentNullException("localName");
489             int depth = this.depth;
490             XPathNavigator nav = GetElemNav(out depth);
491             if (null != nav) {
492                 if ( namespaceName == XmlReservedNs.NsXmlNs ) {
493                     if (localName == "xmlns")
494                         localName = string.Empty;
495                     if(  nav.MoveToFirstNamespace( XPathNamespaceScope.Local ) ) {
496                         do {
497                             if ( nav.LocalName == localName )
498                                 goto FoundMatch;
499                         } while( nav.MoveToNextNamespace( XPathNamespaceScope.Local ) );
500                     }
501                 }
502                 else {
503                     if (null == namespaceName)
504                         namespaceName = string.Empty;
505                     if ( nav.MoveToAttribute( localName, namespaceName ) )
506                         goto FoundMatch;
507                 }
508             }
509             return false;
510
511         FoundMatch:
512             if ( state == State.InReadBinary ) {
513                 readBinaryHelper.Finish();
514                 state = savedState;
515             }
516             MoveToAttr(nav, depth+1);
517             return true;
518         }
519
520         public override bool MoveToFirstAttribute() {
521             int depth;
522             XPathNavigator nav = GetElemNav(out depth);
523             if (null != nav) {
524                 if ( nav.MoveToFirstNamespace( XPathNamespaceScope.Local ) ) {
525                     // attributes are in reverse order
526                     while ( nav.MoveToNextNamespace( XPathNamespaceScope.Local ) )
527                         ;
528                     goto FoundMatch;
529                 }
530                 if ( nav.MoveToFirstAttribute() ) {
531                     goto FoundMatch;
532                 }
533             }
534             return false; 
535         FoundMatch:
536             if ( state == State.InReadBinary ) {
537                 readBinaryHelper.Finish();
538                 state = savedState;
539             }
540             MoveToAttr(nav, depth+1);
541             return true;
542         }            
543         
544         public override bool MoveToNextAttribute() {
545             switch (this.state) {
546                 case State.Content:
547                     return MoveToFirstAttribute();
548
549                 case State.Attribute: {
550                     if (XPathNodeType.Attribute == this.nav.NodeType) 
551                         return this.nav.MoveToNextAttribute();
552                     
553                     // otherwise it is on a namespace... namespace are in reverse order
554                     Debug.Assert( XPathNodeType.Namespace == this.nav.NodeType );
555                     XPathNavigator nav = this.nav.Clone();
556                     if ( !nav.MoveToParent() )
557                         return false; // shouldn't happen
558                     if ( !nav.MoveToFirstNamespace( XPathNamespaceScope.Local ) )
559                         return false; // shouldn't happen
560                     if ( nav.IsSamePosition( this.nav ) ) {
561                         // this was the last one... start walking attributes
562                         nav.MoveToParent();
563                         if (!nav.MoveToFirstAttribute())
564                             return false;
565                         // otherwise we are there
566                         this.nav.MoveTo(nav);
567                         return true;
568                     }
569                     else {
570                         XPathNavigator prev = nav.Clone();
571                         for (;;) {
572                             if ( !nav.MoveToNextNamespace( XPathNamespaceScope.Local ) ) {
573                                 Debug.Fail( "Couldn't find Namespace Node! Should not happen!" );
574                                 return false;
575                             }
576                             if ( nav.IsSamePosition( this.nav ) ) {
577                                 this.nav.MoveTo(prev);
578                                 return true;
579                             }
580                             prev.MoveTo( nav );
581                         }
582                         // found previous namespace position
583                     }
584                 }
585                 case State.AttrVal:
586                     depth--;
587                     this.state = State.Attribute;
588                     if (!MoveToNextAttribute()) {
589                         depth++;
590                         this.state = State.AttrVal;
591                         return false;
592                     }
593                     this.nodeType = XmlNodeType.Attribute;
594                     return true;
595
596                 case State.InReadBinary:
597                     state = savedState;
598                     if (!MoveToNextAttribute()) {
599                         state = State.InReadBinary;
600                         return false;
601                     }
602                     readBinaryHelper.Finish();
603                     return true;
604
605                 default:
606                     return false;
607             }
608         }            
609
610         public override bool MoveToAttribute( string name ) {
611             int depth;
612             XPathNavigator nav = GetElemNav(out depth);
613             if (null == nav)
614                 return false;
615
616             string prefix, localname;
617             ValidateNames.SplitQName( name, out prefix, out localname );
618
619             // watch for a namespace name
620             bool IsXmlnsNoPrefix = false;
621             if ( ( IsXmlnsNoPrefix = ( 0 == prefix.Length && localname == "xmlns" ) )
622                 || ( prefix == "xmlns" ) ) {
623                 if ( IsXmlnsNoPrefix )
624                     localname = string.Empty;
625                 if ( nav.MoveToFirstNamespace(XPathNamespaceScope.Local) ) {
626                     do {
627                         if (nav.LocalName == localname)
628                             goto FoundMatch;
629                     } while ( nav.MoveToNextNamespace(XPathNamespaceScope.Local) );
630                 }
631             }
632             else if ( 0 == prefix.Length ) {
633                 // the empty prefix always means empty namespaceUri for attributes
634                 if ( nav.MoveToAttribute( localname, string.Empty ) )
635                     goto FoundMatch;
636             }
637             else {
638                 if ( nav.MoveToFirstAttribute() ) {
639                     do {
640                         if (nav.LocalName == localname && nav.Prefix == prefix)
641                             goto FoundMatch;
642                     } while (nav.MoveToNextAttribute());
643                 }
644             }
645             return false;
646
647         FoundMatch:
648             if ( state == State.InReadBinary ) {
649                 readBinaryHelper.Finish();
650                 state = savedState;
651             }
652             MoveToAttr(nav, depth+1);
653             return true;
654         }
655
656         public override bool MoveToElement() {
657             switch (this.state) {
658                 case State.Attribute:
659                 case State.AttrVal:
660                     if (!nav.MoveToParent())
661                         return false;
662                     this.depth--;
663                     if (this.state == State.AttrVal)
664                         this.depth--;
665                     this.state = State.Content;
666                     this.nodeType = XmlNodeType.Element;
667                     return true;
668                 case State.InReadBinary:
669                     state = savedState;
670                     if (!MoveToElement()) {
671                         state = State.InReadBinary;
672                         return false;
673                     }
674                     readBinaryHelper.Finish();
675                     break;
676             }
677             return false;
678         }
679
680         public override bool EOF { 
681             get {
682                 return this.state == State.EOF;
683             }
684         }        
685
686         public override ReadState ReadState { 
687             get {
688                 switch (this.state) {
689                     case State.Initial:
690                         return ReadState.Initial;
691                     case State.Content:
692                     case State.EndElement:
693                     case State.Attribute:
694                     case State.AttrVal:
695                     case State.InReadBinary:
696                         return ReadState.Interactive;
697                     case State.EOF:
698                         return ReadState.EndOfFile;
699                     case State.Closed:
700                         return ReadState.Closed;
701                     default:
702                         return ReadState.Error;
703                 }
704             }
705         }
706
707         public override void ResolveEntity() {
708             throw new InvalidOperationException( Res.GetString( Res.Xml_InvalidOperation ) );
709         }
710
711         public override bool ReadAttributeValue() {
712             if ( state == State.InReadBinary ) {
713                 readBinaryHelper.Finish();
714                 state = savedState;
715             }
716             if ( this.state == State.Attribute ) {
717                 this.state = State.AttrVal;
718                 this.nodeType = XmlNodeType.Text;
719                 this.depth++;
720                 return true;
721             }
722             return false;
723         }
724
725         public override bool CanReadBinaryContent {
726             get {
727                 return true;
728             }
729         }
730
731         public override int ReadContentAsBase64( byte[] buffer, int index, int count ) {
732             if ( ReadState != ReadState.Interactive ) {
733                 return 0;
734             }
735
736             // init ReadContentAsBinaryHelper when called first time
737             if ( state != State.InReadBinary ) {
738                 readBinaryHelper = ReadContentAsBinaryHelper.CreateOrReset( readBinaryHelper, this );
739                 savedState = state;
740             }
741
742             // turn off InReadBinary state in order to have a normal Read() behavior when called from readBinaryHelper
743             state = savedState;
744
745             // call to the helper
746             int readCount = readBinaryHelper.ReadContentAsBase64( buffer, index, count );
747
748             // turn on InReadBinary state again and return
749             savedState = state;
750             state = State.InReadBinary;
751             return readCount;
752         }
753
754         public override int ReadContentAsBinHex( byte[] buffer, int index, int count ) {
755             if ( ReadState != ReadState.Interactive ) {
756                 return 0;
757             }
758
759             // init ReadContentAsBinaryHelper when called first time
760             if ( state != State.InReadBinary ) {
761                 readBinaryHelper = ReadContentAsBinaryHelper.CreateOrReset( readBinaryHelper, this );
762                 savedState = state;
763             }
764
765             // turn off InReadBinary state in order to have a normal Read() behavior when called from readBinaryHelper
766             state = savedState;
767
768             // call to the helper
769             int readCount = readBinaryHelper.ReadContentAsBinHex( buffer, index, count );
770
771             // turn on InReadBinary state again and return
772             savedState = state;
773             state = State.InReadBinary;
774             return readCount;
775         }
776
777         public override int ReadElementContentAsBase64( byte[] buffer, int index, int count ) {
778             if ( ReadState != ReadState.Interactive ) {
779                 return 0;
780             }
781
782             // init ReadContentAsBinaryHelper when called first time
783             if ( state != State.InReadBinary ) {
784                 readBinaryHelper = ReadContentAsBinaryHelper.CreateOrReset( readBinaryHelper, this );
785                 savedState = state;
786             }
787
788             // turn off InReadBinary state in order to have a normal Read() behavior when called from readBinaryHelper
789             state = savedState;
790
791             // call to the helper
792             int readCount = readBinaryHelper.ReadElementContentAsBase64( buffer, index, count );
793
794             // turn on InReadBinary state again and return
795             savedState = state;
796             state = State.InReadBinary;
797             return readCount;
798         }
799
800         public override int ReadElementContentAsBinHex( byte[] buffer, int index, int count ) {
801             if ( ReadState != ReadState.Interactive ) {
802                 return 0;
803             }
804
805             // init ReadContentAsBinaryHelper when called first time
806             if ( state != State.InReadBinary ) {
807                 readBinaryHelper = ReadContentAsBinaryHelper.CreateOrReset( readBinaryHelper, this );
808                 savedState = state;
809             }
810
811             // turn off InReadBinary state in order to have a normal Read() behavior when called from readBinaryHelper
812             state = savedState;
813
814             // call to the helper
815             int readCount = readBinaryHelper.ReadElementContentAsBinHex( buffer, index, count );
816
817             // turn on InReadBinary state again and return
818             savedState = state;
819             state = State.InReadBinary;
820             return readCount;
821         }
822
823         public override string LookupNamespace( string prefix ) {
824             return this.nav.LookupNamespace( prefix );
825         }
826         
827         /// <summary>
828         /// Current depth in subtree.
829         /// </summary>
830         public override int Depth {
831             get { return this.depth; }
832         }
833
834         /// <summary>
835         /// Move to the next reader state.  Return false if that is ReaderState.Closed.
836         /// </summary>
837         public override bool Read() {
838             this.attrCount = -1;
839             switch (this.state) {
840                 case State.Error:
841                 case State.Closed:
842                 case State.EOF:
843                     return false;
844
845                 case State.Initial:
846                     // Starting state depends on the navigator's item type
847                     this.nav = this.navToRead;
848                     this.state = State.Content;
849                     if ( XPathNodeType.Root == this.nav.NodeType ) {
850                         if( !nav.MoveToFirstChild() ) {
851                             SetEOF();
852                             return false;
853                         }
854                         this.readEntireDocument = true;
855                     }
856                     else if ( XPathNodeType.Attribute == this.nav.NodeType ) {
857                         this.state = State.Attribute;
858                     }
859                     this.nodeType = ToXmlNodeType( this.nav.NodeType );
860                     break;
861
862                 case State.Content:
863                     if ( this.nav.MoveToFirstChild() ) {
864                         this.nodeType = ToXmlNodeType( this.nav.NodeType );
865                         this.depth++;
866                         this.state = State.Content;
867                     }
868                     else if ( this.nodeType == XmlNodeType.Element 
869                         && !this.nav.IsEmptyElement ) {
870                         this.nodeType = XmlNodeType.EndElement;
871                         this.state = State.EndElement;
872                     }
873                     else
874                         goto case State.EndElement;
875                     break;
876
877                 case State.EndElement:
878                     if ( 0 == depth && !this.readEntireDocument ) {
879                         SetEOF();
880                         return false;
881                     }
882                     else if ( this.nav.MoveToNext() ) {
883                         this.nodeType = ToXmlNodeType( this.nav.NodeType );
884                         this.state = State.Content;
885                     }
886                     else if ( depth > 0 && this.nav.MoveToParent() ) {
887                         Debug.Assert( this.nav.NodeType == XPathNodeType.Element, this.nav.NodeType.ToString() + " == XPathNodeType.Element" );
888                         this.nodeType = XmlNodeType.EndElement;
889                         this.state = State.EndElement;
890                         depth--;
891                     }
892                     else {
893                         SetEOF();
894                         return false;
895                     }
896                     break;
897
898                 case State.Attribute:
899                 case State.AttrVal:
900                     if ( !this.nav.MoveToParent() ) {
901                         SetEOF();
902                         return false;
903                     }
904                     this.nodeType = ToXmlNodeType( this.nav.NodeType );
905                     this.depth--;
906                     if (state == State.AttrVal)
907                         this.depth--;
908                     goto case State.Content;
909                 case State.InReadBinary:
910                     state = savedState;
911                     readBinaryHelper.Finish();
912                     return Read();
913             }
914             return true;
915         }
916
917
918         /// <summary>
919         /// End reading by transitioning into the Closed state.
920         /// </summary>
921         public override void Close() {
922             this.nav = XmlEmptyNavigator.Singleton;
923             this.nodeType = XmlNodeType.None;
924             this.state = State.Closed;
925             this.depth = 0;
926         }
927
928         /// <summary>
929         /// set reader to EOF state
930         /// </summary>
931         private void SetEOF() {
932             this.nav = XmlEmptyNavigator.Singleton;
933             this.nodeType = XmlNodeType.None;
934             this.state = State.EOF;
935             this.depth = 0;
936         }
937     }
938
939 #if NAVREADER_SUPPORTSLINEINFO
940     internal class XPathNavigatorReaderWithLI : XPathNavigatorReader, System.Xml.IXmlLineInfo {
941         internal XPathNavigatorReaderWithLI( XPathNavigator navToRead, IXmlLineInfo xli, IXmlSchemaInfo xsi ) 
942             : base( navToRead, xli, xsi ) {
943         }
944
945         //-----------------------------------------------
946         // IXmlLineInfo
947         //-----------------------------------------------
948
949         public virtual bool HasLineInfo() { return IsReading ? this.lineInfo.HasLineInfo() : false; }
950         public virtual int LineNumber { get { return IsReading ? this.lineInfo.LineNumber : 0; } }
951         public virtual int LinePosition { get { return IsReading ? this.lineInfo.LinePosition : 0; } }
952     }
953
954     internal class XPathNavigatorReaderWithLIAndSI : XPathNavigatorReaderWithLI, System.Xml.IXmlLineInfo, System.Xml.Schema.IXmlSchemaInfo {
955         internal XPathNavigatorReaderWithLIAndSI( XPathNavigator navToRead, IXmlLineInfo xli, IXmlSchemaInfo xsi ) 
956             : base( navToRead, xli, xsi ) {
957         }
958
959         //-----------------------------------------------
960         // IXmlSchemaInfo
961         //-----------------------------------------------
962
963         public virtual XmlSchemaValidity Validity { get { return IsReading ? this.schemaInfo.Validity : XmlSchemaValidity.NotKnown; } }
964         public override bool IsDefault { get { return IsReading ? this.schemaInfo.IsDefault : false; } }
965         public virtual bool IsNil { get { return IsReading ? this.schemaInfo.IsNil : false; } }
966         public virtual XmlSchemaSimpleType MemberType { get { return IsReading ? this.schemaInfo.MemberType : null; } }
967         public virtual XmlSchemaType SchemaType { get { return IsReading ? this.schemaInfo.SchemaType : null; } }
968         public virtual XmlSchemaElement SchemaElement { get { return IsReading ? this.schemaInfo.SchemaElement : null; } }
969         public virtual XmlSchemaAttribute SchemaAttribute { get { return IsReading ? this.schemaInfo.SchemaAttribute : null; } }
970     }
971 #endif
972
973     internal class XPathNavigatorReaderWithSI : XPathNavigatorReader, System.Xml.Schema.IXmlSchemaInfo {
974         internal XPathNavigatorReaderWithSI( XPathNavigator navToRead, IXmlLineInfo xli, IXmlSchemaInfo xsi ) 
975             : base( navToRead, xli, xsi ) {
976         }
977
978         //-----------------------------------------------
979         // IXmlSchemaInfo
980         //-----------------------------------------------
981
982         public virtual XmlSchemaValidity Validity { get { return IsReading ? this.schemaInfo.Validity : XmlSchemaValidity.NotKnown; } }
983         public override bool IsDefault { get { return IsReading ? this.schemaInfo.IsDefault : false; } }
984         public virtual bool IsNil { get { return IsReading ? this.schemaInfo.IsNil : false; } }
985         public virtual XmlSchemaSimpleType MemberType { get { return IsReading ? this.schemaInfo.MemberType : null; } }
986         public virtual XmlSchemaType SchemaType { get { return IsReading ? this.schemaInfo.SchemaType : null; } }
987         public virtual XmlSchemaElement SchemaElement { get { return IsReading ? this.schemaInfo.SchemaElement : null; } }
988         public virtual XmlSchemaAttribute SchemaAttribute { get { return IsReading ? this.schemaInfo.SchemaAttribute : null; } }
989     }
990
991     /// <summary>
992     /// The XmlEmptyNavigator exposes a document node with no children.
993     /// Only one XmlEmptyNavigator exists per AppDomain (Singleton).  That's why the constructor is private.
994     /// Use the Singleton property to get the EmptyNavigator.
995     /// </summary>
996     internal class XmlEmptyNavigator : XPathNavigator {
997         private static volatile XmlEmptyNavigator singleton;
998
999         private XmlEmptyNavigator() {
1000         }
1001
1002         public static XmlEmptyNavigator Singleton {
1003             get {
1004                 if (XmlEmptyNavigator.singleton == null)
1005                     XmlEmptyNavigator.singleton = new XmlEmptyNavigator();
1006                 return XmlEmptyNavigator.singleton;
1007             }
1008         }
1009
1010         //-----------------------------------------------
1011         // XmlReader
1012         //-----------------------------------------------
1013
1014         public override XPathNodeType NodeType {
1015             get { return XPathNodeType.All; }
1016         }
1017
1018         public override string NamespaceURI {
1019             get { return string.Empty; }
1020         }
1021
1022         public override string LocalName {
1023             get { return string.Empty; }
1024         }
1025
1026         public override string Name {
1027             get { return string.Empty; }
1028         }
1029
1030         public override string Prefix {
1031             get { return string.Empty; }
1032         }
1033
1034         public override string BaseURI {
1035             get { return string.Empty; }
1036         }
1037
1038         public override string Value {
1039             get { return string.Empty; }
1040         }
1041
1042         public override bool IsEmptyElement {
1043             get { return false; }
1044         }
1045
1046         public override string XmlLang { 
1047             get { return string.Empty; }
1048         }        
1049
1050         public override bool HasAttributes {
1051             get { return false; }
1052         }
1053
1054         public override bool HasChildren {
1055             get { return false; }
1056         }
1057         
1058         
1059         //-----------------------------------------------
1060         // IXmlNamespaceResolver
1061         //-----------------------------------------------
1062
1063         public override XmlNameTable NameTable {
1064             get { return new NameTable(); }
1065         }
1066
1067         public override bool MoveToFirstChild() {
1068             return false;
1069         }
1070
1071         public override void MoveToRoot() {
1072             //always on root
1073             return;
1074         }        
1075
1076         public override bool MoveToNext() {
1077             return false;
1078         }
1079
1080         public override bool MoveToPrevious() {
1081             return false;
1082         }
1083         
1084         public override bool MoveToFirst() {
1085             return false;
1086         }
1087
1088         public override bool MoveToFirstAttribute() {
1089             return false;
1090         }
1091
1092         public override bool MoveToNextAttribute() {
1093             return false;
1094         }
1095
1096         public override bool MoveToId(string id) {
1097             return false;
1098         }
1099
1100         public override string GetAttribute(string localName, string namespaceName) {
1101             return null;
1102         }
1103
1104         public override bool MoveToAttribute(string localName, string namespaceName) {
1105             return false;
1106         }
1107
1108         public override string GetNamespace( string name ) {
1109             return null;
1110         }
1111
1112         public override bool MoveToNamespace( string prefix ) {
1113             return false;
1114         }
1115         
1116         
1117         public override bool MoveToFirstNamespace(XPathNamespaceScope scope) {
1118             return false;
1119         }
1120
1121         public override bool MoveToNextNamespace(XPathNamespaceScope scope) {
1122             return false;
1123         }
1124
1125         public override bool MoveToParent() {
1126             return false;
1127         }
1128
1129         public override bool MoveTo(XPathNavigator other) {
1130             // Only one instance of XmlEmptyNavigator exists on the system
1131             return (object) this == (object) other;
1132         }
1133
1134         public override XmlNodeOrder ComparePosition(XPathNavigator other) {
1135             // Only one instance of XmlEmptyNavigator exists on the system
1136             return ((object) this == (object) other) ? XmlNodeOrder.Same : XmlNodeOrder.Unknown;
1137         }
1138         
1139         public override bool IsSamePosition(XPathNavigator other) {
1140             // Only one instance of XmlEmptyNavigator exists on the system
1141             return (object) this == (object) other;
1142         }
1143
1144
1145         //-----------------------------------------------
1146         // XPathNavigator2
1147         //-----------------------------------------------
1148         public override XPathNavigator Clone() {
1149             // Singleton, so clone just returns this
1150             return this;
1151         }
1152     }
1153 }