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