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