2009-02-19 Geoff Norton <gnorton@novell.com>
[mono.git] / mcs / class / System.XML / System.Xml / XmlReader.cs
1 //
2 // XmlReader.cs
3 //
4 // Authors:
5 //      Jason Diamond (jason@injektilo.org)
6 //      Gonzalo Paniagua Javier (gonzalo@ximian.com)
7 //      Atsushi Enomoto (ginga@kit.hi-ho.ne.jp)
8 //
9 // (C) 2001, 2002 Jason Diamond  http://injektilo.org/
10 // (c) 2002 Ximian, Inc. (http://www.ximian.com)
11 // (C) 2003 Atsushi Enomoto
12 //
13
14 //
15 // Permission is hereby granted, free of charge, to any person obtaining
16 // a copy of this software and associated documentation files (the
17 // "Software"), to deal in the Software without restriction, including
18 // without limitation the rights to use, copy, modify, merge, publish,
19 // distribute, sublicense, and/or sell copies of the Software, and to
20 // permit persons to whom the Software is furnished to do so, subject to
21 // the following conditions:
22 // 
23 // The above copyright notice and this permission notice shall be
24 // included in all copies or substantial portions of the Software.
25 // 
26 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
27 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
28 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
29 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
30 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
31 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
32 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
33 //
34 using System.Collections;
35 using System.Diagnostics;
36 using System.IO;
37 using System.Text;
38 #if !NET_2_1
39 using System.Xml.Schema; // only required for NET_2_0 (SchemaInfo)
40 using System.Xml.Serialization; // only required for NET_2_0 (SchemaInfo)
41 using Mono.Xml.Schema; // only required for NET_2_0
42 #endif
43 using Mono.Xml; // only required for NET_2_0
44
45 namespace System.Xml
46 {
47 #if NET_2_0
48         public abstract class XmlReader : IDisposable
49 #else
50         public abstract class XmlReader
51 #endif
52         {
53                 private StringBuilder readStringBuffer;
54                 private XmlReaderBinarySupport binary;
55 #if NET_2_0
56                 private XmlReaderSettings settings;
57 #endif
58
59                 #region Constructor
60
61                 protected XmlReader ()
62                 {
63                 }
64
65                 #endregion
66
67                 #region Properties
68
69                 public abstract int AttributeCount { get; }
70
71                 public abstract string BaseURI { get; }
72
73                 internal XmlReaderBinarySupport Binary {
74                         get { return binary; }
75                 }
76
77                 internal XmlReaderBinarySupport.CharGetter BinaryCharGetter {
78                         get { return binary != null ? binary.Getter : null; }
79                         set {
80                                 if (binary == null)
81                                         binary = new XmlReaderBinarySupport (this);
82                                 binary.Getter = value;
83                         }
84                 }
85
86 #if NET_2_0
87                 // To enable it internally in sys.xml, just insert these
88                 // two lines into Read():
89                 //
90                 //      #if NET_2_0
91                 //      if (Binary != null)
92                 //              Binary.Reset ();
93                 //      #endif
94                 //
95                 public virtual bool CanReadBinaryContent {
96                         get { return false; }
97                 }
98
99                 public virtual bool CanReadValueChunk {
100                         get { return false; }
101                 }
102 #else
103                 internal virtual bool CanReadBinaryContent {
104                         get { return false; }
105                 }
106
107                 internal virtual bool CanReadValueChunk {
108                         get { return false; }
109                 }
110 #endif
111
112                 public virtual bool CanResolveEntity
113                 {
114                         get     { return false; }
115                 }
116
117                 public abstract int Depth { get; }
118
119                 public abstract bool EOF { get; }
120
121                 public virtual bool HasAttributes
122                 {
123                         get { return AttributeCount > 0; }
124                 }
125
126 #if !NET_2_1
127                 public abstract bool HasValue { get; }
128 #endif
129
130                 public abstract bool IsEmptyElement { get; }
131
132 #if NET_2_0
133                 public virtual bool IsDefault {
134                         get { return false; }
135                 }
136
137                 public virtual string this [int i] {
138                         get { return GetAttribute (i); }
139                 }
140
141                 public virtual string this [string name] {
142                         get { return GetAttribute (name); }
143                 }
144
145                 public virtual string this [string name, string namespaceURI] {
146                         get { return GetAttribute (name, namespaceURI); }
147                 }
148 #else
149                 public abstract bool IsDefault { get; }
150
151                 public abstract string this [int i] { get; }
152
153                 public abstract string this [string name] { get; }
154
155                 public abstract string this [string localName, string namespaceName] { get; }
156 #endif
157
158                 public abstract string LocalName { get; }
159
160 #if NET_2_0
161                 public virtual string Name {
162                         get {
163                                 return Prefix.Length > 0 ?
164                                         String.Concat (Prefix, ":", LocalName) :
165                                         LocalName;
166                         }
167                 }
168 #else
169                 public abstract string Name { get; }
170 #endif
171
172                 public abstract string NamespaceURI { get; }
173
174                 public abstract XmlNameTable NameTable { get; }
175
176                 public abstract XmlNodeType NodeType { get; }
177
178                 public abstract string Prefix { get; }
179
180 #if NET_2_0
181                 public virtual char QuoteChar {
182                         get { return '\"'; }
183                 }
184 #else
185                 public abstract char QuoteChar { get; }
186 #endif
187
188                 public abstract ReadState ReadState { get; }
189
190 #if NET_2_0
191 #if !NET_2_1
192                 public virtual IXmlSchemaInfo SchemaInfo {
193                         get { return null; }
194                 }
195 #endif
196
197                 public virtual XmlReaderSettings Settings {
198                         get { return settings; }
199                 }
200 #endif
201
202                 public abstract string Value { get; }
203
204 #if NET_2_0
205                 public virtual string XmlLang {
206                         get { return String.Empty; }
207                 }
208
209                 public virtual XmlSpace XmlSpace {
210                         get { return XmlSpace.None; }
211                 }
212 #else
213                 public abstract string XmlLang { get; }
214
215                 public abstract XmlSpace XmlSpace { get; }
216 #endif
217
218                 #endregion
219
220                 #region Methods
221
222                 public abstract void Close ();
223
224 #if NET_2_0
225                 private static XmlNameTable PopulateNameTable (
226                         XmlReaderSettings settings)
227                 {
228                         XmlNameTable nameTable = settings.NameTable;
229                         if (nameTable == null)
230                                 nameTable = new NameTable ();
231                         return nameTable;
232                 }
233
234                 private static XmlParserContext PopulateParserContext (
235                         XmlReaderSettings settings, string baseUri)
236                 {
237                         XmlNameTable nt = PopulateNameTable (settings);
238                         return new XmlParserContext (nt,
239                                 new XmlNamespaceManager (nt),
240                                 null,
241                                 null,
242                                 null,
243                                 null,
244                                 baseUri,
245                                 null,
246                                 XmlSpace.None,
247                                 null);
248                 }
249
250                 private static XmlNodeType GetNodeType (
251                         XmlReaderSettings settings)
252                 {
253                         ConformanceLevel level = settings != null ? settings.ConformanceLevel : ConformanceLevel.Auto;
254                         return
255                                 level == ConformanceLevel.Fragment ?
256                                 XmlNodeType.Element :
257                                 XmlNodeType.Document;
258                 }
259
260                 public static XmlReader Create (Stream stream)
261                 {
262                         return Create (stream, null);
263                 }
264
265                 public static XmlReader Create (string url)
266                 {
267                         return Create (url, null);
268                 }
269
270                 public static XmlReader Create (TextReader reader)
271                 {
272                         return Create (reader, null);
273                 }
274
275                 public static XmlReader Create (string url, XmlReaderSettings settings)
276                 {
277                         return Create (url, settings, null);
278                 }
279
280                 public static XmlReader Create (Stream stream, XmlReaderSettings settings)
281                 {
282                         return Create (stream, settings, String.Empty);
283                 }
284
285                 public static XmlReader Create (TextReader reader, XmlReaderSettings settings)
286                 {
287                         return Create (reader, settings, String.Empty);
288                 }
289
290                 static XmlReaderSettings PopulateSettings (XmlReaderSettings src)
291                 {
292                         if (src == null)
293                                 return new XmlReaderSettings ();
294                         else
295                                 return src.Clone ();
296                 }
297
298                 public static XmlReader Create (Stream stream, XmlReaderSettings settings, string baseUri)
299                 {
300                         settings = PopulateSettings (settings);
301                         return Create (stream, settings,
302                                 PopulateParserContext (settings, baseUri));
303                 }
304
305                 public static XmlReader Create (TextReader reader, XmlReaderSettings settings, string baseUri)
306                 {
307                         settings = PopulateSettings (settings);
308                         return Create (reader, settings,
309                                 PopulateParserContext (settings, baseUri));
310                 }
311
312                 public static XmlReader Create (XmlReader reader, XmlReaderSettings settings)
313                 {
314                         settings = PopulateSettings (settings);
315                         XmlReader r = CreateFilteredXmlReader (reader, settings);
316                         r.settings = settings;
317                         return r;
318                 }
319
320                 public static XmlReader Create (string url, XmlReaderSettings settings, XmlParserContext context)
321                 {
322                         settings = PopulateSettings (settings);
323                         bool closeInputBak = settings.CloseInput;
324                         try {
325                                 settings.CloseInput = true; // forced. See XmlReaderCommonTests.CreateFromUrlClose().
326                                 if (context == null)
327                                         context = PopulateParserContext (settings, url);
328                                 XmlTextReader xtr = new XmlTextReader (false, settings.XmlResolver, url, GetNodeType (settings), context);
329                                 XmlReader ret = CreateCustomizedTextReader (xtr, settings);
330                                 return ret;
331                         } finally {
332                                 settings.CloseInput = closeInputBak;
333                         }
334                 }
335
336                 public static XmlReader Create (Stream stream, XmlReaderSettings settings, XmlParserContext context)
337                 {
338                         settings = PopulateSettings (settings);
339                         if (context == null)
340                                 context = PopulateParserContext (settings, String.Empty);
341                         return CreateCustomizedTextReader (new XmlTextReader (stream, GetNodeType (settings), context), settings);
342                 }
343
344                 public static XmlReader Create (TextReader reader, XmlReaderSettings settings, XmlParserContext context)
345                 {
346                         settings = PopulateSettings (settings);
347                         if (context == null)
348                                 context = PopulateParserContext (settings, String.Empty);
349                         return CreateCustomizedTextReader (new XmlTextReader (context.BaseURI, reader, GetNodeType (settings), context), settings);
350                 }
351
352                 private static XmlReader CreateCustomizedTextReader (XmlTextReader reader, XmlReaderSettings settings)
353                 {
354                         reader.XmlResolver = settings.XmlResolver;
355                         // Normalization is set true by default.
356                         reader.Normalization = true;
357                         reader.EntityHandling = EntityHandling.ExpandEntities;
358
359                         if (settings.ProhibitDtd)
360                                 reader.ProhibitDtd = true;
361
362                         if (!settings.CheckCharacters)
363                                 reader.CharacterChecking = false;
364
365                         // I guess it might be changed in 2.0 RTM to set true
366                         // as default, or just disappear. It goes against
367                         // XmlTextReader's default usage and users will have 
368                         // to close input manually (that's annoying). Moreover,
369                         // MS XmlTextReader consumes text input more than 
370                         // actually read and users can acquire those extra
371                         // consumption by GetRemainder() that returns different
372                         // TextReader.
373                         reader.CloseInput = settings.CloseInput;
374
375                         // I would like to support it in detail later;
376                         // MSDN description looks source of confusion. We don't
377                         // need examples, but precise list of how it works.
378                         reader.Conformance = settings.ConformanceLevel;
379
380                         reader.AdjustLineInfoOffset (settings.LineNumberOffset,
381                                 settings.LinePositionOffset);
382
383                         if (settings.NameTable != null)
384                                 reader.SetNameTable (settings.NameTable);
385
386                         XmlReader r = CreateFilteredXmlReader (reader, settings);
387                         r.settings = settings;
388                         return r;
389                 }
390
391                 private static XmlReader CreateFilteredXmlReader (XmlReader reader, XmlReaderSettings settings)
392                 {
393                         ConformanceLevel conf = ConformanceLevel.Auto;
394                         if (reader is XmlTextReader)
395                                 conf = ((XmlTextReader) reader).Conformance;
396                         else if (reader.Settings != null)
397                                 conf = reader.Settings.ConformanceLevel;
398                         else
399                                 conf = settings.ConformanceLevel;
400                         if (settings.ConformanceLevel != ConformanceLevel.Auto &&
401                                 conf != settings.ConformanceLevel)
402                                 throw new InvalidOperationException (String.Format ("ConformanceLevel cannot be overwritten by a wrapping XmlReader. The source reader has {0}, while {1} is specified.", conf, settings.ConformanceLevel));
403                         settings.ConformanceLevel = conf;
404
405                         reader = CreateValidatingXmlReader (reader, settings);
406
407                         if ( settings.IgnoreComments ||
408                              settings.IgnoreProcessingInstructions ||
409                              settings.IgnoreWhitespace)
410                                 return new XmlFilterReader (reader, settings);
411                         else {
412                                 reader.settings = settings;
413                                 return reader;
414                         }
415                 }
416
417                 private static XmlReader CreateValidatingXmlReader (XmlReader reader, XmlReaderSettings settings)
418                 {
419 #if NET_2_1
420                         return reader;
421 #else
422                         XmlValidatingReader xvr = null;
423                         switch (settings.ValidationType) {
424                         // Auto and XDR are obsoleted in 2.0 and therefore ignored.
425                         default:
426                                 return reader;
427                         case ValidationType.DTD:
428                                 xvr = new XmlValidatingReader (reader);
429                                 xvr.XmlResolver = settings.XmlResolver;
430                                 xvr.ValidationType = ValidationType.DTD;
431                                 break;
432                         case ValidationType.Schema:
433                                 return new XmlSchemaValidatingReader (reader, settings);
434                         }
435
436                         // Actually I don't think they are treated in DTD validation though...
437                         if ((settings.ValidationFlags & XmlSchemaValidationFlags.ProcessIdentityConstraints) == 0)
438                                 throw new NotImplementedException ();
439                         //if ((settings.ValidationFlags & XmlSchemaValidationFlags.ProcessInlineSchema) != 0)
440                         //      throw new NotImplementedException ();
441                         //if ((settings.ValidationFlags & XmlSchemaValidationFlags.ProcessSchemaLocation) != 0)
442                         //      throw new NotImplementedException ();
443                         //if ((settings.ValidationFlags & XmlSchemaValidationFlags.ReportValidationWarnings) == 0)
444                         //      throw new NotImplementedException ();
445
446                         return xvr != null ? xvr : reader;
447 #endif
448                 }
449
450                 void IDisposable.Dispose ()
451                 {
452                         Dispose (false);
453                 }
454
455                 protected virtual void Dispose (bool disposing)
456                 {
457                         if (ReadState != ReadState.Closed)
458                                 Close ();
459                 }
460 #endif
461
462                 public abstract string GetAttribute (int i);
463
464                 public abstract string GetAttribute (string name);
465
466                 public abstract string GetAttribute (
467                         string localName,
468                         string namespaceName);
469
470                 public static bool IsName (string s)
471                 {
472                         return s != null && XmlChar.IsName (s);
473                 }
474
475                 public static bool IsNameToken (string s)
476                 {
477                         return s != null && XmlChar.IsNmToken (s);
478                 }
479
480                 public virtual bool IsStartElement ()
481                 {
482                         return (MoveToContent () == XmlNodeType.Element);
483                 }
484
485                 public virtual bool IsStartElement (string name)
486                 {
487                         if (!IsStartElement ())
488                                 return false;
489
490                         return (Name == name);
491                 }
492
493                 public virtual bool IsStartElement (string localName, string namespaceName)
494                 {
495                         if (!IsStartElement ())
496                                 return false;
497
498                         return (LocalName == localName && NamespaceURI == namespaceName);
499                 }
500
501                 public abstract string LookupNamespace (string prefix);
502
503 #if NET_2_0
504                 public virtual void MoveToAttribute (int i)
505                 {
506                         if (i >= AttributeCount)
507                                 throw new ArgumentOutOfRangeException ();
508                         MoveToFirstAttribute ();
509                         for (int a = 0; a < i; a++)
510                                 MoveToNextAttribute ();
511                 }
512 #else
513                 public abstract void MoveToAttribute (int i);
514 #endif
515
516                 public abstract bool MoveToAttribute (string name);
517
518                 public abstract bool MoveToAttribute (
519                         string localName,
520                         string namespaceName);
521
522                 private bool IsContent (XmlNodeType nodeType)
523                 {
524                         /* MS doc says:
525                          * (non-white space text, CDATA, Element, EndElement, EntityReference, or EndEntity)
526                          */
527                         switch (nodeType) {
528                         case XmlNodeType.Text:
529                                 return true;
530                         case XmlNodeType.CDATA:
531                                 return true;
532                         case XmlNodeType.Element:
533                                 return true;
534                         case XmlNodeType.EndElement:
535                                 return true;
536                         case XmlNodeType.EntityReference:
537                                 return true;
538                         case XmlNodeType.EndEntity:
539                                 return true;
540                         }
541
542                         return false;
543                 }
544
545                 public virtual XmlNodeType MoveToContent ()
546                 {
547                         if (NodeType == XmlNodeType.Attribute)
548                                 MoveToElement ();
549
550                         do {
551                                 if (IsContent (NodeType))
552                                         return NodeType;
553                                 Read ();
554                         } while (!EOF);
555                         return XmlNodeType.None;
556                 }
557
558                 public abstract bool MoveToElement ();
559
560                 public abstract bool MoveToFirstAttribute ();
561
562                 public abstract bool MoveToNextAttribute ();
563
564                 public abstract bool Read ();
565
566                 public abstract bool ReadAttributeValue ();
567
568                 public virtual string ReadElementString ()
569                 {
570                         if (MoveToContent () != XmlNodeType.Element) {
571                                 string error = String.Format ("'{0}' is an invalid node type.",
572                                                               NodeType.ToString ());
573                                 throw XmlError (error);
574                         }
575
576                         string result = String.Empty;
577                         if (!IsEmptyElement) {
578                                 Read ();
579                                 result = ReadString ();
580                                 if (NodeType != XmlNodeType.EndElement) {
581                                         string error = String.Format ("'{0}' is an invalid node type.",
582                                                                       NodeType.ToString ());
583                                         throw XmlError (error);
584                                 }
585                         }
586
587                         Read ();
588                         return result;
589                 }
590
591                 public virtual string ReadElementString (string name)
592                 {
593                         if (MoveToContent () != XmlNodeType.Element) {
594                                 string error = String.Format ("'{0}' is an invalid node type.",
595                                                               NodeType.ToString ());
596                                 throw XmlError (error);
597                         }
598
599                         if (name != Name) {
600                                 string error = String.Format ("The {0} tag from namespace {1} is expected.",
601                                                               Name, NamespaceURI);
602                                 throw XmlError (error);
603                         }
604
605                         string result = String.Empty;
606                         if (!IsEmptyElement) {
607                                 Read ();
608                                 result = ReadString ();
609                                 if (NodeType != XmlNodeType.EndElement) {
610                                         string error = String.Format ("'{0}' is an invalid node type.",
611                                                                       NodeType.ToString ());
612                                         throw XmlError (error);
613                                 }
614                         }
615
616                         Read ();
617                         return result;
618                 }
619
620                 public virtual string ReadElementString (string localName, string namespaceName)
621                 {
622                         if (MoveToContent () != XmlNodeType.Element) {
623                                 string error = String.Format ("'{0}' is an invalid node type.",
624                                                               NodeType.ToString ());
625                                 throw XmlError (error);
626                         }
627
628                         if (localName != LocalName || NamespaceURI != namespaceName) {
629                                 string error = String.Format ("The {0} tag from namespace {1} is expected.",
630                                                               LocalName, NamespaceURI);
631                                 throw XmlError (error);
632                         }
633
634                         string result = String.Empty;
635                         if (!IsEmptyElement) {
636                                 Read ();
637                                 result = ReadString ();
638                                 if (NodeType != XmlNodeType.EndElement) {
639                                         string error = String.Format ("'{0}' is an invalid node type.",
640                                                                       NodeType.ToString ());
641                                         throw XmlError (error);
642                                 }
643                         }
644
645                         Read ();
646                         return result;
647                 }
648
649                 public virtual void ReadEndElement ()
650                 {
651                         if (MoveToContent () != XmlNodeType.EndElement) {
652                                 string error = String.Format ("'{0}' is an invalid node type.",
653                                                               NodeType.ToString ());
654                                 throw XmlError (error);
655                         }
656
657                         Read ();
658                 }
659
660                 public virtual string ReadInnerXml ()
661                 {
662                         if (ReadState != ReadState.Interactive || NodeType == XmlNodeType.EndElement)
663                                 return String.Empty;
664
665                         if (IsEmptyElement) {
666                                 Read ();
667                                 return String.Empty;
668                         }
669                         StringWriter sw = new StringWriter ();
670                         XmlTextWriter xtw = new XmlTextWriter (sw);
671                         if (NodeType == XmlNodeType.Element) {
672                                 int startDepth = Depth;
673                                 Read ();
674                                 while (startDepth < Depth) {
675                                         if (ReadState != ReadState.Interactive)
676                                                 throw XmlError ("Unexpected end of the XML reader.");
677                                         xtw.WriteNode (this, false);
678                                 }
679                                 // reader is now end element, then proceed once more.
680                                 Read ();
681                         }
682                         else
683                                 xtw.WriteNode (this, false);
684
685                         return sw.ToString ();
686                 }
687
688                 public virtual string ReadOuterXml ()
689                 {
690                         if (ReadState != ReadState.Interactive || NodeType == XmlNodeType.EndElement)
691                                 return String.Empty;
692
693                         switch (NodeType) {
694                         case XmlNodeType.Element:
695                         case XmlNodeType.Attribute:
696                                 StringWriter sw = new StringWriter ();
697                                 XmlTextWriter xtw = new XmlTextWriter (sw);
698                                 xtw.WriteNode (this, false);
699                                 return sw.ToString ();
700                         default:
701                                 Skip ();
702                                 return String.Empty;
703                         }
704                 }
705
706                 public virtual void ReadStartElement ()
707                 {
708                         if (MoveToContent () != XmlNodeType.Element) {
709                                 string error = String.Format ("'{0}' is an invalid node type.",
710                                                               NodeType.ToString ());
711                                 throw XmlError (error);
712                         }
713
714                         Read ();
715                 }
716
717                 public virtual void ReadStartElement (string name)
718                 {
719                         if (MoveToContent () != XmlNodeType.Element) {
720                                 string error = String.Format ("'{0}' is an invalid node type.",
721                                                               NodeType.ToString ());
722                                 throw XmlError (error);
723                         }
724
725                         if (name != Name) {
726                                 string error = String.Format ("The {0} tag from namespace {1} is expected.",
727                                                               Name, NamespaceURI);
728                                 throw XmlError (error);
729                         }
730
731                         Read ();
732                 }
733
734                 public virtual void ReadStartElement (string localName, string namespaceName)
735                 {
736                         if (MoveToContent () != XmlNodeType.Element) {
737                                 string error = String.Format ("'{0}' is an invalid node type.",
738                                                               NodeType.ToString ());
739                                 throw XmlError (error);
740                         }
741
742                         if (localName != LocalName || NamespaceURI != namespaceName) {
743                                 string error = String.Format ("Expecting {0} tag from namespace {1}, got {2} and {3} instead",
744                                                               localName, namespaceName,
745                                                               LocalName, NamespaceURI);
746                                 throw XmlError (error);
747                         }
748
749                         Read ();
750                 }
751
752                 public virtual string ReadString ()
753                 {
754                         if (readStringBuffer == null)
755                                 readStringBuffer = new StringBuilder ();
756                         readStringBuffer.Length = 0;
757
758                         MoveToElement ();
759
760                         switch (NodeType) {
761                         default:
762                                 return String.Empty;
763                         case XmlNodeType.Element:
764                                 if (IsEmptyElement)
765                                         return String.Empty;
766                                 do {
767                                         Read ();
768                                         switch (NodeType) {
769                                         case XmlNodeType.Text:
770                                         case XmlNodeType.CDATA:
771                                         case XmlNodeType.Whitespace:
772                                         case XmlNodeType.SignificantWhitespace:
773                                                 readStringBuffer.Append (Value);
774                                                 continue;
775                                         }
776                                         break;
777                                 } while (true);
778                                 break;
779                         case XmlNodeType.Text:
780                         case XmlNodeType.CDATA:
781                         case XmlNodeType.Whitespace:
782                         case XmlNodeType.SignificantWhitespace:
783                                 do {
784                                         switch (NodeType) {
785                                         case XmlNodeType.Text:
786                                         case XmlNodeType.CDATA:
787                                         case XmlNodeType.Whitespace:
788                                         case XmlNodeType.SignificantWhitespace:
789                                                 readStringBuffer.Append (Value);
790                                                 Read ();
791                                                 continue;
792                                         }
793                                         break;
794                                 } while (true);
795                                 break;
796                         }
797                         string ret = readStringBuffer.ToString ();
798                         readStringBuffer.Length = 0;
799                         return ret;
800                 }
801
802 #if NET_2_0
803                 public virtual Type ValueType {
804                         get { return typeof (string); }
805                 }
806
807                 public virtual bool ReadToDescendant (string name)
808                 {
809                         if (ReadState == ReadState.Initial) {
810                                 MoveToContent ();
811                                 if (IsStartElement (name))
812                                         return true;
813                         }
814                         if (NodeType != XmlNodeType.Element || IsEmptyElement)
815                                 return false;
816                         int depth = Depth;
817                         for (Read (); depth < Depth; Read ())
818                                 if (NodeType == XmlNodeType.Element && name == Name)
819                                         return true;
820                         return false;
821                 }
822
823                 public virtual bool ReadToDescendant (string localName, string namespaceURI)
824                 {
825                         if (ReadState == ReadState.Initial) {
826                                 MoveToContent ();
827                                 if (IsStartElement (localName, namespaceURI))
828                                         return true;
829                         }
830                         if (NodeType != XmlNodeType.Element || IsEmptyElement)
831                                 return false;
832                         int depth = Depth;
833                         for (Read (); depth < Depth; Read ())
834                                 if (NodeType == XmlNodeType.Element && localName == LocalName && namespaceURI == NamespaceURI)
835                                         return true;
836                         return false;
837                 }
838
839                 public virtual bool ReadToFollowing (string name)
840                 {
841                         while (Read ())
842                                 if (NodeType == XmlNodeType.Element && name == Name)
843                                         return true;
844                         return false;
845                 }
846
847                 public virtual bool ReadToFollowing (string localName, string namespaceURI)
848                 {
849                         while (Read ())
850                                 if (NodeType == XmlNodeType.Element && localName == Name && namespaceURI == NamespaceURI)
851                                         return true;
852                         return false;
853                 }
854
855                 public virtual bool ReadToNextSibling (string name)
856                 {
857                         if (ReadState != ReadState.Interactive)
858                                 return false;
859                         int depth = Depth;
860                         Skip ();
861                         for (; !EOF && depth <= Depth; Skip ())
862                                 if (NodeType == XmlNodeType.Element && name == Name)
863                                         return true;
864                         return false;
865                 }
866
867                 public virtual bool ReadToNextSibling (string localName, string namespaceURI)
868                 {
869                         if (ReadState != ReadState.Interactive)
870                                 return false;
871                         int depth = Depth;
872                         Skip ();
873                         for (; !EOF && depth <= Depth; Skip ())
874                                 if (NodeType == XmlNodeType.Element && localName == LocalName && namespaceURI == NamespaceURI)
875                                         return true;
876                         return false;
877                 }
878
879                 public virtual XmlReader ReadSubtree ()
880                 {
881                         if (NodeType != XmlNodeType.Element)
882                                 throw new InvalidOperationException (String.Format ("ReadSubtree() can be invoked only when the reader is positioned on an element. Current node is {0}. {1}", NodeType, GetLocation ()));
883                         return new SubtreeXmlReader (this);
884                 }
885
886                 private string ReadContentString ()
887                 {
888                         if (NodeType == XmlNodeType.Attribute)
889                                 return Value;
890                         return ReadContentString (true);
891                 }
892
893                 private string ReadContentString (bool isText)
894                 {
895                         if (isText) {
896                                 switch (NodeType) {
897                                 case XmlNodeType.Text:
898                                 case XmlNodeType.SignificantWhitespace:
899                                 case XmlNodeType.Whitespace:
900                                 case XmlNodeType.CDATA:
901                                         break;
902                                 case XmlNodeType.Element:
903                                         throw new InvalidOperationException (String.Format ("Node type {0} is not supported in this operation.{1}", NodeType, GetLocation ()));
904                                 default:
905                                         return String.Empty;
906                                 }
907                         }
908
909                         string value = String.Empty;
910                         do {
911                                 switch (NodeType) {
912                                 case XmlNodeType.Element:
913                                         if (isText)
914                                                 return value;
915                                         throw XmlError ("Child element is not expected in this operation.");
916                                 case XmlNodeType.EndElement:
917                                         return value;
918                                 case XmlNodeType.Text:
919                                 case XmlNodeType.CDATA:
920                                 case XmlNodeType.SignificantWhitespace:
921                                 case XmlNodeType.Whitespace:
922                                         value += Value;
923                                         break;
924                                 }
925                         } while (Read ());
926                         throw XmlError ("Unexpected end of document.");
927                 }
928
929                 string GetLocation ()
930                 {
931                         IXmlLineInfo li = this as IXmlLineInfo;
932                         return li != null && li.HasLineInfo () ?
933                                 String.Format (" {0} (line {1}, column {2})", BaseURI, li.LineNumber, li.LinePosition) : String.Empty;
934                 }
935
936                 [MonoTODO]
937                 public virtual object ReadElementContentAsObject ()
938                 {
939                         return ReadElementContentAs (ValueType, null);
940                 }
941
942                 [MonoTODO]
943                 public virtual object ReadElementContentAsObject (string localName, string namespaceURI)
944                 {
945                         return ReadElementContentAs (ValueType, null, localName, namespaceURI);
946                 }
947
948                 [MonoTODO]
949                 public virtual object ReadContentAsObject ()
950                 {
951                         return ReadContentAs (ValueType, null);
952                 }
953
954                 public virtual object ReadElementContentAs (Type type, IXmlNamespaceResolver resolver)
955                 {
956                         bool isEmpty = IsEmptyElement;
957                         ReadStartElement ();
958                         object obj = ValueAs (isEmpty ? String.Empty : ReadContentString (false), type, resolver);
959                         if (!isEmpty)
960                                 ReadEndElement ();
961                         return obj;
962                 }
963
964                 public virtual object ReadElementContentAs (Type type, IXmlNamespaceResolver resolver, string localName, string namespaceURI)
965                 {
966                         ReadStartElement (localName, namespaceURI);
967                         object obj = ReadContentAs (type, resolver);
968                         ReadEndElement ();
969                         return obj;
970                 }
971
972                 public virtual object ReadContentAs (Type type, IXmlNamespaceResolver resolver)
973                 {
974                         return ValueAs (ReadContentString (), type, resolver);
975                 }
976
977                 private object ValueAs (string text, Type type, IXmlNamespaceResolver resolver)
978                 {
979                         try {
980                                 if (type == typeof (object))
981                                         return text;
982                                 if (type == typeof (XmlQualifiedName)) {
983                                         if (resolver != null)
984                                                 return XmlQualifiedName.Parse (text, resolver);
985                                         else
986                                                 return XmlQualifiedName.Parse (text, this);
987                                 }
988
989                                 switch (Type.GetTypeCode (type)) {
990                                 case TypeCode.Boolean:
991                                         return XQueryConvert.StringToBoolean (text);
992                                 case TypeCode.DateTime:
993                                         return XQueryConvert.StringToDateTime (text);
994                                 case TypeCode.Decimal:
995                                         return XQueryConvert.StringToDecimal (text);
996                                 case TypeCode.Double:
997                                         return XQueryConvert.StringToDouble (text);
998                                 case TypeCode.Int32:
999                                         return XQueryConvert.StringToInt (text);
1000                                 case TypeCode.Int64:
1001                                         return XQueryConvert.StringToInteger (text);
1002                                 case TypeCode.Single:
1003                                         return XQueryConvert.StringToFloat (text);
1004                                 case TypeCode.String:
1005                                         return text;
1006                                 }
1007                         } catch (Exception ex) {
1008                                 throw XmlError (String.Format ("Current text value '{0}' is not acceptable for specified type '{1}'. {2}", text, type, ex != null ? ex.Message : String.Empty), ex);
1009                         }
1010                         throw new ArgumentException (String.Format ("Specified type '{0}' is not supported.", type));
1011                 }
1012
1013                 public virtual bool ReadElementContentAsBoolean ()
1014                 {
1015                         try {
1016                                 return XQueryConvert.StringToBoolean (ReadElementContentAsString ());
1017                         } catch (FormatException ex) {
1018                                 throw XmlError ("Typed value is invalid.", ex);
1019                         }
1020                 }
1021
1022                 public virtual DateTime ReadElementContentAsDateTime ()
1023                 {
1024                         try {
1025                                 return XQueryConvert.StringToDateTime (ReadElementContentAsString ());
1026                         } catch (FormatException ex) {
1027                                 throw XmlError ("Typed value is invalid.", ex);
1028                         }
1029                 }
1030
1031                 public virtual decimal ReadElementContentAsDecimal ()
1032                 {
1033                         try {
1034                                 return XQueryConvert.StringToDecimal (ReadElementContentAsString ());
1035                         } catch (FormatException ex) {
1036                                 throw XmlError ("Typed value is invalid.", ex);
1037                         }
1038                 }
1039
1040                 public virtual double ReadElementContentAsDouble ()
1041                 {
1042                         try {
1043                                 return XQueryConvert.StringToDouble (ReadElementContentAsString ());
1044                         } catch (FormatException ex) {
1045                                 throw XmlError ("Typed value is invalid.", ex);
1046                         }
1047                 }
1048
1049                 public virtual float ReadElementContentAsFloat ()
1050                 {
1051                         try {
1052                                 return XQueryConvert.StringToFloat (ReadElementContentAsString ());
1053                         } catch (FormatException ex) {
1054                                 throw XmlError ("Typed value is invalid.", ex);
1055                         }
1056                 }
1057
1058                 public virtual int ReadElementContentAsInt ()
1059                 {
1060                         try {
1061                                 return XQueryConvert.StringToInt (ReadElementContentAsString ());
1062                         } catch (FormatException ex) {
1063                                 throw XmlError ("Typed value is invalid.", ex);
1064                         }
1065                 }
1066
1067                 public virtual long ReadElementContentAsLong ()
1068                 {
1069                         try {
1070                                 return XQueryConvert.StringToInteger (ReadElementContentAsString ());
1071                         } catch (FormatException ex) {
1072                                 throw XmlError ("Typed value is invalid.", ex);
1073                         }
1074                 }
1075
1076                 public virtual string ReadElementContentAsString ()
1077                 {
1078                         bool isEmpty = IsEmptyElement;
1079                         // unlike ReadStartElement() it rejects non-content nodes (this check is done before MoveToContent())
1080                         if (NodeType != XmlNodeType.Element)
1081                                 throw new InvalidOperationException (String.Format ("'{0}' is an element node.", NodeType));
1082                         ReadStartElement ();
1083                         if (isEmpty)
1084                                 return String.Empty;
1085                         string s = ReadContentString (false);
1086                         ReadEndElement ();
1087                         return s;
1088                 }
1089
1090                 public virtual bool ReadElementContentAsBoolean (string localName, string namespaceURI)
1091                 {
1092                         try {
1093                                 return XQueryConvert.StringToBoolean (ReadElementContentAsString (localName, namespaceURI));
1094                         } catch (FormatException ex) {
1095                                 throw XmlError ("Typed value is invalid.", ex);
1096                         }
1097                 }
1098
1099                 public virtual DateTime ReadElementContentAsDateTime (string localName, string namespaceURI)
1100                 {
1101                         try {
1102                                 return XQueryConvert.StringToDateTime (ReadElementContentAsString (localName, namespaceURI));
1103                         } catch (FormatException ex) {
1104                                 throw XmlError ("Typed value is invalid.", ex);
1105                         }
1106                 }
1107
1108                 public virtual decimal ReadElementContentAsDecimal (string localName, string namespaceURI)
1109                 {
1110                         try {
1111                                 return XQueryConvert.StringToDecimal (ReadElementContentAsString (localName, namespaceURI));
1112                         } catch (FormatException ex) {
1113                                 throw XmlError ("Typed value is invalid.", ex);
1114                         }
1115                 }
1116
1117                 public virtual double ReadElementContentAsDouble (string localName, string namespaceURI)
1118                 {
1119                         try {
1120                                 return XQueryConvert.StringToDouble (ReadElementContentAsString (localName, namespaceURI));
1121                         } catch (FormatException ex) {
1122                                 throw XmlError ("Typed value is invalid.", ex);
1123                         }
1124                 }
1125
1126                 public virtual float ReadElementContentAsFloat (string localName, string namespaceURI)
1127                 {
1128                         try {
1129                                 return XQueryConvert.StringToFloat (ReadElementContentAsString (localName, namespaceURI));
1130                         } catch (FormatException ex) {
1131                                 throw XmlError ("Typed value is invalid.", ex);
1132                         }
1133                 }
1134
1135                 public virtual int ReadElementContentAsInt (string localName, string namespaceURI)
1136                 {
1137                         try {
1138                                 return XQueryConvert.StringToInt (ReadElementContentAsString (localName, namespaceURI));
1139                         } catch (FormatException ex) {
1140                                 throw XmlError ("Typed value is invalid.", ex);
1141                         }
1142                 }
1143
1144                 public virtual long ReadElementContentAsLong (string localName, string namespaceURI)
1145                 {
1146                         try {
1147                                 return XQueryConvert.StringToInteger (ReadElementContentAsString (localName, namespaceURI));
1148                         } catch (FormatException ex) {
1149                                 throw XmlError ("Typed value is invalid.", ex);
1150                         }
1151                 }
1152
1153                 public virtual string ReadElementContentAsString (string localName, string namespaceURI)
1154                 {
1155                         bool isEmpty = IsEmptyElement;
1156                         // unlike ReadStartElement() it rejects non-content nodes (this check is done before MoveToContent())
1157                         if (NodeType != XmlNodeType.Element)
1158                                 throw new InvalidOperationException (String.Format ("'{0}' is an element node.", NodeType));
1159                         ReadStartElement (localName, namespaceURI);
1160                         if (isEmpty)
1161                                 return String.Empty;
1162                         string s = ReadContentString (false);
1163                         ReadEndElement ();
1164                         return s;
1165                 }
1166
1167                 public virtual bool ReadContentAsBoolean ()
1168                 {
1169                         try {
1170                                 return XQueryConvert.StringToBoolean (ReadContentString ());
1171                         } catch (FormatException ex) {
1172                                 throw XmlError ("Typed value is invalid.", ex);
1173                         }
1174                 }
1175
1176                 public virtual DateTime ReadContentAsDateTime ()
1177                 {
1178                         try {
1179                                 return XQueryConvert.StringToDateTime (ReadContentString ());
1180                         } catch (FormatException ex) {
1181                                 throw XmlError ("Typed value is invalid.", ex);
1182                         }
1183                 }
1184
1185                 public virtual decimal ReadContentAsDecimal ()
1186                 {
1187                         try {
1188                                 return XQueryConvert.StringToDecimal (ReadContentString ());
1189                         } catch (FormatException ex) {
1190                                 throw XmlError ("Typed value is invalid.", ex);
1191                         }
1192                 }
1193
1194                 public virtual double ReadContentAsDouble ()
1195                 {
1196                         try {
1197                                 return XQueryConvert.StringToDouble (ReadContentString ());
1198                         } catch (FormatException ex) {
1199                                 throw XmlError ("Typed value is invalid.", ex);
1200                         }
1201                 }
1202
1203                 public virtual float ReadContentAsFloat ()
1204                 {
1205                         try {
1206                                 return XQueryConvert.StringToFloat (ReadContentString ());
1207                         } catch (FormatException ex) {
1208                                 throw XmlError ("Typed value is invalid.", ex);
1209                         }
1210                 }
1211
1212                 public virtual int ReadContentAsInt ()
1213                 {
1214                         try {
1215                                 return XQueryConvert.StringToInt (ReadContentString ());
1216                         } catch (FormatException ex) {
1217                                 throw XmlError ("Typed value is invalid.", ex);
1218                         }
1219                 }
1220
1221                 public virtual long ReadContentAsLong ()
1222                 {
1223                         try {
1224                                 return XQueryConvert.StringToInteger (ReadContentString ());
1225                         } catch (FormatException ex) {
1226                                 throw XmlError ("Typed value is invalid.", ex);
1227                         }
1228                 }
1229
1230                 public virtual string ReadContentAsString ()
1231                 {
1232                         return ReadContentString ();
1233                 }
1234
1235                 public virtual int ReadContentAsBase64 (
1236                         byte [] buffer, int offset, int length)
1237                 {
1238                         CheckSupport ();
1239                         return binary.ReadContentAsBase64 (
1240                                 buffer, offset, length);
1241                 }
1242
1243                 public virtual int ReadContentAsBinHex (
1244                         byte [] buffer, int offset, int length)
1245                 {
1246                         CheckSupport ();
1247                         return binary.ReadContentAsBinHex (
1248                                 buffer, offset, length);
1249                 }
1250
1251                 public virtual int ReadElementContentAsBase64 (
1252                         byte [] buffer, int offset, int length)
1253                 {
1254                         CheckSupport ();
1255                         return binary.ReadElementContentAsBase64 (
1256                                 buffer, offset, length);
1257                 }
1258
1259                 public virtual int ReadElementContentAsBinHex (
1260                         byte [] buffer, int offset, int length)
1261                 {
1262                         CheckSupport ();
1263                         return binary.ReadElementContentAsBinHex (
1264                                 buffer, offset, length);
1265                 }
1266
1267                 private void CheckSupport ()
1268                 {
1269                         // Default implementation expects both.
1270                         if (!CanReadBinaryContent || !CanReadValueChunk)
1271                                 throw new NotSupportedException ();
1272                         if (binary == null)
1273                                 binary = new XmlReaderBinarySupport (this);
1274                 }
1275                 
1276 #endif
1277
1278 #if NET_2_0
1279                 public virtual int ReadValueChunk (
1280                         char [] buffer, int offset, int length)
1281 #else
1282                 internal virtual int ReadValueChunk (
1283                         char [] buffer, int offset, int length)
1284 #endif
1285                 {
1286                         if (!CanReadValueChunk)
1287                                 throw new NotSupportedException ();
1288                         if (binary == null)
1289                                 binary = new XmlReaderBinarySupport (this);
1290                         return binary.ReadValueChunk (buffer, offset, length);
1291                 }
1292
1293                 public abstract void ResolveEntity ();
1294
1295                 public virtual void Skip ()
1296                 {
1297                         if (ReadState != ReadState.Interactive)
1298                                 return;
1299
1300                         MoveToElement ();
1301                         if (NodeType != XmlNodeType.Element || IsEmptyElement) {
1302                                 Read ();
1303                                 return;
1304                         }
1305                                 
1306                         int depth = Depth;
1307                         while (Read () && depth < Depth)
1308                                 ;
1309                         if (NodeType == XmlNodeType.EndElement)
1310                                 Read ();
1311                 }
1312
1313                 private XmlException XmlError (string message)
1314                 {
1315                         return new XmlException (this as IXmlLineInfo, BaseURI, message);
1316                 }
1317 #if NET_2_0
1318                 private XmlException XmlError (string message, Exception innerException)
1319                 {
1320                         return new XmlException (this as IXmlLineInfo, BaseURI, message);
1321                 }
1322 #endif
1323                 #endregion
1324         }
1325 }