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