2008-05-07 Atsushi Enomoto <atsushi@ximian.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                                 baseUri,
241                                 XmlSpace.None);
242                 }
243
244                 private static XmlNodeType GetNodeType (
245                         XmlReaderSettings settings)
246                 {
247                         ConformanceLevel level = settings != null ? settings.ConformanceLevel : ConformanceLevel.Auto;
248                         return
249                                 level == ConformanceLevel.Fragment ?
250                                 XmlNodeType.Element :
251                                 XmlNodeType.Document;
252                 }
253
254                 public static XmlReader Create (Stream stream)
255                 {
256                         return Create (stream, null);
257                 }
258
259                 public static XmlReader Create (string url)
260                 {
261                         return Create (url, null);
262                 }
263
264                 public static XmlReader Create (TextReader reader)
265                 {
266                         return Create (reader, null);
267                 }
268
269                 public static XmlReader Create (string url, XmlReaderSettings settings)
270                 {
271                         return Create (url, settings, null);
272                 }
273
274                 public static XmlReader Create (Stream stream, XmlReaderSettings settings)
275                 {
276                         return Create (stream, settings, String.Empty);
277                 }
278
279                 public static XmlReader Create (TextReader reader, XmlReaderSettings settings)
280                 {
281                         return Create (reader, settings, String.Empty);
282                 }
283
284                 static XmlReaderSettings PopulateSettings (XmlReaderSettings src)
285                 {
286                         if (src == null)
287                                 return new XmlReaderSettings ();
288                         else
289                                 return src.Clone ();
290                 }
291
292                 public static XmlReader Create (Stream stream, XmlReaderSettings settings, string baseUri)
293                 {
294                         settings = PopulateSettings (settings);
295                         return Create (stream, settings,
296                                 PopulateParserContext (settings, baseUri));
297                 }
298
299                 public static XmlReader Create (TextReader reader, XmlReaderSettings settings, string baseUri)
300                 {
301                         settings = PopulateSettings (settings);
302                         return Create (reader, settings,
303                                 PopulateParserContext (settings, baseUri));
304                 }
305
306                 public static XmlReader Create (XmlReader reader, XmlReaderSettings settings)
307                 {
308                         settings = PopulateSettings (settings);
309                         XmlReader r = CreateFilteredXmlReader (reader, settings);
310                         r.settings = settings;
311                         return r;
312                 }
313
314                 public static XmlReader Create (string url, XmlReaderSettings settings, XmlParserContext context)
315                 {
316                         settings = PopulateSettings (settings);
317                         bool closeInputBak = settings.CloseInput;
318                         try {
319                                 settings.CloseInput = true; // forced. See XmlReaderCommonTests.CreateFromUrlClose().
320                                 if (context == null)
321                                         context = PopulateParserContext (settings, url);
322                                 XmlTextReader xtr = new XmlTextReader (false, settings.XmlResolver, url, GetNodeType (settings), context);
323                                 XmlReader ret = CreateCustomizedTextReader (xtr, settings);
324                                 return ret;
325                         } finally {
326                                 settings.CloseInput = closeInputBak;
327                         }
328                 }
329
330                 public static XmlReader Create (Stream stream, XmlReaderSettings settings, XmlParserContext context)
331                 {
332                         settings = PopulateSettings (settings);
333                         if (context == null)
334                                 context = PopulateParserContext (settings, String.Empty);
335                         return CreateCustomizedTextReader (new XmlTextReader (stream, GetNodeType (settings), context), settings);
336                 }
337
338                 public static XmlReader Create (TextReader reader, XmlReaderSettings settings, XmlParserContext context)
339                 {
340                         settings = PopulateSettings (settings);
341                         if (context == null)
342                                 context = PopulateParserContext (settings, String.Empty);
343                         return CreateCustomizedTextReader (new XmlTextReader (context.BaseURI, reader, GetNodeType (settings), context), settings);
344                 }
345
346                 private static XmlReader CreateCustomizedTextReader (XmlTextReader reader, XmlReaderSettings settings)
347                 {
348                         reader.XmlResolver = settings.XmlResolver;
349                         // Normalization is set true by default.
350                         reader.Normalization = true;
351                         reader.EntityHandling = EntityHandling.ExpandEntities;
352
353                         if (settings.ProhibitDtd)
354                                 reader.ProhibitDtd = true;
355
356                         if (!settings.CheckCharacters)
357                                 reader.CharacterChecking = false;
358
359                         // I guess it might be changed in 2.0 RTM to set true
360                         // as default, or just disappear. It goes against
361                         // XmlTextReader's default usage and users will have 
362                         // to close input manually (that's annoying). Moreover,
363                         // MS XmlTextReader consumes text input more than 
364                         // actually read and users can acquire those extra
365                         // consumption by GetRemainder() that returns different
366                         // TextReader.
367                         reader.CloseInput = settings.CloseInput;
368
369                         // I would like to support it in detail later;
370                         // MSDN description looks source of confusion. We don't
371                         // need examples, but precise list of how it works.
372                         reader.Conformance = settings.ConformanceLevel;
373
374                         reader.AdjustLineInfoOffset (settings.LineNumberOffset,
375                                 settings.LinePositionOffset);
376
377                         if (settings.NameTable != null)
378                                 reader.SetNameTable (settings.NameTable);
379
380                         XmlReader r = CreateFilteredXmlReader (reader, settings);
381                         r.settings = settings;
382                         return r;
383                 }
384
385                 private static XmlReader CreateFilteredXmlReader (XmlReader reader, XmlReaderSettings settings)
386                 {
387                         ConformanceLevel conf = ConformanceLevel.Auto;
388                         if (reader is XmlTextReader)
389                                 conf = ((XmlTextReader) reader).Conformance;
390                         else if (reader.Settings != null)
391                                 conf = reader.Settings.ConformanceLevel;
392                         else
393                                 conf = settings.ConformanceLevel;
394                         if (settings.ConformanceLevel != ConformanceLevel.Auto &&
395                                 conf != settings.ConformanceLevel)
396                                 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));
397                         settings.ConformanceLevel = conf;
398
399                         reader = CreateValidatingXmlReader (reader, settings);
400
401                         if ( settings.IgnoreComments ||
402                              settings.IgnoreProcessingInstructions ||
403                              settings.IgnoreWhitespace)
404                                 return new XmlFilterReader (reader, settings);
405                         else {
406                                 reader.settings = settings;
407                                 return reader;
408                         }
409                 }
410
411                 private static XmlReader CreateValidatingXmlReader (XmlReader reader, XmlReaderSettings settings)
412                 {
413 #if NET_2_1
414                         return reader;
415 #else
416                         XmlValidatingReader xvr = null;
417                         switch (settings.ValidationType) {
418                         // Auto and XDR are obsoleted in 2.0 and therefore ignored.
419                         default:
420                                 return reader;
421                         case ValidationType.DTD:
422                                 xvr = new XmlValidatingReader (reader);
423                                 xvr.XmlResolver = settings.XmlResolver;
424                                 xvr.ValidationType = ValidationType.DTD;
425                                 break;
426                         case ValidationType.Schema:
427                                 return new XmlSchemaValidatingReader (reader, settings);
428                         }
429
430                         // Actually I don't think they are treated in DTD validation though...
431                         if ((settings.ValidationFlags & XmlSchemaValidationFlags.ProcessIdentityConstraints) == 0)
432                                 throw new NotImplementedException ();
433                         //if ((settings.ValidationFlags & XmlSchemaValidationFlags.ProcessInlineSchema) != 0)
434                         //      throw new NotImplementedException ();
435                         //if ((settings.ValidationFlags & XmlSchemaValidationFlags.ProcessSchemaLocation) != 0)
436                         //      throw new NotImplementedException ();
437                         //if ((settings.ValidationFlags & XmlSchemaValidationFlags.ReportValidationWarnings) == 0)
438                         //      throw new NotImplementedException ();
439
440                         return xvr != null ? xvr : reader;
441 #endif
442                 }
443
444                 void IDisposable.Dispose ()
445                 {
446                         Dispose (false);
447                 }
448
449                 protected virtual void Dispose (bool disposing)
450                 {
451                         if (ReadState != ReadState.Closed)
452                                 Close ();
453                 }
454 #endif
455
456                 public abstract string GetAttribute (int i);
457
458                 public abstract string GetAttribute (string name);
459
460                 public abstract string GetAttribute (
461                         string localName,
462                         string namespaceName);
463
464                 public static bool IsName (string s)
465                 {
466                         return s != null && XmlChar.IsName (s);
467                 }
468
469                 public static bool IsNameToken (string s)
470                 {
471                         return s != null && XmlChar.IsNmToken (s);
472                 }
473
474                 public virtual bool IsStartElement ()
475                 {
476                         return (MoveToContent () == XmlNodeType.Element);
477                 }
478
479                 public virtual bool IsStartElement (string name)
480                 {
481                         if (!IsStartElement ())
482                                 return false;
483
484                         return (Name == name);
485                 }
486
487                 public virtual bool IsStartElement (string localName, string namespaceName)
488                 {
489                         if (!IsStartElement ())
490                                 return false;
491
492                         return (LocalName == localName && NamespaceURI == namespaceName);
493                 }
494
495                 public abstract string LookupNamespace (string prefix);
496
497 #if NET_2_0
498                 public virtual void MoveToAttribute (int i)
499                 {
500                         if (i >= AttributeCount)
501                                 throw new ArgumentOutOfRangeException ();
502                         MoveToFirstAttribute ();
503                         for (int a = 0; a < i; a++)
504                                 MoveToNextAttribute ();
505                 }
506 #else
507                 public abstract void MoveToAttribute (int i);
508 #endif
509
510                 public abstract bool MoveToAttribute (string name);
511
512                 public abstract bool MoveToAttribute (
513                         string localName,
514                         string namespaceName);
515
516                 private bool IsContent (XmlNodeType nodeType)
517                 {
518                         /* MS doc says:
519                          * (non-white space text, CDATA, Element, EndElement, EntityReference, or EndEntity)
520                          */
521                         switch (nodeType) {
522                         case XmlNodeType.Text:
523                                 return true;
524                         case XmlNodeType.CDATA:
525                                 return true;
526                         case XmlNodeType.Element:
527                                 return true;
528                         case XmlNodeType.EndElement:
529                                 return true;
530                         case XmlNodeType.EntityReference:
531                                 return true;
532                         case XmlNodeType.EndEntity:
533                                 return true;
534                         }
535
536                         return false;
537                 }
538
539                 public virtual XmlNodeType MoveToContent ()
540                 {
541                         if (NodeType == XmlNodeType.Attribute)
542                                 MoveToElement ();
543
544                         do {
545                                 if (IsContent (NodeType))
546                                         return NodeType;
547                                 Read ();
548                         } while (!EOF);
549                         return XmlNodeType.None;
550                 }
551
552                 public abstract bool MoveToElement ();
553
554                 public abstract bool MoveToFirstAttribute ();
555
556                 public abstract bool MoveToNextAttribute ();
557
558                 public abstract bool Read ();
559
560 #if !NET_2_1
561                 public abstract bool ReadAttributeValue ();
562 #endif
563
564                 public virtual string ReadElementString ()
565                 {
566                         if (MoveToContent () != XmlNodeType.Element) {
567                                 string error = String.Format ("'{0}' is an invalid node type.",
568                                                               NodeType.ToString ());
569                                 throw XmlError (error);
570                         }
571
572                         string result = String.Empty;
573                         if (!IsEmptyElement) {
574                                 Read ();
575                                 result = ReadString ();
576                                 if (NodeType != XmlNodeType.EndElement) {
577                                         string error = String.Format ("'{0}' is an invalid node type.",
578                                                                       NodeType.ToString ());
579                                         throw XmlError (error);
580                                 }
581                         }
582
583                         Read ();
584                         return result;
585                 }
586
587                 public virtual string ReadElementString (string name)
588                 {
589                         if (MoveToContent () != XmlNodeType.Element) {
590                                 string error = String.Format ("'{0}' is an invalid node type.",
591                                                               NodeType.ToString ());
592                                 throw XmlError (error);
593                         }
594
595                         if (name != Name) {
596                                 string error = String.Format ("The {0} tag from namespace {1} is expected.",
597                                                               Name, NamespaceURI);
598                                 throw XmlError (error);
599                         }
600
601                         string result = String.Empty;
602                         if (!IsEmptyElement) {
603                                 Read ();
604                                 result = ReadString ();
605                                 if (NodeType != XmlNodeType.EndElement) {
606                                         string error = String.Format ("'{0}' is an invalid node type.",
607                                                                       NodeType.ToString ());
608                                         throw XmlError (error);
609                                 }
610                         }
611
612                         Read ();
613                         return result;
614                 }
615
616                 public virtual string ReadElementString (string localName, string namespaceName)
617                 {
618                         if (MoveToContent () != XmlNodeType.Element) {
619                                 string error = String.Format ("'{0}' is an invalid node type.",
620                                                               NodeType.ToString ());
621                                 throw XmlError (error);
622                         }
623
624                         if (localName != LocalName || NamespaceURI != namespaceName) {
625                                 string error = String.Format ("The {0} tag from namespace {1} is expected.",
626                                                               LocalName, NamespaceURI);
627                                 throw XmlError (error);
628                         }
629
630                         string result = String.Empty;
631                         if (!IsEmptyElement) {
632                                 Read ();
633                                 result = ReadString ();
634                                 if (NodeType != XmlNodeType.EndElement) {
635                                         string error = String.Format ("'{0}' is an invalid node type.",
636                                                                       NodeType.ToString ());
637                                         throw XmlError (error);
638                                 }
639                         }
640
641                         Read ();
642                         return result;
643                 }
644
645                 public virtual void ReadEndElement ()
646                 {
647                         if (MoveToContent () != XmlNodeType.EndElement) {
648                                 string error = String.Format ("'{0}' is an invalid node type.",
649                                                               NodeType.ToString ());
650                                 throw XmlError (error);
651                         }
652
653                         Read ();
654                 }
655
656                 public virtual string ReadInnerXml ()
657                 {
658                         if (ReadState != ReadState.Interactive || NodeType == XmlNodeType.EndElement)
659                                 return String.Empty;
660
661                         if (IsEmptyElement) {
662                                 Read ();
663                                 return String.Empty;
664                         }
665                         StringWriter sw = new StringWriter ();
666                         XmlTextWriter xtw = new XmlTextWriter (sw);
667                         if (NodeType == XmlNodeType.Element) {
668                                 int startDepth = Depth;
669                                 Read ();
670                                 while (startDepth < Depth) {
671                                         if (ReadState != ReadState.Interactive)
672                                                 throw XmlError ("Unexpected end of the XML reader.");
673                                         xtw.WriteNode (this, false);
674                                 }
675                                 // reader is now end element, then proceed once more.
676                                 Read ();
677                         }
678                         else
679                                 xtw.WriteNode (this, false);
680
681                         return sw.ToString ();
682                 }
683
684                 public virtual string ReadOuterXml ()
685                 {
686                         if (ReadState != ReadState.Interactive || NodeType == XmlNodeType.EndElement)
687                                 return String.Empty;
688
689                         switch (NodeType) {
690                         case XmlNodeType.Element:
691                         case XmlNodeType.Attribute:
692                                 StringWriter sw = new StringWriter ();
693                                 XmlTextWriter xtw = new XmlTextWriter (sw);
694                                 xtw.WriteNode (this, false);
695                                 return sw.ToString ();
696                         default:
697                                 Skip ();
698                                 return String.Empty;
699                         }
700                 }
701
702                 public virtual void ReadStartElement ()
703                 {
704                         if (MoveToContent () != XmlNodeType.Element) {
705                                 string error = String.Format ("'{0}' is an invalid node type.",
706                                                               NodeType.ToString ());
707                                 throw XmlError (error);
708                         }
709
710                         Read ();
711                 }
712
713                 public virtual void ReadStartElement (string name)
714                 {
715                         if (MoveToContent () != XmlNodeType.Element) {
716                                 string error = String.Format ("'{0}' is an invalid node type.",
717                                                               NodeType.ToString ());
718                                 throw XmlError (error);
719                         }
720
721                         if (name != Name) {
722                                 string error = String.Format ("The {0} tag from namespace {1} is expected.",
723                                                               Name, NamespaceURI);
724                                 throw XmlError (error);
725                         }
726
727                         Read ();
728                 }
729
730                 public virtual void ReadStartElement (string localName, string namespaceName)
731                 {
732                         if (MoveToContent () != XmlNodeType.Element) {
733                                 string error = String.Format ("'{0}' is an invalid node type.",
734                                                               NodeType.ToString ());
735                                 throw XmlError (error);
736                         }
737
738                         if (localName != LocalName || NamespaceURI != namespaceName) {
739                                 string error = String.Format ("Expecting {0} tag from namespace {1}, got {2} and {3} instead",
740                                                               localName, namespaceName,
741                                                               LocalName, NamespaceURI);
742                                 throw XmlError (error);
743                         }
744
745                         Read ();
746                 }
747
748                 public virtual string ReadString ()
749                 {
750                         if (readStringBuffer == null)
751                                 readStringBuffer = new StringBuilder ();
752                         readStringBuffer.Length = 0;
753
754                         MoveToElement ();
755
756                         switch (NodeType) {
757                         default:
758                                 return String.Empty;
759                         case XmlNodeType.Element:
760                                 if (IsEmptyElement)
761                                         return String.Empty;
762                                 do {
763                                         Read ();
764                                         switch (NodeType) {
765                                         case XmlNodeType.Text:
766                                         case XmlNodeType.CDATA:
767                                         case XmlNodeType.Whitespace:
768                                         case XmlNodeType.SignificantWhitespace:
769                                                 readStringBuffer.Append (Value);
770                                                 continue;
771                                         }
772                                         break;
773                                 } while (true);
774                                 break;
775                         case XmlNodeType.Text:
776                         case XmlNodeType.CDATA:
777                         case XmlNodeType.Whitespace:
778                         case XmlNodeType.SignificantWhitespace:
779                                 do {
780                                         switch (NodeType) {
781                                         case XmlNodeType.Text:
782                                         case XmlNodeType.CDATA:
783                                         case XmlNodeType.Whitespace:
784                                         case XmlNodeType.SignificantWhitespace:
785                                                 readStringBuffer.Append (Value);
786                                                 Read ();
787                                                 continue;
788                                         }
789                                         break;
790                                 } while (true);
791                                 break;
792                         }
793                         string ret = readStringBuffer.ToString ();
794                         readStringBuffer.Length = 0;
795                         return ret;
796                 }
797
798 #if NET_2_0
799                 public virtual Type ValueType {
800                         get { return typeof (string); }
801                 }
802
803                 public virtual bool ReadToDescendant (string name)
804                 {
805                         if (ReadState == ReadState.Initial) {
806                                 MoveToContent ();
807                                 if (IsStartElement (name))
808                                         return true;
809                         }
810                         if (NodeType != XmlNodeType.Element || IsEmptyElement)
811                                 return false;
812                         int depth = Depth;
813                         for (Read (); depth < Depth; Read ())
814                                 if (NodeType == XmlNodeType.Element && name == Name)
815                                         return true;
816                         return false;
817                 }
818
819                 public virtual bool ReadToDescendant (string localName, string namespaceURI)
820                 {
821                         if (ReadState == ReadState.Initial) {
822                                 MoveToContent ();
823                                 if (IsStartElement (localName, namespaceURI))
824                                         return true;
825                         }
826                         if (NodeType != XmlNodeType.Element || IsEmptyElement)
827                                 return false;
828                         int depth = Depth;
829                         for (Read (); depth < Depth; Read ())
830                                 if (NodeType == XmlNodeType.Element && localName == LocalName && namespaceURI == NamespaceURI)
831                                         return true;
832                         return false;
833                 }
834
835                 public virtual bool ReadToFollowing (string name)
836                 {
837                         while (Read ())
838                                 if (NodeType == XmlNodeType.Element && name == Name)
839                                         return true;
840                         return false;
841                 }
842
843                 public virtual bool ReadToFollowing (string localName, string namespaceURI)
844                 {
845                         while (Read ())
846                                 if (NodeType == XmlNodeType.Element && localName == Name && namespaceURI == NamespaceURI)
847                                         return true;
848                         return false;
849                 }
850
851                 public virtual bool ReadToNextSibling (string name)
852                 {
853                         if (ReadState != ReadState.Interactive)
854                                 return false;
855                         int depth = Depth;
856                         Skip ();
857                         for (; !EOF && depth <= Depth; Skip ())
858                                 if (NodeType == XmlNodeType.Element && name == Name)
859                                         return true;
860                         return false;
861                 }
862
863                 public virtual bool ReadToNextSibling (string localName, string namespaceURI)
864                 {
865                         if (ReadState != ReadState.Interactive)
866                                 return false;
867                         int depth = Depth;
868                         Skip ();
869                         for (; !EOF && depth <= Depth; Skip ())
870                                 if (NodeType == XmlNodeType.Element && localName == LocalName && namespaceURI == NamespaceURI)
871                                         return true;
872                         return false;
873                 }
874
875                 public virtual XmlReader ReadSubtree ()
876                 {
877                         return new SubtreeXmlReader (this);
878                 }
879
880                 private string ReadContentString ()
881                 {
882                         if (NodeType == XmlNodeType.Attribute)
883                                 return Value;
884                         return ReadContentString (true);
885                 }
886
887                 private string ReadContentString (bool isText)
888                 {
889                         if (isText) {
890                                 switch (NodeType) {
891                                 case XmlNodeType.Text:
892                                 case XmlNodeType.SignificantWhitespace:
893                                 case XmlNodeType.Whitespace:
894                                 case XmlNodeType.CDATA:
895                                         break;
896                                 default:
897                                         throw new InvalidOperationException (String.Format ("Node type {0} is not supported in this operation.{1}", NodeType, GetLocation ()));
898                                 }
899                         }
900
901                         string value = String.Empty;
902                         do {
903                                 switch (NodeType) {
904                                 case XmlNodeType.Element:
905                                         if (isText)
906                                                 return value;
907                                         throw XmlError ("Child element is not expected in this operation.");
908                                 case XmlNodeType.EndElement:
909                                         return value;
910                                 case XmlNodeType.Text:
911                                 case XmlNodeType.CDATA:
912                                 case XmlNodeType.SignificantWhitespace:
913                                 case XmlNodeType.Whitespace:
914                                         value += Value;
915                                         break;
916                                 }
917                         } while (Read ());
918                         throw XmlError ("Unexpected end of document.");
919                 }
920
921                 string GetLocation ()
922                 {
923                         IXmlLineInfo li = this as IXmlLineInfo;
924                         return li != null && li.HasLineInfo () ?
925                                 String.Format (" {0} (line {1}, column {2})", BaseURI, li.LineNumber, li.LinePosition) : String.Empty;
926                 }
927
928                 [MonoTODO]
929                 public virtual object ReadElementContentAsObject ()
930                 {
931                         return ReadElementContentAs (ValueType, null);
932                 }
933
934                 [MonoTODO]
935                 public virtual object ReadElementContentAsObject (string localName, string namespaceURI)
936                 {
937                         return ReadElementContentAs (ValueType, null, localName, namespaceURI);
938                 }
939
940                 [MonoTODO]
941                 public virtual object ReadContentAsObject ()
942                 {
943                         return ReadContentAs (ValueType, null);
944                 }
945
946                 public virtual object ReadElementContentAs (Type type, IXmlNamespaceResolver resolver)
947                 {
948                         bool isEmpty = IsEmptyElement;
949                         ReadStartElement ();
950                         object obj = ValueAs (isEmpty ? String.Empty : ReadContentString (false), type, resolver);
951                         if (!isEmpty)
952                                 ReadEndElement ();
953                         return obj;
954                 }
955
956                 public virtual object ReadElementContentAs (Type type, IXmlNamespaceResolver resolver, string localName, string namespaceURI)
957                 {
958                         ReadStartElement (localName, namespaceURI);
959                         object obj = ReadContentAs (type, resolver);
960                         ReadEndElement ();
961                         return obj;
962                 }
963
964                 public virtual object ReadContentAs (Type type, IXmlNamespaceResolver resolver)
965                 {
966                         return ValueAs (ReadContentString (), type, resolver);
967                 }
968
969                 private object ValueAs (string text, Type type, IXmlNamespaceResolver resolver)
970                 {
971                         try {
972                                 if (type == typeof (object))
973                                         return text;
974                                 if (type == typeof (XmlQualifiedName)) {
975                                         if (resolver != null)
976                                                 return XmlQualifiedName.Parse (text, resolver);
977                                         else
978                                                 return XmlQualifiedName.Parse (text, this);
979                                 }
980
981                                 switch (Type.GetTypeCode (type)) {
982                                 case TypeCode.Boolean:
983                                         return XQueryConvert.StringToBoolean (text);
984                                 case TypeCode.DateTime:
985                                         return XQueryConvert.StringToDateTime (text);
986                                 case TypeCode.Decimal:
987                                         return XQueryConvert.StringToDecimal (text);
988                                 case TypeCode.Double:
989                                         return XQueryConvert.StringToDouble (text);
990                                 case TypeCode.Int32:
991                                         return XQueryConvert.StringToInt (text);
992                                 case TypeCode.Int64:
993                                         return XQueryConvert.StringToInteger (text);
994                                 case TypeCode.Single:
995                                         return XQueryConvert.StringToFloat (text);
996                                 case TypeCode.String:
997                                         return text;
998                                 }
999                         } catch (Exception ex) {
1000                                 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);
1001                         }
1002                         throw new ArgumentException (String.Format ("Specified type '{0}' is not supported.", type));
1003                 }
1004
1005                 public virtual bool ReadElementContentAsBoolean ()
1006                 {
1007                         try {
1008                                 return XQueryConvert.StringToBoolean (ReadElementContentAsString ());
1009                         } catch (FormatException ex) {
1010                                 throw XmlError ("Typed value is invalid.", ex);
1011                         }
1012                 }
1013
1014                 public virtual DateTime ReadElementContentAsDateTime ()
1015                 {
1016                         try {
1017                                 return XQueryConvert.StringToDateTime (ReadElementContentAsString ());
1018                         } catch (FormatException ex) {
1019                                 throw XmlError ("Typed value is invalid.", ex);
1020                         }
1021                 }
1022
1023                 public virtual decimal ReadElementContentAsDecimal ()
1024                 {
1025                         try {
1026                                 return XQueryConvert.StringToDecimal (ReadElementContentAsString ());
1027                         } catch (FormatException ex) {
1028                                 throw XmlError ("Typed value is invalid.", ex);
1029                         }
1030                 }
1031
1032                 public virtual double ReadElementContentAsDouble ()
1033                 {
1034                         try {
1035                                 return XQueryConvert.StringToDouble (ReadElementContentAsString ());
1036                         } catch (FormatException ex) {
1037                                 throw XmlError ("Typed value is invalid.", ex);
1038                         }
1039                 }
1040
1041                 public virtual float ReadElementContentAsFloat ()
1042                 {
1043                         try {
1044                                 return XQueryConvert.StringToFloat (ReadElementContentAsString ());
1045                         } catch (FormatException ex) {
1046                                 throw XmlError ("Typed value is invalid.", ex);
1047                         }
1048                 }
1049
1050                 public virtual int ReadElementContentAsInt ()
1051                 {
1052                         try {
1053                                 return XQueryConvert.StringToInt (ReadElementContentAsString ());
1054                         } catch (FormatException ex) {
1055                                 throw XmlError ("Typed value is invalid.", ex);
1056                         }
1057                 }
1058
1059                 public virtual long ReadElementContentAsLong ()
1060                 {
1061                         try {
1062                                 return XQueryConvert.StringToInteger (ReadElementContentAsString ());
1063                         } catch (FormatException ex) {
1064                                 throw XmlError ("Typed value is invalid.", ex);
1065                         }
1066                 }
1067
1068                 public virtual string ReadElementContentAsString ()
1069                 {
1070                         bool isEmpty = IsEmptyElement;
1071                         ReadStartElement ();
1072                         if (isEmpty)
1073                                 return String.Empty;
1074                         string s = ReadContentString (false);
1075                         ReadEndElement ();
1076                         return s;
1077                 }
1078
1079                 public virtual bool ReadElementContentAsBoolean (string localName, string namespaceURI)
1080                 {
1081                         try {
1082                                 return XQueryConvert.StringToBoolean (ReadElementContentAsString (localName, namespaceURI));
1083                         } catch (FormatException ex) {
1084                                 throw XmlError ("Typed value is invalid.", ex);
1085                         }
1086                 }
1087
1088                 public virtual DateTime ReadElementContentAsDateTime (string localName, string namespaceURI)
1089                 {
1090                         try {
1091                                 return XQueryConvert.StringToDateTime (ReadElementContentAsString (localName, namespaceURI));
1092                         } catch (FormatException ex) {
1093                                 throw XmlError ("Typed value is invalid.", ex);
1094                         }
1095                 }
1096
1097                 public virtual decimal ReadElementContentAsDecimal (string localName, string namespaceURI)
1098                 {
1099                         try {
1100                                 return XQueryConvert.StringToDecimal (ReadElementContentAsString (localName, namespaceURI));
1101                         } catch (FormatException ex) {
1102                                 throw XmlError ("Typed value is invalid.", ex);
1103                         }
1104                 }
1105
1106                 public virtual double ReadElementContentAsDouble (string localName, string namespaceURI)
1107                 {
1108                         try {
1109                                 return XQueryConvert.StringToDouble (ReadElementContentAsString (localName, namespaceURI));
1110                         } catch (FormatException ex) {
1111                                 throw XmlError ("Typed value is invalid.", ex);
1112                         }
1113                 }
1114
1115                 public virtual float ReadElementContentAsFloat (string localName, string namespaceURI)
1116                 {
1117                         try {
1118                                 return XQueryConvert.StringToFloat (ReadElementContentAsString (localName, namespaceURI));
1119                         } catch (FormatException ex) {
1120                                 throw XmlError ("Typed value is invalid.", ex);
1121                         }
1122                 }
1123
1124                 public virtual int ReadElementContentAsInt (string localName, string namespaceURI)
1125                 {
1126                         try {
1127                                 return XQueryConvert.StringToInt (ReadElementContentAsString (localName, namespaceURI));
1128                         } catch (FormatException ex) {
1129                                 throw XmlError ("Typed value is invalid.", ex);
1130                         }
1131                 }
1132
1133                 public virtual long ReadElementContentAsLong (string localName, string namespaceURI)
1134                 {
1135                         try {
1136                                 return XQueryConvert.StringToInteger (ReadElementContentAsString (localName, namespaceURI));
1137                         } catch (FormatException ex) {
1138                                 throw XmlError ("Typed value is invalid.", ex);
1139                         }
1140                 }
1141
1142                 public virtual string ReadElementContentAsString (string localName, string namespaceURI)
1143                 {
1144                         bool isEmpty = IsEmptyElement;
1145                         ReadStartElement (localName, namespaceURI);
1146                         if (isEmpty)
1147                                 return String.Empty;
1148                         string s = ReadContentString (false);
1149                         ReadEndElement ();
1150                         return s;
1151                 }
1152
1153                 public virtual bool ReadContentAsBoolean ()
1154                 {
1155                         try {
1156                                 return XQueryConvert.StringToBoolean (ReadContentString ());
1157                         } catch (FormatException ex) {
1158                                 throw XmlError ("Typed value is invalid.", ex);
1159                         }
1160                 }
1161
1162                 public virtual DateTime ReadContentAsDateTime ()
1163                 {
1164                         try {
1165                                 return XQueryConvert.StringToDateTime (ReadContentString ());
1166                         } catch (FormatException ex) {
1167                                 throw XmlError ("Typed value is invalid.", ex);
1168                         }
1169                 }
1170
1171                 public virtual decimal ReadContentAsDecimal ()
1172                 {
1173                         try {
1174                                 return XQueryConvert.StringToDecimal (ReadContentString ());
1175                         } catch (FormatException ex) {
1176                                 throw XmlError ("Typed value is invalid.", ex);
1177                         }
1178                 }
1179
1180                 public virtual double ReadContentAsDouble ()
1181                 {
1182                         try {
1183                                 return XQueryConvert.StringToDouble (ReadContentString ());
1184                         } catch (FormatException ex) {
1185                                 throw XmlError ("Typed value is invalid.", ex);
1186                         }
1187                 }
1188
1189                 public virtual float ReadContentAsFloat ()
1190                 {
1191                         try {
1192                                 return XQueryConvert.StringToFloat (ReadContentString ());
1193                         } catch (FormatException ex) {
1194                                 throw XmlError ("Typed value is invalid.", ex);
1195                         }
1196                 }
1197
1198                 public virtual int ReadContentAsInt ()
1199                 {
1200                         try {
1201                                 return XQueryConvert.StringToInt (ReadContentString ());
1202                         } catch (FormatException ex) {
1203                                 throw XmlError ("Typed value is invalid.", ex);
1204                         }
1205                 }
1206
1207                 public virtual long ReadContentAsLong ()
1208                 {
1209                         try {
1210                                 return XQueryConvert.StringToInteger (ReadContentString ());
1211                         } catch (FormatException ex) {
1212                                 throw XmlError ("Typed value is invalid.", ex);
1213                         }
1214                 }
1215
1216                 public virtual string ReadContentAsString ()
1217                 {
1218                         return ReadContentString ();
1219                 }
1220
1221                 public virtual int ReadContentAsBase64 (
1222                         byte [] buffer, int offset, int length)
1223                 {
1224                         CheckSupport ();
1225                         return binary.ReadContentAsBase64 (
1226                                 buffer, offset, length);
1227                 }
1228
1229                 public virtual int ReadContentAsBinHex (
1230                         byte [] buffer, int offset, int length)
1231                 {
1232                         CheckSupport ();
1233                         return binary.ReadContentAsBinHex (
1234                                 buffer, offset, length);
1235                 }
1236
1237                 public virtual int ReadElementContentAsBase64 (
1238                         byte [] buffer, int offset, int length)
1239                 {
1240                         CheckSupport ();
1241                         return binary.ReadElementContentAsBase64 (
1242                                 buffer, offset, length);
1243                 }
1244
1245                 public virtual int ReadElementContentAsBinHex (
1246                         byte [] buffer, int offset, int length)
1247                 {
1248                         CheckSupport ();
1249                         return binary.ReadElementContentAsBinHex (
1250                                 buffer, offset, length);
1251                 }
1252 #endif
1253
1254 #if NET_2_0
1255                 public virtual int ReadValueChunk (
1256                         char [] buffer, int offset, int length)
1257 #else
1258                 internal virtual int ReadValueChunk (
1259                         char [] buffer, int offset, int length)
1260 #endif
1261                 {
1262                         if (!CanReadValueChunk)
1263                                 throw new NotSupportedException ();
1264                         if (binary == null)
1265                                 binary = new XmlReaderBinarySupport (this);
1266                         return binary.ReadValueChunk (buffer, offset, length);
1267                 }
1268
1269                 private void CheckSupport ()
1270                 {
1271                         // Default implementation expects both.
1272                         if (!CanReadBinaryContent || !CanReadValueChunk)
1273                                 throw new NotSupportedException ();
1274                         if (binary == null)
1275                                 binary = new XmlReaderBinarySupport (this);
1276                 }
1277
1278 #if !NET_2_1
1279                 public abstract void ResolveEntity ();
1280 #endif
1281
1282                 public virtual void Skip ()
1283                 {
1284                         if (ReadState != ReadState.Interactive)
1285                                 return;
1286
1287                         MoveToElement ();
1288                         if (NodeType != XmlNodeType.Element || IsEmptyElement) {
1289                                 Read ();
1290                                 return;
1291                         }
1292                                 
1293                         int depth = Depth;
1294                         while (Read () && depth < Depth)
1295                                 ;
1296                         if (NodeType == XmlNodeType.EndElement)
1297                                 Read ();
1298                 }
1299
1300                 private XmlException XmlError (string message)
1301                 {
1302                         return new XmlException (this as IXmlLineInfo, BaseURI, message);
1303                 }
1304
1305                 private XmlException XmlError (string message, Exception innerException)
1306                 {
1307                         return new XmlException (this as IXmlLineInfo, BaseURI, message);
1308                 }
1309
1310                 #endregion
1311         }
1312 }