2004-10-18 Atsushi Enomoto <atsushi@ximian.com>
[mono.git] / mcs / class / System.XML / System.Xml / XmlTextReader.cs
1 //
2 // System.Xml.XmlTextReader
3 //
4 // Author:
5 //   Jason Diamond (jason@injektilo.org)
6 //   Adam Treat (manyoso@yahoo.com)
7 //   Atsushi Enomoto  (ginga@kit.hi-ho.ne.jp)
8 //
9 // (C) 2001, 2002 Jason Diamond  http://injektilo.org/
10 //
11
12 //
13 // Permission is hereby granted, free of charge, to any person obtaining
14 // a copy of this software and associated documentation files (the
15 // "Software"), to deal in the Software without restriction, including
16 // without limitation the rights to use, copy, modify, merge, publish,
17 // distribute, sublicense, and/or sell copies of the Software, and to
18 // permit persons to whom the Software is furnished to do so, subject to
19 // the following conditions:
20 // 
21 // The above copyright notice and this permission notice shall be
22 // included in all copies or substantial portions of the Software.
23 // 
24 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
25 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
26 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
27 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
28 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
29 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
30 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
31 //
32
33 // FIXME:
34 //
35 //   Some thought needs to be given to performance.
36 //
37 //   If current node is on an Attribute, Prefix might be null, and
38 //   in several fields which uses XmlReader, it should be considered.
39 //
40
41 using System;
42 using System.Collections;
43 using System.Globalization;
44 using System.IO;
45 using System.Security.Policy;
46 using System.Text;
47 using System.Xml.Schema;
48 using Mono.Xml;
49
50 namespace System.Xml
51 {
52 #if NET_2_0
53         public class XmlTextReader : XmlReader,
54                 IXmlLineInfo, IXmlNamespaceResolver
55 #else
56         public class XmlTextReader : XmlReader, IXmlLineInfo
57 #endif
58         {
59                 #region Constructors
60
61                 protected XmlTextReader ()
62                 {
63                 }
64
65                 public XmlTextReader (Stream input)
66                         : this (new XmlStreamReader (input))
67                 {
68                 }
69
70                 public XmlTextReader (string url)
71                         : this(url, new NameTable ())
72                 {
73                 }
74
75                 public XmlTextReader (TextReader input)
76                         : this (input, new NameTable ())
77                 {
78                 }
79
80                 protected XmlTextReader (XmlNameTable nt)
81                         : this (String.Empty, null, XmlNodeType.None, null)
82                 {
83                 }
84
85                 public XmlTextReader (Stream input, XmlNameTable nt)
86                         : this(new XmlStreamReader (input), nt)
87                 {
88                 }
89
90                 public XmlTextReader (string url, Stream input)
91                         : this (url, new XmlStreamReader (input))
92                 {
93                 }
94
95                 public XmlTextReader (string url, TextReader input)
96                         : this (url, input, new NameTable ())
97                 {
98                 }
99
100                 public XmlTextReader (string url, XmlNameTable nt)
101                 {
102                         Uri uri = resolver.ResolveUri (null, url);
103                         Stream s = resolver.GetEntity (uri, null, typeof (Stream)) as Stream;
104                         XmlParserContext ctx = new XmlParserContext (nt,
105                                 new XmlNamespaceManager (nt),
106                                 String.Empty,
107                                 XmlSpace.None);
108                         this.InitializeContext (uri.ToString(), ctx, new XmlStreamReader (s), XmlNodeType.Document);
109                 }
110
111                 public XmlTextReader (TextReader input, XmlNameTable nt)
112                         : this (String.Empty, input, nt)
113                 {
114                 }
115
116                 public XmlTextReader (Stream xmlFragment, XmlNodeType fragType, XmlParserContext context)
117                         : this (context != null ? context.BaseURI : String.Empty,
118                                 new XmlStreamReader (xmlFragment),
119                         fragType,
120                         context)
121                 {
122                 }
123
124                 public XmlTextReader (string url, Stream input, XmlNameTable nt)
125                         : this (url, new XmlStreamReader (input), nt)
126                 {
127                 }
128
129                 public XmlTextReader (string url, TextReader input, XmlNameTable nt)
130                         : this (url, input, XmlNodeType.Document, null)
131                 {
132                 }
133
134                 public XmlTextReader (string xmlFragment, XmlNodeType fragType, XmlParserContext context)
135                         : this (context != null ? context.BaseURI : String.Empty,
136                                 new StringReader (xmlFragment),
137                                 fragType,
138                                 context)
139                 {
140                 }
141
142                 XmlTextReader (string url, TextReader fragment, XmlNodeType fragType, XmlParserContext context)
143                 {
144                         InitializeContext (url, context, fragment, fragType);
145                 }
146
147                 #endregion
148
149                 #region Properties
150
151                 public override int AttributeCount
152                 {
153                         get { return attributeCount; }
154                 }
155
156                 public override string BaseURI
157                 {
158                         get { return parserContext.BaseURI; }
159                 }
160
161 #if NET_2_0
162                 public override bool CanResolveEntity {
163                         get { return true; }
164                 }
165
166 #endif
167
168                 internal bool CharacterChecking {
169                         get { return checkCharacters && normalization; }
170                         set { checkCharacters = value; }
171                 }
172
173                 // for XmlReaderSettings.CloseInput support
174                 internal bool CloseInput {
175                         get { return closeInput; }
176                         set { closeInput = value; }
177                 }
178
179                 public override int Depth
180                 {
181                         get {
182                                 int nodeTypeMod = currentToken.NodeType == XmlNodeType.Element  ? 0 : -1;
183                                 if (currentAttributeValue >= 0)
184                                         return nodeTypeMod + elementDepth + 2; // inside attribute value.
185                                 else if (currentAttribute >= 0)
186                                         return nodeTypeMod + elementDepth + 1;
187                                 return elementDepth;
188                         }
189                 }
190
191                 public Encoding Encoding
192                 {
193                         get { return parserContext.Encoding; }
194                 }
195 #if NET_2_0
196                 [MonoTODO]
197                 public EntityHandling EntityHandling {
198                         get { return entityHandling; }
199                         set { entityHandling = value; }
200                 }
201 #endif
202
203                 public override bool EOF {
204                         get { return readState == ReadState.EndOfFile; }
205                 }
206
207 #if NET_2_0
208                 [MonoTODO]
209                 public override Evidence Evidence {
210                         get { return base.Evidence; }
211                 }
212 #endif
213
214                 public override bool HasValue {
215                         get { return cursorToken.Value != null; }
216                 }
217
218                 public override bool IsDefault {
219                         // XmlTextReader does not expand default attributes.
220                         get { return false; }
221                 }
222
223                 public override bool IsEmptyElement {
224                         get { return cursorToken.IsEmptyElement; }
225                 }
226
227                 public override string this [int i] {
228                         get { return GetAttribute (i); }
229                 }
230
231                 public override string this [string name] {
232                         get { return GetAttribute (name); }
233                 }
234
235                 public override string this [string localName, string namespaceName] {
236                         get { return GetAttribute (localName, namespaceName); }
237                 }
238
239                 public int LineNumber {
240                         get {
241                                 if (useProceedingLineInfo)
242                                         return line;
243                                 else
244                                         return cursorToken.LineNumber;
245                         }
246                 }
247
248                 public int LinePosition {
249                         get {
250                                 if (useProceedingLineInfo)
251                                         return column;
252                                 else
253                                         return cursorToken.LinePosition;
254                         }
255                 }
256
257                 public override string LocalName {
258                         get { return cursorToken.LocalName; }
259                 }
260
261                 public override string Name {
262                         get { return cursorToken.Name; }
263                 }
264
265                 public bool Namespaces {
266                         get { return namespaces; }
267                         set { 
268                                 if (readState != ReadState.Initial)
269                                         throw new InvalidOperationException ("Namespaces have to be set before reading.");
270                                 namespaces = value;
271                         }
272                 }
273
274                 public override string NamespaceURI {
275                         get { return cursorToken.NamespaceURI; }
276                 }
277
278                 public override XmlNameTable NameTable {
279                         get { return parserContext.NameTable; }
280                 }
281
282                 public override XmlNodeType NodeType {
283                         get { return cursorToken.NodeType; }
284                 }
285
286                 public bool Normalization {
287                         get { return normalization; }
288                         set { normalization = value; }
289                 }
290
291                 public override string Prefix {
292                         get { return cursorToken.Prefix; }
293                 }
294
295 #if NET_2_0
296                 public bool ProhibitDtd {
297                         get { return prohibitDtd; }
298                         set { prohibitDtd = value; }
299                 }
300 #endif
301
302                 public override char QuoteChar {
303                         get { return cursorToken.QuoteChar; }
304                 }
305
306                 public override ReadState ReadState {
307                         get { return readState; }
308                 }
309
310 #if NET_2_0
311                 public override XmlReaderSettings Settings {
312                         get { return base.Settings; }
313                 }
314 #endif
315
316                 public override string Value {
317                         get { return cursorToken.Value != null ? cursorToken.Value : String.Empty; }
318                 }
319
320                 public WhitespaceHandling WhitespaceHandling {
321                         get { return whitespaceHandling; }
322                         set { whitespaceHandling = value; }
323                 }
324
325                 public override string XmlLang {
326                         get { return parserContext.XmlLang; }
327                 }
328
329                 public XmlResolver XmlResolver {
330                         set { resolver = value; }
331                 }
332
333                 public override XmlSpace XmlSpace {
334                         get { return parserContext.XmlSpace; }
335                 }
336
337                 #endregion
338
339                 #region Methods
340
341                 public override void Close ()
342                 {
343                         readState = ReadState.Closed;
344
345                         cursorToken.Clear ();
346                         currentToken.Clear ();
347                         attributeCount = 0;
348                         if (closeInput && reader != null)
349                                 reader.Close ();
350                 }
351
352                 public override string GetAttribute (int i)
353                 {
354                         if (i >= attributeCount)
355                                 throw new ArgumentOutOfRangeException ("i is smaller than AttributeCount");
356                         else {
357                                 return attributeTokens [i].Value;
358                         }
359                 }
360
361                 // MS.NET 1.0 msdn says that this method returns String.Empty
362                 // for absent attribute, but in fact it returns null.
363                 // This description is corrected in MS.NET 1.1 msdn.
364                 public override string GetAttribute (string name)
365                 {
366                         for (int i = 0; i < attributeCount; i++)
367                                 if (attributeTokens [i].Name == name)
368                                         return attributeTokens [i].Value;
369                         return null;
370                 }
371
372                 private int GetIndexOfQualifiedAttribute (string localName, string namespaceURI)
373                 {
374                         for (int i = 0; i < attributeCount; i++) {
375                                 XmlAttributeTokenInfo ti = attributeTokens [i];
376                                 if (ti.LocalName == localName && ti.NamespaceURI == namespaceURI)
377                                         return i;
378                         }
379                         return -1;
380                 }
381
382                 internal XmlParserContext GetInternalParserContext ()
383                 {
384                         return parserContext;
385                 }
386
387                 public override string GetAttribute (string localName, string namespaceURI)
388                 {
389                         int idx = this.GetIndexOfQualifiedAttribute (localName, namespaceURI);
390                         if (idx < 0)
391                                 return null;
392                         return attributeTokens [idx].Value;
393                 }
394
395 #if NET_2_0
396                 public IDictionary GetNamespacesInScope (XmlNamespaceScope scope)
397                 {
398                         return parserContext.NamespaceManager.GetNamespacesInScope (scope);
399                 }
400 #endif
401
402                 public TextReader GetRemainder ()
403                 {
404                         if (peekCharsIndex == peekCharsLength)
405                                 return reader;
406                         return new StringReader (new string (peekChars, peekCharsIndex, peekCharsLength - peekCharsIndex) + reader.ReadToEnd ());
407                 }
408
409 #if NET_2_0
410                 public bool HasLineInfo ()
411 #else
412                 bool IXmlLineInfo.HasLineInfo ()
413 #endif
414                 {
415                         return true;
416                 }
417
418                 public override string LookupNamespace (string prefix)
419                 {
420                         return LookupNamespace (prefix, false);
421                 }
422
423 #if NET_2_0
424                 public override string LookupNamespace (string prefix, bool atomizedName)
425 #else
426                 internal override string LookupNamespace (string prefix, bool atomizedName)
427 #endif
428                 {
429                         return parserContext.NamespaceManager.LookupNamespace (prefix, atomizedName);
430                 }
431
432 #if NET_2_0
433                 string IXmlNamespaceResolver.LookupPrefix (string ns)
434                 {
435                         return LookupPrefix (ns, false);
436                 }
437
438                 public string LookupPrefix (string ns, bool atomizedName)
439                 {
440                         return parserContext.NamespaceManager.LookupPrefix (ns, atomizedName);
441                 }
442 #endif
443
444                 public override void MoveToAttribute (int i)
445                 {
446                         if (i >= attributeCount)
447                                 throw new ArgumentOutOfRangeException ("attribute index out of range.");
448
449                         currentAttribute = i;
450                         currentAttributeValue = -1;
451                         cursorToken = attributeTokens [i];
452                 }
453
454                 public override bool MoveToAttribute (string name)
455                 {
456                         for (int i = 0; i < attributeCount; i++) {
457                                 XmlAttributeTokenInfo ti = attributeTokens [i];
458                                 if (ti.Name == name) {
459                                         MoveToAttribute (i);
460                                         return true;
461                                 }
462                         }
463                         return false;
464                 }
465
466                 public override bool MoveToAttribute (string localName, string namespaceName)
467                 {
468                         int idx = GetIndexOfQualifiedAttribute (localName, namespaceName);
469                         if (idx < 0)
470                                 return false;
471                         MoveToAttribute (idx);
472                         return true;
473                 }
474
475                 public override bool MoveToElement ()
476                 {
477                         if (currentToken == null)       // for attribute .ctor()
478                                 return false;
479
480                         if (cursorToken == currentToken)
481                                 return false;
482
483                         if (currentAttribute >= 0) {
484                                 currentAttribute = -1;
485                                 currentAttributeValue = -1;
486                                 cursorToken = currentToken;
487                                 return true;
488                         }
489                         else
490                                 return false;
491                 }
492
493                 public override bool MoveToFirstAttribute ()
494                 {
495                         if (attributeCount == 0)
496                                 return false;
497                         MoveToElement ();
498                         return MoveToNextAttribute ();
499                 }
500
501                 public override bool MoveToNextAttribute ()
502                 {
503                         if (currentAttribute == 0 && attributeCount == 0)
504                                 return false;
505                         if (currentAttribute + 1 < attributeCount) {
506                                 currentAttribute++;
507                                 currentAttributeValue = -1;
508                                 cursorToken = attributeTokens [currentAttribute];
509                                 return true;
510                         }
511                         else
512                                 return false;
513                 }
514
515                 public override bool Read ()
516                 {
517                         if (startNodeType == XmlNodeType.Attribute) {
518                                 if (currentAttribute == 0)
519                                         return false;   // already read.
520                                 ClearAttributes ();
521                                 IncrementAttributeToken ();
522                                 ReadAttributeValueTokens ('"');
523                                 cursorToken = attributeTokens [0];
524                                 currentAttributeValue = -1;
525                                 readState = ReadState.Interactive;
526                                 return true;
527                         }
528
529                         bool more = false;
530                         readState = ReadState.Interactive;
531                         currentLinkedNodeLineNumber = line;
532                         currentLinkedNodeLinePosition = column;
533                         useProceedingLineInfo = true;
534
535                         cursorToken = currentToken;
536                         attributeCount = 0;
537                         currentAttribute = currentAttributeValue = -1;
538                         currentToken.Clear ();
539
540                         // It was moved from end of ReadStartTag ().
541                         if (depthUp) {
542                                 ++depth;
543                                 depthUp = false;
544                         }
545
546                         if (shouldSkipUntilEndTag) {
547                                 shouldSkipUntilEndTag = false;
548                                 return ReadUntilEndTag ();
549                         }
550
551                         base64CacheStartsAt = -1;
552
553                         more = ReadContent ();
554
555                         if (!more && startNodeType == XmlNodeType.Document && currentState != XmlNodeType.EndElement)
556                                 throw new XmlException ("Document element did not appear.");
557
558                         useProceedingLineInfo = false;
559                         return more;
560                 }
561
562                 public override bool ReadAttributeValue ()
563                 {
564                         if (readState == ReadState.Initial && startNodeType == XmlNodeType.Attribute) {
565                                 Read ();
566                         }
567
568                         if (currentAttribute < 0)
569                                 return false;
570                         XmlAttributeTokenInfo ti = attributeTokens [currentAttribute];
571                         if (currentAttributeValue < 0)
572                                 currentAttributeValue = ti.ValueTokenStartIndex - 1;
573
574                         if (currentAttributeValue < ti.ValueTokenEndIndex) {
575                                 currentAttributeValue++;
576                                 cursorToken = attributeValueTokens [currentAttributeValue];
577                                 return true;
578                         }
579                         else
580                                 return false;
581                 }
582
583                 private int SkipIgnorableBase64Chars (char [] chars, int charsLength, int i)
584                 {
585                         while (chars [i] == '=' || XmlChar.IsWhitespace (chars [i]))
586                                 if (charsLength == ++i)
587                                         break;
588                         return i;
589                 }
590
591                 public int ReadBase64 (byte [] buffer, int offset, int length)
592                 {
593                         if (offset < 0)
594                                 throw new ArgumentOutOfRangeException ("offset", offset, "Offset must be non-negative integer.");
595                         else if (length < 0)
596                                 throw new ArgumentOutOfRangeException ("length", length, "Length must be non-negative integer.");
597                         else if (buffer.Length < offset + length)
598                                 throw new ArgumentOutOfRangeException ("buffer length is smaller than the sum of offset and length.");
599
600                         if (length == 0)        // It does not raise an error.
601                                 return 0;
602
603                         int bufIndex = offset;
604                         int bufLast = offset + length;
605
606                         if (base64CacheStartsAt >= 0) {
607                                 for (int i = base64CacheStartsAt; i < 3; i++) {
608                                         buffer [bufIndex++] = base64Cache [base64CacheStartsAt++];
609                                         if (bufIndex == bufLast)
610                                                 return bufLast - offset;
611                                 }
612                         }
613
614                         for (int i = 0; i < 3; i++)
615                                 base64Cache [i] = 0;
616                         base64CacheStartsAt = -1;
617
618                         int max = (int) System.Math.Ceiling (4.0 / 3 * length);
619                         int additional = max % 4;
620                         if (additional > 0)
621                                 max += 4 - additional;
622                         char [] chars = new char [max];
623                         int charsLength = ReadChars (chars, 0, max);
624
625                         byte b = 0;
626                         byte work = 0;
627                         bool loop = true;
628                         for (int i = 0; i < charsLength - 3; i++) {
629                                 if ((i = SkipIgnorableBase64Chars (chars, charsLength, i)) == charsLength)
630                                         break;
631                                 b = (byte) (GetBase64Byte (chars [i]) << 2);
632                                 if (bufIndex < bufLast)
633                                         buffer [bufIndex] = b;
634                                 else {
635                                         if (base64CacheStartsAt < 0)
636                                                 base64CacheStartsAt = 0;
637                                         base64Cache [0] = b;
638                                 }
639                                 // charsLength mod 4 might not equals to 0.
640                                 if (++i == charsLength)
641                                         break;
642                                 if ((i = SkipIgnorableBase64Chars (chars, charsLength, i))  == charsLength)
643                                         break;
644                                 b = GetBase64Byte (chars [i]);
645                                 work = (byte) (b >> 4);
646                                 if (bufIndex < bufLast) {
647                                         buffer [bufIndex] += work;
648                                         bufIndex++;
649                                 }
650                                 else
651                                         base64Cache [0] += work;
652
653                                 work = (byte) ((b & 0xf) << 4);
654                                 if (bufIndex < bufLast) {
655                                         buffer [bufIndex] = work;
656                                 }
657                                 else {
658                                         if (base64CacheStartsAt < 0)
659                                                 base64CacheStartsAt = 1;
660                                         base64Cache [1] = work;
661                                 }
662
663                                 if (++i == charsLength)
664                                         break;
665                                 if ((i = SkipIgnorableBase64Chars (chars, charsLength, i)) == charsLength)
666                                         break;
667                                 b = GetBase64Byte (chars [i]);
668                                 work = (byte) (b >> 2);
669                                 if (bufIndex < bufLast) {
670                                         buffer [bufIndex] += work;
671                                         bufIndex++;
672                                 }
673                                 else
674                                         base64Cache [1] += work;
675
676                                 work = (byte) ((b & 3) << 6);
677                                 if (bufIndex < bufLast)
678                                         buffer [bufIndex] = work;
679                                 else {
680                                         if (base64CacheStartsAt < 0)
681                                                 base64CacheStartsAt = 2;
682                                         base64Cache [2] = work;
683                                 }
684                                 if (++i == charsLength)
685                                         break;
686                                 if ((i = SkipIgnorableBase64Chars (chars, charsLength, i)) == charsLength)
687                                         break;
688                                 work = GetBase64Byte (chars [i]);
689                                 if (bufIndex < bufLast) {
690                                         buffer [bufIndex] += work;
691                                         bufIndex++;
692                                 }
693                                 else
694                                         base64Cache [2] += work;
695                         }
696                         return System.Math.Min (bufLast - offset, bufIndex - offset);
697                 }
698
699                 public int ReadBinHex (byte [] buffer, int offset, int length)
700                 {
701                         if (offset < 0)
702                                 throw new ArgumentOutOfRangeException ("offset", offset, "Offset must be non-negative integer.");
703                         else if (length < 0)
704                                 throw new ArgumentOutOfRangeException ("length", length, "Length must be non-negative integer.");
705                         else if (buffer.Length < offset + length)
706                                 throw new ArgumentOutOfRangeException ("buffer length is smaller than the sum of offset and length.");
707
708                         if (length == 0)
709                                 return 0;
710
711                         char [] chars = new char [length * 2];
712                         int charsLength = ReadChars (chars, 0, length * 2);
713                         return XmlConvert.FromBinHexString (chars, offset, charsLength, buffer);
714                 }
715
716                 public int ReadChars (char [] buffer, int offset, int length)
717                 {
718                         return ReadCharsInternal (buffer, offset, length);
719                 }
720
721 #if NET_2_0
722                 public override string ReadString ()
723                 {
724                         return ReadStringInternal ();
725                 }
726 #elif NET_1_1
727 #else
728                 public override string ReadInnerXml ()
729                 {
730                         return ReadInnerXmlInternal ();
731                 }
732
733                 public override string ReadOuterXml ()
734                 {
735                         return ReadOuterXmlInternal ();
736                 }
737
738                 public override string ReadString ()
739                 {
740                         return ReadStringInternal ();
741                 }
742 #endif
743
744                 public void ResetState ()
745                 {
746                         throw new InvalidOperationException ("Cannot call ResetState when parsing an XML fragment.");
747                         Init ();
748                 }
749
750 #if NET_2_0
751                 [MonoTODO]
752                 public override bool ReadValueAsBoolean ()
753                 {
754                         return base.ReadValueAsBoolean ();
755                 }
756
757                 [MonoTODO]
758                 public override DateTime ReadValueAsDateTime ()
759                 {
760                         return base.ReadValueAsDateTime ();
761                 }
762
763                 [MonoTODO]
764                 public override decimal ReadValueAsDecimal ()
765                 {
766                         return base.ReadValueAsDecimal ();
767                 }
768
769                 [MonoTODO]
770                 public override double ReadValueAsDouble ()
771                 {
772                         return base.ReadValueAsDouble ();
773                 }
774
775                 [MonoTODO]
776                 public override int ReadValueAsInt32 ()
777                 {
778                         return base.ReadValueAsInt32 ();
779                 }
780
781                 [MonoTODO]
782                 public override long ReadValueAsInt64 ()
783                 {
784                         return base.ReadValueAsInt64 ();
785                 }
786
787                 [MonoTODO]
788                 public override ICollection ReadValueAsList ()
789                 {
790                         return base.ReadValueAsList ();
791                 }
792
793                 [MonoTODO]
794                 public override float ReadValueAsSingle ()
795                 {
796                         return base.ReadValueAsSingle ();
797                 }
798
799                 [MonoTODO]
800                 public override string ReadValueAsString ()
801                 {
802                         return ReadString ();
803                 }
804
805                 [MonoTODO]
806                 public override object ReadValueAs (Type type)
807                 {
808                         return base.ReadValueAs (type);
809                 }
810
811                 [MonoTODO]
812                 public override object ReadValueAs (Type type, IXmlNamespaceResolver resolver)
813                 {
814                         return base.ReadValueAs (type, resolver);
815                 }
816 #endif
817
818                 public override void ResolveEntity ()
819                 {
820                         // XmlTextReader does not resolve entities.
821                         throw new InvalidOperationException ("XmlTextReader cannot resolve external entities.");
822                 }
823
824 #if NET_2_0
825                 [MonoTODO ("Implement for performance reason")]
826                 public override void Skip ()
827                 {
828                         base.Skip ();
829                 }
830 #endif
831                 #endregion
832
833                 #region Internals
834                 // Parsed DTD Objects
835 #if DTD_HANDLE_EVENTS
836                 internal event ValidationEventHandler ValidationEventHandler;
837 #endif
838
839                 internal DTDObjectModel DTD {
840                         get { return parserContext.Dtd; }
841                 }
842
843                 internal XmlResolver Resolver {
844                         get { return resolver; }
845                 }
846                 #endregion
847
848                 #region Privates
849                 internal class XmlTokenInfo
850                 {
851                         public XmlTokenInfo (XmlTextReader xtr, bool isPrimaryToken)
852                         {
853                                 this.isPrimaryToken = isPrimaryToken;
854                                 Reader = xtr;
855                                 Clear ();
856                         }
857
858                         bool isPrimaryToken;
859                         string valueCache;
860
861                         protected XmlTextReader Reader;
862
863                         public string Name;
864                         public string LocalName;
865                         public string Prefix;
866                         public string NamespaceURI;
867                         public bool IsEmptyElement;
868                         public char QuoteChar;
869                         public int LineNumber;
870                         public int LinePosition;
871
872                         public XmlNodeType NodeType;
873
874                         public virtual string Value {
875                                 get {
876                                         if (valueCache != null)
877                                                 return valueCache;
878                                         switch (NodeType) {
879                                         case XmlNodeType.Text:
880                                         case XmlNodeType.SignificantWhitespace:
881                                         case XmlNodeType.Whitespace:
882                                         case XmlNodeType.Comment:
883                                         case XmlNodeType.CDATA:
884                                         case XmlNodeType.ProcessingInstruction:
885                                                 valueCache = Reader.CreateValueString ();
886                                                 return valueCache;
887                                         }
888                                         return null;
889                                 }
890                                 set { valueCache = value; }
891                         }
892
893                         public virtual void Clear ()
894                         {
895                                 valueCache = null;
896                                 NodeType = XmlNodeType.None;
897                                 Name = LocalName = Prefix = NamespaceURI = String.Empty;
898                                 IsEmptyElement = false;
899                                 QuoteChar = '"';
900                                 LineNumber = LinePosition = 0;
901                         }
902
903                         internal virtual void FillNames ()
904                         {
905                                 if (Reader.Namespaces) {
906                                         int indexOfColon = -1;
907                                         switch (NodeType) {
908                                         case XmlNodeType.Attribute:
909                                         case XmlNodeType.Element:
910                                         case XmlNodeType.EndElement:
911                                                 indexOfColon = Name.IndexOf (':');
912                                                 break;
913                                         }
914
915                                         if (indexOfColon == -1) {
916                                                 Prefix = String.Empty;
917                                                 LocalName = Name;
918                                         } else {
919                                                 // This improves speed by at least nearly 5%, but eats more memory at least nearly 0.3%
920                                                 // However, this might be reverted if NameTable is got improved.
921                                                 char [] nameArr = Name.ToCharArray ();
922                                                 Prefix = Reader.NameTable.Add (nameArr, 0, indexOfColon);
923                                                 LocalName = Reader.NameTable.Add (nameArr, indexOfColon + 1, nameArr.Length - indexOfColon - 1);
924 //                                              Prefix = Reader.NameTable.Add (Name.Substring (0, indexOfColon));
925 //                                              LocalName = Reader.NameTable.Add (Name.Substring (indexOfColon + 1));
926                                         }
927
928                                         // NamespaceURI
929                                         switch (NodeType) {
930                                         case XmlNodeType.Attribute:
931                                                 if (Prefix.Length == 0)
932                                                         NamespaceURI = string.Empty;
933                                                 else
934                                                         NamespaceURI = Reader.LookupNamespace (Prefix, true);
935                                                 break;
936
937                                         case XmlNodeType.Element:
938                                         case XmlNodeType.EndElement:
939                                                 NamespaceURI = Reader.LookupNamespace (Prefix, true);
940                                                 break;
941                                         default:
942                                                 NamespaceURI = "";
943                                                 break;
944                                         }
945                                 } else {
946                                         Prefix = String.Empty;
947                                         LocalName = Name;
948                                 }
949                         }
950                 }
951
952                 internal class XmlAttributeTokenInfo : XmlTokenInfo
953                 {
954                         public XmlAttributeTokenInfo (XmlTextReader reader)
955                                 : base (reader, false)
956                         {
957                                 NodeType = XmlNodeType.Attribute;
958                         }
959
960                         public int ValueTokenStartIndex;
961                         public int ValueTokenEndIndex;
962                         string valueCache;
963                         bool cachedNormalization;
964                         StringBuilder tmpBuilder = new StringBuilder ();
965
966                         public override string Value {
967                                 get {
968                                         if (cachedNormalization != Reader.Normalization)
969                                                 valueCache = null;
970                                         if (valueCache != null)
971                                                 return valueCache;
972
973                                         cachedNormalization = Reader.Normalization;
974
975                                         // An empty value should return String.Empty.
976                                         if (ValueTokenStartIndex == ValueTokenEndIndex) {
977                                                 XmlTokenInfo ti = Reader.attributeValueTokens [ValueTokenStartIndex];
978                                                 if (ti.NodeType == XmlNodeType.EntityReference)
979                                                         valueCache = String.Concat ("&", ti.Name, ";");
980                                                 else
981                                                         valueCache = ti.Value;
982                                                 if (cachedNormalization)
983                                                         NormalizeSpaces ();
984                                                 return valueCache;
985                                         }
986
987                                         tmpBuilder.Length = 0;
988                                         for (int i = ValueTokenStartIndex; i <= ValueTokenEndIndex; i++) {
989                                                 XmlTokenInfo ti = Reader.attributeValueTokens [i];
990                                                 if (ti.NodeType == XmlNodeType.Text)
991                                                         tmpBuilder.Append (ti.Value);
992                                                 else {
993                                                         tmpBuilder.Append ('&');
994                                                         tmpBuilder.Append (ti.Name);
995                                                         tmpBuilder.Append (';');
996                                                 }
997                                         }
998
999                                         valueCache = tmpBuilder.ToString ();
1000                                         if (cachedNormalization)
1001                                                 NormalizeSpaces ();
1002                                         return valueCache;
1003                                 }
1004
1005                                 set { valueCache = value; }
1006                         }
1007
1008                         public override void Clear ()
1009                         {
1010                                 base.Clear ();
1011                                 valueCache = null;
1012                                 NodeType = XmlNodeType.Attribute;
1013                                 ValueTokenStartIndex = ValueTokenEndIndex = 0;
1014                         }
1015
1016                         internal override void FillNames ()
1017                         {
1018                                 base.FillNames ();
1019                                 if (Prefix == "xmlns" || Name == "xmlns")
1020                                         NamespaceURI = XmlNamespaceManager.XmlnsXmlns;
1021                         }
1022
1023                         private void NormalizeSpaces ()
1024                         {
1025                                 tmpBuilder.Length = 0;
1026                                 for (int i = 0; i < valueCache.Length; i++)
1027                                         switch (valueCache [i]) {
1028                                         case '\r':
1029                                                 if (i + 1 < valueCache.Length && valueCache [i + 1] == '\n')
1030                                                         i++;
1031                                                 goto case '\n';
1032                                         case '\t':
1033                                         case '\n':
1034                                                 tmpBuilder.Append (' ');
1035                                                 break;
1036                                         default:
1037                                                 tmpBuilder.Append (valueCache [i]);
1038                                                 break;
1039                                         }
1040                                 valueCache = tmpBuilder.ToString ();
1041                         }
1042                 }
1043
1044                 private XmlTokenInfo cursorToken;
1045                 private XmlTokenInfo currentToken;
1046                 private XmlAttributeTokenInfo currentAttributeToken;
1047                 private XmlTokenInfo currentAttributeValueToken;
1048                 private XmlAttributeTokenInfo [] attributeTokens = new XmlAttributeTokenInfo [10];
1049                 private XmlTokenInfo [] attributeValueTokens = new XmlTokenInfo [10];
1050                 private int currentAttribute;
1051                 private int currentAttributeValue;
1052                 private int attributeCount;
1053
1054                 private XmlParserContext parserContext;
1055
1056                 private ReadState readState;
1057
1058                 private int depth;
1059                 private int elementDepth;
1060                 private bool depthUp;
1061
1062                 private bool popScope;
1063
1064                 private string [] elementNames;
1065                 int elementNameStackPos;
1066
1067                 private bool allowMultipleRoot;
1068
1069                 private bool isStandalone;
1070
1071                 private bool returnEntityReference;
1072                 private string entityReferenceName;
1073
1074                 private char [] nameBuffer;
1075                 private int nameLength;
1076                 private int nameCapacity;
1077                 private const int initialNameCapacity = 32;
1078
1079                 private char [] valueBuffer;
1080                 private int valueLength;
1081                 private int valueCapacity;
1082                 private const int initialValueCapacity = 256;
1083
1084                 private char [] currentTagBuffer;
1085                 private int currentTagLength;
1086                 private int currentTagCapacity;
1087                 private const int initialCurrentTagCapacity = 256;
1088
1089                 private TextReader reader;
1090                 private char [] peekChars;
1091                 private int peekCharsIndex;
1092                 private int peekCharsLength;
1093                 private const int peekCharCapacity = 1024;
1094
1095                 private int line;
1096                 private int column;
1097
1098                 private int currentLinkedNodeLineNumber;
1099                 private int currentLinkedNodeLinePosition;
1100                 private bool useProceedingLineInfo;
1101
1102                 private XmlNodeType startNodeType;
1103                 // State machine attribute.
1104                 //      XmlDeclaration: after the first node.
1105                 //      DocumentType: after doctypedecl
1106                 //      Element: inside document element
1107                 //      EndElement: after document element
1108                 private XmlNodeType currentState;
1109
1110                 // For ReadChars()/ReadBase64()/ReadBinHex()
1111                 private bool shouldSkipUntilEndTag;
1112                 private byte [] base64Cache = new byte [3];
1113                 private int base64CacheStartsAt;
1114
1115                 // These values are never re-initialized.
1116                 private bool namespaces = true;
1117                 private WhitespaceHandling whitespaceHandling = WhitespaceHandling.All;
1118                 private XmlResolver resolver = new XmlUrlResolver ();
1119                 private bool normalization = false;
1120
1121                 private bool checkCharacters;
1122                 private bool prohibitDtd = false;
1123                 private bool closeInput = true;
1124                 private EntityHandling entityHandling; // 2.0
1125
1126                 private void Init ()
1127                 {
1128                         currentToken = new XmlTokenInfo (this, true);
1129                         cursorToken = currentToken;
1130                         currentAttribute = -1;
1131                         currentAttributeValue = -1;
1132                         attributeCount = 0;
1133
1134                         readState = ReadState.Initial;
1135                         allowMultipleRoot = false;
1136
1137                         depth = 0;
1138                         elementDepth = 0;
1139                         depthUp = false;
1140
1141                         popScope = allowMultipleRoot = false;
1142                         elementNames = new string [10];
1143                         elementNameStackPos = 0;
1144
1145                         isStandalone = false;
1146                         returnEntityReference = false;
1147                         entityReferenceName = String.Empty;
1148
1149                         nameBuffer = new char [initialNameCapacity];
1150                         nameLength = 0;
1151                         nameCapacity = initialNameCapacity;
1152
1153                         valueBuffer = new char [initialValueCapacity];
1154                         valueLength = 0;
1155                         valueCapacity = initialValueCapacity;
1156
1157                         currentTagBuffer = new char [initialCurrentTagCapacity];
1158                         currentTagLength = 0;
1159                         currentTagCapacity = initialCurrentTagCapacity;
1160
1161                         peekCharsIndex = 0;
1162                         peekCharsLength = 0;
1163                         if (peekChars == null)
1164                                 peekChars = new char [peekCharCapacity];
1165
1166                         line = 1;
1167                         column = 1;
1168                         currentTagLength = 0;
1169
1170                         currentLinkedNodeLineNumber = currentLinkedNodeLinePosition = 0;
1171                         useProceedingLineInfo = false;
1172
1173                         currentState = XmlNodeType.None;
1174
1175                         shouldSkipUntilEndTag = false;
1176                         base64CacheStartsAt = -1;
1177
1178                         checkCharacters = true;
1179 #if NET_2_0
1180                         if (Settings != null)
1181                                 checkCharacters = Settings.CheckCharacters;
1182 #endif
1183                         prohibitDtd = false;
1184                         closeInput = true;
1185                         entityHandling = EntityHandling.ExpandCharEntities;
1186                 }
1187
1188                 private void InitializeContext (string url, XmlParserContext context, TextReader fragment, XmlNodeType fragType)
1189                 {
1190                         startNodeType = fragType;
1191                         parserContext = context;
1192                         if (context == null) {
1193                                 XmlNameTable nt = new NameTable ();
1194                                 parserContext = new XmlParserContext (nt,
1195                                         new XmlNamespaceManager (nt),
1196                                         String.Empty,
1197                                         XmlSpace.None);
1198                         }
1199
1200                         if (url != null && url.Length > 0) {
1201                                 Uri uri = null;
1202                                 try {
1203                                         uri = new Uri (url);
1204                                 } catch (Exception) {
1205                                         string path = Path.GetFullPath ("./a");
1206                                         uri = new Uri (new Uri (path), url);
1207                                 }
1208                                 parserContext.BaseURI = uri.ToString ();
1209                         }
1210
1211                         Init ();
1212
1213                         reader = fragment;
1214
1215                         switch (fragType) {
1216                         case XmlNodeType.Attribute:
1217                                 reader = new StringReader (fragment.ReadToEnd ().Replace ("\"", "&quot;"));
1218                                 break;
1219                         case XmlNodeType.Element:
1220                                 currentState = XmlNodeType.Element;
1221                                 allowMultipleRoot = true;
1222                                 break;
1223                         case XmlNodeType.Document:
1224                                 break;
1225                         default:
1226                                 throw new XmlException (String.Format ("NodeType {0} is not allowed to create XmlTextReader.", fragType));
1227                         }
1228                 }
1229
1230 #if NET_2_0
1231                 [MonoTODO ("Test")]
1232                 internal ConformanceLevel Conformance {
1233                         set {
1234                                 if (value == ConformanceLevel.Fragment) {
1235                                         currentState = XmlNodeType.Element;
1236                                         allowMultipleRoot = true;
1237                                 }
1238                         }
1239                 }
1240
1241                 internal void AdjustLineInfoOffset (int lineNumberOffset, int linePositionOffset)
1242                 {
1243                         line += lineNumberOffset;
1244                         column += linePositionOffset;
1245                 }
1246
1247                 internal void SetNameTable (XmlNameTable nameTable)
1248                 {
1249                         parserContext.NameTable = nameTable;
1250                 }
1251 #endif
1252
1253                 // Use this method rather than setting the properties
1254                 // directly so that all the necessary properties can
1255                 // be changed in harmony with each other. Maybe the
1256                 // fields should be in a seperate class to help enforce
1257                 // this.
1258                 private void SetProperties (
1259                         XmlNodeType nodeType,
1260                         string name,
1261                         bool isEmptyElement,
1262                         string value,
1263                         bool clearAttributes)
1264                 {
1265                         SetProperties (currentToken, nodeType, name, isEmptyElement, value, clearAttributes);
1266                         currentToken.LineNumber = this.currentLinkedNodeLineNumber;
1267                         currentToken.LinePosition = this.currentLinkedNodeLinePosition;
1268                 }
1269
1270                 private void SetProperties (
1271                         XmlTokenInfo token,
1272                         XmlNodeType nodeType,
1273                         string name,
1274                         bool isEmptyElement,
1275                         string value,
1276                         bool clearAttributes)
1277                 {
1278                         token.Clear ();
1279                         token.NodeType = nodeType;
1280                         token.Name = name;
1281                         token.IsEmptyElement = isEmptyElement;
1282                         token.Value = value;
1283                         this.elementDepth = depth;
1284
1285                         if (clearAttributes)
1286                                 ClearAttributes ();
1287
1288                         token.FillNames ();
1289                 }
1290
1291                 private void ClearAttributes ()
1292                 {
1293                         for (int i = 0; i < attributeCount; i++)
1294                                 attributeTokens [i].Clear ();
1295                         attributeCount = 0;
1296                         currentAttribute = -1;
1297                         currentAttributeValue = -1;
1298                 }
1299
1300                 private int PeekChar ()
1301                 {
1302                         if (peekCharsLength == peekCharsIndex) {
1303                                 if (!ReadTextReader ())
1304                                         return -1;
1305                                 return PeekChar ();
1306                         }
1307                         else {
1308                                 char c = peekChars [peekCharsIndex];
1309                                 if (c != 0) return c;
1310                                 else return -1;
1311                         }
1312                 }
1313
1314                 private int ReadChar ()
1315                 {
1316                         int ch;
1317
1318                         if (peekCharsLength == peekCharsIndex) {
1319                                 if (!ReadTextReader ())
1320                                         return -1;
1321                                 return ReadChar ();
1322                         }
1323                         ch = peekChars [peekCharsIndex++];
1324
1325                         if (ch == '\n') {
1326                                 line++;
1327                                 column = 1;
1328                         } else if (ch == 0) {
1329                                 return -1;
1330                         } else {
1331                                 column++;
1332                         }
1333                         if (currentState != XmlNodeType.Element)
1334                                 AppendCurrentTagChar (ch);
1335                         return ch;
1336                 }
1337
1338                 private bool ReadTextReader ()
1339                 {
1340                         peekCharsIndex = 0;
1341                         peekCharsLength = reader.Read (peekChars, 0, peekCharCapacity);
1342                         if (peekCharsLength == 0)
1343                                 return false;
1344                         return true;
1345                 }
1346
1347                 private string ExpandSurrogateChar (int ch)
1348                 {
1349                         if (ch < Char.MaxValue)
1350                                 return ((char) ch).ToString ();
1351                         else {
1352                                 char [] tmp = new char [] {(char) (ch / 0x10000 + 0xD800 - 1), (char) (ch % 0x10000 + 0xDC00)};
1353                                 return new string (tmp);
1354                         }
1355                 }
1356
1357                 // This should really keep track of some state so
1358                 // that it's not possible to have more than one document
1359                 // element or text outside of the document element.
1360                 private bool ReadContent ()
1361                 {
1362                         currentTagLength = 0;
1363                         if (popScope) {
1364                                 parserContext.NamespaceManager.PopScope ();
1365                                 popScope = false;
1366                         }
1367
1368                         if (returnEntityReference)
1369                                 SetEntityReferenceProperties ();
1370                         else {
1371                                 int c = PeekChar ();
1372                                 if (c == -1) {
1373                                         readState = ReadState.EndOfFile;
1374                                         ClearValueBuffer ();
1375                                         SetProperties (
1376                                                 XmlNodeType.None, // nodeType
1377                                                 String.Empty, // name
1378                                                 false, // isEmptyElement
1379                                                 null, // value
1380                                                 true // clearAttributes
1381                                         );
1382                                         if (depth > 0)
1383                                                 throw new XmlException ("unexpected end of file. Current depth is " + depth);
1384
1385                                         return false;
1386                                 } else {
1387                                         switch ((char) c) {
1388                                         case '<':
1389                                                 ReadChar ();
1390                                                 ReadTag ();
1391                                                 break;
1392                                         case '\r': goto case ' ';
1393                                         case '\n': goto case ' ';
1394                                         case '\t': goto case ' ';
1395                                         case ' ':
1396                                                 if (whitespaceHandling == WhitespaceHandling.All ||
1397                                                         whitespaceHandling == WhitespaceHandling.Significant)
1398                                                         ReadWhitespace ();
1399                                                 else {
1400                                                         SkipWhitespace ();
1401                                                         return ReadContent ();
1402                                                 }
1403                                                 break;
1404                                         default:
1405                                                 ReadText (true);
1406                                                 break;
1407                                         }
1408                                 }
1409                         }
1410                         return this.ReadState != ReadState.EndOfFile;
1411                 }
1412
1413                 private void SetEntityReferenceProperties ()
1414                 {
1415                         DTDEntityDeclaration decl = DTD != null ? DTD.EntityDecls [entityReferenceName] : null;
1416                         if (this.isStandalone)
1417                                 if (DTD == null || decl == null || !decl.IsInternalSubset)
1418                                         throw new XmlException (this as IXmlLineInfo,
1419                                                 "Standalone document must not contain any references to an non-internally declared entity.");
1420                         if (decl != null && decl.NotationName != null)
1421                                 throw new XmlException (this as IXmlLineInfo,
1422                                         "Reference to any unparsed entities is not allowed here.");
1423
1424                         ClearValueBuffer ();
1425                         SetProperties (
1426                                 XmlNodeType.EntityReference, // nodeType
1427                                 entityReferenceName, // name
1428                                 false, // isEmptyElement
1429                                 null, // value
1430                                 true // clearAttributes
1431                         );
1432
1433                         returnEntityReference = false;
1434                         entityReferenceName = String.Empty;
1435                 }
1436
1437                 // The leading '<' has already been consumed.
1438                 private void ReadTag ()
1439                 {
1440                         switch (PeekChar ())
1441                         {
1442                         case '/':
1443                                 ReadChar ();
1444                                 ReadEndTag ();
1445                                 break;
1446                         case '?':
1447                                 ReadChar ();
1448                                 ReadProcessingInstruction ();
1449                                 break;
1450                         case '!':
1451                                 ReadChar ();
1452                                 ReadDeclaration ();
1453                                 break;
1454                         default:
1455                                 ReadStartTag ();
1456                                 break;
1457                         }
1458                 }
1459
1460                 // The leading '<' has already been consumed.
1461                 private void ReadStartTag ()
1462                 {
1463                         if (currentState == XmlNodeType.EndElement)
1464                                 throw new XmlException (this as IXmlLineInfo,
1465                                         "Multiple document element was detected.");
1466                         currentState = XmlNodeType.Element;
1467
1468                         parserContext.NamespaceManager.PushScope ();
1469
1470                         currentLinkedNodeLineNumber = line;
1471                         currentLinkedNodeLinePosition = column;
1472
1473                         string name = ReadName ();
1474                         if (currentState == XmlNodeType.EndElement)
1475                                 throw new XmlException (this as IXmlLineInfo,"document has terminated, cannot open new element");
1476
1477                         bool isEmptyElement = false;
1478
1479                         ClearAttributes ();
1480
1481                         SkipWhitespace ();
1482                         if (XmlChar.IsFirstNameChar (PeekChar ()))
1483                                 ReadAttributes (false);
1484                         cursorToken = this.currentToken;
1485
1486                         // fill namespaces
1487                         for (int i = 0; i < attributeCount; i++)
1488                                 attributeTokens [i].FillNames ();
1489
1490                         // quick name check
1491                         for (int i = 0; i < attributeCount; i++) {
1492                                 for (int j = i + 1; j < attributeCount; j++)
1493                                         if (Object.ReferenceEquals (attributeTokens [i].Name, attributeTokens [j].Name) ||
1494                                                 (Object.ReferenceEquals (attributeTokens [i].LocalName, attributeTokens [j].LocalName) &&
1495                                                 Object.ReferenceEquals (attributeTokens [i].NamespaceURI, attributeTokens [j].NamespaceURI)))
1496                                                 throw new XmlException (this as IXmlLineInfo,
1497                                                         "Attribute name and qualified name must be identical.");
1498                         }
1499
1500                         string baseUri = GetAttribute ("xml:base");
1501                         if (baseUri != null) {
1502                                 if (this.resolver != null)
1503                                         parserContext.BaseURI = resolver.ResolveUri (new Uri (BaseURI), baseUri).ToString ();
1504                                 else
1505                                         parserContext.BaseURI = baseUri;
1506                         }
1507                         string xmlLang = GetAttribute ("xml:lang");
1508                         if (xmlLang != null)
1509                                 parserContext.XmlLang = xmlLang;
1510                         string xmlSpaceAttr = GetAttribute ("xml:space");
1511                         if (xmlSpaceAttr != null) {
1512                                 if (xmlSpaceAttr == "preserve")
1513                                         parserContext.XmlSpace = XmlSpace.Preserve;
1514                                 else if (xmlSpaceAttr == "default")
1515                                         parserContext.XmlSpace = XmlSpace.Default;
1516                                 else
1517                                         throw new XmlException (this as IXmlLineInfo,String.Format ("Invalid xml:space value: {0}", xmlSpaceAttr));
1518                         }
1519                         if (PeekChar () == '/') {
1520                                 ReadChar ();
1521                                 isEmptyElement = true;
1522                                 popScope = true;
1523                         }
1524                         else {
1525                                 depthUp = true;
1526                                 PushElementName (name);
1527                                 parserContext.PushScope ();
1528                         }
1529
1530                         Expect ('>');
1531                         SetProperties (
1532                                 XmlNodeType.Element, // nodeType
1533                                 name, // name
1534                                 isEmptyElement, // isEmptyElement
1535                                 null, // value
1536                                 false // clearAttributes
1537                         );
1538
1539                         if (LookupNamespace (Prefix) == null)
1540                                 throw new XmlException (String.Format ("'{0}' is undeclared namespace.", Prefix));
1541                         try {
1542                                 for (int i = 0; i < attributeCount; i++) {
1543                                         MoveToAttribute (i);
1544                                         if (LookupNamespace (Prefix) == null)
1545                                                 throw new XmlException (String.Format ("'{0}' is undeclared namespace.", Prefix));
1546                                 }
1547                         } finally {
1548                                 MoveToElement ();
1549                         }
1550
1551                         if (IsEmptyElement)
1552                                 CheckCurrentStateUpdate ();
1553                 }
1554
1555                 private void PushElementName (string name)
1556                 {
1557                         if (elementNames.Length == elementNameStackPos) {
1558                                 string [] newArray = new string [elementNames.Length * 2];
1559                                 Array.Copy (elementNames, 0, newArray, 0, elementNameStackPos);
1560                                 elementNames = newArray;
1561                         }
1562                         elementNames [elementNameStackPos++] = name;
1563                 }
1564
1565                 // The reader is positioned on the first character
1566                 // of the element's name.
1567                 private void ReadEndTag ()
1568                 {
1569                         if (currentState != XmlNodeType.Element)
1570                                 throw new XmlException (this as IXmlLineInfo,
1571                                         "End tag cannot appear in this state.");
1572
1573                         currentLinkedNodeLineNumber = line;
1574                         currentLinkedNodeLinePosition = column;
1575
1576                         string name = ReadName ();
1577                         if (elementNameStackPos == 0)
1578                                 throw new XmlException (this as IXmlLineInfo,"closing element without matching opening element");
1579                         string expected = elementNames [--elementNameStackPos];
1580                         if (expected != name)
1581                                 throw new XmlException (this as IXmlLineInfo,String.Format ("unmatched closing element: expected {0} but found {1}", expected, name));
1582                         parserContext.PopScope ();
1583
1584                         ExpectAfterWhitespace ('>');
1585
1586                         --depth;
1587
1588                         SetProperties (
1589                                 XmlNodeType.EndElement, // nodeType
1590                                 name, // name
1591                                 false, // isEmptyElement
1592                                 null, // value
1593                                 true // clearAttributes
1594                         );
1595
1596                         popScope = true;
1597
1598                         CheckCurrentStateUpdate ();
1599                 }
1600
1601                 private void CheckCurrentStateUpdate ()
1602                 {
1603                         if (depth == 0 && !allowMultipleRoot && (IsEmptyElement || NodeType == XmlNodeType.EndElement))
1604                                 currentState = XmlNodeType.EndElement;
1605                 }
1606
1607                 private void AppendNameChar (int ch)
1608                 {
1609                         if (nameLength == nameCapacity)
1610                                 ExpandNameCapacity ();
1611                         if (ch < Char.MaxValue)
1612                                 nameBuffer [nameLength++] = (char) ch;
1613                         else {
1614                                 nameBuffer [nameLength++] = (char) (ch / 0x10000 + 0xD800 - 1);
1615                                 if (nameLength == nameCapacity)
1616                                         ExpandNameCapacity ();
1617                                 nameBuffer [nameLength++] = (char) (ch % 0x10000 + 0xDC00);
1618                         }
1619                 }
1620
1621                 private void ExpandNameCapacity ()
1622                 {
1623                         nameCapacity = nameCapacity * 2;
1624                         char [] oldNameBuffer = nameBuffer;
1625                         nameBuffer = new char [nameCapacity];
1626                         Array.Copy (oldNameBuffer, nameBuffer, nameLength);
1627                 }
1628
1629                 private string CreateNameString ()
1630                 {
1631                         return parserContext.NameTable.Add (nameBuffer, 0, nameLength);
1632                 }
1633
1634                 private void AppendValueChar (int ch)
1635                 {
1636                         if (valueLength == valueCapacity)
1637                                 ExpandValueCapacity ();
1638                         if (ch < Char.MaxValue)
1639                                 valueBuffer [valueLength++] = (char) ch;
1640                         else {
1641                                 valueBuffer [valueLength++] = (char) (ch / 0x10000 + 0xD800 - 1);
1642                                 if (valueLength == valueCapacity)
1643                                         ExpandValueCapacity ();
1644                                 valueBuffer [valueLength++] = (char) (ch % 0x10000 + 0xDC00);
1645                         }
1646                 }
1647
1648                 private void ExpandValueCapacity ()
1649                 {
1650                         valueCapacity = valueCapacity * 2;
1651                         char [] oldValueBuffer = valueBuffer;
1652                         valueBuffer = new char [valueCapacity];
1653                         Array.Copy (oldValueBuffer, valueBuffer, valueLength);
1654                 }
1655
1656                 private string CreateValueString ()
1657                 {
1658                         return new string (valueBuffer, 0, valueLength);
1659                 }
1660
1661                 private void ClearValueBuffer ()
1662                 {
1663                         valueLength = 0;
1664                 }
1665
1666                 private void AppendCurrentTagChar (int ch)
1667                 {
1668                         if (currentTagLength == currentTagCapacity)
1669                                 ExpandCurrentTagCapacity ();
1670                         if (ch < Char.MaxValue)
1671                                 currentTagBuffer [currentTagLength++] = (char) ch;
1672                         else {
1673                                 currentTagBuffer [currentTagLength++] = (char) (ch / 0x10000 + 0xD800 - 1);
1674                                 if (currentTagLength == currentTagCapacity)
1675                                         ExpandCurrentTagCapacity ();
1676                                 currentTagBuffer [currentTagLength++] = (char) (ch % 0x10000 + 0xDC00);
1677                         }
1678                 }
1679
1680                 private void ExpandCurrentTagCapacity ()
1681                 {
1682                         currentTagCapacity = currentTagCapacity * 2;
1683                         char [] oldCurrentTagBuffer = currentTagBuffer;
1684                         currentTagBuffer = new char [currentTagCapacity];
1685                         Array.Copy (oldCurrentTagBuffer, currentTagBuffer, currentTagLength);
1686                 }
1687
1688                 private string CreateCurrentTagString ()
1689                 {
1690                         return new string (currentTagBuffer, 0, currentTagLength);
1691                 }
1692
1693                 private void ClearCurrentTagBuffer ()
1694                 {
1695                         currentTagLength = 0;
1696                 }
1697
1698                 // The reader is positioned on the first character
1699                 // of the text.
1700                 private void ReadText (bool notWhitespace)
1701                 {
1702                         if (currentState != XmlNodeType.Element)
1703                                 throw new XmlException (this as IXmlLineInfo,
1704                                         "Text node cannot appear in this state.");
1705
1706                         if (notWhitespace)
1707                                 ClearValueBuffer ();
1708
1709                         int ch = PeekChar ();
1710                         bool previousWasCloseBracket = false;
1711
1712                         while (ch != '<' && ch != -1) {
1713                                 if (ch == '&') {
1714                                         ReadChar ();
1715                                         ch = ReadReference (false);
1716                                         if (returnEntityReference) // Returns -1 if char validation should not be done
1717                                                 break;
1718                                 } else if (normalization && ch == '\r') {
1719                                         ReadChar ();
1720                                         ch = ReadChar ();
1721                                         if (ch != '\n')
1722                                                 // append '\n' instead of '\r'.
1723                                                 AppendValueChar ('\n');
1724                                         // and in case of "\r\n", discard '\r'.
1725                                 } else {
1726                                         if (CharacterChecking && XmlChar.IsInvalid (ch))
1727                                                 throw new XmlException (this, "Not allowed character was found.");
1728                                         ch = ReadChar ();
1729                                 }
1730
1731                                 AppendValueChar (ch);
1732
1733                                 // Block "]]>"
1734                                 if (ch == ']') {
1735                                         if (previousWasCloseBracket)
1736                                                 if (PeekChar () == '>')
1737                                                         throw new XmlException (this as IXmlLineInfo,
1738                                                                 "Inside text content, character sequence ']]>' is not allowed.");
1739                                         previousWasCloseBracket = true;
1740                                 }
1741                                 else if (previousWasCloseBracket)
1742                                         previousWasCloseBracket = false;
1743                                 ch = PeekChar ();
1744                                 notWhitespace = true;
1745                         }
1746
1747                         if (returnEntityReference && valueLength == 0) {
1748                                 SetEntityReferenceProperties ();
1749                         } else {
1750                                 XmlNodeType nodeType = notWhitespace ? XmlNodeType.Text :
1751                                         this.XmlSpace == XmlSpace.Preserve ? XmlNodeType.SignificantWhitespace : XmlNodeType.Whitespace;
1752                                 SetProperties (
1753                                         nodeType, // nodeType
1754                                         String.Empty, // name
1755                                         false, // isEmptyElement
1756                                         null, // value: create only when required
1757                                         true // clearAttributes
1758                                 );
1759                         }
1760                 }
1761
1762                 // The leading '&' has already been consumed.
1763                 // Returns true if the entity reference isn't a simple
1764                 // character reference or one of the predefined entities.
1765                 // This allows the ReadText method to break so that the
1766                 // next call to Read will return the EntityReference node.
1767                 private int ReadReference (bool ignoreEntityReferences)
1768                 {
1769                         if (PeekChar () == '#') {
1770                                 ReadChar ();
1771                                 return ReadCharacterReference ();
1772                         } else
1773                                 return ReadEntityReference (ignoreEntityReferences);
1774                 }
1775
1776                 private int ReadCharacterReference ()
1777                 {
1778                         int value = 0;
1779
1780                         if (PeekChar () == 'x') {
1781                                 ReadChar ();
1782
1783                                 while (PeekChar () != ';' && PeekChar () != -1) {
1784                                         int ch = ReadChar ();
1785
1786                                         if (ch >= '0' && ch <= '9')
1787                                                 value = (value << 4) + ch - '0';
1788                                         else if (ch >= 'A' && ch <= 'F')
1789                                                 value = (value << 4) + ch - 'A' + 10;
1790                                         else if (ch >= 'a' && ch <= 'f')
1791                                                 value = (value << 4) + ch - 'a' + 10;
1792                                         else
1793                                                 throw new XmlException (this as IXmlLineInfo,
1794                                                         String.Format (CultureInfo.InvariantCulture, 
1795                                                                 "invalid hexadecimal digit: {0} (#x{1:X})",
1796                                                                 (char) ch,
1797                                                                 ch));
1798                                 }
1799                         } else {
1800                                 while (PeekChar () != ';' && PeekChar () != -1) {
1801                                         int ch = ReadChar ();
1802
1803                                         if (ch >= '0' && ch <= '9')
1804                                                 value = value * 10 + ch - '0';
1805                                         else
1806                                                 throw new XmlException (this as IXmlLineInfo,
1807                                                         String.Format (CultureInfo.InvariantCulture, 
1808                                                                 "invalid decimal digit: {0} (#x{1:X})",
1809                                                                 (char) ch,
1810                                                                 ch));
1811                                 }
1812                         }
1813
1814                         ReadChar (); // ';'
1815
1816                         // There is no way to save surrogate pairs...
1817                         if (CharacterChecking && XmlChar.IsInvalid (value))
1818                                 throw new XmlException (this as IXmlLineInfo,
1819                                         "Referenced character was not allowed in XML. Normalization is " + normalization + ", checkCharacters = " + checkCharacters);
1820                         return value;
1821                 }
1822
1823                 // Returns -1 if it should not be validated.
1824                 // Real EOF must not be detected here.
1825                 private int ReadEntityReference (bool ignoreEntityReferences)
1826                 {
1827                         string name = ReadName ();
1828                         Expect (';');
1829
1830                         int predefined = XmlChar.GetPredefinedEntity (name);
1831                         if (predefined >= 0)
1832                                 return predefined;
1833                         else {
1834                                 if (ignoreEntityReferences) {
1835                                         AppendValueChar ('&');
1836                                         for (int i = 0; i < name.Length; i++)
1837                                                 AppendValueChar (name [i]);
1838                                         AppendValueChar (';');
1839                                 } else {
1840                                         returnEntityReference = true;
1841                                         entityReferenceName = name;
1842                                 }
1843                         }
1844                         return -1;
1845                 }
1846
1847                 // The reader is positioned on the first character of
1848                 // the attribute name.
1849                 private void ReadAttributes (bool isXmlDecl)
1850                 {
1851                         int peekChar = -1;
1852                         bool requireWhitespace = false;
1853                         currentAttribute = -1;
1854                         currentAttributeValue = -1;
1855
1856                         do {
1857                                 if (!SkipWhitespace () && requireWhitespace)
1858                                         throw new XmlException ("Unexpected token. Name is required here.");
1859
1860                                 IncrementAttributeToken ();
1861                                 currentAttributeToken.LineNumber = line;
1862                                 currentAttributeToken.LinePosition = column;
1863
1864                                 currentAttributeToken.LocalName = 
1865                                         currentAttributeToken.Name = ReadName ();
1866                                 ExpectAfterWhitespace ('=');
1867                                 SkipWhitespace ();
1868                                 ReadAttributeValueTokens (-1);
1869                                 attributeCount++;
1870
1871                                 if (currentAttributeToken.Name == "xmlns")
1872                                         parserContext.NamespaceManager.AddNamespace (String.Empty, GetAttribute (currentAttribute));
1873                                 else if (currentAttributeToken.Name.StartsWith ("xmlns:")) {
1874                                         string nsPrefix = currentAttributeToken.Name.Substring (6);
1875                                         parserContext.NamespaceManager.AddNamespace (nsPrefix, GetAttribute (currentAttribute));
1876                                 }
1877
1878                                 if (!SkipWhitespace ())
1879                                         requireWhitespace = true;
1880                                 peekChar = PeekChar ();
1881                                 if (isXmlDecl) {
1882                                         if (peekChar == '?')
1883                                                 break;
1884                                 }
1885                                 else if (peekChar == '/' || peekChar == '>')
1886                                         break;
1887                         } while (peekChar != -1);
1888
1889                         currentAttribute = -1;
1890                         currentAttributeValue = -1;
1891                 }
1892
1893                 private void AddAttribute (string name, string value)
1894                 {
1895                         IncrementAttributeToken ();
1896                         XmlAttributeTokenInfo ati = attributeTokens [currentAttribute];
1897                         ati.Name = "SYSTEM";
1898                         ati.FillNames ();
1899                         IncrementAttributeValueToken ();
1900                         XmlTokenInfo vti = attributeValueTokens [currentAttributeValue];
1901                         vti.Value = value;
1902                         SetProperties (vti, XmlNodeType.Text, String.Empty, false, value, false);
1903                         attributeCount++;
1904                 }
1905
1906                 private void IncrementAttributeToken ()
1907                 {
1908                         currentAttribute++;
1909                         if (attributeTokens.Length == currentAttribute) {
1910                                 XmlAttributeTokenInfo [] newArray = 
1911                                         new XmlAttributeTokenInfo [attributeTokens.Length * 2];
1912                                 attributeTokens.CopyTo (newArray, 0);
1913                                 attributeTokens = newArray;
1914                         }
1915                         if (attributeTokens [currentAttribute] == null)
1916                                 attributeTokens [currentAttribute] = new XmlAttributeTokenInfo (this);
1917                         currentAttributeToken = attributeTokens [currentAttribute];
1918                         currentAttributeToken.Clear ();
1919                 }
1920
1921                 private void IncrementAttributeValueToken ()
1922                 {
1923                         ClearValueBuffer ();
1924                         currentAttributeValue++;
1925                         if (attributeValueTokens.Length == currentAttributeValue) {
1926                                 XmlTokenInfo [] newArray = new XmlTokenInfo [attributeValueTokens.Length * 2];
1927                                 attributeValueTokens.CopyTo (newArray, 0);
1928                                 attributeValueTokens = newArray;
1929                         }
1930                         if (attributeValueTokens [currentAttributeValue] == null)
1931                                 attributeValueTokens [currentAttributeValue] = new XmlTokenInfo (this, false);
1932                         currentAttributeValueToken = attributeValueTokens [currentAttributeValue];
1933                         currentAttributeValueToken.Clear ();
1934                 }
1935
1936                 // LAMESPEC: Orthodox XML reader should normalize attribute values
1937                 private void ReadAttributeValueTokens (int dummyQuoteChar)
1938                 {
1939                         int quoteChar = (dummyQuoteChar < 0) ? ReadChar () : dummyQuoteChar;
1940
1941                         if (quoteChar != '\'' && quoteChar != '\"')
1942                                 throw new XmlException (this as IXmlLineInfo,"an attribute value was not quoted");
1943                         currentAttributeToken.QuoteChar = (char) quoteChar;
1944
1945                         IncrementAttributeValueToken ();
1946                         currentAttributeToken.ValueTokenStartIndex = currentAttributeValue;
1947                         currentAttributeValueToken.LineNumber = line;
1948                         currentAttributeValueToken.LinePosition = column;
1949
1950                         bool incrementToken = false;
1951                         bool isNewToken = true;
1952                         bool loop = true;
1953                         int ch = 0;
1954                         while (loop) {
1955                                 ch = ReadChar ();
1956                                 if (ch == quoteChar)
1957                                         break;
1958
1959                                 if (incrementToken) {
1960                                         IncrementAttributeValueToken ();
1961                                         currentAttributeValueToken.LineNumber = line;
1962                                         currentAttributeValueToken.LinePosition = column;
1963                                         incrementToken = false;
1964                                         isNewToken = true;
1965                                 }
1966
1967                                 switch (ch)
1968                                 {
1969                                 case '<':
1970                                         throw new XmlException (this as IXmlLineInfo,"attribute values cannot contain '<'");
1971                                 case -1:
1972                                         if (dummyQuoteChar < 0)
1973                                                 throw new XmlException (this as IXmlLineInfo,"unexpected end of file in an attribute value");
1974                                         else    // Attribute value constructor.
1975                                                 loop = false;
1976                                         break;
1977                                 case '&':
1978                                         int startPosition = currentTagLength - 1;
1979                                         if (PeekChar () == '#') {
1980                                                 ReadChar ();
1981                                                 ch = ReadCharacterReference ();
1982                                                 if (CharacterChecking && XmlChar.IsInvalid (ch))
1983                                                         throw new XmlException (this as IXmlLineInfo,
1984                                                                 "Not allowed character was found.");
1985                                                 AppendValueChar (ch);
1986                                                 break;
1987                                         }
1988                                         // Check XML 1.0 section 3.1 WFC.
1989                                         string entName = ReadName ();
1990                                         Expect (';');
1991                                         int predefined = XmlChar.GetPredefinedEntity (entName);
1992                                         if (predefined < 0) {
1993                                                 CheckAttributeEntityReferenceWFC (entName);
1994                                                 currentAttributeValueToken.Value = CreateValueString ();
1995                                                 currentAttributeValueToken.NodeType = XmlNodeType.Text;
1996                                                 if (!isNewToken)
1997                                                         IncrementAttributeValueToken ();
1998                                                 currentAttributeValueToken.Name = entName;
1999                                                 currentAttributeValueToken.Value = String.Empty;
2000                                                 currentAttributeValueToken.NodeType = XmlNodeType.EntityReference;
2001                                                 incrementToken = true;
2002                                         }
2003                                         else
2004                                                 AppendValueChar (predefined);
2005                                         break;
2006                                 default:
2007                                         if (CharacterChecking && XmlChar.IsInvalid (ch))
2008                                                 throw new XmlException (this, "Invalid character was found.");
2009                                         AppendValueChar (ch);
2010                                         break;
2011                                 }
2012
2013                                 isNewToken = false;
2014                         }
2015                         if (!incrementToken) {
2016                                 currentAttributeValueToken.Value = CreateValueString ();
2017                                 currentAttributeValueToken.NodeType = XmlNodeType.Text;
2018                         }
2019                         currentAttributeToken.ValueTokenEndIndex = currentAttributeValue;
2020
2021                 }
2022
2023                 private void CheckAttributeEntityReferenceWFC (string entName)
2024                 {
2025                         DTDEntityDeclaration entDecl = 
2026                                 DTD == null ? null : DTD.EntityDecls [entName];
2027                         if (DTD != null && resolver != null && entDecl == null)
2028                                 throw new XmlException (this, "Referenced entity does not exist.");
2029
2030                         if (entDecl == null)
2031                                 return;
2032
2033                         if (entDecl.HasExternalReference)
2034                                 throw new XmlException (this, "Reference to external entities is not allowed in the value of an attribute.");
2035                         if (isStandalone && !entDecl.IsInternalSubset)
2036                                 throw new XmlException (this, "Reference to external entities is not allowed in the internal subset.");
2037                         if (entDecl.EntityValue.IndexOf ('<') >= 0)
2038                                 throw new XmlException (this, "Attribute must not contain character '<' either directly or indirectly by way of entity references.");
2039                 }
2040
2041                 // The reader is positioned on the first character
2042                 // of the target.
2043                 //
2044                 // It may be xml declaration or processing instruction.
2045                 private void ReadProcessingInstruction ()
2046                 {
2047                         string target = ReadName ();
2048                         if (target == "xml") {
2049                                 ReadXmlDeclaration ();
2050                                 return;
2051                         } else if (target.ToLower (CultureInfo.InvariantCulture) == "xml")
2052                                 throw new XmlException (this as IXmlLineInfo,
2053                                         "Not allowed processing instruction name which starts with 'X', 'M', 'L' was found.");
2054
2055                         if (currentState == XmlNodeType.None)
2056                                 currentState = XmlNodeType.XmlDeclaration;
2057
2058                         if (!SkipWhitespace ())
2059                                 if (PeekChar () != '?')
2060                                         throw new XmlException (this as IXmlLineInfo,
2061                                                 "Invalid processing instruction name was found.");
2062
2063                         ClearValueBuffer ();
2064
2065                         while (PeekChar () != -1) {
2066                                 int ch = ReadChar ();
2067
2068                                 if (ch == '?' && PeekChar () == '>') {
2069                                         ReadChar ();
2070                                         break;
2071                                 }
2072
2073                                 if (CharacterChecking && XmlChar.IsInvalid (ch))
2074                                         throw new XmlException (this, "Invalid character was found.");
2075                                 AppendValueChar (ch);
2076                         }
2077
2078                         SetProperties (
2079                                 XmlNodeType.ProcessingInstruction, // nodeType
2080                                 target, // name
2081                                 false, // isEmptyElement
2082                                 null, // value: create only when required
2083                                 true // clearAttributes
2084                         );
2085                 }
2086
2087                 // The reader is positioned after "<?xml "
2088                 private void ReadXmlDeclaration ()
2089                 {
2090                         if (currentState != XmlNodeType.None) {
2091                                 throw new XmlException (this as IXmlLineInfo,
2092                                         "XML declaration cannot appear in this state.");
2093                         }
2094                         currentState = XmlNodeType.XmlDeclaration;
2095
2096                         ClearAttributes ();
2097
2098                         ReadAttributes (true);  // They must have "version."
2099                         string version = GetAttribute ("version");
2100
2101                         string message = null;
2102
2103                         if (attributeTokens [0].Name != "version" || version != "1.0")
2104                                 message = "Version 1.0 declaration is required in XML Declaration.";
2105                         else if (attributeCount > 1 &&
2106                                         (attributeTokens [1].Name != "encoding" &&
2107                                         attributeTokens [1].Name != "standalone"))
2108                                 message = "Invalid Xml Declaration markup was found.";
2109                         else if (attributeCount > 2 && attributeTokens [2].Name != "standalone")
2110                                 message = "Invalid Xml Declaration markup was found.";
2111                         string sa = GetAttribute ("standalone");
2112                         if (sa != null && sa != "yes" && sa != "no")
2113                                 message = "Only 'yes' or 'no' is allowed for standalone.";
2114
2115                         this.isStandalone = (sa == "yes");
2116
2117                         if (message != null)
2118                                 throw new XmlException (this as IXmlLineInfo, message);
2119
2120                         SetProperties (
2121                                 XmlNodeType.XmlDeclaration, // nodeType
2122                                 "xml", // name
2123                                 false, // isEmptyElement
2124                                 new string (currentTagBuffer, 6, currentTagLength - 6), // value
2125                                 false // clearAttributes
2126                         );
2127
2128                         Expect ("?>");
2129                 }
2130
2131                 internal void SkipTextDeclaration ()
2132                 {
2133                         this.currentState = XmlNodeType.Element;
2134
2135                         if (PeekChar () != '<')
2136                                 return;
2137
2138                         ReadChar ();
2139
2140                         if (PeekChar () != '?') {
2141                                 peekCharsIndex = 0;
2142                                 return;
2143                         }
2144                         ReadChar ();
2145
2146                         while (peekCharsIndex < 6) {
2147                                 if (PeekChar () < 0)
2148                                         break;
2149                                 else
2150                                         ReadChar ();
2151                         }
2152                         if (new string (peekChars, 2, 4) != "xml ") {
2153                                 if (new string (peekChars, 2, 3).ToLower (CultureInfo.InvariantCulture) == "xml") {
2154                                         throw new XmlException (this as IXmlLineInfo,
2155                                                 "Processing instruction name must not be character sequence 'X' 'M' 'L' with case insensitivity.");
2156                                 }
2157                                 peekCharsIndex = 0;
2158                                 return;
2159                         }
2160
2161                         SkipWhitespace ();
2162
2163                         // version decl
2164                         if (PeekChar () == 'v') {
2165                                 Expect ("version");
2166                                 ExpectAfterWhitespace ('=');
2167                                 SkipWhitespace ();
2168                                 int quoteChar = ReadChar ();
2169                                 char [] expect1_0 = new char [3];
2170                                 int versionLength = 0;
2171                                 switch (quoteChar) {
2172                                 case '\'':
2173                                 case '"':
2174                                         while (PeekChar () != quoteChar) {
2175                                                 if (PeekChar () == -1)
2176                                                         throw new XmlException (this as IXmlLineInfo,
2177                                                                 "Invalid version declaration inside text declaration.");
2178                                                 else if (versionLength == 3)
2179                                                         throw new XmlException (this as IXmlLineInfo,
2180                                                                 "Invalid version number inside text declaration.");
2181                                                 else {
2182                                                         expect1_0 [versionLength] = (char) ReadChar ();
2183                                                         versionLength++;
2184                                                         if (versionLength == 3 && new String (expect1_0) != "1.0")
2185                                                                 throw new XmlException (this as IXmlLineInfo,
2186                                                                         "Invalid version number inside text declaration.");
2187                                                 }
2188                                         }
2189                                         ReadChar ();
2190                                         SkipWhitespace ();
2191                                         break;
2192                                 default:
2193                                         throw new XmlException (this as IXmlLineInfo,
2194                                                 "Invalid version declaration inside text declaration.");
2195                                 }
2196                         }
2197
2198                         if (PeekChar () == 'e') {
2199                                 Expect ("encoding");
2200                                 ExpectAfterWhitespace ('=');
2201                                 SkipWhitespace ();
2202                                 int quoteChar = ReadChar ();
2203                                 switch (quoteChar) {
2204                                 case '\'':
2205                                 case '"':
2206                                         while (PeekChar () != quoteChar)
2207                                                 if (ReadChar () == -1)
2208                                                         throw new XmlException (this as IXmlLineInfo,
2209                                                                 "Invalid encoding declaration inside text declaration.");
2210                                         ReadChar ();
2211                                         SkipWhitespace ();
2212                                         break;
2213                                 default:
2214                                         throw new XmlException (this as IXmlLineInfo,
2215                                                 "Invalid encoding declaration inside text declaration.");
2216                                 }
2217                                 // Encoding value should be checked inside XmlInputStream.
2218                         }
2219                         else
2220                                 throw new XmlException (this as IXmlLineInfo,
2221                                         "Encoding declaration is mandatory in text declaration.");
2222
2223                         Expect ("?>");
2224                 }
2225
2226                 // The reader is positioned on the first character after
2227                 // the leading '<!'.
2228                 private void ReadDeclaration ()
2229                 {
2230                         int ch = PeekChar ();
2231
2232                         switch (ch)
2233                         {
2234                         case '-':
2235                                 Expect ("--");
2236                                 ReadComment ();
2237                                 break;
2238                         case '[':
2239                                 ReadChar ();
2240                                 Expect ("CDATA[");
2241                                 ReadCDATA ();
2242                                 break;
2243                         case 'D':
2244                                 Expect ("DOCTYPE");
2245                                 ReadDoctypeDecl ();
2246                                 break;
2247                         default:
2248                                 throw new XmlException (this as IXmlLineInfo,
2249                                         "Unexpected declaration markup was found.");
2250                         }
2251                 }
2252
2253                 // The reader is positioned on the first character after
2254                 // the leading '<!--'.
2255                 private void ReadComment ()
2256                 {
2257                         if (currentState == XmlNodeType.None)
2258                                 currentState = XmlNodeType.XmlDeclaration;
2259
2260                         ClearValueBuffer ();
2261
2262                         while (PeekChar () != -1) {
2263                                 int ch = ReadChar ();
2264
2265                                 if (ch == '-' && PeekChar () == '-') {
2266                                         ReadChar ();
2267
2268                                         if (PeekChar () != '>')
2269                                                 throw new XmlException (this as IXmlLineInfo,"comments cannot contain '--'");
2270
2271                                         ReadChar ();
2272                                         break;
2273                                 }
2274
2275                                 if (XmlChar.IsInvalid (ch))
2276                                         throw new XmlException (this as IXmlLineInfo,
2277                                                 "Not allowed character was found.");
2278
2279                                 AppendValueChar (ch);
2280                         }
2281
2282                         SetProperties (
2283                                 XmlNodeType.Comment, // nodeType
2284                                 String.Empty, // name
2285                                 false, // isEmptyElement
2286                                 null, // value: create only when required
2287                                 true // clearAttributes
2288                         );
2289                 }
2290
2291                 // The reader is positioned on the first character after
2292                 // the leading '<![CDATA['.
2293                 private void ReadCDATA ()
2294                 {
2295                         if (currentState != XmlNodeType.Element)
2296                                 throw new XmlException (this as IXmlLineInfo,
2297                                         "CDATA section cannot appear in this state.");
2298
2299                         ClearValueBuffer ();
2300
2301                         bool skip = false;
2302                         int ch = 0;
2303                         while (PeekChar () != -1) {
2304                                 if (!skip)
2305                                         ch = ReadChar ();
2306                                 skip = false;
2307
2308                                 if (ch == ']' && PeekChar () == ']') {
2309                                         ch = ReadChar (); // ']'
2310
2311                                         if (PeekChar () == '>') {
2312                                                 ReadChar (); // '>'
2313                                                 break;
2314                                         } else {
2315                                                 skip = true;
2316                                         }
2317                                 }
2318                                 if (normalization && ch == '\r') {
2319                                         ch = PeekChar ();
2320                                         if (ch != '\n')
2321                                                 // append '\n' instead of '\r'.
2322                                                 AppendValueChar ('\n');
2323                                         // otherwise, discard '\r'.
2324                                         continue;
2325                                 }
2326                                 if (CharacterChecking && XmlChar.IsInvalid (ch))
2327                                         throw new XmlException (this, "Invalid character was found.");
2328
2329                                 AppendValueChar (ch);
2330                         }
2331
2332                         SetProperties (
2333                                 XmlNodeType.CDATA, // nodeType
2334                                 String.Empty, // name
2335                                 false, // isEmptyElement
2336                                 null, // value: create only when required
2337                                 true // clearAttributes
2338                         );
2339                 }
2340
2341                 // The reader is positioned on the first character after
2342                 // the leading '<!DOCTYPE'.
2343                 private void ReadDoctypeDecl ()
2344                 {
2345                         if (prohibitDtd)
2346                                 throw new XmlException (this as IXmlLineInfo,
2347                                         "Document Type Declaration (DTD) is prohibited in this XML.");
2348                         switch (currentState) {
2349                         case XmlNodeType.DocumentType:
2350                         case XmlNodeType.Element:
2351                         case XmlNodeType.EndElement:
2352                                 throw new XmlException (this as IXmlLineInfo,
2353                                         "Document type cannot appear in this state.");
2354                         }
2355                         currentState = XmlNodeType.DocumentType;
2356
2357                         string doctypeName = null;
2358                         string publicId = null;
2359                         string systemId = null;
2360                         int intSubsetStartLine = 0;
2361                         int intSubsetStartColumn = 0;
2362
2363                         SkipWhitespace ();
2364                         doctypeName = ReadName ();
2365                         SkipWhitespace ();
2366                         switch(PeekChar ())
2367                         {
2368                         case 'S':
2369                                 systemId = ReadSystemLiteral (true);
2370                                 break;
2371                         case 'P':
2372                                 publicId = ReadPubidLiteral ();
2373                                 if (!SkipWhitespace ())
2374                                         throw new XmlException (this as IXmlLineInfo,
2375                                                 "Whitespace is required between PUBLIC id and SYSTEM id.");
2376                                 systemId = ReadSystemLiteral (false);
2377                                 break;
2378                         }
2379                         SkipWhitespace ();
2380
2381
2382                         if(PeekChar () == '[')
2383                         {
2384                                 // read markupdecl etc. or end of decl
2385                                 ReadChar ();
2386                                 intSubsetStartLine = this.LineNumber;
2387                                 intSubsetStartColumn = this.LinePosition;
2388                                 int startPos = currentTagLength;
2389                                 ReadInternalSubset ();
2390                                 int endPos = currentTagLength - 1;
2391                                 parserContext.InternalSubset = new string (currentTagBuffer, startPos, endPos - startPos);
2392                         }
2393                         // end of DOCTYPE decl.
2394                         ExpectAfterWhitespace ('>');
2395
2396                         GenerateDTDObjectModel (doctypeName, publicId,
2397                                 systemId, parserContext.InternalSubset,
2398                                 intSubsetStartLine, intSubsetStartColumn);
2399
2400                         // set properties for <!DOCTYPE> node
2401                         SetProperties (
2402                                 XmlNodeType.DocumentType, // nodeType
2403                                 doctypeName, // name
2404                                 false, // isEmptyElement
2405                                 parserContext.InternalSubset, // value
2406                                 true // clearAttributes
2407                                 );
2408
2409                         if (publicId != null)
2410                                 AddAttribute ("PUBLIC", publicId);
2411                         if (systemId != null)
2412                                 AddAttribute ("SYSTEM", systemId);
2413                         currentAttribute = currentAttributeValue = -1;
2414                 }
2415
2416                 internal DTDObjectModel GenerateDTDObjectModel (string name, string publicId,
2417                         string systemId, string internalSubset)
2418                 {
2419                         return GenerateDTDObjectModel (name, publicId, systemId, internalSubset, 0, 0);
2420                 }
2421
2422                 internal DTDObjectModel GenerateDTDObjectModel (string name, string publicId,
2423                         string systemId, string internalSubset, int intSubsetStartLine, int intSubsetStartColumn)
2424                 {
2425                         // now compile DTD
2426                         parserContext.Dtd = new DTDObjectModel (this.NameTable);        // merges both internal and external subsets in the meantime,
2427                         DTD.BaseURI = BaseURI;
2428                         DTD.Name = name;
2429                         DTD.PublicId = publicId;
2430                         DTD.SystemId = systemId;
2431                         DTD.InternalSubset = internalSubset;
2432                         DTD.XmlResolver = resolver;
2433                         DTD.IsStandalone = isStandalone;
2434                         DTD.LineNumber = line;
2435                         DTD.LinePosition = column;
2436
2437                         DTDReader dr = new DTDReader (DTD, intSubsetStartLine, intSubsetStartColumn);
2438                         dr.Normalization = this.normalization;
2439 #if DTD_HANDLE_EVENTS
2440                         dr.ValidationEventHandler += new ValidationEventHandler (OnValidationEvent);
2441 #endif
2442                         return dr.GenerateDTDObjectModel ();
2443                 }
2444
2445                 private void OnValidationEvent (object o, ValidationEventArgs e)
2446                 {
2447 #if DTD_HANDLE_EVENTS
2448                         if (ValidationEventHandler != null)
2449                                 // Override object as this.
2450                                 ValidationEventHandler (this, e);
2451 #endif
2452                 }
2453
2454                 private enum DtdInputState
2455                 {
2456                         Free = 1,
2457                         ElementDecl,
2458                         AttlistDecl,
2459                         EntityDecl,
2460                         NotationDecl,
2461                         PI,
2462                         Comment,
2463                         InsideSingleQuoted,
2464                         InsideDoubleQuoted,
2465                 }
2466
2467                 private class DtdInputStateStack
2468                 {
2469                         Stack intern = new Stack ();
2470                         public DtdInputStateStack ()
2471                         {
2472                                 Push (DtdInputState.Free);
2473                         }
2474
2475                         public DtdInputState Peek ()
2476                         {
2477                                 return (DtdInputState) intern.Peek ();
2478                         }
2479
2480                         public DtdInputState Pop ()
2481                         {
2482                                 return (DtdInputState) intern.Pop ();
2483                         }
2484
2485                         public void Push (DtdInputState val)
2486                         {
2487                                 intern.Push (val);
2488                         }
2489                 }
2490
2491
2492                 DtdInputStateStack stateStack = new DtdInputStateStack ();
2493                 DtdInputState State {
2494                         get { return stateStack.Peek (); }
2495                 }
2496
2497                 // Simply read but not generate any result.
2498                 private void ReadInternalSubset ()
2499                 {
2500                         bool continueParse = true;
2501
2502                         while (continueParse) {
2503                                 switch (ReadChar ()) {
2504                                 case ']':
2505                                         switch (State) {
2506                                         case DtdInputState.Free:
2507                                                 continueParse = false;
2508                                                 break;
2509                                         case DtdInputState.InsideDoubleQuoted:
2510                                                 continue;
2511                                         case DtdInputState.InsideSingleQuoted:
2512                                                 continue;
2513                                         default:
2514                                                 throw new XmlException (this as IXmlLineInfo,"unexpected end of file at DTD.");
2515                                         }
2516                                         break;
2517                                 case -1:
2518                                         throw new XmlException (this as IXmlLineInfo,"unexpected end of file at DTD.");
2519                                 case '<':
2520                                         switch (State) {
2521                                         case DtdInputState.InsideDoubleQuoted:
2522                                         case DtdInputState.InsideSingleQuoted:
2523                                         case DtdInputState.Comment:
2524                                                 continue;       // well-formed
2525                                         }
2526                                         int c = ReadChar ();
2527                                         switch (c) {
2528                                         case '?':
2529                                                 stateStack.Push (DtdInputState.PI);
2530                                                 break;
2531                                         case '!':
2532                                                 switch (ReadChar ()) {
2533                                                 case 'E':
2534                                                         switch (ReadChar ()) {
2535                                                         case 'L':
2536                                                                 Expect ("EMENT");
2537                                                                 stateStack.Push (DtdInputState.ElementDecl);
2538                                                                 break;
2539                                                         case 'N':
2540                                                                 Expect ("TITY");
2541                                                                 stateStack.Push (DtdInputState.EntityDecl);
2542                                                                 break;
2543                                                         default:
2544                                                                 throw new XmlException (this as IXmlLineInfo,"unexpected token '<!E'.");
2545                                                         }
2546                                                         break;
2547                                                 case 'A':
2548                                                         Expect ("TTLIST");
2549                                                         stateStack.Push (DtdInputState.AttlistDecl);
2550                                                         break;
2551                                                 case 'N':
2552                                                         Expect ("OTATION");
2553                                                         stateStack.Push (DtdInputState.NotationDecl);
2554                                                         break;
2555                                                 case '-':
2556                                                         Expect ("-");
2557                                                         stateStack.Push (DtdInputState.Comment);
2558                                                         break;
2559                                                 }
2560                                                 break;
2561                                         default:
2562                                                 throw new XmlException (this as IXmlLineInfo, String.Format ("unexpected '<{0}'.", (char) c));
2563                                         }
2564                                         break;
2565                                 case '\'':
2566                                         if (State == DtdInputState.InsideSingleQuoted)
2567                                                 stateStack.Pop ();
2568                                         else if (State != DtdInputState.InsideDoubleQuoted && State != DtdInputState.Comment)
2569                                                 stateStack.Push (DtdInputState.InsideSingleQuoted);
2570                                         break;
2571                                 case '"':
2572                                         if (State == DtdInputState.InsideDoubleQuoted)
2573                                                 stateStack.Pop ();
2574                                         else if (State != DtdInputState.InsideSingleQuoted && State != DtdInputState.Comment)
2575                                                 stateStack.Push (DtdInputState.InsideDoubleQuoted);
2576                                         break;
2577                                 case '>':
2578                                         switch (State) {
2579                                         case DtdInputState.ElementDecl:
2580                                                 goto case DtdInputState.NotationDecl;
2581                                         case DtdInputState.AttlistDecl:
2582                                                 goto case DtdInputState.NotationDecl;
2583                                         case DtdInputState.EntityDecl:
2584                                                 goto case DtdInputState.NotationDecl;
2585                                         case DtdInputState.NotationDecl:
2586                                                 stateStack.Pop ();
2587                                                 break;
2588                                         case DtdInputState.InsideDoubleQuoted:
2589                                         case DtdInputState.InsideSingleQuoted:
2590                                         case DtdInputState.Comment:
2591                                                 continue;
2592                                         default:
2593                                                 throw new XmlException (this as IXmlLineInfo,"unexpected token '>'");
2594                                         }
2595                                         break;
2596                                 case '?':
2597                                         if (State == DtdInputState.PI) {
2598                                                 if (ReadChar () == '>')
2599                                                         stateStack.Pop ();
2600                                         }
2601                                         break;
2602                                 case '-':
2603                                         if (State == DtdInputState.Comment) {
2604                                                 if (PeekChar () == '-') {
2605                                                         ReadChar ();
2606                                                         Expect ('>');
2607                                                         stateStack.Pop ();
2608                                                 }
2609                                         }
2610                                         break;
2611                                 case '%':
2612                                         if (State != DtdInputState.Free && State != DtdInputState.EntityDecl && State != DtdInputState.Comment && State != DtdInputState.InsideDoubleQuoted && State != DtdInputState.InsideSingleQuoted)
2613                                                 throw new XmlException (this as IXmlLineInfo,"Parameter Entity Reference cannot appear as a part of markupdecl (see XML spec 2.8).");
2614                                         break;
2615                                 }
2616                         }
2617                 }
2618
2619                 // The reader is positioned on the first 'S' of "SYSTEM".
2620                 private string ReadSystemLiteral (bool expectSYSTEM)
2621                 {
2622                         if(expectSYSTEM) {
2623                                 Expect ("SYSTEM");
2624                                 if (!SkipWhitespace ())
2625                                         throw new XmlException (this as IXmlLineInfo,
2626                                                 "Whitespace is required after 'SYSTEM'.");
2627                         }
2628                         else
2629                                 SkipWhitespace ();
2630                         int quoteChar = ReadChar ();    // apos or quot
2631                         int startPos = currentTagLength;
2632                         int c = 0;
2633                         ClearValueBuffer ();
2634                         while (c != quoteChar) {
2635                                 c = ReadChar ();
2636                                 if (c < 0)
2637                                         throw new XmlException (this as IXmlLineInfo,"Unexpected end of stream in ExternalID.");
2638                                 if (c != quoteChar)
2639                                         AppendValueChar (c);
2640                         }
2641                         return CreateValueString ();
2642                 }
2643
2644                 private string ReadPubidLiteral()
2645                 {
2646                         Expect ("PUBLIC");
2647                         if (!SkipWhitespace ())
2648                                 throw new XmlException (this as IXmlLineInfo,
2649                                         "Whitespace is required after 'PUBLIC'.");
2650                         int quoteChar = ReadChar ();
2651                         int startPos = currentTagLength;
2652                         int c = 0;
2653                         ClearValueBuffer ();
2654                         while(c != quoteChar)
2655                         {
2656                                 c = ReadChar ();
2657                                 if(c < 0) throw new XmlException (this as IXmlLineInfo,"Unexpected end of stream in ExternalID.");
2658                                 if(c != quoteChar && !XmlChar.IsPubidChar (c))
2659                                         throw new XmlException (this as IXmlLineInfo,"character '" + (char) c + "' not allowed for PUBLIC ID");
2660                                 if (c != quoteChar)
2661                                         AppendValueChar (c);
2662                         }
2663                         return CreateValueString ();
2664                 }
2665
2666                 // The reader is positioned on the first character
2667                 // of the name.
2668                 private string ReadName ()
2669                 {
2670                         int ch = PeekChar ();
2671                         if (!XmlChar.IsFirstNameChar (ch))
2672                                 throw new XmlException (this as IXmlLineInfo,String.Format (CultureInfo.InvariantCulture, "a name did not start with a legal character {0} ({1})", ch, (char) ch));
2673
2674                         nameLength = 0;
2675
2676                         AppendNameChar (ReadChar ());
2677
2678                         while (XmlChar.IsNameChar (PeekChar ())) {
2679                                 AppendNameChar (ReadChar ());
2680                         }
2681
2682                         return CreateNameString ();
2683                 }
2684
2685                 // Read the next character and compare it against the
2686                 // specified character.
2687                 private void Expect (int expected)
2688                 {
2689                         int ch = ReadChar ();
2690
2691                         if (ch != expected) {
2692                                 throw new XmlException (this as IXmlLineInfo,
2693                                         String.Format (CultureInfo.InvariantCulture, 
2694                                                 "expected '{0}' ({1:X}) but found '{2}' ({3:X})",
2695                                                 (char) expected,
2696                                                 expected,
2697                                                 (char) ch,
2698                                                 ch));
2699                         }
2700                 }
2701
2702                 private void Expect (string expected)
2703                 {
2704                         int len = expected.Length;
2705                         for(int i=0; i< len; i++)
2706                                 Expect (expected[i]);
2707                 }
2708
2709                 private void ExpectAfterWhitespace (char c)
2710                 {
2711                         while (true) {
2712                                 int i = ReadChar ();
2713                                 if (i < 0x21 && XmlChar.IsWhitespace (i))
2714                                         continue;
2715                                 if (c != i)
2716                                         throw new XmlException (this, String.Format (CultureInfo.InvariantCulture, "Expected {0}, but found {1} [{2}]", c, (char) i, i));
2717                                 break;
2718                         }
2719                 }
2720
2721                 // Does not consume the first non-whitespace character.
2722                 private bool SkipWhitespace ()
2723                 {
2724                         bool skipped = XmlChar.IsWhitespace (PeekChar ());
2725                         if (!skipped)
2726                                 return false;
2727                         while (XmlChar.IsWhitespace (PeekChar ()))
2728                                 ReadChar ();
2729                         return skipped;
2730                 }
2731
2732                 private void ReadWhitespace ()
2733                 {
2734                         if (currentState == XmlNodeType.None)
2735                                 currentState = XmlNodeType.XmlDeclaration;
2736
2737                         ClearValueBuffer ();
2738                         int ch = PeekChar ();
2739                         do {
2740                                 AppendValueChar (ReadChar ());
2741                         } while ((ch = PeekChar ()) != -1 && XmlChar.IsWhitespace (ch));
2742
2743                         if (currentState == XmlNodeType.Element && ch != -1 && ch != '<')
2744                                 ReadText (false);
2745                         else {
2746                                 XmlNodeType nodeType = (this.XmlSpace == XmlSpace.Preserve) ?
2747                                         XmlNodeType.SignificantWhitespace : XmlNodeType.Whitespace;
2748                                 SetProperties (nodeType,
2749                                                String.Empty,
2750                                                false,
2751                                                null, // value: create only when required
2752                                                true);
2753                         }
2754
2755                         return;
2756                 }
2757
2758                 // Since ReadBase64() is processed for every 4 chars, it does
2759                 // not handle '=' here.
2760                 private byte GetBase64Byte (char ch)
2761                 {
2762                         switch (ch) {
2763                         case '+':
2764                                 return 62;
2765                         case '/':
2766                                 return 63;
2767                         default:
2768                                 if (ch >= 'A' && ch <= 'Z')
2769                                         return (byte) (ch - 'A');
2770                                 else if (ch >= 'a' && ch <= 'z')
2771                                         return (byte) (ch - 'a' + 26);
2772                                 else if (ch >= '0' && ch <= '9')
2773                                         return (byte) (ch - '0' + 52);
2774                                 else
2775                                         throw new XmlException ("Invalid Base64 character was found.");
2776                         }
2777                 }
2778
2779                 // Returns -1 if it should throw an error.
2780                 private int ReadCharsInternal (char [] buffer, int offset, int length)
2781                 {
2782                         if (IsEmptyElement) {
2783                                 Read ();
2784                                 return 0;
2785                         }
2786
2787                         if (offset < 0)
2788                                 throw new ArgumentOutOfRangeException ("offset", offset, "Offset must be non-negative integer.");
2789                         else if (length < 0)
2790                                 throw new ArgumentOutOfRangeException ("length", length, "Length must be non-negative integer.");
2791                         else if (buffer.Length < offset + length)
2792                                 throw new ArgumentOutOfRangeException ("buffer length is smaller than the sum of offset and length.");
2793
2794                         if (NodeType != XmlNodeType.Element)
2795                                 return 0;
2796
2797                         shouldSkipUntilEndTag = true;
2798
2799                         int bufIndex = offset;
2800                         for (int i = 0; i < length; i++) {
2801                                 int c = PeekChar ();
2802                                 switch (c) {
2803                                 case -1:
2804                                         throw new XmlException (this as IXmlLineInfo, "Unexpected end of xml.");
2805                                 case '<':
2806                                         ReadChar ();
2807                                         if (PeekChar () != '/') {
2808                                                 buffer [bufIndex++] = '<';
2809                                                 continue;
2810                                         }
2811                                         // Seems to skip immediate EndElement
2812                                         Expect ('/');
2813                                         if (depthUp) {
2814                                                 depth++;
2815                                                 depthUp = false;
2816                                         }
2817                                         ReadEndTag ();
2818                                         shouldSkipUntilEndTag = false;
2819                                         Read (); // move to the next node
2820                                         return i;
2821                                 default:
2822                                         ReadChar ();
2823                                         if (c < Char.MaxValue)
2824                                                 buffer [bufIndex++] = (char) c;
2825                                         else {
2826                                                 buffer [bufIndex++] = (char) (c / 0x10000 + 0xD800 - 1);
2827                                                 buffer [bufIndex++] = (char) (c % 0x10000 + 0xDC00);
2828                                         }
2829                                         break;
2830                                 }
2831                         }
2832                         return length;
2833                 }
2834
2835                 private bool ReadUntilEndTag ()
2836                 {
2837                         int ch;
2838                         do {
2839                                 ch = ReadChar ();
2840                                 switch (ch) {
2841                                 case -1:
2842                                         throw new XmlException (this as IXmlLineInfo,
2843                                                 "Unexpected end of xml.");
2844                                 case '<':
2845                                         if (PeekChar () != '/')
2846                                                 continue;
2847                                         ReadChar ();
2848                                         string name = ReadName ();
2849                                         if (name != elementNames [elementNameStackPos - 1])
2850                                                 continue;
2851                                         Expect ('>');
2852                                         depth--;
2853                                         elementNames [--elementNameStackPos] = null;
2854                                         return Read ();
2855                                 }
2856                         } while (true);
2857                 }
2858                 #endregion
2859         }
2860 }