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