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