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