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