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