2004-01-28 Atsushi Enomoto <atsushi@ximian.com>
[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 ((char) peek_char);
392                                 else
393                                         return new StringReader (((char) 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                 internal DTDObjectModel DTD {
778                         get { return parserContext.Dtd; }
779                 }
780
781                 internal XmlResolver Resolver {
782                         get { return resolver; }
783                 }
784                 #endregion
785
786                 #region Privates
787                 internal class XmlTokenInfo
788                 {
789                         public XmlTokenInfo (XmlTextReader xtr)
790                         {
791                                 Reader = xtr;
792                                 Clear ();
793                         }
794
795                         string valueCache;
796
797                         protected XmlTextReader Reader;
798
799                         public string Name;
800                         public string LocalName;
801                         public string Prefix;
802                         public string NamespaceURI;
803                         public bool IsEmptyElement;
804                         public char QuoteChar;
805                         public int LineNumber;
806                         public int LinePosition;
807
808                         public XmlNodeType NodeType;
809
810                         public virtual string Value {
811                                 get {
812                                         if (valueCache != null)
813                                                 return valueCache;
814                                         else if (Reader.valueBuilderAvailable) {
815                                                 valueCache = Reader.valueBuilder.ToString ();
816                                                 return valueCache;
817                                         }
818                                         return valueCache;
819                                 }
820                                 set {
821                                         valueCache = value;
822                                 }
823                         }
824
825                         public virtual void Clear ()
826                         {
827                                 valueCache = null;
828                                 NodeType = XmlNodeType.None;
829                                 Name = LocalName = Prefix = NamespaceURI = String.Empty;
830                                 IsEmptyElement = false;
831                                 QuoteChar = '"';
832                                 LineNumber = LinePosition = 0;
833                         }
834
835                         internal virtual void FillNames ()
836                         {
837                                 if (Reader.Namespaces) {
838                                         int indexOfColon = Name.IndexOf (':');
839
840                                         if (indexOfColon == -1) {
841                                                 Prefix = String.Empty;
842                                                 LocalName = Name;
843                                         } else {
844                                                 // This improves speed by at least nearly 5%, but eats more memory at least nearly 0.3%
845                                                 // However, this might be reverted if NameTable is got improved.
846                                                 char [] nameArr = Name.ToCharArray ();
847                                                 Prefix = Reader.NameTable.Add (nameArr, 0, indexOfColon);
848                                                 LocalName = Reader.NameTable.Add (nameArr, indexOfColon + 1, nameArr.Length - indexOfColon - 1);
849 //                                              Prefix = Reader.NameTable.Add (Name.Substring (0, indexOfColon));
850 //                                              LocalName = Reader.NameTable.Add (Name.Substring (indexOfColon + 1));
851                                         }
852
853                                         // NamespaceURI
854                                         switch (NodeType) {
855                                         case XmlNodeType.Attribute:
856                                                 if (Prefix == string.Empty)
857                                                         NamespaceURI = string.Empty;
858                                                 else
859                                                         NamespaceURI = Reader.LookupNamespace (Prefix, true);
860                                                 break;
861
862                                         case XmlNodeType.Element:
863                                         case XmlNodeType.EndElement:
864                                                 NamespaceURI = Reader.LookupNamespace (Prefix, true);
865                                                 break;
866                                         default:
867                                                 NamespaceURI = "";
868                                                 break;
869                                         }
870                                 } else {
871                                         Prefix = String.Empty;
872                                         LocalName = Name;
873                                 }
874                         }
875                 }
876
877                 internal class XmlAttributeTokenInfo : XmlTokenInfo
878                 {
879                         public XmlAttributeTokenInfo (XmlTextReader reader)
880                                 : base (reader)
881                         {
882                                 NodeType = XmlNodeType.Attribute;
883                         }
884
885                         public int ValueTokenStartIndex;
886                         public int ValueTokenEndIndex;
887                         string valueCache;
888                         bool cachedNormalization;
889                         StringBuilder tmpBuilder = new StringBuilder ();
890
891                         public override string Value {
892                                 get {
893                                         if (cachedNormalization != Reader.Normalization)
894                                                 valueCache = null;
895                                         if (valueCache != null)
896                                                 return valueCache;
897                                         cachedNormalization = Reader.Normalization;
898
899                                         // An empty value should return String.Empty.
900                                         if (ValueTokenStartIndex == ValueTokenEndIndex) {
901                                                 XmlTokenInfo ti = Reader.attributeValueTokens [ValueTokenStartIndex];
902                                                 if (ti.NodeType == XmlNodeType.EntityReference)
903                                                         valueCache = String.Concat ("&", ti.Name, ";");
904                                                 else
905                                                         valueCache = ti.Value;
906                                                 if (cachedNormalization)
907                                                         NormalizeSpaces ();
908                                                 return valueCache;
909                                         }
910
911                                         tmpBuilder.Length = 0;
912                                         for (int i = ValueTokenStartIndex; i <= ValueTokenEndIndex; i++) {
913                                                 XmlTokenInfo ti = Reader.attributeValueTokens [i];
914                                                 if (ti.NodeType == XmlNodeType.Text)
915                                                         tmpBuilder.Append (ti.Value);
916                                                 else {
917                                                         tmpBuilder.Append ('&');
918                                                         tmpBuilder.Append (ti.Name);
919                                                         tmpBuilder.Append (';');
920                                                 }
921                                         }
922
923                                         valueCache = tmpBuilder.ToString ();
924                                         if (cachedNormalization)
925                                                 NormalizeSpaces ();
926                                         return valueCache;
927                                 }
928                                 set {
929                                         valueCache = value;
930                                 }
931                         }
932
933                         public override void Clear ()
934                         {
935                                 base.Clear ();
936                                 valueCache = null;
937                                 NodeType = XmlNodeType.Attribute;
938                                 ValueTokenStartIndex = ValueTokenEndIndex = 0;
939                         }
940
941                         internal override void FillNames ()
942                         {
943                                 base.FillNames ();
944                                 if (Prefix == "xmlns" || Name == "xmlns")
945                                         NamespaceURI = XmlNamespaceManager.XmlnsXmlns;
946                         }
947
948                         private void NormalizeSpaces ()
949                         {
950                                 tmpBuilder.Length = 0;
951                                 for (int i = 0; i < valueCache.Length; i++)
952                                         switch (valueCache [i]) {
953                                         case '\r':
954                                                 if (i + 1 < valueCache.Length && valueCache [i + 1] == '\n')
955                                                         i++;
956                                                 goto case '\n';
957                                         case '\t':
958                                         case '\n':
959                                                 tmpBuilder.Append (' ');
960                                                 break;
961                                         default:
962                                                 tmpBuilder.Append (valueCache [i]);
963                                                 break;
964                                         }
965                                 valueCache = tmpBuilder.ToString ();
966                         }
967                 }
968
969                 private XmlTokenInfo cursorToken;
970                 private XmlTokenInfo currentToken;
971                 private XmlAttributeTokenInfo currentAttributeToken;
972                 private XmlTokenInfo currentAttributeValueToken;
973                 private XmlAttributeTokenInfo [] attributeTokens = new XmlAttributeTokenInfo [10];
974                 private XmlTokenInfo [] attributeValueTokens = new XmlTokenInfo [10];
975                 private int currentAttribute;
976                 private int currentAttributeValue;
977                 private int attributeCount;
978
979                 private XmlParserContext parserContext;
980
981                 private ReadState readState;
982
983                 private int depth;
984                 private int elementDepth;
985                 private bool depthUp;
986
987                 private bool popScope;
988                 private Stack elementStack = new Stack();
989                 private bool allowMultipleRoot;
990
991                 private bool isStandalone;
992
993                 private StringBuilder valueBuilder;
994                 private bool valueBuilderAvailable = false;
995
996                 private bool returnEntityReference;
997                 private string entityReferenceName;
998
999                 private char [] nameBuffer;
1000                 private int nameLength;
1001                 private int nameCapacity;
1002                 private const int initialNameCapacity = 256;
1003
1004                 private StringBuilder valueBuffer = new StringBuilder (512);
1005
1006                 private TextReader reader;
1007                 private bool can_seek;
1008                 private bool has_peek;
1009                 private int peek_char;
1010                 private bool hasPeekChars;
1011                 private char [] peekChars;
1012                 private int peekCharsIndex;
1013
1014                 private int line;
1015                 private int column;
1016                 private StringBuilder currentTag = new StringBuilder ();
1017
1018                 private int currentLinkedNodeLineNumber;
1019                 private int currentLinkedNodeLinePosition;
1020                 private bool useProceedingLineInfo;
1021
1022                 // A buffer for ReadContent for ReadOuterXml
1023
1024                 private XmlNodeType startNodeType;
1025                 // State machine attribute.
1026                 //      XmlDeclaration: after the first node.
1027                 //      DocumentType: after doctypedecl
1028                 //      Element: inside document element
1029                 //      EndElement: after document element
1030                 private XmlNodeType currentState;
1031
1032                 // For ReadChars()/ReadBase64()/ReadBinHex()
1033                 private bool shouldSkipUntilEndTag;
1034                 private byte [] base64Cache = new byte [3];
1035                 private int base64CacheStartsAt;
1036
1037                 // These values are never re-initialized.
1038                 private bool namespaces = true;
1039                 private WhitespaceHandling whitespaceHandling = WhitespaceHandling.All;
1040                 private XmlResolver resolver = new XmlUrlResolver ();
1041                 private bool normalization = false;
1042
1043                 private void Init ()
1044                 {
1045                         currentToken = new XmlTokenInfo (this);
1046                         cursorToken = currentToken;
1047                         currentAttribute = -1;
1048                         currentAttributeValue = -1;
1049                         attributeCount = 0;
1050
1051                         readState = ReadState.Initial;
1052                         allowMultipleRoot = false;
1053
1054                         depth = 0;
1055                         elementDepth = 0;
1056                         depthUp = false;
1057
1058                         popScope = allowMultipleRoot = false;
1059                         elementStack.Clear ();
1060
1061                         isStandalone = false;
1062                         valueBuilderAvailable = false;
1063                         returnEntityReference = false;
1064                         entityReferenceName = String.Empty;
1065
1066                         nameBuffer = new char [initialNameCapacity];
1067                         nameLength = 0;
1068                         nameCapacity = initialNameCapacity;
1069
1070                         can_seek = has_peek = false;
1071                         peek_char = peekCharsIndex = 0;
1072                         peekChars = new char [6];
1073
1074                         line = 1;
1075                         column = 0;
1076                         currentTag.Length = 0;
1077
1078                         valueBuffer.Length = 0;
1079
1080                         currentLinkedNodeLineNumber = currentLinkedNodeLinePosition = 0;
1081                         useProceedingLineInfo = false;
1082
1083                         currentState = XmlNodeType.None;
1084
1085                         shouldSkipUntilEndTag = false;
1086                         base64CacheStartsAt = -1;
1087                 }
1088
1089                 private void InitializeContext (string url, XmlParserContext context, TextReader fragment, XmlNodeType fragType)
1090                 {
1091                         startNodeType = fragType;
1092                         parserContext = context;
1093                         if (context == null) {
1094                                 XmlNameTable nt = new NameTable ();
1095                                 parserContext = new XmlParserContext (nt,
1096                                         new XmlNamespaceManager (nt),
1097                                         String.Empty,
1098                                         XmlSpace.None);
1099                         }
1100
1101                         if (url != null && url.Length > 0) {
1102                                 Uri uri = null;
1103                                 try {
1104                                         uri = new Uri (url);
1105                                 } catch (Exception) {
1106                                         string path = Path.GetFullPath ("./a");
1107                                         uri = new Uri (new Uri (path), url);
1108                                 }
1109                                 parserContext.BaseURI = uri.ToString ();
1110                         }
1111
1112                         Init ();
1113
1114                         switch (fragType) {
1115                         case XmlNodeType.Attribute:
1116                                 fragment = new StringReader (fragment.ReadToEnd ().Replace ("\"", "&quot;"));
1117                                 break;
1118                         case XmlNodeType.Element:
1119                                 currentState = XmlNodeType.Element;
1120                                 allowMultipleRoot = true;
1121                                 break;
1122                         case XmlNodeType.Document:
1123                                 break;
1124                         default:
1125                                 throw new XmlException (String.Format ("NodeType {0} is not allowed to create XmlTextReader.", fragType));
1126                         }
1127
1128                         reader = fragment;
1129                 }
1130
1131                 // Use this method rather than setting the properties
1132                 // directly so that all the necessary properties can
1133                 // be changed in harmony with each other. Maybe the
1134                 // fields should be in a seperate class to help enforce
1135                 // this.
1136                 private void SetProperties (
1137                         XmlNodeType nodeType,
1138                         string name,
1139                         bool isEmptyElement,
1140                         string value,
1141                         bool clearAttributes)
1142                 {
1143                         SetProperties (currentToken, nodeType, name, isEmptyElement, value, clearAttributes);
1144                         currentToken.LineNumber = this.currentLinkedNodeLineNumber;
1145                         currentToken.LinePosition = this.currentLinkedNodeLinePosition;
1146                 }
1147
1148                 private void SetProperties (
1149                         XmlTokenInfo token,
1150                         XmlNodeType nodeType,
1151                         string name,
1152                         bool isEmptyElement,
1153                         string value,
1154                         bool clearAttributes)
1155                 {
1156                         this.valueBuilderAvailable = false;
1157                         token.Clear ();
1158                         token.NodeType = nodeType;
1159                         token.Name = name;
1160                         token.IsEmptyElement = isEmptyElement;
1161                         token.Value = value;
1162                         this.elementDepth = depth;
1163
1164                         if (clearAttributes)
1165                                 ClearAttributes ();
1166
1167                         token.FillNames ();
1168                 }
1169
1170                 private void SetProperties (
1171                         XmlNodeType nodeType,
1172                         string name,
1173                         bool isEmptyElement,
1174                         bool clearAttributes,
1175                         StringBuilder value) {
1176                         SetProperties (nodeType, name, isEmptyElement, (string)null, clearAttributes);
1177                         this.valueBuilderAvailable = true;
1178                         this.valueBuilder = value;
1179                 }
1180
1181                 private void ClearAttributes ()
1182                 {
1183                         for (int i = 0; i < attributeCount; i++)
1184                                 attributeTokens [i].Clear ();
1185                         attributeCount = 0;
1186                         currentAttribute = -1;
1187                         currentAttributeValue = -1;
1188                 }
1189
1190                 private int PeekChar ()
1191                 {
1192                         if (can_seek)
1193                                 return reader.Peek ();
1194
1195                         if (hasPeekChars)
1196                                 return peekChars [peekCharsIndex];
1197
1198                         if (has_peek)
1199                                 return peek_char;
1200
1201                         peek_char = reader.Read ();
1202                         has_peek = true;
1203                         return peek_char;
1204                 }
1205
1206                 private int ReadChar ()
1207                 {
1208                         int ch;
1209
1210                         if (hasPeekChars) {
1211                                 ch = peekChars [peekCharsIndex++];
1212                                 if (peekChars [peekCharsIndex] == 0)
1213                                         hasPeekChars = false;
1214                         } else if (has_peek) {
1215                                 ch = peek_char;
1216                                 has_peek = false;
1217                         } else {
1218                                 ch = reader.Read ();
1219                         }
1220
1221                         if (ch == '\n') {
1222                                 line++;
1223                                 column = 1;
1224                         } else {
1225                                 column++;
1226                         }
1227                         currentTag.Append ((char) ch);
1228                         return ch;
1229                 }
1230
1231                 // This should really keep track of some state so
1232                 // that it's not possible to have more than one document
1233                 // element or text outside of the document element.
1234                 private bool ReadContent ()
1235                 {
1236                         currentTag.Length = 0;
1237                         if (popScope) {
1238                                 parserContext.NamespaceManager.PopScope ();
1239                                 popScope = false;
1240                         }
1241
1242                         if (returnEntityReference)
1243                                 SetEntityReferenceProperties ();
1244                         else {
1245                                 switch (PeekChar ()) {
1246                                 case '<':
1247                                         ReadChar ();
1248                                         ReadTag ();
1249                                         break;
1250                                 case '\r': goto case ' ';
1251                                 case '\n': goto case ' ';
1252                                 case '\t': goto case ' ';
1253                                 case ' ':
1254                                         if (whitespaceHandling == WhitespaceHandling.All ||
1255                                                 whitespaceHandling == WhitespaceHandling.Significant)
1256                                                 ReadWhitespace ();
1257                                         else {
1258                                                 SkipWhitespace ();
1259                                                 return ReadContent ();
1260                                         }
1261                                         break;
1262                                 case -1:
1263                                         readState = ReadState.EndOfFile;
1264                                         SetProperties (
1265                                                 XmlNodeType.None, // nodeType
1266                                                 String.Empty, // name
1267                                                 false, // isEmptyElement
1268                                                 (string) null, // value
1269                                                 true // clearAttributes
1270                                         );
1271                                         if (depth > 0)
1272                                                 throw new XmlException ("unexpected end of file. Current depth is " + depth);
1273
1274                                         return false;
1275                                 default:
1276                                         ReadText (true);
1277                                         break;
1278                                 }
1279                         }
1280                         return this.ReadState != ReadState.EndOfFile;
1281                 }
1282
1283                 private void SetEntityReferenceProperties ()
1284                 {
1285                         DTDEntityDeclaration decl = DTD != null ? DTD.EntityDecls [entityReferenceName] : null;
1286 //                      if (DTD != null && resolver != null && decl == null)
1287 //                              throw new XmlException (this as IXmlLineInfo, "Entity declaration does not exist.");
1288                         if (this.isStandalone)
1289                                 if (DTD == null || decl == null || !decl.IsInternalSubset)
1290                                         throw new XmlException (this as IXmlLineInfo,
1291                                                 "Standalone document must not contain any references to an non-internally declared entity.");
1292                         if (decl != null && decl.NotationName != null)
1293                                 throw new XmlException (this as IXmlLineInfo,
1294                                         "Reference to any unparsed entities is not allowed here.");
1295
1296                         SetProperties (
1297                                 XmlNodeType.EntityReference, // nodeType
1298                                 entityReferenceName, // name
1299                                 false, // isEmptyElement
1300                                 (string) null, // value
1301                                 true // clearAttributes
1302                         );
1303
1304                         returnEntityReference = false;
1305                         entityReferenceName = String.Empty;
1306                 }
1307
1308                 // The leading '<' has already been consumed.
1309                 private void ReadTag ()
1310                 {
1311                         switch (PeekChar ())
1312                         {
1313                         case '/':
1314                                 ReadChar ();
1315                                 ReadEndTag ();
1316                                 break;
1317                         case '?':
1318                                 ReadChar ();
1319                                 ReadProcessingInstruction ();
1320                                 break;
1321                         case '!':
1322                                 ReadChar ();
1323                                 ReadDeclaration ();
1324                                 break;
1325                         default:
1326                                 ReadStartTag ();
1327                                 break;
1328                         }
1329                 }
1330
1331                 // The leading '<' has already been consumed.
1332                 private void ReadStartTag ()
1333                 {
1334                         if (currentState == XmlNodeType.EndElement)
1335                                 throw new XmlException (this as IXmlLineInfo,
1336                                         "Element cannot appear in this state.");
1337                         currentState = XmlNodeType.Element;
1338
1339                         parserContext.NamespaceManager.PushScope ();
1340
1341                         string name = ReadName ();
1342                         if (currentState == XmlNodeType.EndElement)
1343                                 throw new XmlException (this as IXmlLineInfo,"document has terminated, cannot open new element");
1344
1345                         bool isEmptyElement = false;
1346
1347                         ClearAttributes ();
1348
1349                         SkipWhitespace ();
1350                         if (XmlChar.IsFirstNameChar (PeekChar ()))
1351                                 ReadAttributes (false);
1352                         cursorToken = this.currentToken;
1353
1354                         // fill namespaces
1355                         for (int i = 0; i < attributeCount; i++)
1356                                 attributeTokens [i].FillNames ();
1357
1358                         // quick name check
1359                         for (int i = 0; i < attributeCount; i++)
1360                                 for (int j = i + 1; j < attributeCount; j++)
1361                                         if (Object.ReferenceEquals (attributeTokens [i].Name, attributeTokens [j].Name) ||
1362                                                 (Object.ReferenceEquals (attributeTokens [i].LocalName, attributeTokens [j].LocalName) &&
1363                                                 Object.ReferenceEquals (attributeTokens [i].NamespaceURI, attributeTokens [j].NamespaceURI)))
1364                                                 throw new XmlException (this as IXmlLineInfo,
1365                                                         "Attribute name and qualified name must be identical.");
1366
1367                         string baseUri = GetAttribute ("xml:base");
1368                         if (baseUri != null)
1369                                 parserContext.BaseURI = baseUri;
1370                         string xmlLang = GetAttribute ("xml:lang");
1371                         if (xmlLang != null)
1372                                 parserContext.XmlLang = xmlLang;
1373                         string xmlSpaceAttr = GetAttribute ("xml:space");
1374                         if (xmlSpaceAttr != null) {
1375                                 if (xmlSpaceAttr == "preserve")
1376                                         parserContext.XmlSpace = XmlSpace.Preserve;
1377                                 else if (xmlSpaceAttr == "default")
1378                                         parserContext.XmlSpace = XmlSpace.Default;
1379                                 else
1380                                         throw new XmlException (this as IXmlLineInfo,String.Format ("Invalid xml:space value: {0}", xmlSpaceAttr));
1381                         }
1382                         if (PeekChar () == '/') {
1383                                 ReadChar ();
1384                                 isEmptyElement = true;
1385                                 popScope = true;
1386                         }
1387                         else {
1388                                 depthUp = true;
1389                                 elementStack.Push (name);
1390                                 parserContext.PushScope ();
1391                         }
1392
1393                         Expect ('>');
1394
1395                         SetProperties (
1396                                 XmlNodeType.Element, // nodeType
1397                                 name, // name
1398                                 isEmptyElement, // isEmptyElement
1399                                 (string) null, // value
1400                                 false // clearAttributes
1401                         );
1402                 }
1403
1404                 // The reader is positioned on the first character
1405                 // of the element's name.
1406                 private void ReadEndTag ()
1407                 {
1408                         if (currentState != XmlNodeType.Element)
1409                                 throw new XmlException (this as IXmlLineInfo,
1410                                         "End tag cannot appear in this state.");
1411
1412                         string name = ReadName ();
1413                         if (elementStack.Count == 0)
1414                                 throw new XmlException (this as IXmlLineInfo,"closing element without matching opening element");
1415                         string expected = (string)elementStack.Pop();
1416                         if (expected != name)
1417                                 throw new XmlException (this as IXmlLineInfo,String.Format ("unmatched closing element: expected {0} but found {1}", expected, name));
1418                         parserContext.PopScope ();
1419
1420                         ExpectAfterWhitespace ('>');
1421
1422                         --depth;
1423
1424                         SetProperties (
1425                                 XmlNodeType.EndElement, // nodeType
1426                                 name, // name
1427                                 false, // isEmptyElement
1428                                 (string) null, // value
1429                                 true // clearAttributes
1430                         );
1431
1432                         popScope = true;
1433                 }
1434
1435                 private void AppendNameChar (int ch)
1436                 {
1437                         CheckNameCapacity ();
1438                         nameBuffer [nameLength++] = (char)ch;
1439                 }
1440
1441                 private void CheckNameCapacity ()
1442                 {
1443                         if (nameLength == nameCapacity) {
1444                                 nameCapacity = nameCapacity * 2;
1445                                 char [] oldNameBuffer = nameBuffer;
1446                                 nameBuffer = new char [nameCapacity];
1447                                 Array.Copy (oldNameBuffer, nameBuffer, nameLength);
1448                         }
1449                 }
1450
1451                 private string CreateNameString ()
1452                 {
1453                         return parserContext.NameTable.Add (nameBuffer, 0, nameLength);
1454                 }
1455
1456                 private void AppendValueChar (int ch)
1457                 {
1458                         valueBuffer.Append ((char)ch);
1459                 }
1460
1461                 private string CreateValueString ()
1462                 {
1463                         return valueBuffer.ToString ();
1464                 }
1465                 
1466                 private void ClearValueBuffer ()
1467                 {
1468                         valueBuffer.Length = 0;
1469                 }
1470
1471                 // The reader is positioned on the first character
1472                 // of the text.
1473                 private void ReadText (bool notWhitespace)
1474                 {
1475                         if (currentState != XmlNodeType.Element)
1476                                 throw new XmlException (this as IXmlLineInfo,
1477                                         "Text node cannot appear in this state.");
1478
1479                         if (notWhitespace)
1480                                 ClearValueBuffer ();
1481
1482                         int ch = PeekChar ();
1483                         int previousCloseBracketLine = 0;
1484                         int previousCloseBracketColumn = 0;
1485
1486                         while (ch != '<' && ch != -1) {
1487                                 if (ch == '&') {
1488                                         ReadChar ();
1489                                         ch = ReadReference (false);
1490                                         if (returnEntityReference) // Returns -1 if char validation should not be done
1491                                                 break;
1492                                 }
1493                                 else
1494                                         ch = ReadChar ();
1495
1496                                 if (normalization && XmlConstructs.IsInvalid (ch))
1497                                         throw new XmlException (this as IXmlLineInfo,
1498                                                 "Not allowed character was found.");
1499                                 AppendValueChar (ch);
1500
1501                                 // Block "]]>"
1502                                 if (ch == ']') {
1503                                         if (previousCloseBracketColumn == LinePosition - 1 &&
1504                                                 previousCloseBracketLine == LineNumber)
1505                                                 if (PeekChar () == '>')
1506                                                         throw new XmlException (this as IXmlLineInfo,
1507                                                                 "Inside text content, character sequence ']]>' is not allowed.");
1508                                         // This tricky style is required to check "] ]]>"
1509                                         previousCloseBracketColumn = LinePosition;
1510                                         previousCloseBracketLine = LineNumber;
1511                                 }
1512                                 ch = PeekChar ();
1513                                 notWhitespace = true;
1514                         }
1515
1516                         if (returnEntityReference && valueBuffer.Length == 0) {
1517                                 SetEntityReferenceProperties ();
1518                         } else {
1519                                 XmlNodeType nodeType = notWhitespace ? XmlNodeType.Text :
1520                                         this.XmlSpace == XmlSpace.Preserve ? XmlNodeType.SignificantWhitespace : XmlNodeType.Whitespace;
1521                                 SetProperties (
1522                                         nodeType, // nodeType
1523                                         String.Empty, // name
1524                                         false, // isEmptyElement
1525                                         true, // clearAttributes
1526                                         valueBuffer // value
1527                                 );
1528                         }
1529                 }
1530
1531                 // The leading '&' has already been consumed.
1532                 // Returns true if the entity reference isn't a simple
1533                 // character reference or one of the predefined entities.
1534                 // This allows the ReadText method to break so that the
1535                 // next call to Read will return the EntityReference node.
1536                 private int ReadReference (bool ignoreEntityReferences)
1537                 {
1538                         if (PeekChar () == '#') {
1539                                 ReadChar ();
1540                                 return ReadCharacterReference ();
1541                         } else
1542                                 return ReadEntityReference (ignoreEntityReferences);
1543                 }
1544
1545                 private int ReadCharacterReference ()
1546                 {
1547                         int value = 0;
1548
1549                         if (PeekChar () == 'x') {
1550                                 ReadChar ();
1551
1552                                 while (PeekChar () != ';' && PeekChar () != -1) {
1553                                         int ch = ReadChar ();
1554
1555                                         if (ch >= '0' && ch <= '9')
1556                                                 value = (value << 4) + ch - '0';
1557                                         else if (ch >= 'A' && ch <= 'F')
1558                                                 value = (value << 4) + ch - 'A' + 10;
1559                                         else if (ch >= 'a' && ch <= 'f')
1560                                                 value = (value << 4) + ch - 'a' + 10;
1561                                         else
1562                                                 throw new XmlException (this as IXmlLineInfo,
1563                                                         String.Format (
1564                                                                 "invalid hexadecimal digit: {0} (#x{1:X})",
1565                                                                 (char)ch,
1566                                                                 ch));
1567                                 }
1568                         } else {
1569                                 while (PeekChar () != ';' && PeekChar () != -1) {
1570                                         int ch = ReadChar ();
1571
1572                                         if (ch >= '0' && ch <= '9')
1573                                                 value = value * 10 + ch - '0';
1574                                         else
1575                                                 throw new XmlException (this as IXmlLineInfo,
1576                                                         String.Format (
1577                                                                 "invalid decimal digit: {0} (#x{1:X})",
1578                                                                 (char)ch,
1579                                                                 ch));
1580                                 }
1581                         }
1582
1583                         ReadChar (); // ';'
1584
1585                         // There is no way to save surrogate pairs...
1586                         if (normalization && value < 0xffff && !XmlConstructs.IsValid (value))
1587                                 throw new XmlException (this as IXmlLineInfo,
1588                                         "Referenced character was not allowed in XML.");
1589                         return value;
1590                 }
1591
1592                 // Returns -1 if it should not be validated.
1593                 // Real EOF must not be detected here.
1594                 private int ReadEntityReference (bool ignoreEntityReferences)
1595                 {
1596                         nameLength = 0;
1597
1598                         int ch = PeekChar ();
1599
1600                         while (ch != ';' && ch != -1) {
1601                                 AppendNameChar (ReadChar ());
1602                                 ch = PeekChar ();
1603                         }
1604
1605                         Expect (';');
1606
1607                         string name = CreateNameString ();
1608                         if (!XmlChar.IsName (name))
1609                                 throw new XmlException (this as IXmlLineInfo,
1610                                         "Invalid entity reference name was found.");
1611
1612                         char predefined = XmlChar.GetPredefinedEntity (name);
1613                         if (predefined != 0)
1614 //                              AppendValueChar (predefined);
1615                                 return predefined;
1616                         else {
1617                                 if (ignoreEntityReferences) {
1618                                         AppendValueChar ('&');
1619
1620                                         foreach (char ch2 in name) {
1621                                                 AppendValueChar (ch2);
1622                                         }
1623
1624                                         AppendValueChar (';');
1625                                 } else {
1626                                         returnEntityReference = true;
1627                                         entityReferenceName = name;
1628                                 }
1629                         }
1630                         return -1;
1631                 }
1632
1633                 // The reader is positioned on the first character of
1634                 // the attribute name.
1635                 private void ReadAttributes (bool endsWithQuestion)
1636                 {
1637                         int peekChar = -1;
1638                         bool requireWhitespace = false;
1639                         currentAttribute = -1;
1640                         currentAttributeValue = -1;
1641
1642                         do {
1643                                 if (!SkipWhitespace () && requireWhitespace)
1644                                         throw new XmlException ("Unexpected token. Name is required here.");
1645
1646                                 IncrementAttributeToken ();
1647                                 currentAttributeToken.LineNumber = line;
1648                                 currentAttributeToken.LinePosition = column;
1649
1650                                 currentAttributeToken.Name = ReadName ();
1651                                 ExpectAfterWhitespace ('=');
1652                                 SkipWhitespace ();
1653                                 ReadAttributeValueTokens (-1);
1654                                 attributeCount++;
1655
1656                                 if (currentAttributeToken.Name == "xmlns")
1657                                         parserContext.NamespaceManager.AddNamespace (String.Empty, GetAttribute (currentAttribute));
1658                                 else if (currentAttributeToken.Name.StartsWith ("xmlns:")) {
1659                                         string nsPrefix = currentAttributeToken.Name.Substring (6);
1660                                         parserContext.NamespaceManager.AddNamespace (nsPrefix, GetAttribute (currentAttribute));
1661                                 }
1662
1663                                 if (!SkipWhitespace ())
1664                                         requireWhitespace = true;
1665                                 peekChar = PeekChar ();
1666                                 if (endsWithQuestion) {
1667                                         if (peekChar == '?')
1668                                                 break;
1669                                 }
1670                                 else if (peekChar == '/' || peekChar == '>')
1671                                         break;
1672                         } while (peekChar != -1);
1673
1674                         currentAttribute = -1;
1675                         currentAttributeValue = -1;
1676                 }
1677
1678                 private void AddAttribute (string name, string value)
1679                 {
1680                         IncrementAttributeToken ();
1681                         XmlAttributeTokenInfo ati = attributeTokens [currentAttribute];
1682                         ati.Name = "SYSTEM";
1683                         ati.FillNames ();
1684                         IncrementAttributeValueToken ();
1685                         XmlTokenInfo vti = attributeValueTokens [currentAttributeValue];
1686                         vti.Value = value;
1687                         SetProperties (vti, XmlNodeType.Text, name, false, value, false);
1688                         attributeCount++;
1689                 }
1690
1691                 private void IncrementAttributeToken ()
1692                 {
1693                         currentAttribute++;
1694                         if (attributeTokens.Length == currentAttribute) {
1695                                 XmlAttributeTokenInfo [] newArray = 
1696                                         new XmlAttributeTokenInfo [attributeTokens.Length * 2];
1697                                 attributeTokens.CopyTo (newArray, 0);
1698                                 attributeTokens = newArray;
1699                         }
1700                         if (attributeTokens [currentAttribute] == null)
1701                                 attributeTokens [currentAttribute] = new XmlAttributeTokenInfo (this);
1702                         currentAttributeToken = attributeTokens [currentAttribute];
1703                         currentAttributeToken.Clear ();
1704                 }
1705
1706                 private void IncrementAttributeValueToken ()
1707                 {
1708                         ClearValueBuffer ();
1709                         currentAttributeValue++;
1710                         if (attributeValueTokens.Length == currentAttributeValue) {
1711                                 XmlTokenInfo [] newArray = new XmlTokenInfo [attributeValueTokens.Length * 2];
1712                                 attributeValueTokens.CopyTo (newArray, 0);
1713                                 attributeValueTokens = newArray;
1714                         }
1715                         if (attributeValueTokens [currentAttributeValue] == null)
1716                                 attributeValueTokens [currentAttributeValue] = new XmlTokenInfo (this);
1717                         currentAttributeValueToken = attributeValueTokens [currentAttributeValue];
1718                         currentAttributeValueToken.Clear ();
1719                 }
1720
1721                 private void ReadAttributeValueTokens (int dummyQuoteChar)
1722                 {
1723                         int quoteChar = (dummyQuoteChar < 0) ? ReadChar () : dummyQuoteChar;
1724
1725                         if (quoteChar != '\'' && quoteChar != '\"')
1726                                 throw new XmlException (this as IXmlLineInfo,"an attribute value was not quoted");
1727                         currentAttributeToken.QuoteChar = (char) quoteChar;
1728
1729                         IncrementAttributeValueToken ();
1730                         currentAttributeToken.ValueTokenStartIndex = currentAttributeValue;
1731                         currentAttributeValueToken.LineNumber = line;
1732                         currentAttributeValueToken.LinePosition = column;
1733
1734                         bool incrementToken = false;
1735                         bool isNewToken = true;
1736                         bool loop = true;
1737                         int ch = 0;
1738                         while (loop) {
1739                                 ch = ReadChar ();
1740                                 if (ch == quoteChar)
1741                                         break;
1742
1743                                 if (incrementToken) {
1744                                         IncrementAttributeValueToken ();
1745                                         currentAttributeValueToken.LineNumber = line;
1746                                         currentAttributeValueToken.LinePosition = column;
1747                                         incrementToken = false;
1748                                         isNewToken = true;
1749                                 }
1750
1751                                 switch (ch)
1752                                 {
1753                                 case '<':
1754                                         throw new XmlException (this as IXmlLineInfo,"attribute values cannot contain '<'");
1755                                 case -1:
1756                                         if (dummyQuoteChar < 0)
1757                                                 throw new XmlException (this as IXmlLineInfo,"unexpected end of file in an attribute value");
1758                                         else    // Attribute value constructor.
1759                                                 loop = false;
1760                                         break;
1761                                 case '&':
1762                                         int startPosition = currentTag.Length - 1;
1763                                         if (PeekChar () == '#') {
1764                                                 ReadChar ();
1765                                                 ch = ReadCharacterReference ();
1766                                                 AppendValueChar (ch);
1767                                                 break;
1768                                         }
1769                                         // Check XML 1.0 section 3.1 WFC.
1770                                         string entName = ReadName ();
1771                                         Expect (';');
1772                                         int predefined = XmlChar.GetPredefinedEntity (entName);
1773                                         if (predefined == 0) {
1774                                                 DTDEntityDeclaration entDecl = 
1775                                                         DTD == null ? null : DTD.EntityDecls [entName];
1776                                                 if (DTD != null && resolver != null && entDecl == null)
1777                                                         throw new XmlException (this as IXmlLineInfo, "Entity declaration does not exist.");
1778                                                 if (entDecl != null && entDecl.HasExternalReference)
1779                                                         throw new XmlException (this as IXmlLineInfo,
1780                                                                 "Reference to external entities is not allowed in the value of an attribute.");
1781                                                 if (isStandalone && !entDecl.IsInternalSubset)
1782                                                         throw new XmlException (this as IXmlLineInfo,
1783                                                                 "Reference to external entities is not allowed in the value of an attribute.");
1784                                                 if (entDecl != null && entDecl.EntityValue.IndexOf ('<') >= 0)
1785                                                         throw new XmlException (this as IXmlLineInfo,
1786                                                                 "Attribute must not contain character '<' either directly or indirectly by way of entity references.");
1787                                                 currentAttributeValueToken.Value = CreateValueString ();
1788                                                 currentAttributeValueToken.NodeType = XmlNodeType.Text;
1789                                                 if (!isNewToken)
1790                                                         IncrementAttributeValueToken ();
1791                                                 currentAttributeValueToken.Name = entName;
1792                                                 currentAttributeValueToken.Value = String.Empty;
1793                                                 currentAttributeValueToken.NodeType = XmlNodeType.EntityReference;
1794                                                 incrementToken = true;
1795                                         }
1796                                         else
1797                                                 AppendValueChar (predefined);
1798                                         break;
1799                                 default:
1800                                         AppendValueChar (ch);
1801                                         break;
1802                                 }
1803
1804                                 isNewToken = false;
1805                         }
1806                         if (!incrementToken) {
1807                                 currentAttributeValueToken.Value = CreateValueString ();
1808                                 currentAttributeValueToken.NodeType = XmlNodeType.Text;
1809                         }
1810                         currentAttributeToken.ValueTokenEndIndex = currentAttributeValue;
1811
1812                 }
1813
1814                 // The reader is positioned on the first character
1815                 // of the target.
1816                 //
1817                 // It may be xml declaration or processing instruction.
1818                 private void ReadProcessingInstruction ()
1819                 {
1820                         string target = ReadName ();
1821                         if (target == "xml") {
1822                                 ReadXmlDeclaration ();
1823                                 return;
1824                         } else if (target.ToLower () == "xml")
1825                                 throw new XmlException (this as IXmlLineInfo,
1826                                         "Not allowed processing instruction name which starts with 'X', 'M', 'L' was found.");
1827
1828                         if (currentState == XmlNodeType.None)
1829                                 currentState = XmlNodeType.XmlDeclaration;
1830
1831                         if (!SkipWhitespace ())
1832                                 if (PeekChar () != '?')
1833                                         throw new XmlException (this as IXmlLineInfo,
1834                                                 "Invalid processing instruction name was found.");
1835
1836                         ClearValueBuffer ();
1837
1838                         while (PeekChar () != -1) {
1839                                 int ch = ReadChar ();
1840
1841                                 if (ch == '?' && PeekChar () == '>') {
1842                                         ReadChar ();
1843                                         break;
1844                                 }
1845
1846                                 AppendValueChar ((char)ch);
1847                         }
1848
1849                         SetProperties (
1850                                 XmlNodeType.ProcessingInstruction, // nodeType
1851                                 target, // name
1852                                 false, // isEmptyElement
1853                                 true, // clearAttributes
1854                                 valueBuffer // value
1855                         );
1856                 }
1857
1858                 // The reader is positioned after "<?xml "
1859                 private void ReadXmlDeclaration ()
1860                 {
1861                         if (currentState != XmlNodeType.None) {
1862                                 throw new XmlException (this as IXmlLineInfo,
1863                                         "XML declaration cannot appear in this state.");
1864                         }
1865                         currentState = XmlNodeType.XmlDeclaration;
1866
1867                         ClearAttributes ();
1868
1869                         ReadAttributes (true);  // They must have "version."
1870                         string version = GetAttribute ("version");
1871
1872                         string message = null;
1873
1874                         if (attributeTokens [0].Name != "version" || version != "1.0")
1875                                 message = "Version 1.0 declaration is required in XML Declaration.";
1876                         else if (attributeCount > 1 &&
1877                                         (attributeTokens [1].Name != "encoding" &&
1878                                         attributeTokens [1].Name != "standalone"))
1879                                 message = "Invalid Xml Declaration markup was found.";
1880                         else if (attributeCount > 2 && attributeTokens [2].Name != "standalone")
1881                                 message = "Invalid Xml Declaration markup was found.";
1882                         string sa = GetAttribute ("standalone");
1883                         if (sa != null && sa != "yes" && sa != "no")
1884                                 message = "Only 'yes' or 'no' is allowed for standalone.";
1885
1886                         this.isStandalone = (sa == "yes");
1887
1888                         if (message != null)
1889                                 throw new XmlException (this as IXmlLineInfo, message);
1890
1891                         SetProperties (
1892                                 XmlNodeType.XmlDeclaration, // nodeType
1893                                 "xml", // name
1894                                 false, // isEmptyElement
1895                                 currentTag.ToString (6, currentTag.Length - 6), // value
1896                                 false // clearAttributes
1897                         );
1898
1899                         Expect ("?>");
1900                 }
1901
1902                 internal void SkipTextDeclaration ()
1903                 {
1904                         this.currentState = XmlNodeType.Element;
1905
1906                         if (PeekChar () != '<')
1907                                 return;
1908
1909                         ReadChar ();
1910                         peekChars [0] = '<';
1911
1912                         if (PeekChar () != '?') {
1913                                 hasPeekChars = true;
1914                                 return;
1915                         }
1916                         ReadChar ();
1917                         peekChars [1] = '?';
1918
1919                         for (int i = 2; i < 6; i++) {
1920                                 if (PeekChar () == 0)
1921                                         break;
1922                                 else
1923                                         peekChars [i] = (char) ReadChar ();
1924                         }
1925                         if (new string (peekChars, 2, 4) != "xml ") {
1926                                 if (new string (peekChars, 2, 3).ToLower () == "xml") {
1927                                         throw new XmlException (this as IXmlLineInfo,
1928                                                 "Processing instruction name must not be character sequence 'X' 'M' 'L' with case insensitivity.");
1929                                 }
1930                                 hasPeekChars = true;
1931                                 return;
1932                         }
1933
1934                         for (int i = 0; i < 6; i++)
1935                                 peekChars [i] = '\0';
1936
1937                         SkipWhitespace ();
1938
1939                         // version decl
1940                         if (PeekChar () == 'v') {
1941                                 Expect ("version");
1942                                 ExpectAfterWhitespace ('=');
1943                                 SkipWhitespace ();
1944                                 int quoteChar = ReadChar ();
1945                                 char [] expect1_0 = new char [3];
1946                                 int versionLength = 0;
1947                                 switch (quoteChar) {
1948                                 case '\'':
1949                                 case '"':
1950                                         while (PeekChar () != quoteChar) {
1951                                                 if (PeekChar () == -1)
1952                                                         throw new XmlException (this as IXmlLineInfo,
1953                                                                 "Invalid version declaration inside text declaration.");
1954                                                 else if (versionLength == 3)
1955                                                         throw new XmlException (this as IXmlLineInfo,
1956                                                                 "Invalid version number inside text declaration.");
1957                                                 else {
1958                                                         expect1_0 [versionLength] = (char) ReadChar ();
1959                                                         versionLength++;
1960                                                         if (versionLength == 3 && new String (expect1_0) != "1.0")
1961                                                                 throw new XmlException (this as IXmlLineInfo,
1962                                                                         "Invalid version number inside text declaration.");
1963                                                 }
1964                                         }
1965                                         ReadChar ();
1966                                         SkipWhitespace ();
1967                                         break;
1968                                 default:
1969                                         throw new XmlException (this as IXmlLineInfo,
1970                                                 "Invalid version declaration inside text declaration.");
1971                                 }
1972                         }
1973
1974                         if (PeekChar () == 'e') {
1975                                 Expect ("encoding");
1976                                 ExpectAfterWhitespace ('=');
1977                                 SkipWhitespace ();
1978                                 int quoteChar = ReadChar ();
1979                                 switch (quoteChar) {
1980                                 case '\'':
1981                                 case '"':
1982                                         while (PeekChar () != quoteChar)
1983                                                 if (ReadChar () == -1)
1984                                                         throw new XmlException (this as IXmlLineInfo,
1985                                                                 "Invalid encoding declaration inside text declaration.");
1986                                         ReadChar ();
1987                                         SkipWhitespace ();
1988                                         break;
1989                                 default:
1990                                         throw new XmlException (this as IXmlLineInfo,
1991                                                 "Invalid encoding declaration inside text declaration.");
1992                                 }
1993                                 // Encoding value should be checked inside XmlInputStream.
1994                         }
1995                         else
1996                                 throw new XmlException (this as IXmlLineInfo,
1997                                         "Encoding declaration is mandatory in text declaration.");
1998
1999                         Expect ("?>");
2000                 }
2001
2002                 // The reader is positioned on the first character after
2003                 // the leading '<!'.
2004                 private void ReadDeclaration ()
2005                 {
2006                         int ch = PeekChar ();
2007
2008                         switch (ch)
2009                         {
2010                         case '-':
2011                                 Expect ("--");
2012                                 ReadComment ();
2013                                 break;
2014                         case '[':
2015                                 ReadChar ();
2016                                 Expect ("CDATA[");
2017                                 ReadCDATA ();
2018                                 break;
2019                         case 'D':
2020                                 Expect ("DOCTYPE");
2021                                 ReadDoctypeDecl ();
2022                                 break;
2023                         default:
2024                                 throw new XmlException (this as IXmlLineInfo,
2025                                         "Unexpected declaration markup was found.");
2026                         }
2027                 }
2028
2029                 // The reader is positioned on the first character after
2030                 // the leading '<!--'.
2031                 private void ReadComment ()
2032                 {
2033                         if (currentState == XmlNodeType.None)
2034                                 currentState = XmlNodeType.XmlDeclaration;
2035
2036                         ClearValueBuffer ();
2037
2038                         while (PeekChar () != -1) {
2039                                 int ch = ReadChar ();
2040
2041                                 if (ch == '-' && PeekChar () == '-') {
2042                                         ReadChar ();
2043
2044                                         if (PeekChar () != '>')
2045                                                 throw new XmlException (this as IXmlLineInfo,"comments cannot contain '--'");
2046
2047                                         ReadChar ();
2048                                         break;
2049                                 }
2050
2051                                 if (XmlConstructs.IsInvalid (ch))
2052                                         throw new XmlException (this as IXmlLineInfo,
2053                                                 "Not allowed character was found.");
2054
2055                                 AppendValueChar ((char)ch);
2056                         }
2057
2058                         SetProperties (
2059                                 XmlNodeType.Comment, // nodeType
2060                                 String.Empty, // name
2061                                 false, // isEmptyElement
2062                                 true, // clearAttributes
2063                                 valueBuffer // value
2064                         );
2065                 }
2066
2067                 // The reader is positioned on the first character after
2068                 // the leading '<![CDATA['.
2069                 private void ReadCDATA ()
2070                 {
2071                         if (currentState != XmlNodeType.Element)
2072                                 throw new XmlException (this as IXmlLineInfo,
2073                                         "CDATA section cannot appear in this state.");
2074
2075                         ClearValueBuffer ();
2076
2077                         bool skip = false;
2078                         int ch = 0;
2079                         while (PeekChar () != -1) {
2080                                 if (!skip)
2081                                         ch = ReadChar ();
2082                                 skip = false;
2083
2084                                 if (ch == ']' && PeekChar () == ']') {
2085                                         ch = ReadChar (); // ']'
2086
2087                                         if (PeekChar () == '>') {
2088                                                 ReadChar (); // '>'
2089                                                 break;
2090                                         } else {
2091                                                 skip = true;
2092 //                                              AppendValueChar (']');
2093 //                                              AppendValueChar (']');
2094 //                                              ch = ReadChar ();
2095                                         }
2096                                 }
2097
2098                                 AppendValueChar ((char)ch);
2099                         }
2100
2101                         SetProperties (
2102                                 XmlNodeType.CDATA, // 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 '<!DOCTYPE'.
2112                 private void ReadDoctypeDecl ()
2113                 {
2114                         switch (currentState) {
2115                         case XmlNodeType.DocumentType:
2116                         case XmlNodeType.Element:
2117                         case XmlNodeType.EndElement:
2118                                 throw new XmlException (this as IXmlLineInfo,
2119                                         "Document type cannot appear in this state.");
2120                         }
2121                         currentState = XmlNodeType.DocumentType;
2122
2123                         string doctypeName = null;
2124                         string publicId = null;
2125                         string systemId = null;
2126                         int intSubsetStartLine = 0;
2127                         int intSubsetStartColumn = 0;
2128
2129                         SkipWhitespace ();
2130                         doctypeName = ReadName ();
2131                         SkipWhitespace ();
2132                         switch(PeekChar ())
2133                         {
2134                         case 'S':
2135                                 systemId = ReadSystemLiteral (true);
2136                                 break;
2137                         case 'P':
2138                                 publicId = ReadPubidLiteral ();
2139                                 if (!SkipWhitespace ())
2140                                         throw new XmlException (this as IXmlLineInfo,
2141                                                 "Whitespace is required between PUBLIC id and SYSTEM id.");
2142                                 systemId = ReadSystemLiteral (false);
2143                                 break;
2144                         }
2145                         SkipWhitespace ();
2146
2147
2148                         if(PeekChar () == '[')
2149                         {
2150                                 // read markupdecl etc. or end of decl
2151                                 ReadChar ();
2152                                 intSubsetStartLine = this.LineNumber;
2153                                 intSubsetStartColumn = this.LinePosition;
2154                                 int startPos = currentTag.Length;
2155                                 ReadInternalSubset ();
2156                                 int endPos = currentTag.Length - 1;
2157                                 parserContext.InternalSubset = currentTag.ToString (startPos, endPos - startPos);
2158                         }
2159                         // end of DOCTYPE decl.
2160                         ExpectAfterWhitespace ('>');
2161
2162                         GenerateDTDObjectModel (doctypeName, publicId,
2163                                 systemId, parserContext.InternalSubset,
2164                                 intSubsetStartLine, intSubsetStartColumn);
2165
2166                         // set properties for <!DOCTYPE> node
2167                         SetProperties (
2168                                 XmlNodeType.DocumentType, // nodeType
2169                                 doctypeName, // name
2170                                 false, // isEmptyElement
2171                                 parserContext.InternalSubset, // value
2172                                 true // clearAttributes
2173                                 );
2174
2175                         if (publicId != null)
2176                                 AddAttribute ("PUBLIC", publicId);
2177                         if (systemId != null)
2178                                 AddAttribute ("SYSTEM", systemId);
2179                 }
2180
2181                 internal DTDObjectModel GenerateDTDObjectModel (string name, string publicId,
2182                         string systemId, string internalSubset)
2183                 {
2184                         return GenerateDTDObjectModel (name, publicId, systemId, internalSubset, 0, 0);
2185                 }
2186
2187                 internal DTDObjectModel GenerateDTDObjectModel (string name, string publicId,
2188                         string systemId, string internalSubset, int intSubsetStartLine, int intSubsetStartColumn)
2189                 {
2190                         // now compile DTD
2191                         parserContext.Dtd = new DTDObjectModel (this.NameTable);        // merges both internal and external subsets in the meantime,
2192                         DTD.BaseURI = BaseURI;
2193                         DTD.Name = name;
2194                         DTD.PublicId = publicId;
2195                         DTD.SystemId = systemId;
2196                         DTD.InternalSubset = internalSubset;
2197                         DTD.XmlResolver = resolver;
2198                         DTD.IsStandalone = isStandalone;
2199                         DTD.LineNumber = line;
2200                         DTD.LinePosition = column;
2201
2202                         DTDReader dr = new DTDReader (DTD, intSubsetStartLine, intSubsetStartColumn);
2203                         dr.Normalization = this.normalization;
2204                         return dr.GenerateDTDObjectModel ();
2205                 }
2206
2207                 private enum DtdInputState
2208                 {
2209                         Free = 1,
2210                         ElementDecl,
2211                         AttlistDecl,
2212                         EntityDecl,
2213                         NotationDecl,
2214                         PI,
2215                         Comment,
2216                         InsideSingleQuoted,
2217                         InsideDoubleQuoted,
2218                 }
2219
2220                 private class DtdInputStateStack
2221                 {
2222                         Stack intern = new Stack ();
2223                         public DtdInputStateStack ()
2224                         {
2225                                 Push (DtdInputState.Free);
2226                         }
2227
2228                         public DtdInputState Peek ()
2229                         {
2230                                 return (DtdInputState) intern.Peek ();
2231                         }
2232
2233                         public DtdInputState Pop ()
2234                         {
2235                                 return (DtdInputState) intern.Pop ();
2236                         }
2237
2238                         public void Push (DtdInputState val)
2239                         {
2240                                 intern.Push (val);
2241                         }
2242                 }
2243
2244
2245                 DtdInputStateStack stateStack = new DtdInputStateStack ();
2246                 DtdInputState State {
2247                         get { return stateStack.Peek (); }
2248                 }
2249
2250                 // Simply read but not generate any result.
2251                 private void ReadInternalSubset ()
2252                 {
2253                         bool continueParse = true;
2254
2255                         while (continueParse) {
2256                                 switch (ReadChar ()) {
2257                                 case ']':
2258                                         switch (State) {
2259                                         case DtdInputState.Free:
2260                                                 continueParse = false;
2261                                                 break;
2262                                         case DtdInputState.InsideDoubleQuoted:
2263                                                 continue;
2264                                         case DtdInputState.InsideSingleQuoted:
2265                                                 continue;
2266                                         default:
2267                                                 throw new XmlException (this as IXmlLineInfo,"unexpected end of file at DTD.");
2268                                         }
2269                                         break;
2270                                 case -1:
2271                                         throw new XmlException (this as IXmlLineInfo,"unexpected end of file at DTD.");
2272                                 case '<':
2273                                         if (State == DtdInputState.InsideDoubleQuoted ||
2274                                                 State == DtdInputState.InsideSingleQuoted)
2275                                                 continue;       // well-formed
2276                                         switch (ReadChar ()) {
2277                                         case '?':
2278                                                 stateStack.Push (DtdInputState.PI);
2279                                                 break;
2280                                         case '!':
2281                                                 switch (ReadChar ()) {
2282                                                 case 'E':
2283                                                         switch (ReadChar ()) {
2284                                                         case 'L':
2285                                                                 Expect ("EMENT");
2286                                                                 stateStack.Push (DtdInputState.ElementDecl);
2287                                                                 break;
2288                                                         case 'N':
2289                                                                 Expect ("TITY");
2290                                                                 stateStack.Push (DtdInputState.EntityDecl);
2291                                                                 break;
2292                                                         default:
2293                                                                 throw new XmlException (this as IXmlLineInfo,"unexpected token '<!E'.");
2294                                                         }
2295                                                         break;
2296                                                 case 'A':
2297                                                         Expect ("TTLIST");
2298                                                         stateStack.Push (DtdInputState.AttlistDecl);
2299                                                         break;
2300                                                 case 'N':
2301                                                         Expect ("OTATION");
2302                                                         stateStack.Push (DtdInputState.NotationDecl);
2303                                                         break;
2304                                                 case '-':
2305                                                         Expect ("-");
2306                                                         stateStack.Push (DtdInputState.Comment);
2307                                                         break;
2308                                                 }
2309                                                 break;
2310                                         default:
2311                                                 throw new XmlException (this as IXmlLineInfo,"unexpected '>'.");
2312                                         }
2313                                         break;
2314                                 case '\'':
2315                                         if (State == DtdInputState.InsideSingleQuoted)
2316                                                 stateStack.Pop ();
2317                                         else if (State != DtdInputState.InsideDoubleQuoted && State != DtdInputState.Comment)
2318                                                 stateStack.Push (DtdInputState.InsideSingleQuoted);
2319                                         break;
2320                                 case '"':
2321                                         if (State == DtdInputState.InsideDoubleQuoted)
2322                                                 stateStack.Pop ();
2323                                         else if (State != DtdInputState.InsideSingleQuoted && State != DtdInputState.Comment)
2324                                                 stateStack.Push (DtdInputState.InsideDoubleQuoted);
2325                                         break;
2326                                 case '>':
2327                                         switch (State) {
2328                                         case DtdInputState.ElementDecl:
2329                                                 goto case DtdInputState.NotationDecl;
2330                                         case DtdInputState.AttlistDecl:
2331                                                 goto case DtdInputState.NotationDecl;
2332                                         case DtdInputState.EntityDecl:
2333                                                 goto case DtdInputState.NotationDecl;
2334                                         case DtdInputState.NotationDecl:
2335                                                 stateStack.Pop ();
2336                                                 break;
2337                                         case DtdInputState.InsideDoubleQuoted:
2338                                                 continue;
2339                                         case DtdInputState.InsideSingleQuoted:
2340                                                 continue; // well-formed
2341                                         case DtdInputState.Comment:
2342                                                 continue;
2343                                         default:
2344                                                 throw new XmlException (this as IXmlLineInfo,"unexpected token '>'");
2345                                         }
2346                                         break;
2347                                 case '?':
2348                                         if (State == DtdInputState.PI) {
2349                                                 if (ReadChar () == '>')
2350                                                         stateStack.Pop ();
2351                                         }
2352                                         break;
2353                                 case '-':
2354                                         if (State == DtdInputState.Comment) {
2355                                                 if (PeekChar () == '-') {
2356                                                         ReadChar ();
2357                                                         Expect ('>');
2358                                                         stateStack.Pop ();
2359                                                 }
2360                                         }
2361                                         break;
2362                                 case '%':
2363                                         if (State != DtdInputState.Free && State != DtdInputState.EntityDecl && State != DtdInputState.Comment && State != DtdInputState.InsideDoubleQuoted && State != DtdInputState.InsideSingleQuoted)
2364                                                 throw new XmlException (this as IXmlLineInfo,"Parameter Entity Reference cannot appear as a part of markupdecl (see XML spec 2.8).");
2365                                         break;
2366                                 }
2367                         }
2368                 }
2369
2370                 // The reader is positioned on the first 'S' of "SYSTEM".
2371                 private string ReadSystemLiteral (bool expectSYSTEM)
2372                 {
2373                         if(expectSYSTEM) {
2374                                 Expect ("SYSTEM");
2375                                 if (!SkipWhitespace ())
2376                                         throw new XmlException (this as IXmlLineInfo,
2377                                                 "Whitespace is required after 'SYSTEM'.");
2378                         }
2379                         else
2380                                 SkipWhitespace ();
2381                         int quoteChar = ReadChar ();    // apos or quot
2382                         int startPos = currentTag.Length;
2383                         int c = 0;
2384                         ClearValueBuffer ();
2385                         while (c != quoteChar) {
2386                                 c = ReadChar ();
2387                                 if (c < 0)
2388                                         throw new XmlException (this as IXmlLineInfo,"Unexpected end of stream in ExternalID.");
2389                                 if (c != quoteChar)
2390                                         AppendValueChar (c);
2391                         }
2392                         return CreateValueString (); //currentTag.ToString (startPos, currentTag.Length - 1 - startPos);
2393                 }
2394
2395                 private string ReadPubidLiteral()
2396                 {
2397                         Expect ("PUBLIC");
2398                         if (!SkipWhitespace ())
2399                                 throw new XmlException (this as IXmlLineInfo,
2400                                         "Whitespace is required after 'PUBLIC'.");
2401                         int quoteChar = ReadChar ();
2402                         int startPos = currentTag.Length;
2403                         int c = 0;
2404                         ClearValueBuffer ();
2405                         while(c != quoteChar)
2406                         {
2407                                 c = ReadChar ();
2408                                 if(c < 0) throw new XmlException (this as IXmlLineInfo,"Unexpected end of stream in ExternalID.");
2409                                 if(c != quoteChar && !XmlChar.IsPubidChar (c))
2410                                         throw new XmlException (this as IXmlLineInfo,"character '" + (char)c + "' not allowed for PUBLIC ID");
2411                                 if (c != quoteChar)
2412                                         AppendValueChar (c);
2413                         }
2414                         return CreateValueString (); //currentTag.ToString (startPos, currentTag.Length - 1 - startPos);
2415                 }
2416
2417                 // The reader is positioned on the first character
2418                 // of the name.
2419                 private string ReadName ()
2420                 {
2421                         return ReadNameOrNmToken(false);
2422                 }
2423
2424                 // The reader is positioned on the first character
2425                 // of the name.
2426                 private string ReadNmToken ()
2427                 {
2428                         return ReadNameOrNmToken(true);
2429                 }
2430
2431                 private string ReadNameOrNmToken (bool isNameToken)
2432                 {
2433                         int ch = PeekChar ();
2434                         if(isNameToken) {
2435                                 if (!XmlChar.IsNameChar ((char) ch))
2436                                         throw new XmlException (this as IXmlLineInfo,String.Format ("a nmtoken did not start with a legal character {0} ({1})", ch, (char)ch));
2437                         }
2438                         else {
2439                                 if (!XmlChar.IsFirstNameChar (ch))
2440                                         throw new XmlException (this as IXmlLineInfo,String.Format ("a name did not start with a legal character {0} ({1})", ch, (char)ch));
2441                         }
2442
2443                         nameLength = 0;
2444
2445                         AppendNameChar (ReadChar ());
2446
2447                         while (XmlChar.IsNameChar (PeekChar ())) {
2448                                 AppendNameChar (ReadChar ());
2449                         }
2450
2451                         return CreateNameString ();
2452                 }
2453
2454                 // Read the next character and compare it against the
2455                 // specified character.
2456                 private void Expect (int expected)
2457                 {
2458                         int ch = ReadChar ();
2459
2460                         if (ch != expected) {
2461                                 throw new XmlException (this as IXmlLineInfo,
2462                                         String.Format (
2463                                                 "expected '{0}' ({1:X}) but found '{2}' ({3:X})",
2464                                                 (char)expected,
2465                                                 expected,
2466                                                 (char)ch,
2467                                                 ch));
2468                         }
2469                 }
2470
2471                 private void Expect (string expected)
2472                 {
2473                         int len = expected.Length;
2474                         for(int i=0; i< len; i++)
2475                                 Expect (expected[i]);
2476                 }
2477
2478                 private void ExpectAfterWhitespace (char c)
2479                 {
2480                         while (true) {
2481                                 int i = ReadChar ();
2482                                 if (XmlChar.IsWhitespace (i))
2483                                         continue;
2484                                 if (c != i)
2485                                         throw new XmlException (String.Join (String.Empty, new string [] {"Expected ", c.ToString (), ", but found " + (char) i, "[", i.ToString (), "]"}));
2486                                 break;
2487                         }
2488                 }
2489
2490                 // Does not consume the first non-whitespace character.
2491                 private bool SkipWhitespace ()
2492                 {
2493                         bool skipped = XmlChar.IsWhitespace (PeekChar ());
2494                         while (XmlChar.IsWhitespace (PeekChar ()))
2495                                 ReadChar ();
2496                         return skipped;
2497                 }
2498
2499                 private void ReadWhitespace ()
2500                 {
2501                         if (currentState == XmlNodeType.None)
2502                                 currentState = XmlNodeType.XmlDeclaration;
2503
2504                         ClearValueBuffer ();
2505                         int ch = PeekChar ();
2506                         do {
2507                                 AppendValueChar (ReadChar ());
2508                         } while ((ch = PeekChar ()) != -1 && XmlChar.IsWhitespace (ch));
2509
2510                         if (currentState == XmlNodeType.Element && ch != -1 && ch != '<')
2511                                 ReadText (false);
2512                         else {
2513                                 XmlNodeType nodeType = (this.XmlSpace == XmlSpace.Preserve) ?
2514                                         XmlNodeType.SignificantWhitespace : XmlNodeType.Whitespace;
2515                                 SetProperties (nodeType,
2516                                                String.Empty,
2517                                                false,
2518                                                true,
2519                                                valueBuffer);
2520                         }
2521
2522                         return; // (PeekChar () != -1);
2523                 }
2524
2525                 private byte GetBase64Byte (char ch)
2526                 {
2527                         switch (ch) {
2528                         case '+':
2529                                 return 62;
2530                         case '/':
2531                                 return 63;
2532                         case '=':
2533                                 return 0;
2534                         default:
2535                                 if (ch >= 'A' && ch <= 'Z')
2536                                         return (byte) (ch - 'A');
2537                                 else if (ch >= 'a' && ch <= 'z')
2538                                         return (byte) (ch - 'a' + 26);
2539                                 else if (ch >= '0' && ch <= '9')
2540                                         return (byte) (ch - '0' + 52);
2541                                 else
2542                                         throw new XmlException ("Invalid Base64 character was found.");
2543                         }
2544                 }
2545
2546                 // Returns -1 if it should throw an error.
2547                 private int ReadCharsInternal (char [] buffer, int offset, int length)
2548                 {
2549                         shouldSkipUntilEndTag = true;
2550
2551                         if (offset < 0)
2552                                 throw new ArgumentOutOfRangeException ("offset", offset, "Offset must be non-negative integer.");
2553                         else if (length < 0)
2554                                 throw new ArgumentOutOfRangeException ("length", length, "Length must be non-negative integer.");
2555                         else if (buffer.Length < offset + length)
2556                                 throw new ArgumentOutOfRangeException ("buffer length is smaller than the sum of offset and length.");
2557
2558                         if (NodeType != XmlNodeType.Element)
2559                                 return 0;
2560
2561                         int bufIndex = offset;
2562                         for (int i = 0; i < length; i++) {
2563                                 int c = PeekChar ();
2564                                 switch (c) {
2565                                 case -1:
2566                                         throw new XmlException (this as IXmlLineInfo, "Unexpected end of xml.");
2567                                 case '<':
2568                                         ReadChar ();
2569                                         if (PeekChar () != '/') {
2570                                                 buffer [bufIndex++] = '<';
2571                                                 continue;
2572                                         }
2573                                         // Seems to skip immediate EndElement
2574                                         Expect ('/');
2575                                         string name = ReadName ();
2576                                         if (name != (string) this.elementStack.Peek ()) {
2577                                                 if (i + 1 < length) {
2578                                                         buffer [bufIndex++] = '<';
2579                                                         buffer [bufIndex++] = '/';
2580                                                 }
2581                                                 for (int n = 0; n < name.Length && i + n + 1 < length; n++)
2582                                                         buffer [bufIndex++] = name [n];
2583                                                 continue;
2584                                         }
2585                                         Expect ('>');
2586                                         depth--;
2587                                         this.elementStack.Pop ();
2588                                         shouldSkipUntilEndTag = false;
2589                                         Read ();
2590                                         return i;
2591                                 default:
2592                                         buffer [bufIndex++] = (char) ReadChar ();
2593                                         break;
2594                                 }
2595                         }
2596                         return length;
2597                 }
2598
2599                 private bool ReadUntilEndTag ()
2600                 {
2601                         int ch;
2602                         do {
2603                                 ch = ReadChar ();
2604                                 switch (ch) {
2605                                 case -1:
2606                                         throw new XmlException (this as IXmlLineInfo,
2607                                                 "Unexpected end of xml.");
2608                                 case '<':
2609                                         if (PeekChar () != '/')
2610                                                 continue;
2611                                         ReadChar ();
2612                                         string name = ReadName ();
2613                                         if (name != (string) this.elementStack.Peek ())
2614                                                 continue;
2615                                         Expect ('>');
2616                                         depth--;
2617                                         this.elementStack.Pop ();
2618                                         return Read ();
2619                                 }
2620                         } while (true);
2621                 }
2622                 #endregion
2623         }
2624 }