2004-10-18 Atsushi Enomoto <atsushi@ximian.com>
[mono.git] / mcs / class / System.XML / System.Xml / XmlTextReader.cs
index 21162130b1893dbfb48b3ebc95d8cfb421fac7c4..f1d5b59e8b04e5f2364e7c63c64d26bd4fe4522d 100644 (file)
@@ -4,43 +4,58 @@
 // Author:
 //   Jason Diamond (jason@injektilo.org)
 //   Adam Treat (manyoso@yahoo.com)
+//   Atsushi Enomoto  (ginga@kit.hi-ho.ne.jp)
 //
 // (C) 2001, 2002 Jason Diamond  http://injektilo.org/
 //
 
-// FIXME:
-//   This can only parse basic XML: elements, attributes, processing
-//   instructions, and comments are OK.
-//
-//   It barfs on DOCTYPE declarations.
-//     => No barfing, but parsing is incomplete.
-//        DTD nodes are not still created.
-//
-//   There's also no checking being done for either well-formedness
-//   or validity.
-//
-//   NameTables aren't being used everywhere yet.
 //
-//   Some thought needs to be given to performance. There's too many
-//   strings being allocated.
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+// 
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+// 
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 //
-//   Some of the MoveTo methods haven't been implemented yet.
+
+// FIXME:
 //
-//   LineNumber and LinePosition aren't being tracked.
+//   Some thought needs to be given to performance.
 //
-//   xml:space, xml:lang, and xml:base aren't being tracked.
+//   If current node is on an Attribute, Prefix might be null, and
+//   in several fields which uses XmlReader, it should be considered.
 //
 
 using System;
 using System.Collections;
+using System.Globalization;
 using System.IO;
+using System.Security.Policy;
 using System.Text;
+using System.Xml.Schema;
+using Mono.Xml;
 
 namespace System.Xml
 {
+#if NET_2_0
+       public class XmlTextReader : XmlReader,
+               IXmlLineInfo, IXmlNamespaceResolver
+#else
        public class XmlTextReader : XmlReader, IXmlLineInfo
+#endif
        {
-               WhitespaceHandling whitespaceHandling = WhitespaceHandling.All;
                #region Constructors
 
                protected XmlTextReader ()
@@ -48,7 +63,7 @@ namespace System.Xml
                }
 
                public XmlTextReader (Stream input)
-                       : this (new StreamReader (input))
+                       : this (new XmlStreamReader (input))
                {
                }
 
@@ -68,12 +83,12 @@ namespace System.Xml
                }
 
                public XmlTextReader (Stream input, XmlNameTable nt)
-                       : this(new StreamReader (input), nt)
+                       : this(new XmlStreamReader (input), nt)
                {
                }
 
                public XmlTextReader (string url, Stream input)
-                       : this (url, new StreamReader (input))
+                       : this (url, new XmlStreamReader (input))
                {
                }
 
@@ -82,45 +97,51 @@ namespace System.Xml
                {
                }
 
-               [MonoTODO("Non-filename-url must be supported. Waiting for WebClient")]
                public XmlTextReader (string url, XmlNameTable nt)
-                       // : this(url, new StreamReader ((Stream)new XmlUrlResolver ().GetEntity (new Uri (url), null, typeof(Stream))), nt)
-                       : this (url, new StreamReader (url), nt)
                {
+                       Uri uri = resolver.ResolveUri (null, url);
+                       Stream s = resolver.GetEntity (uri, null, typeof (Stream)) as Stream;
+                       XmlParserContext ctx = new XmlParserContext (nt,
+                               new XmlNamespaceManager (nt),
+                               String.Empty,
+                               XmlSpace.None);
+                       this.InitializeContext (uri.ToString(), ctx, new XmlStreamReader (s), XmlNodeType.Document);
                }
 
                public XmlTextReader (TextReader input, XmlNameTable nt)
-                       : this(String.Empty, input, nt)
+                       : this (String.Empty, input, nt)
                {
                }
 
                public XmlTextReader (Stream xmlFragment, XmlNodeType fragType, XmlParserContext context)
-                       : this (String.Empty, new StreamReader (xmlFragment), fragType, context)
+                       : this (context != null ? context.BaseURI : String.Empty,
+                               new XmlStreamReader (xmlFragment),
+                       fragType,
+                       context)
                {
                }
 
                public XmlTextReader (string url, Stream input, XmlNameTable nt)
-                       : this (url, new StreamReader (input), nt)
+                       : this (url, new XmlStreamReader (input), nt)
                {
                }
 
                public XmlTextReader (string url, TextReader input, XmlNameTable nt)
-                       : this (url, input, XmlNodeType.Document, new XmlParserContext (nt, new XmlNamespaceManager (nt), null, XmlSpace.None))
+                       : this (url, input, XmlNodeType.Document, null)
                {
                }
 
-               [MonoTODO("TODO as same as private XmlTextReader(TextReader, XmlNodeType, XmlParserContext)")]
                public XmlTextReader (string xmlFragment, XmlNodeType fragType, XmlParserContext context)
-                       : this (String.Empty, new StringReader (xmlFragment), fragType, context)
+                       : this (context != null ? context.BaseURI : String.Empty,
+                               new StringReader (xmlFragment),
+                               fragType,
+                               context)
                {
                }
 
-               // TODO still remains as described at head of this file,
-               // but it might not be TODO of the constructors...
                XmlTextReader (string url, TextReader fragment, XmlNodeType fragType, XmlParserContext context)
                {
-                       this.SetReaderContext(url, context);
-                       this.SetReaderFragment(fragment, fragType);
+                       InitializeContext (url, context, fragment, fragType);
                }
 
                #endregion
@@ -129,7 +150,7 @@ namespace System.Xml
 
                public override int AttributeCount
                {
-                       get { return attributes.Count; }
+                       get { return attributeCount; }
                }
 
                public override string BaseURI
@@ -137,9 +158,32 @@ namespace System.Xml
                        get { return parserContext.BaseURI; }
                }
 
+#if NET_2_0
+               public override bool CanResolveEntity {
+                       get { return true; }
+               }
+
+#endif
+
+               internal bool CharacterChecking {
+                       get { return checkCharacters && normalization; }
+                       set { checkCharacters = value; }
+               }
+
+               // for XmlReaderSettings.CloseInput support
+               internal bool CloseInput {
+                       get { return closeInput; }
+                       set { closeInput = value; }
+               }
+
                public override int Depth
                {
                        get {
+                               int nodeTypeMod = currentToken.NodeType == XmlNodeType.Element  ? 0 : -1;
+                               if (currentAttributeValue >= 0)
+                                       return nodeTypeMod + elementDepth + 2; // inside attribute value.
+                               else if (currentAttribute >= 0)
+                                       return nodeTypeMod + elementDepth + 1;
                                return elementDepth;
                        }
                }
@@ -148,571 +192,881 @@ namespace System.Xml
                {
                        get { return parserContext.Encoding; }
                }
+#if NET_2_0
+               [MonoTODO]
+               public EntityHandling EntityHandling {
+                       get { return entityHandling; }
+                       set { entityHandling = value; }
+               }
+#endif
 
-               public override bool EOF
-               {
-                       get
-                       {
-                               return
-                                       readState == ReadState.EndOfFile ||
-                                       readState == ReadState.Closed;
-                       }
+               public override bool EOF {
+                       get { return readState == ReadState.EndOfFile; }
                }
 
-               public override bool HasValue
-               {
-                       get { return value != String.Empty;     }
+#if NET_2_0
+               [MonoTODO]
+               public override Evidence Evidence {
+                       get { return base.Evidence; }
                }
+#endif
 
-               public override bool IsDefault
-               {
-                       get
-                       {
-                               // XmlTextReader does not expand default attributes.
-                               return false;
-                       }
+               public override bool HasValue {
+                       get { return cursorToken.Value != null; }
                }
 
-               public override bool IsEmptyElement
-               {
-                       get { return isEmptyElement; }
+               public override bool IsDefault {
+                       // XmlTextReader does not expand default attributes.
+                       get { return false; }
                }
 
-               public override string this [int i]
-               {
+               public override bool IsEmptyElement {
+                       get { return cursorToken.IsEmptyElement; }
+               }
+
+               public override string this [int i] {
                        get { return GetAttribute (i); }
                }
 
-               public override string this [string name]
-               {
+               public override string this [string name] {
                        get { return GetAttribute (name); }
                }
 
-               public override string this [string localName, string namespaceName]
-               {
+               public override string this [string localName, string namespaceName] {
                        get { return GetAttribute (localName, namespaceName); }
                }
 
-               public int LineNumber
-               {
-                       get { return line; }
+               public int LineNumber {
+                       get {
+                               if (useProceedingLineInfo)
+                                       return line;
+                               else
+                                       return cursorToken.LineNumber;
+                       }
                }
 
-               public int LinePosition
-               {
-                       get { return column; }
+               public int LinePosition {
+                       get {
+                               if (useProceedingLineInfo)
+                                       return column;
+                               else
+                                       return cursorToken.LinePosition;
+                       }
                }
 
-               public override string LocalName
-               {
-                       get { return localName; }
+               public override string LocalName {
+                       get { return cursorToken.LocalName; }
                }
 
-               public override string Name
-               {
-                       get { return name; }
+               public override string Name {
+                       get { return cursorToken.Name; }
                }
 
-               [MonoTODO]
-               public bool Namespaces
-               {
-                       get { throw new NotImplementedException (); }
-                       set { throw new NotImplementedException (); }
+               public bool Namespaces {
+                       get { return namespaces; }
+                       set { 
+                               if (readState != ReadState.Initial)
+                                       throw new InvalidOperationException ("Namespaces have to be set before reading.");
+                               namespaces = value;
+                       }
                }
 
-               public override string NamespaceURI
-               {
-                       get { return namespaceURI; }
+               public override string NamespaceURI {
+                       get { return cursorToken.NamespaceURI; }
                }
 
-               public override XmlNameTable NameTable
-               {
+               public override XmlNameTable NameTable {
                        get { return parserContext.NameTable; }
                }
 
-               public override XmlNodeType NodeType
-               {
-                       get { return nodeType; }
+               public override XmlNodeType NodeType {
+                       get { return cursorToken.NodeType; }
                }
 
-               [MonoTODO]
-               public bool Normalization
-               {
-                       get { throw new NotImplementedException (); }
-                       set { throw new NotImplementedException (); }
+               public bool Normalization {
+                       get { return normalization; }
+                       set { normalization = value; }
                }
 
-               public override string Prefix
-               {
-                       get { return prefix; }
+               public override string Prefix {
+                       get { return cursorToken.Prefix; }
                }
 
-               public override char QuoteChar
-               {
-                       get {
-                               // value string holds attribute quotation char.
-                               if (NodeType == XmlNodeType.Attribute)
-                                       return value [0];
-                               else
-                                       return '"';
-                       }
+#if NET_2_0
+               public bool ProhibitDtd {
+                       get { return prohibitDtd; }
+                       set { prohibitDtd = value; }
                }
+#endif
 
-               public override ReadState ReadState
-               {
+               public override char QuoteChar {
+                       get { return cursorToken.QuoteChar; }
+               }
+
+               public override ReadState ReadState {
                        get { return readState; }
                }
 
-               public override string Value
-               {
-                       get {
-                               if(NodeType == XmlNodeType.Attribute)
-                                       return ResolveAttributeValue(value);
-                               else
-                                       return value;
-                       }
+#if NET_2_0
+               public override XmlReaderSettings Settings {
+                       get { return base.Settings; }
                }
+#endif
 
-               public WhitespaceHandling WhitespaceHandling
-               {
+               public override string Value {
+                       get { return cursorToken.Value != null ? cursorToken.Value : String.Empty; }
+               }
+
+               public WhitespaceHandling WhitespaceHandling {
                        get { return whitespaceHandling; }
                        set { whitespaceHandling = value; }
                }
 
-               [MonoTODO]
-               public override string XmlLang
-               {
-                       get { throw new NotImplementedException (); }
+               public override string XmlLang {
+                       get { return parserContext.XmlLang; }
                }
 
-               [MonoTODO]
-               public XmlResolver XmlResolver
-               {
-                       set { throw new NotImplementedException (); }
+               public XmlResolver XmlResolver {
+                       set { resolver = value; }
                }
 
-               [MonoTODO]
-               public override XmlSpace XmlSpace
-               {
-                       get { throw new NotImplementedException (); }
+               public override XmlSpace XmlSpace {
+                       get { return parserContext.XmlSpace; }
                }
 
                #endregion
 
                #region Methods
 
-               [MonoTODO]
                public override void Close ()
                {
                        readState = ReadState.Closed;
+
+                       cursorToken.Clear ();
+                       currentToken.Clear ();
+                       attributeCount = 0;
+                       if (closeInput && reader != null)
+                               reader.Close ();
                }
 
-               [MonoTODO]
                public override string GetAttribute (int i)
                {
-                       if (i > attributes.Count)
+                       if (i >= attributeCount)
                                throw new ArgumentOutOfRangeException ("i is smaller than AttributeCount");
-                       else
-                               return ResolveAttributeValue (attributes [orderedAttributes [i]] as string);
+                       else {
+                               return attributeTokens [i].Value;
+                       }
                }
 
+               // MS.NET 1.0 msdn says that this method returns String.Empty
+               // for absent attribute, but in fact it returns null.
+               // This description is corrected in MS.NET 1.1 msdn.
                public override string GetAttribute (string name)
                {
-                       return attributes.ContainsKey (name) ?
-                               ResolveAttributeValue (attributes [name] as string) : String.Empty;
+                       for (int i = 0; i < attributeCount; i++)
+                               if (attributeTokens [i].Name == name)
+                                       return attributeTokens [i].Value;
+                       return null;
                }
 
-               public override string GetAttribute (string localName, string namespaceURI)
+               private int GetIndexOfQualifiedAttribute (string localName, string namespaceURI)
                {
-                       foreach (DictionaryEntry entry in attributes)
-                       {
-                               string thisName = entry.Key as string;
-
-                               int indexOfColon = thisName.IndexOf (':');
-
-                               if (indexOfColon != -1) {
-                                       string thisLocalName = thisName.Substring (indexOfColon + 1);
+                       for (int i = 0; i < attributeCount; i++) {
+                               XmlAttributeTokenInfo ti = attributeTokens [i];
+                               if (ti.LocalName == localName && ti.NamespaceURI == namespaceURI)
+                                       return i;
+                       }
+                       return -1;
+               }
 
-                                       if (localName == thisLocalName) {
-                                               string thisPrefix = thisName.Substring (0, indexOfColon);
-                                               string thisNamespaceURI = LookupNamespace (thisPrefix);
+               internal XmlParserContext GetInternalParserContext ()
+               {
+                       return parserContext;
+               }
 
-                                               if (namespaceURI == thisNamespaceURI)
-                                                       return attributes.ContainsKey (thisName) ?
-                                                               ResolveAttributeValue (attributes [thisName] as string) : String.Empty;
-                                       }
-                               } else if (localName == "xmlns" && namespaceURI == "http://www.w3.org/2000/xmlns/" && thisName == "xmlns")
-                                       return attributes.ContainsKey (thisName) ? 
-                                               ResolveAttributeValue (attributes [thisName] as string) : String.Empty;
-                       }
+               public override string GetAttribute (string localName, string namespaceURI)
+               {
+                       int idx = this.GetIndexOfQualifiedAttribute (localName, namespaceURI);
+                       if (idx < 0)
+                               return null;
+                       return attributeTokens [idx].Value;
+               }
 
-                       return String.Empty;
+#if NET_2_0
+               public IDictionary GetNamespacesInScope (XmlNamespaceScope scope)
+               {
+                       return parserContext.NamespaceManager.GetNamespacesInScope (scope);
                }
+#endif
 
-               [MonoTODO]
                public TextReader GetRemainder ()
                {
-                       throw new NotImplementedException ();
+                       if (peekCharsIndex == peekCharsLength)
+                               return reader;
+                       return new StringReader (new string (peekChars, peekCharsIndex, peekCharsLength - peekCharsIndex) + reader.ReadToEnd ());
                }
 
-               [MonoTODO]
+#if NET_2_0
+               public bool HasLineInfo ()
+#else
                bool IXmlLineInfo.HasLineInfo ()
+#endif
                {
-                       return false;
+                       return true;
                }
 
                public override string LookupNamespace (string prefix)
                {
-                       return parserContext.NamespaceManager.LookupNamespace (prefix);
+                       return LookupNamespace (prefix, false);
                }
 
-               public override void MoveToAttribute (int i)
+#if NET_2_0
+               public override string LookupNamespace (string prefix, bool atomizedName)
+#else
+               internal override string LookupNamespace (string prefix, bool atomizedName)
+#endif
                {
-                       MoveToElement ();
-
-                       if (attributes == null || orderedAttributes.Count < i || i < 0)
-                               throw new ArgumentOutOfRangeException ("attribute index out of range.");
+                       return parserContext.NamespaceManager.LookupNamespace (prefix, atomizedName);
+               }
 
-                       string name = orderedAttributes [i] as string;
-                       string value = attributes [name] as string;
-                       SetProperties (
-                               XmlNodeType.Attribute, // nodeType
-                               name, // name
-                               false, // isEmptyElement
-                               value, // value
-                               false // clearAttributes
-                               );
+#if NET_2_0
+               string IXmlNamespaceResolver.LookupPrefix (string ns)
+               {
+                       return LookupPrefix (ns, false);
                }
 
-               public override bool MoveToAttribute (string name)
+               public string LookupPrefix (string ns, bool atomizedName)
                {
-                       MoveToElement ();
-                       bool match = false;
+                       return parserContext.NamespaceManager.LookupPrefix (ns, atomizedName);
+               }
+#endif
 
-                       if (attributes == null)
-                               return false;
+               public override void MoveToAttribute (int i)
+               {
+                       if (i >= attributeCount)
+                               throw new ArgumentOutOfRangeException ("attribute index out of range.");
 
-                       if (orderedAttributesEnumerator == null) {
-                               SaveProperties ();
-                               orderedAttributesEnumerator = orderedAttributes.GetEnumerator ();
-                       }
+                       currentAttribute = i;
+                       currentAttributeValue = -1;
+                       cursorToken = attributeTokens [i];
+               }
 
-                       while (orderedAttributesEnumerator.MoveNext ()) {
-                               if(name == orderedAttributesEnumerator.Current as string) {
-                                       match = true;
-                                       break;
+               public override bool MoveToAttribute (string name)
+               {
+                       for (int i = 0; i < attributeCount; i++) {
+                               XmlAttributeTokenInfo ti = attributeTokens [i];
+                               if (ti.Name == name) {
+                                       MoveToAttribute (i);
+                                       return true;
                                }
                        }
-
-                       if (match) {
-                               string value = attributes [name] as string;
-                               SetProperties (
-                                       XmlNodeType.Attribute, // nodeType
-                                       name, // name
-                                       false, // isEmptyElement
-                                       value, // value
-                                       false // clearAttributes
-                               );
-                       }
-
-                       return match;
+                       return false;
                }
 
-               [MonoTODO]
                public override bool MoveToAttribute (string localName, string namespaceName)
                {
-                       throw new NotImplementedException ();
+                       int idx = GetIndexOfQualifiedAttribute (localName, namespaceName);
+                       if (idx < 0)
+                               return false;
+                       MoveToAttribute (idx);
+                       return true;
                }
 
                public override bool MoveToElement ()
                {
-                       if (orderedAttributesEnumerator != null) {
-                               orderedAttributesEnumerator = null;
-                               RestoreProperties ();
+                       if (currentToken == null)       // for attribute .ctor()
+                               return false;
+
+                       if (cursorToken == currentToken)
+                               return false;
+
+                       if (currentAttribute >= 0) {
+                               currentAttribute = -1;
+                               currentAttributeValue = -1;
+                               cursorToken = currentToken;
                                return true;
                        }
-
-                       return false;
+                       else
+                               return false;
                }
 
                public override bool MoveToFirstAttribute ()
                {
+                       if (attributeCount == 0)
+                               return false;
                        MoveToElement ();
                        return MoveToNextAttribute ();
                }
 
                public override bool MoveToNextAttribute ()
                {
-                       if (attributes == null)
+                       if (currentAttribute == 0 && attributeCount == 0)
                                return false;
-
-                       if (orderedAttributesEnumerator == null) {
-                               SaveProperties ();
-                               orderedAttributesEnumerator = orderedAttributes.GetEnumerator ();
-                       }
-
-                       if (orderedAttributesEnumerator.MoveNext ()) {
-                               string name = orderedAttributesEnumerator.Current as string;
-                               string value = attributes [name] as string;
-                               SetProperties (
-                                       XmlNodeType.Attribute, // nodeType
-                                       name, // name
-                                       false, // isEmptyElement
-                                       value, // value
-                                       false // clearAttributes
-                               );
+                       if (currentAttribute + 1 < attributeCount) {
+                               currentAttribute++;
+                               currentAttributeValue = -1;
+                               cursorToken = attributeTokens [currentAttribute];
                                return true;
                        }
-
-                       return false;
+                       else
+                               return false;
                }
 
                public override bool Read ()
                {
-                       bool more = false;
+                       if (startNodeType == XmlNodeType.Attribute) {
+                               if (currentAttribute == 0)
+                                       return false;   // already read.
+                               ClearAttributes ();
+                               IncrementAttributeToken ();
+                               ReadAttributeValueTokens ('"');
+                               cursorToken = attributeTokens [0];
+                               currentAttributeValue = -1;
+                               readState = ReadState.Interactive;
+                               return true;
+                       }
 
+                       bool more = false;
                        readState = ReadState.Interactive;
+                       currentLinkedNodeLineNumber = line;
+                       currentLinkedNodeLinePosition = column;
+                       useProceedingLineInfo = true;
+
+                       cursorToken = currentToken;
+                       attributeCount = 0;
+                       currentAttribute = currentAttributeValue = -1;
+                       currentToken.Clear ();
+
+                       // It was moved from end of ReadStartTag ().
+                       if (depthUp) {
+                               ++depth;
+                               depthUp = false;
+                       }
+
+                       if (shouldSkipUntilEndTag) {
+                               shouldSkipUntilEndTag = false;
+                               return ReadUntilEndTag ();
+                       }
+
+                       base64CacheStartsAt = -1;
 
                        more = ReadContent ();
 
+                       if (!more && startNodeType == XmlNodeType.Document && currentState != XmlNodeType.EndElement)
+                               throw new XmlException ("Document element did not appear.");
+
+                       useProceedingLineInfo = false;
                        return more;
                }
 
-               [MonoTODO("This method should consider entity references")]
                public override bool ReadAttributeValue ()
                {
-                       // reading attribute value phase now stopped
-                       if(attributeStringCurrentPosition < 0 ||
-                                       attributeString.Length < attributeStringCurrentPosition) {
-                               attributeStringCurrentPosition = 0;
-                               attributeString = String.Empty;
+                       if (readState == ReadState.Initial && startNodeType == XmlNodeType.Attribute) {
+                               Read ();
+                       }
+
+                       if (currentAttribute < 0)
                                return false;
+                       XmlAttributeTokenInfo ti = attributeTokens [currentAttribute];
+                       if (currentAttributeValue < 0)
+                               currentAttributeValue = ti.ValueTokenStartIndex - 1;
+
+                       if (currentAttributeValue < ti.ValueTokenEndIndex) {
+                               currentAttributeValue++;
+                               cursorToken = attributeValueTokens [currentAttributeValue];
+                               return true;
                        }
+                       else
+                               return false;
+               }
+
+               private int SkipIgnorableBase64Chars (char [] chars, int charsLength, int i)
+               {
+                       while (chars [i] == '=' || XmlChar.IsWhitespace (chars [i]))
+                               if (charsLength == ++i)
+                                       break;
+                       return i;
+               }
+
+               public int ReadBase64 (byte [] buffer, int offset, int length)
+               {
+                       if (offset < 0)
+                               throw new ArgumentOutOfRangeException ("offset", offset, "Offset must be non-negative integer.");
+                       else if (length < 0)
+                               throw new ArgumentOutOfRangeException ("length", length, "Length must be non-negative integer.");
+                       else if (buffer.Length < offset + length)
+                               throw new ArgumentOutOfRangeException ("buffer length is smaller than the sum of offset and length.");
 
-                       // If not started, then initialize attributeString when parsing is at start.
-                       if(attributeStringCurrentPosition == 0)
-                               attributeString =
-                                       value.Substring (1, value.Length - 2);
-
-                       bool returnEntity = false;
-                       value = String.Empty;
-                       int nextPosition = attributeString.IndexOf ('&',
-                               attributeStringCurrentPosition);
-
-                       // if attribute string starts from '&' then it may be (unparsable) entity reference.
-                       if(nextPosition == 0) {
-                               string parsed = ReadAttributeValueEntityReference ();
-                               if(parsed == null) {
-                                       // return entity (It is only this case to return entity reference.)
-                                       int endEntityPosition = attributeString.IndexOf (';',
-                                               attributeStringCurrentPosition);
-                                       SetProperties (XmlNodeType.EntityReference,
-                                               attributeString.Substring (attributeStringCurrentPosition + 1,
-                                               endEntityPosition - attributeStringCurrentPosition - 1),
-                                               false,
-                                               String.Empty,
-                                               false);
-                                       attributeStringCurrentPosition = endEntityPosition + 1;
+                       if (length == 0)        // It does not raise an error.
+                               return 0;
 
-                                       return true;
+                       int bufIndex = offset;
+                       int bufLast = offset + length;
+
+                       if (base64CacheStartsAt >= 0) {
+                               for (int i = base64CacheStartsAt; i < 3; i++) {
+                                       buffer [bufIndex++] = base64Cache [base64CacheStartsAt++];
+                                       if (bufIndex == bufLast)
+                                               return bufLast - offset;
                                }
-                               else
-                                       value += parsed;
                        }
 
-                       // Other case always set text node.
-                       while(!returnEntity) {
-                               nextPosition = attributeString.IndexOf ('&', attributeStringCurrentPosition);
-                               if(nextPosition < 0) {
-                                       // Reached to the end of value string.
-                                       value += attributeString.Substring (attributeStringCurrentPosition);
-                                       attributeStringCurrentPosition = -1;
+                       for (int i = 0; i < 3; i++)
+                               base64Cache [i] = 0;
+                       base64CacheStartsAt = -1;
+
+                       int max = (int) System.Math.Ceiling (4.0 / 3 * length);
+                       int additional = max % 4;
+                       if (additional > 0)
+                               max += 4 - additional;
+                       char [] chars = new char [max];
+                       int charsLength = ReadChars (chars, 0, max);
+
+                       byte b = 0;
+                       byte work = 0;
+                       bool loop = true;
+                       for (int i = 0; i < charsLength - 3; i++) {
+                               if ((i = SkipIgnorableBase64Chars (chars, charsLength, i)) == charsLength)
                                        break;
-                               } else if(nextPosition == attributeStringCurrentPosition) {
-                                       string parsed = ReadAttributeValueEntityReference ();
-                                       if(parsed != null)
-                                               value += parsed;
-                                       else {
-                                               // Found that an entity reference starts from this point.
-                                               // Then once stop to parse attribute value and then return text.
-                                               value += attributeString.Substring (attributeStringCurrentPosition,
-                                                       nextPosition - attributeStringCurrentPosition);
-                                               break;
-                                       }
-                               } else {
-                                       value += attributeString.Substring (attributeStringCurrentPosition,
-                                               nextPosition - attributeStringCurrentPosition);
-                                       attributeStringCurrentPosition = nextPosition;
-                                       continue;
+                               b = (byte) (GetBase64Byte (chars [i]) << 2);
+                               if (bufIndex < bufLast)
+                                       buffer [bufIndex] = b;
+                               else {
+                                       if (base64CacheStartsAt < 0)
+                                               base64CacheStartsAt = 0;
+                                       base64Cache [0] = b;
+                               }
+                               // charsLength mod 4 might not equals to 0.
+                               if (++i == charsLength)
+                                       break;
+                               if ((i = SkipIgnorableBase64Chars (chars, charsLength, i))  == charsLength)
+                                       break;
+                               b = GetBase64Byte (chars [i]);
+                               work = (byte) (b >> 4);
+                               if (bufIndex < bufLast) {
+                                       buffer [bufIndex] += work;
+                                       bufIndex++;
+                               }
+                               else
+                                       base64Cache [0] += work;
+
+                               work = (byte) ((b & 0xf) << 4);
+                               if (bufIndex < bufLast) {
+                                       buffer [bufIndex] = work;
+                               }
+                               else {
+                                       if (base64CacheStartsAt < 0)
+                                               base64CacheStartsAt = 1;
+                                       base64Cache [1] = work;
+                               }
+
+                               if (++i == charsLength)
+                                       break;
+                               if ((i = SkipIgnorableBase64Chars (chars, charsLength, i)) == charsLength)
+                                       break;
+                               b = GetBase64Byte (chars [i]);
+                               work = (byte) (b >> 2);
+                               if (bufIndex < bufLast) {
+                                       buffer [bufIndex] += work;
+                                       bufIndex++;
+                               }
+                               else
+                                       base64Cache [1] += work;
+
+                               work = (byte) ((b & 3) << 6);
+                               if (bufIndex < bufLast)
+                                       buffer [bufIndex] = work;
+                               else {
+                                       if (base64CacheStartsAt < 0)
+                                               base64CacheStartsAt = 2;
+                                       base64Cache [2] = work;
+                               }
+                               if (++i == charsLength)
+                                       break;
+                               if ((i = SkipIgnorableBase64Chars (chars, charsLength, i)) == charsLength)
+                                       break;
+                               work = GetBase64Byte (chars [i]);
+                               if (bufIndex < bufLast) {
+                                       buffer [bufIndex] += work;
+                                       bufIndex++;
                                }
+                               else
+                                       base64Cache [2] += work;
                        }
+                       return System.Math.Min (bufLast - offset, bufIndex - offset);
+               }
 
-                       SetProperties(XmlNodeType.Text,
-                               "#text",
-                               false,
-                               value,
-                               false);
+               public int ReadBinHex (byte [] buffer, int offset, int length)
+               {
+                       if (offset < 0)
+                               throw new ArgumentOutOfRangeException ("offset", offset, "Offset must be non-negative integer.");
+                       else if (length < 0)
+                               throw new ArgumentOutOfRangeException ("length", length, "Length must be non-negative integer.");
+                       else if (buffer.Length < offset + length)
+                               throw new ArgumentOutOfRangeException ("buffer length is smaller than the sum of offset and length.");
 
-                       return true;
+                       if (length == 0)
+                               return 0;
+
+                       char [] chars = new char [length * 2];
+                       int charsLength = ReadChars (chars, 0, length * 2);
+                       return XmlConvert.FromBinHexString (chars, offset, charsLength, buffer);
+               }
+
+               public int ReadChars (char [] buffer, int offset, int length)
+               {
+                       return ReadCharsInternal (buffer, offset, length);
+               }
+
+#if NET_2_0
+               public override string ReadString ()
+               {
+                       return ReadStringInternal ();
+               }
+#elif NET_1_1
+#else
+               public override string ReadInnerXml ()
+               {
+                       return ReadInnerXmlInternal ();
+               }
+
+               public override string ReadOuterXml ()
+               {
+                       return ReadOuterXmlInternal ();
+               }
+
+               public override string ReadString ()
+               {
+                       return ReadStringInternal ();
+               }
+#endif
+
+               public void ResetState ()
+               {
+                       throw new InvalidOperationException ("Cannot call ResetState when parsing an XML fragment.");
+                       Init ();
                }
 
+#if NET_2_0
                [MonoTODO]
-               public int ReadBase64 (byte [] buffer, int offset, int length)
+               public override bool ReadValueAsBoolean ()
                {
-                       throw new NotImplementedException ();
+                       return base.ReadValueAsBoolean ();
                }
 
                [MonoTODO]
-               public int ReadBinHex (byte [] buffer, int offset, int length)
+               public override DateTime ReadValueAsDateTime ()
                {
-                       throw new NotImplementedException ();
+                       return base.ReadValueAsDateTime ();
                }
 
                [MonoTODO]
-               public int ReadChars (char [] buffer, int offset, int length)
+               public override decimal ReadValueAsDecimal ()
                {
-                       throw new NotImplementedException ();
+                       return base.ReadValueAsDecimal ();
                }
 
                [MonoTODO]
-               public override string ReadInnerXml ()
+               public override double ReadValueAsDouble ()
                {
-                       // Still need a Well Formedness check.
-                       // Will wait for Validating reader ;-)
-                       if (NodeType == XmlNodeType.Attribute) {
-                               return Value;
-                       } else {
-                               saveToXmlBuffer = true;
-                               string startname = this.Name;
-                               string endname = string.Empty;
-                               readState = ReadState.Interactive;
+                       return base.ReadValueAsDouble ();
+               }
 
-                               while (startname != endname) {
-                                       ReadContent ();
-                                       endname = this.Name;
-                               }
+               [MonoTODO]
+               public override int ReadValueAsInt32 ()
+               {
+                       return base.ReadValueAsInt32 ();
+               }
 
-                               xmlBuffer.Replace (currentTag.ToString (), "");
-                               saveToXmlBuffer = false;
-                               string InnerXml = xmlBuffer.ToString ();
-                               xmlBuffer.Length = 0;
-                               return InnerXml;
-                       }
+               [MonoTODO]
+               public override long ReadValueAsInt64 ()
+               {
+                       return base.ReadValueAsInt64 ();
                }
 
                [MonoTODO]
-               public override string ReadOuterXml ()
+               public override ICollection ReadValueAsList ()
                {
-                       if (NodeType == XmlNodeType.Attribute) {
-                               return Name + "=\"" + Value.Replace ("\"", "&quot;") + "\"";
-                       } else {
-                               saveToXmlBuffer = true;
-                               xmlBuffer.Append (currentTag.ToString ());
-                               int startDepth = Depth;
-                               readState = ReadState.Interactive;
+                       return base.ReadValueAsList ();
+               }
 
-                               do {
-                                       ReadContent ();
-                               } while (Depth > startDepth);
+               [MonoTODO]
+               public override float ReadValueAsSingle ()
+               {
+                       return base.ReadValueAsSingle ();
+               }
 
-                               saveToXmlBuffer = false;
-                               string OuterXml = xmlBuffer.ToString ();
-                               xmlBuffer.Length = 0;
-                               return OuterXml;
-                       }
+               [MonoTODO]
+               public override string ReadValueAsString ()
+               {
+                       return ReadString ();
                }
 
                [MonoTODO]
-               public override string ReadString ()
+               public override object ReadValueAs (Type type)
                {
-                       throw new NotImplementedException ();
+                       return base.ReadValueAs (type);
                }
 
                [MonoTODO]
-               public void ResetState ()
+               public override object ReadValueAs (Type type, IXmlNamespaceResolver resolver)
                {
-                       throw new NotImplementedException ();
+                       return base.ReadValueAs (type, resolver);
                }
+#endif
 
                public override void ResolveEntity ()
                {
-                       // XmlTextReaders don't resolve entities.
+                       // XmlTextReader does not resolve entities.
                        throw new InvalidOperationException ("XmlTextReader cannot resolve external entities.");
                }
 
+#if NET_2_0
+               [MonoTODO ("Implement for performance reason")]
+               public override void Skip ()
+               {
+                       base.Skip ();
+               }
+#endif
                #endregion
 
                #region Internals
-               internal string publicId;
-               internal string systemId;
+               // Parsed DTD Objects
+#if DTD_HANDLE_EVENTS
+               internal event ValidationEventHandler ValidationEventHandler;
+#endif
 
-               internal void SetReaderContext (string url, XmlParserContext context)
+               internal DTDObjectModel DTD {
+                       get { return parserContext.Dtd; }
+               }
+
+               internal XmlResolver Resolver {
+                       get { return resolver; }
+               }
+               #endregion
+
+               #region Privates
+               internal class XmlTokenInfo
                {
-                       parserContext = context;
-                       parserContext.BaseURI = url;
-                       Init ();
+                       public XmlTokenInfo (XmlTextReader xtr, bool isPrimaryToken)
+                       {
+                               this.isPrimaryToken = isPrimaryToken;
+                               Reader = xtr;
+                               Clear ();
+                       }
+
+                       bool isPrimaryToken;
+                       string valueCache;
+
+                       protected XmlTextReader Reader;
+
+                       public string Name;
+                       public string LocalName;
+                       public string Prefix;
+                       public string NamespaceURI;
+                       public bool IsEmptyElement;
+                       public char QuoteChar;
+                       public int LineNumber;
+                       public int LinePosition;
+
+                       public XmlNodeType NodeType;
+
+                       public virtual string Value {
+                               get {
+                                       if (valueCache != null)
+                                               return valueCache;
+                                       switch (NodeType) {
+                                       case XmlNodeType.Text:
+                                       case XmlNodeType.SignificantWhitespace:
+                                       case XmlNodeType.Whitespace:
+                                       case XmlNodeType.Comment:
+                                       case XmlNodeType.CDATA:
+                                       case XmlNodeType.ProcessingInstruction:
+                                               valueCache = Reader.CreateValueString ();
+                                               return valueCache;
+                                       }
+                                       return null;
+                               }
+                               set { valueCache = value; }
+                       }
+
+                       public virtual void Clear ()
+                       {
+                               valueCache = null;
+                               NodeType = XmlNodeType.None;
+                               Name = LocalName = Prefix = NamespaceURI = String.Empty;
+                               IsEmptyElement = false;
+                               QuoteChar = '"';
+                               LineNumber = LinePosition = 0;
+                       }
+
+                       internal virtual void FillNames ()
+                       {
+                               if (Reader.Namespaces) {
+                                       int indexOfColon = -1;
+                                       switch (NodeType) {
+                                       case XmlNodeType.Attribute:
+                                       case XmlNodeType.Element:
+                                       case XmlNodeType.EndElement:
+                                               indexOfColon = Name.IndexOf (':');
+                                               break;
+                                       }
+
+                                       if (indexOfColon == -1) {
+                                               Prefix = String.Empty;
+                                               LocalName = Name;
+                                       } else {
+                                               // This improves speed by at least nearly 5%, but eats more memory at least nearly 0.3%
+                                               // However, this might be reverted if NameTable is got improved.
+                                               char [] nameArr = Name.ToCharArray ();
+                                               Prefix = Reader.NameTable.Add (nameArr, 0, indexOfColon);
+                                               LocalName = Reader.NameTable.Add (nameArr, indexOfColon + 1, nameArr.Length - indexOfColon - 1);
+//                                             Prefix = Reader.NameTable.Add (Name.Substring (0, indexOfColon));
+//                                             LocalName = Reader.NameTable.Add (Name.Substring (indexOfColon + 1));
+                                       }
+
+                                       // NamespaceURI
+                                       switch (NodeType) {
+                                       case XmlNodeType.Attribute:
+                                               if (Prefix.Length == 0)
+                                                       NamespaceURI = string.Empty;
+                                               else
+                                                       NamespaceURI = Reader.LookupNamespace (Prefix, true);
+                                               break;
+
+                                       case XmlNodeType.Element:
+                                       case XmlNodeType.EndElement:
+                                               NamespaceURI = Reader.LookupNamespace (Prefix, true);
+                                               break;
+                                       default:
+                                               NamespaceURI = "";
+                                               break;
+                                       }
+                               } else {
+                                       Prefix = String.Empty;
+                                       LocalName = Name;
+                               }
+                       }
                }
 
-               internal void SetReaderFragment(TextReader fragment, XmlNodeType fragType)
+               internal class XmlAttributeTokenInfo : XmlTokenInfo
                {
-                       this.reader = fragment;
-                       can_seek = fragment != null && fragment.Peek () != -1;
+                       public XmlAttributeTokenInfo (XmlTextReader reader)
+                               : base (reader, false)
+                       {
+                               NodeType = XmlNodeType.Attribute;
+                       }
+
+                       public int ValueTokenStartIndex;
+                       public int ValueTokenEndIndex;
+                       string valueCache;
+                       bool cachedNormalization;
+                       StringBuilder tmpBuilder = new StringBuilder ();
+
+                       public override string Value {
+                               get {
+                                       if (cachedNormalization != Reader.Normalization)
+                                               valueCache = null;
+                                       if (valueCache != null)
+                                               return valueCache;
+
+                                       cachedNormalization = Reader.Normalization;
+
+                                       // An empty value should return String.Empty.
+                                       if (ValueTokenStartIndex == ValueTokenEndIndex) {
+                                               XmlTokenInfo ti = Reader.attributeValueTokens [ValueTokenStartIndex];
+                                               if (ti.NodeType == XmlNodeType.EntityReference)
+                                                       valueCache = String.Concat ("&", ti.Name, ";");
+                                               else
+                                                       valueCache = ti.Value;
+                                               if (cachedNormalization)
+                                                       NormalizeSpaces ();
+                                               return valueCache;
+                                       }
+
+                                       tmpBuilder.Length = 0;
+                                       for (int i = ValueTokenStartIndex; i <= ValueTokenEndIndex; i++) {
+                                               XmlTokenInfo ti = Reader.attributeValueTokens [i];
+                                               if (ti.NodeType == XmlNodeType.Text)
+                                                       tmpBuilder.Append (ti.Value);
+                                               else {
+                                                       tmpBuilder.Append ('&');
+                                                       tmpBuilder.Append (ti.Name);
+                                                       tmpBuilder.Append (';');
+                                               }
+                                       }
+
+                                       valueCache = tmpBuilder.ToString ();
+                                       if (cachedNormalization)
+                                               NormalizeSpaces ();
+                                       return valueCache;
+                               }
 
-                       if (fragType == XmlNodeType.Attribute)
-                               value = "''";
-/*     for future use
-                       switch(fragType)
+                               set { valueCache = value; }
+                       }
+
+                       public override void Clear ()
                        {
-                       case XmlNodeType.Attribute:     // attribute content
-                               parserContext.InputState = XmlParserInputState.AttributeValue;
-                               break;
-                       case XmlNodeType.DocumentFragment:      // element content
-                               parserContext.InputState = XmlParserInputState.Content;
-                               break;
-                       case XmlNodeType.Element:       // one element
-                               parserContext.InputState = XmlParserInputState.StartTag;
-                               break;
-                       case XmlNodeType.Document:      // document content
-                               parserContext.InputState = XmlParserInputState.Start;
-                               break;
-                       default:
-                               throw new InvalidOperationException("setting this xml node type not allowed.");
+                               base.Clear ();
+                               valueCache = null;
+                               NodeType = XmlNodeType.Attribute;
+                               ValueTokenStartIndex = ValueTokenEndIndex = 0;
+                       }
+
+                       internal override void FillNames ()
+                       {
+                               base.FillNames ();
+                               if (Prefix == "xmlns" || Name == "xmlns")
+                                       NamespaceURI = XmlNamespaceManager.XmlnsXmlns;
+                       }
+
+                       private void NormalizeSpaces ()
+                       {
+                               tmpBuilder.Length = 0;
+                               for (int i = 0; i < valueCache.Length; i++)
+                                       switch (valueCache [i]) {
+                                       case '\r':
+                                               if (i + 1 < valueCache.Length && valueCache [i + 1] == '\n')
+                                                       i++;
+                                               goto case '\n';
+                                       case '\t':
+                                       case '\n':
+                                               tmpBuilder.Append (' ');
+                                               break;
+                                       default:
+                                               tmpBuilder.Append (valueCache [i]);
+                                               break;
+                                       }
+                               valueCache = tmpBuilder.ToString ();
                        }
-*/
                }
-               #endregion
 
-               #region Privates
+               private XmlTokenInfo cursorToken;
+               private XmlTokenInfo currentToken;
+               private XmlAttributeTokenInfo currentAttributeToken;
+               private XmlTokenInfo currentAttributeValueToken;
+               private XmlAttributeTokenInfo [] attributeTokens = new XmlAttributeTokenInfo [10];
+               private XmlTokenInfo [] attributeValueTokens = new XmlTokenInfo [10];
+               private int currentAttribute;
+               private int currentAttributeValue;
+               private int attributeCount;
 
                private XmlParserContext parserContext;
 
-               private TextReader reader;
                private ReadState readState;
 
                private int depth;
                private int elementDepth;
-               private bool depthDown;
+               private bool depthUp;
 
                private bool popScope;
 
-               private XmlNodeType nodeType;
-               private string name;
-               private string prefix;
-               private string localName;
-               private string namespaceURI;
-               private bool isEmptyElement;
-               private string value;
-
-               private XmlNodeType saveNodeType;
-               private string saveName;
-               private string savePrefix;
-               private string saveLocalName;
-               private string saveNamespaceURI;
-               private bool saveIsEmptyElement;
-
-               private Hashtable attributes;
-               private ArrayList orderedAttributes;
-               private IEnumerator orderedAttributesEnumerator;
+               private string [] elementNames;
+               int elementNameStackPos;
+
+               private bool allowMultipleRoot;
+
+               private bool isStandalone;
 
                private bool returnEntityReference;
                private string entityReferenceName;
@@ -720,45 +1074,75 @@ namespace System.Xml
                private char [] nameBuffer;
                private int nameLength;
                private int nameCapacity;
-               private const int initialNameCapacity = 256;
+               private const int initialNameCapacity = 32;
 
                private char [] valueBuffer;
                private int valueLength;
                private int valueCapacity;
-               private const int initialValueCapacity = 8192;
+               private const int initialValueCapacity = 256;
 
-               private StringBuilder xmlBuffer; // This is for Read(Inner|Outer)Xml
-               private StringBuilder currentTag; // A buffer for ReadContent for ReadOuterXml
-               private bool saveToXmlBuffer;
-               private int line = 1;
-               private int column = 1;
-               private bool has_peek;
-               private bool can_seek;
-               private int peek_char;
+               private char [] currentTagBuffer;
+               private int currentTagLength;
+               private int currentTagCapacity;
+               private const int initialCurrentTagCapacity = 256;
 
-               private string attributeString = String.Empty;
-               private int attributeStringCurrentPosition;
+               private TextReader reader;
+               private char [] peekChars;
+               private int peekCharsIndex;
+               private int peekCharsLength;
+               private const int peekCharCapacity = 1024;
+
+               private int line;
+               private int column;
+
+               private int currentLinkedNodeLineNumber;
+               private int currentLinkedNodeLinePosition;
+               private bool useProceedingLineInfo;
+
+               private XmlNodeType startNodeType;
+               // State machine attribute.
+               //      XmlDeclaration: after the first node.
+               //      DocumentType: after doctypedecl
+               //      Element: inside document element
+               //      EndElement: after document element
+               private XmlNodeType currentState;
+
+               // For ReadChars()/ReadBase64()/ReadBinHex()
+               private bool shouldSkipUntilEndTag;
+               private byte [] base64Cache = new byte [3];
+               private int base64CacheStartsAt;
+
+               // These values are never re-initialized.
+               private bool namespaces = true;
+               private WhitespaceHandling whitespaceHandling = WhitespaceHandling.All;
+               private XmlResolver resolver = new XmlUrlResolver ();
+               private bool normalization = false;
+
+               private bool checkCharacters;
+               private bool prohibitDtd = false;
+               private bool closeInput = true;
+               private EntityHandling entityHandling; // 2.0
 
                private void Init ()
                {
+                       currentToken = new XmlTokenInfo (this, true);
+                       cursorToken = currentToken;
+                       currentAttribute = -1;
+                       currentAttributeValue = -1;
+                       attributeCount = 0;
+
                        readState = ReadState.Initial;
+                       allowMultipleRoot = false;
 
                        depth = 0;
-                       depthDown = false;
-
-                       popScope = false;
+                       elementDepth = 0;
+                       depthUp = false;
 
-                       nodeType = XmlNodeType.None;
-                       name = String.Empty;
-                       prefix = String.Empty;
-                       localName = string.Empty;
-                       isEmptyElement = false;
-                       value = String.Empty;
-
-                       attributes = new Hashtable ();
-                       orderedAttributes = new ArrayList ();
-                       orderedAttributesEnumerator = null;
+                       popScope = allowMultipleRoot = false;
+                       elementNames = new string [10];
+                       elementNameStackPos = 0;
 
+                       isStandalone = false;
                        returnEntityReference = false;
                        entityReferenceName = String.Empty;
 
@@ -770,10 +1154,102 @@ namespace System.Xml
                        valueLength = 0;
                        valueCapacity = initialValueCapacity;
 
-                       xmlBuffer = new StringBuilder ();
-                       currentTag = new StringBuilder ();
+                       currentTagBuffer = new char [initialCurrentTagCapacity];
+                       currentTagLength = 0;
+                       currentTagCapacity = initialCurrentTagCapacity;
+
+                       peekCharsIndex = 0;
+                       peekCharsLength = 0;
+                       if (peekChars == null)
+                               peekChars = new char [peekCharCapacity];
+
+                       line = 1;
+                       column = 1;
+                       currentTagLength = 0;
+
+                       currentLinkedNodeLineNumber = currentLinkedNodeLinePosition = 0;
+                       useProceedingLineInfo = false;
+
+                       currentState = XmlNodeType.None;
+
+                       shouldSkipUntilEndTag = false;
+                       base64CacheStartsAt = -1;
+
+                       checkCharacters = true;
+#if NET_2_0
+                       if (Settings != null)
+                               checkCharacters = Settings.CheckCharacters;
+#endif
+                       prohibitDtd = false;
+                       closeInput = true;
+                       entityHandling = EntityHandling.ExpandCharEntities;
                }
 
+               private void InitializeContext (string url, XmlParserContext context, TextReader fragment, XmlNodeType fragType)
+               {
+                       startNodeType = fragType;
+                       parserContext = context;
+                       if (context == null) {
+                               XmlNameTable nt = new NameTable ();
+                               parserContext = new XmlParserContext (nt,
+                                       new XmlNamespaceManager (nt),
+                                       String.Empty,
+                                       XmlSpace.None);
+                       }
+
+                       if (url != null && url.Length > 0) {
+                               Uri uri = null;
+                               try {
+                                       uri = new Uri (url);
+                               } catch (Exception) {
+                                       string path = Path.GetFullPath ("./a");
+                                       uri = new Uri (new Uri (path), url);
+                               }
+                               parserContext.BaseURI = uri.ToString ();
+                       }
+
+                       Init ();
+
+                       reader = fragment;
+
+                       switch (fragType) {
+                       case XmlNodeType.Attribute:
+                               reader = new StringReader (fragment.ReadToEnd ().Replace ("\"", "&quot;"));
+                               break;
+                       case XmlNodeType.Element:
+                               currentState = XmlNodeType.Element;
+                               allowMultipleRoot = true;
+                               break;
+                       case XmlNodeType.Document:
+                               break;
+                       default:
+                               throw new XmlException (String.Format ("NodeType {0} is not allowed to create XmlTextReader.", fragType));
+                       }
+               }
+
+#if NET_2_0
+               [MonoTODO ("Test")]
+               internal ConformanceLevel Conformance {
+                       set {
+                               if (value == ConformanceLevel.Fragment) {
+                                       currentState = XmlNodeType.Element;
+                                       allowMultipleRoot = true;
+                               }
+                       }
+               }
+
+               internal void AdjustLineInfoOffset (int lineNumberOffset, int linePositionOffset)
+               {
+                       line += lineNumberOffset;
+                       column += linePositionOffset;
+               }
+
+               internal void SetNameTable (XmlNameTable nameTable)
+               {
+                       parserContext.NameTable = nameTable;
+               }
+#endif
+
                // Use this method rather than setting the properties
                // directly so that all the necessary properties can
                // be changed in harmony with each other. Maybe the
@@ -786,156 +1262,149 @@ namespace System.Xml
                        string value,
                        bool clearAttributes)
                {
-                       this.nodeType = nodeType;
-                       this.name = name;
-                       this.isEmptyElement = isEmptyElement;
-                       this.value = value;
+                       SetProperties (currentToken, nodeType, name, isEmptyElement, value, clearAttributes);
+                       currentToken.LineNumber = this.currentLinkedNodeLineNumber;
+                       currentToken.LinePosition = this.currentLinkedNodeLinePosition;
+               }
+
+               private void SetProperties (
+                       XmlTokenInfo token,
+                       XmlNodeType nodeType,
+                       string name,
+                       bool isEmptyElement,
+                       string value,
+                       bool clearAttributes)
+               {
+                       token.Clear ();
+                       token.NodeType = nodeType;
+                       token.Name = name;
+                       token.IsEmptyElement = isEmptyElement;
+                       token.Value = value;
                        this.elementDepth = depth;
 
                        if (clearAttributes)
                                ClearAttributes ();
 
-                       int indexOfColon = name.IndexOf (':');
-
-                       if (indexOfColon == -1) {
-                               prefix = String.Empty;
-                               localName = name;
-                       } else {
-                               prefix = name.Substring (0, indexOfColon);
-                               localName = name.Substring (indexOfColon + 1);
-                       }
-
-                       namespaceURI = LookupNamespace (prefix);
-               }
-
-               private void SaveProperties ()
-               {
-                       saveNodeType = nodeType;
-                       saveName = name;
-                       savePrefix = prefix;
-                       saveLocalName = localName;
-                       saveNamespaceURI = namespaceURI;
-                       saveIsEmptyElement = isEmptyElement;
-                       // An element's value is always String.Empty.
-               }
-
-               private void RestoreProperties ()
-               {
-                       nodeType = saveNodeType;
-                       name = saveName;
-                       prefix = savePrefix;
-                       localName = saveLocalName;
-                       namespaceURI = saveNamespaceURI;
-                       isEmptyElement = saveIsEmptyElement;
-                       value = String.Empty;
-               }
-
-               private void AddAttribute (string name, string value)
-               {
-                       attributes.Add (name, value);
-                       orderedAttributes.Add (name);
+                       token.FillNames ();
                }
 
                private void ClearAttributes ()
                {
-                       if (attributes.Count > 0) {
-                               attributes.Clear ();
-                               orderedAttributes.Clear ();
-                       }
-
-                       orderedAttributesEnumerator = null;
+                       for (int i = 0; i < attributeCount; i++)
+                               attributeTokens [i].Clear ();
+                       attributeCount = 0;
+                       currentAttribute = -1;
+                       currentAttributeValue = -1;
                }
 
                private int PeekChar ()
                {
-                       if (can_seek)
-                               return reader.Peek ();
-
-                       if (has_peek)
-                               return peek_char;
-
-                       peek_char = reader.Read ();
-                       has_peek = true;
-                       return peek_char;
+                       if (peekCharsLength == peekCharsIndex) {
+                               if (!ReadTextReader ())
+                                       return -1;
+                               return PeekChar ();
+                       }
+                       else {
+                               char c = peekChars [peekCharsIndex];
+                               if (c != 0) return c;
+                               else return -1;
+                       }
                }
 
                private int ReadChar ()
                {
                        int ch;
-                       if (has_peek) {
-                               ch = peek_char;
-                               has_peek = false;
-                       } else {
-                               ch = reader.Read ();
+
+                       if (peekCharsLength == peekCharsIndex) {
+                               if (!ReadTextReader ())
+                                       return -1;
+                               return ReadChar ();
                        }
+                       ch = peekChars [peekCharsIndex++];
 
                        if (ch == '\n') {
                                line++;
                                column = 1;
+                       } else if (ch == 0) {
+                               return -1;
                        } else {
                                column++;
                        }
-                       if (saveToXmlBuffer) {
-                               xmlBuffer.Append ((char) ch);
-                       }
-                       currentTag.Append ((char) ch);
+                       if (currentState != XmlNodeType.Element)
+                               AppendCurrentTagChar (ch);
                        return ch;
                }
 
+               private bool ReadTextReader ()
+               {
+                       peekCharsIndex = 0;
+                       peekCharsLength = reader.Read (peekChars, 0, peekCharCapacity);
+                       if (peekCharsLength == 0)
+                               return false;
+                       return true;
+               }
+
+               private string ExpandSurrogateChar (int ch)
+               {
+                       if (ch < Char.MaxValue)
+                               return ((char) ch).ToString ();
+                       else {
+                               char [] tmp = new char [] {(char) (ch / 0x10000 + 0xD800 - 1), (char) (ch % 0x10000 + 0xDC00)};
+                               return new string (tmp);
+                       }
+               }
+
                // This should really keep track of some state so
                // that it's not possible to have more than one document
                // element or text outside of the document element.
                private bool ReadContent ()
                {
-                       currentTag.Length = 0;
+                       currentTagLength = 0;
                        if (popScope) {
                                parserContext.NamespaceManager.PopScope ();
                                popScope = false;
                        }
 
-                       if (returnEntityReference) {
+                       if (returnEntityReference)
                                SetEntityReferenceProperties ();
-                       } else {
-                       switch (PeekChar ())
-                               {
-                               case '<':
-                                       ReadChar ();
-                                       ReadTag ();
-                                       break;
-                               case '\r':
-                                       if (whitespaceHandling == WhitespaceHandling.All ||
-                                           whitespaceHandling == WhitespaceHandling.Significant)
-                                               return ReadWhitespace ();
-
-                                       ReadChar ();
-                                       return ReadContent ();
-                               case '\n':
-                                       if (whitespaceHandling == WhitespaceHandling.All ||
-                                           whitespaceHandling == WhitespaceHandling.Significant)
-                                               return ReadWhitespace ();
-
-                                       ReadChar ();
-                                       return ReadContent ();
-                               case ' ':
-                                       if (whitespaceHandling == WhitespaceHandling.All ||
-                                           whitespaceHandling == WhitespaceHandling.Significant)
-                                               return ReadWhitespace ();
-
-                                       SkipWhitespace ();
-                                       return ReadContent ();
-                               case -1:
+                       else {
+                               int c = PeekChar ();
+                               if (c == -1) {
                                        readState = ReadState.EndOfFile;
+                                       ClearValueBuffer ();
                                        SetProperties (
                                                XmlNodeType.None, // nodeType
                                                String.Empty, // name
                                                false, // isEmptyElement
-                                               String.Empty, // value
+                                               null, // value
                                                true // clearAttributes
                                        );
-                                       break;
-                               default:
-                                       ReadText (true);
-                                       break;
+                                       if (depth > 0)
+                                               throw new XmlException ("unexpected end of file. Current depth is " + depth);
+
+                                       return false;
+                               } else {
+                                       switch ((char) c) {
+                                       case '<':
+                                               ReadChar ();
+                                               ReadTag ();
+                                               break;
+                                       case '\r': goto case ' ';
+                                       case '\n': goto case ' ';
+                                       case '\t': goto case ' ';
+                                       case ' ':
+                                               if (whitespaceHandling == WhitespaceHandling.All ||
+                                                       whitespaceHandling == WhitespaceHandling.Significant)
+                                                       ReadWhitespace ();
+                                               else {
+                                                       SkipWhitespace ();
+                                                       return ReadContent ();
+                                               }
+                                               break;
+                                       default:
+                                               ReadText (true);
+                                               break;
+                                       }
                                }
                        }
                        return this.ReadState != ReadState.EndOfFile;
@@ -943,11 +1412,21 @@ namespace System.Xml
 
                private void SetEntityReferenceProperties ()
                {
+                       DTDEntityDeclaration decl = DTD != null ? DTD.EntityDecls [entityReferenceName] : null;
+                       if (this.isStandalone)
+                               if (DTD == null || decl == null || !decl.IsInternalSubset)
+                                       throw new XmlException (this as IXmlLineInfo,
+                                               "Standalone document must not contain any references to an non-internally declared entity.");
+                       if (decl != null && decl.NotationName != null)
+                               throw new XmlException (this as IXmlLineInfo,
+                                       "Reference to any unparsed entities is not allowed here.");
+
+                       ClearValueBuffer ();
                        SetProperties (
                                XmlNodeType.EntityReference, // nodeType
                                entityReferenceName, // name
                                false, // isEmptyElement
-                               String.Empty, // value
+                               null, // value
                                true // clearAttributes
                        );
 
@@ -981,49 +1460,128 @@ namespace System.Xml
                // The leading '<' has already been consumed.
                private void ReadStartTag ()
                {
+                       if (currentState == XmlNodeType.EndElement)
+                               throw new XmlException (this as IXmlLineInfo,
+                                       "Multiple document element was detected.");
+                       currentState = XmlNodeType.Element;
+
                        parserContext.NamespaceManager.PushScope ();
 
+                       currentLinkedNodeLineNumber = line;
+                       currentLinkedNodeLinePosition = column;
+
                        string name = ReadName ();
-                       SkipWhitespace ();
+                       if (currentState == XmlNodeType.EndElement)
+                               throw new XmlException (this as IXmlLineInfo,"document has terminated, cannot open new element");
 
                        bool isEmptyElement = false;
 
                        ClearAttributes ();
 
+                       SkipWhitespace ();
                        if (XmlChar.IsFirstNameChar (PeekChar ()))
-                               ReadAttributes ();
+                               ReadAttributes (false);
+                       cursorToken = this.currentToken;
+
+                       // fill namespaces
+                       for (int i = 0; i < attributeCount; i++)
+                               attributeTokens [i].FillNames ();
+
+                       // quick name check
+                       for (int i = 0; i < attributeCount; i++) {
+                               for (int j = i + 1; j < attributeCount; j++)
+                                       if (Object.ReferenceEquals (attributeTokens [i].Name, attributeTokens [j].Name) ||
+                                               (Object.ReferenceEquals (attributeTokens [i].LocalName, attributeTokens [j].LocalName) &&
+                                               Object.ReferenceEquals (attributeTokens [i].NamespaceURI, attributeTokens [j].NamespaceURI)))
+                                               throw new XmlException (this as IXmlLineInfo,
+                                                       "Attribute name and qualified name must be identical.");
+                       }
 
+                       string baseUri = GetAttribute ("xml:base");
+                       if (baseUri != null) {
+                               if (this.resolver != null)
+                                       parserContext.BaseURI = resolver.ResolveUri (new Uri (BaseURI), baseUri).ToString ();
+                               else
+                                       parserContext.BaseURI = baseUri;
+                       }
+                       string xmlLang = GetAttribute ("xml:lang");
+                       if (xmlLang != null)
+                               parserContext.XmlLang = xmlLang;
+                       string xmlSpaceAttr = GetAttribute ("xml:space");
+                       if (xmlSpaceAttr != null) {
+                               if (xmlSpaceAttr == "preserve")
+                                       parserContext.XmlSpace = XmlSpace.Preserve;
+                               else if (xmlSpaceAttr == "default")
+                                       parserContext.XmlSpace = XmlSpace.Default;
+                               else
+                                       throw new XmlException (this as IXmlLineInfo,String.Format ("Invalid xml:space value: {0}", xmlSpaceAttr));
+                       }
                        if (PeekChar () == '/') {
                                ReadChar ();
                                isEmptyElement = true;
-                               depthDown = true;
                                popScope = true;
                        }
+                       else {
+                               depthUp = true;
+                               PushElementName (name);
+                               parserContext.PushScope ();
+                       }
 
                        Expect ('>');
-
                        SetProperties (
                                XmlNodeType.Element, // nodeType
                                name, // name
                                isEmptyElement, // isEmptyElement
-                               String.Empty, // value
+                               null, // value
                                false // clearAttributes
                        );
 
-                       if (!depthDown)
-                               ++depth;
-                       else
-                               depthDown = false;
+                       if (LookupNamespace (Prefix) == null)
+                               throw new XmlException (String.Format ("'{0}' is undeclared namespace.", Prefix));
+                       try {
+                               for (int i = 0; i < attributeCount; i++) {
+                                       MoveToAttribute (i);
+                                       if (LookupNamespace (Prefix) == null)
+                                               throw new XmlException (String.Format ("'{0}' is undeclared namespace.", Prefix));
+                               }
+                       } finally {
+                               MoveToElement ();
+                       }
+
+                       if (IsEmptyElement)
+                               CheckCurrentStateUpdate ();
+               }
 
+               private void PushElementName (string name)
+               {
+                       if (elementNames.Length == elementNameStackPos) {
+                               string [] newArray = new string [elementNames.Length * 2];
+                               Array.Copy (elementNames, 0, newArray, 0, elementNameStackPos);
+                               elementNames = newArray;
+                       }
+                       elementNames [elementNameStackPos++] = name;
                }
 
                // The reader is positioned on the first character
                // of the element's name.
                private void ReadEndTag ()
                {
+                       if (currentState != XmlNodeType.Element)
+                               throw new XmlException (this as IXmlLineInfo,
+                                       "End tag cannot appear in this state.");
+
+                       currentLinkedNodeLineNumber = line;
+                       currentLinkedNodeLinePosition = column;
+
                        string name = ReadName ();
-                       SkipWhitespace ();
-                       Expect ('>');
+                       if (elementNameStackPos == 0)
+                               throw new XmlException (this as IXmlLineInfo,"closing element without matching opening element");
+                       string expected = elementNames [--elementNameStackPos];
+                       if (expected != name)
+                               throw new XmlException (this as IXmlLineInfo,String.Format ("unmatched closing element: expected {0} but found {1}", expected, name));
+                       parserContext.PopScope ();
+
+                       ExpectAfterWhitespace ('>');
 
                        --depth;
 
@@ -1031,83 +1589,171 @@ namespace System.Xml
                                XmlNodeType.EndElement, // nodeType
                                name, // name
                                false, // isEmptyElement
-                               String.Empty, // value
+                               null, // value
                                true // clearAttributes
                        );
 
                        popScope = true;
+
+                       CheckCurrentStateUpdate ();
                }
 
-               private void AppendNameChar (int ch)
+               private void CheckCurrentStateUpdate ()
                {
-                       CheckNameCapacity ();
-                       nameBuffer [nameLength++] = (char)ch;
+                       if (depth == 0 && !allowMultipleRoot && (IsEmptyElement || NodeType == XmlNodeType.EndElement))
+                               currentState = XmlNodeType.EndElement;
                }
 
-               private void CheckNameCapacity ()
+               private void AppendNameChar (int ch)
                {
-                       if (nameLength == nameCapacity) {
-                               nameCapacity = nameCapacity * 2;
-                               char [] oldNameBuffer = nameBuffer;
-                               nameBuffer = new char [nameCapacity];
-                               Array.Copy (oldNameBuffer, nameBuffer, nameLength);
+                       if (nameLength == nameCapacity)
+                               ExpandNameCapacity ();
+                       if (ch < Char.MaxValue)
+                               nameBuffer [nameLength++] = (char) ch;
+                       else {
+                               nameBuffer [nameLength++] = (char) (ch / 0x10000 + 0xD800 - 1);
+                               if (nameLength == nameCapacity)
+                                       ExpandNameCapacity ();
+                               nameBuffer [nameLength++] = (char) (ch % 0x10000 + 0xDC00);
                        }
                }
 
+               private void ExpandNameCapacity ()
+               {
+                       nameCapacity = nameCapacity * 2;
+                       char [] oldNameBuffer = nameBuffer;
+                       nameBuffer = new char [nameCapacity];
+                       Array.Copy (oldNameBuffer, nameBuffer, nameLength);
+               }
+
                private string CreateNameString ()
                {
-                       return new String (nameBuffer, 0, nameLength);
+                       return parserContext.NameTable.Add (nameBuffer, 0, nameLength);
                }
 
                private void AppendValueChar (int ch)
                {
-                       CheckValueCapacity ();
-                       valueBuffer [valueLength++] = (char)ch;
+                       if (valueLength == valueCapacity)
+                               ExpandValueCapacity ();
+                       if (ch < Char.MaxValue)
+                               valueBuffer [valueLength++] = (char) ch;
+                       else {
+                               valueBuffer [valueLength++] = (char) (ch / 0x10000 + 0xD800 - 1);
+                               if (valueLength == valueCapacity)
+                                       ExpandValueCapacity ();
+                               valueBuffer [valueLength++] = (char) (ch % 0x10000 + 0xDC00);
+                       }
                }
 
-               private void CheckValueCapacity ()
+               private void ExpandValueCapacity ()
                {
-                       if (valueLength == valueCapacity) {
-                               valueCapacity = valueCapacity * 2;
-                               char [] oldValueBuffer = valueBuffer;
-                               valueBuffer = new char [valueCapacity];
-                               Array.Copy (oldValueBuffer, valueBuffer, valueLength);
-                       }
+                       valueCapacity = valueCapacity * 2;
+                       char [] oldValueBuffer = valueBuffer;
+                       valueBuffer = new char [valueCapacity];
+                       Array.Copy (oldValueBuffer, valueBuffer, valueLength);
                }
 
                private string CreateValueString ()
                {
-                       return new String (valueBuffer, 0, valueLength);
+                       return new string (valueBuffer, 0, valueLength);
+               }
+
+               private void ClearValueBuffer ()
+               {
+                       valueLength = 0;
+               }
+
+               private void AppendCurrentTagChar (int ch)
+               {
+                       if (currentTagLength == currentTagCapacity)
+                               ExpandCurrentTagCapacity ();
+                       if (ch < Char.MaxValue)
+                               currentTagBuffer [currentTagLength++] = (char) ch;
+                       else {
+                               currentTagBuffer [currentTagLength++] = (char) (ch / 0x10000 + 0xD800 - 1);
+                               if (currentTagLength == currentTagCapacity)
+                                       ExpandCurrentTagCapacity ();
+                               currentTagBuffer [currentTagLength++] = (char) (ch % 0x10000 + 0xDC00);
+                       }
+               }
+
+               private void ExpandCurrentTagCapacity ()
+               {
+                       currentTagCapacity = currentTagCapacity * 2;
+                       char [] oldCurrentTagBuffer = currentTagBuffer;
+                       currentTagBuffer = new char [currentTagCapacity];
+                       Array.Copy (oldCurrentTagBuffer, currentTagBuffer, currentTagLength);
+               }
+
+               private string CreateCurrentTagString ()
+               {
+                       return new string (currentTagBuffer, 0, currentTagLength);
+               }
+
+               private void ClearCurrentTagBuffer ()
+               {
+                       currentTagLength = 0;
                }
 
                // The reader is positioned on the first character
                // of the text.
-               private void ReadText (bool cleanValue)
+               private void ReadText (bool notWhitespace)
                {
-                       if (cleanValue)
-                               valueLength = 0;
+                       if (currentState != XmlNodeType.Element)
+                               throw new XmlException (this as IXmlLineInfo,
+                                       "Text node cannot appear in this state.");
+
+                       if (notWhitespace)
+                               ClearValueBuffer ();
 
                        int ch = PeekChar ();
+                       bool previousWasCloseBracket = false;
 
                        while (ch != '<' && ch != -1) {
                                if (ch == '&') {
                                        ReadChar ();
-                                       if (ReadReference (false))
+                                       ch = ReadReference (false);
+                                       if (returnEntityReference) // Returns -1 if char validation should not be done
                                                break;
-                               } else
-                                       AppendValueChar (ReadChar ());
+                               } else if (normalization && ch == '\r') {
+                                       ReadChar ();
+                                       ch = ReadChar ();
+                                       if (ch != '\n')
+                                               // append '\n' instead of '\r'.
+                                               AppendValueChar ('\n');
+                                       // and in case of "\r\n", discard '\r'.
+                               } else {
+                                       if (CharacterChecking && XmlChar.IsInvalid (ch))
+                                               throw new XmlException (this, "Not allowed character was found.");
+                                       ch = ReadChar ();
+                               }
 
+                               AppendValueChar (ch);
+
+                               // Block "]]>"
+                               if (ch == ']') {
+                                       if (previousWasCloseBracket)
+                                               if (PeekChar () == '>')
+                                                       throw new XmlException (this as IXmlLineInfo,
+                                                               "Inside text content, character sequence ']]>' is not allowed.");
+                                       previousWasCloseBracket = true;
+                               }
+                               else if (previousWasCloseBracket)
+                                       previousWasCloseBracket = false;
                                ch = PeekChar ();
+                               notWhitespace = true;
                        }
 
                        if (returnEntityReference && valueLength == 0) {
                                SetEntityReferenceProperties ();
                        } else {
+                               XmlNodeType nodeType = notWhitespace ? XmlNodeType.Text :
+                                       this.XmlSpace == XmlSpace.Preserve ? XmlNodeType.SignificantWhitespace : XmlNodeType.Whitespace;
                                SetProperties (
-                                       XmlNodeType.Text, // nodeType
+                                       nodeType, // nodeType
                                        String.Empty, // name
                                        false, // isEmptyElement
-                                       CreateValueString (), // value
+                                       null, // value: create only when required
                                        true // clearAttributes
                                );
                        }
@@ -1118,18 +1764,16 @@ namespace System.Xml
                // character reference or one of the predefined entities.
                // This allows the ReadText method to break so that the
                // next call to Read will return the EntityReference node.
-               private bool ReadReference (bool ignoreEntityReferences)
+               private int ReadReference (bool ignoreEntityReferences)
                {
                        if (PeekChar () == '#') {
                                ReadChar ();
-                               ReadCharacterReference ();
+                               return ReadCharacterReference ();
                        } else
-                               ReadEntityReference (ignoreEntityReferences);
-
-                       return returnEntityReference;
+                               return ReadEntityReference (ignoreEntityReferences);
                }
 
-               private void ReadCharacterReference ()
+               private int ReadCharacterReference ()
                {
                        int value = 0;
 
@@ -1146,10 +1790,10 @@ namespace System.Xml
                                        else if (ch >= 'a' && ch <= 'f')
                                                value = (value << 4) + ch - 'a' + 10;
                                        else
-                                               throw new XmlException (
-                                                       String.Format (
+                                               throw new XmlException (this as IXmlLineInfo,
+                                                       String.Format (CultureInfo.InvariantCulture, 
                                                                "invalid hexadecimal digit: {0} (#x{1:X})",
-                                                               (char)ch,
+                                                               (char) ch,
                                                                ch));
                                }
                        } else {
@@ -1159,137 +1803,264 @@ namespace System.Xml
                                        if (ch >= '0' && ch <= '9')
                                                value = value * 10 + ch - '0';
                                        else
-                                               throw new XmlException (
-                                                       String.Format (
+                                               throw new XmlException (this as IXmlLineInfo,
+                                                       String.Format (CultureInfo.InvariantCulture, 
                                                                "invalid decimal digit: {0} (#x{1:X})",
-                                                               (char)ch,
+                                                               (char) ch,
                                                                ch));
                                }
                        }
 
                        ReadChar (); // ';'
 
-                       AppendValueChar (value);
+                       // There is no way to save surrogate pairs...
+                       if (CharacterChecking && XmlChar.IsInvalid (value))
+                               throw new XmlException (this as IXmlLineInfo,
+                                       "Referenced character was not allowed in XML. Normalization is " + normalization + ", checkCharacters = " + checkCharacters);
+                       return value;
                }
 
-               private void ReadEntityReference (bool ignoreEntityReferences)
+               // Returns -1 if it should not be validated.
+               // Real EOF must not be detected here.
+               private int ReadEntityReference (bool ignoreEntityReferences)
                {
-                       nameLength = 0;
-
-                       int ch = PeekChar ();
-
-                       while (ch != ';' && ch != -1) {
-                               AppendNameChar (ReadChar ());
-                               ch = PeekChar ();
-                       }
-
+                       string name = ReadName ();
                        Expect (';');
 
-                       string name = CreateNameString ();
-
-                       switch (name)
-                       {
-                               case "lt":
-                                       AppendValueChar ('<');
-                                       break;
-                               case "gt":
-                                       AppendValueChar ('>');
-                                       break;
-                               case "amp":
+                       int predefined = XmlChar.GetPredefinedEntity (name);
+                       if (predefined >= 0)
+                               return predefined;
+                       else {
+                               if (ignoreEntityReferences) {
                                        AppendValueChar ('&');
-                                       break;
-                               case "apos":
-                                       AppendValueChar ('\'');
-                                       break;
-                               case "quot":
-                                       AppendValueChar ('"');
-                                       break;
-                               default:
-                                       if (ignoreEntityReferences) {
-                                               AppendValueChar ('&');
-
-                                               foreach (char ch2 in name) {
-                                                       AppendValueChar (ch2);
-                                               }
-
-                                               AppendValueChar (';');
-                                       } else {
-                                               returnEntityReference = true;
-                                               entityReferenceName = name;
-                                       }
-                                       break;
+                                       for (int i = 0; i < name.Length; i++)
+                                               AppendValueChar (name [i]);
+                                       AppendValueChar (';');
+                               } else {
+                                       returnEntityReference = true;
+                                       entityReferenceName = name;
+                               }
                        }
+                       return -1;
                }
 
                // The reader is positioned on the first character of
                // the attribute name.
-               private void ReadAttributes ()
+               private void ReadAttributes (bool isXmlDecl)
                {
+                       int peekChar = -1;
+                       bool requireWhitespace = false;
+                       currentAttribute = -1;
+                       currentAttributeValue = -1;
+
                        do {
-                               string name = ReadName ();
-                               SkipWhitespace ();
-                               Expect ('=');
-                               SkipWhitespace ();
-                               string value = ReadAttribute ();
+                               if (!SkipWhitespace () && requireWhitespace)
+                                       throw new XmlException ("Unexpected token. Name is required here.");
+
+                               IncrementAttributeToken ();
+                               currentAttributeToken.LineNumber = line;
+                               currentAttributeToken.LinePosition = column;
+
+                               currentAttributeToken.LocalName = 
+                                       currentAttributeToken.Name = ReadName ();
+                               ExpectAfterWhitespace ('=');
                                SkipWhitespace ();
+                               ReadAttributeValueTokens (-1);
+                               attributeCount++;
+
+                               if (currentAttributeToken.Name == "xmlns")
+                                       parserContext.NamespaceManager.AddNamespace (String.Empty, GetAttribute (currentAttribute));
+                               else if (currentAttributeToken.Name.StartsWith ("xmlns:")) {
+                                       string nsPrefix = currentAttributeToken.Name.Substring (6);
+                                       parserContext.NamespaceManager.AddNamespace (nsPrefix, GetAttribute (currentAttribute));
+                               }
 
-                               if (name == "xmlns")
-                                       parserContext.NamespaceManager.AddNamespace (String.Empty, ResolveAttributeValue (value));
-                               else if (name.StartsWith ("xmlns:"))
-                                       parserContext.NamespaceManager.AddNamespace (name.Substring (6), ResolveAttributeValue (value));
+                               if (!SkipWhitespace ())
+                                       requireWhitespace = true;
+                               peekChar = PeekChar ();
+                               if (isXmlDecl) {
+                                       if (peekChar == '?')
+                                               break;
+                               }
+                               else if (peekChar == '/' || peekChar == '>')
+                                       break;
+                       } while (peekChar != -1);
 
-                               AddAttribute (name, value);
-                       } while (PeekChar () != '/' && PeekChar () != '>' && PeekChar () != -1);
+                       currentAttribute = -1;
+                       currentAttributeValue = -1;
                }
 
-               // The reader is positioned on the quote character.
-               private string ReadAttribute ()
+               private void AddAttribute (string name, string value)
                {
-                       valueLength = 0;
+                       IncrementAttributeToken ();
+                       XmlAttributeTokenInfo ati = attributeTokens [currentAttribute];
+                       ati.Name = "SYSTEM";
+                       ati.FillNames ();
+                       IncrementAttributeValueToken ();
+                       XmlTokenInfo vti = attributeValueTokens [currentAttributeValue];
+                       vti.Value = value;
+                       SetProperties (vti, XmlNodeType.Text, String.Empty, false, value, false);
+                       attributeCount++;
+               }
+
+               private void IncrementAttributeToken ()
+               {
+                       currentAttribute++;
+                       if (attributeTokens.Length == currentAttribute) {
+                               XmlAttributeTokenInfo [] newArray = 
+                                       new XmlAttributeTokenInfo [attributeTokens.Length * 2];
+                               attributeTokens.CopyTo (newArray, 0);
+                               attributeTokens = newArray;
+                       }
+                       if (attributeTokens [currentAttribute] == null)
+                               attributeTokens [currentAttribute] = new XmlAttributeTokenInfo (this);
+                       currentAttributeToken = attributeTokens [currentAttribute];
+                       currentAttributeToken.Clear ();
+               }
 
-                       int quoteChar = ReadChar ();
+               private void IncrementAttributeValueToken ()
+               {
+                       ClearValueBuffer ();
+                       currentAttributeValue++;
+                       if (attributeValueTokens.Length == currentAttributeValue) {
+                               XmlTokenInfo [] newArray = new XmlTokenInfo [attributeValueTokens.Length * 2];
+                               attributeValueTokens.CopyTo (newArray, 0);
+                               attributeValueTokens = newArray;
+                       }
+                       if (attributeValueTokens [currentAttributeValue] == null)
+                               attributeValueTokens [currentAttributeValue] = new XmlTokenInfo (this, false);
+                       currentAttributeValueToken = attributeValueTokens [currentAttributeValue];
+                       currentAttributeValueToken.Clear ();
+               }
 
-                       if (quoteChar != '\'' && quoteChar != '\"')
-                               throw new XmlException ("an attribute value was not quoted");
+               // LAMESPEC: Orthodox XML reader should normalize attribute values
+               private void ReadAttributeValueTokens (int dummyQuoteChar)
+               {
+                       int quoteChar = (dummyQuoteChar < 0) ? ReadChar () : dummyQuoteChar;
 
-                       // this keeps quote char to get QuoteChar property correctly.
-                       AppendValueChar (quoteChar);
+                       if (quoteChar != '\'' && quoteChar != '\"')
+                               throw new XmlException (this as IXmlLineInfo,"an attribute value was not quoted");
+                       currentAttributeToken.QuoteChar = (char) quoteChar;
+
+                       IncrementAttributeValueToken ();
+                       currentAttributeToken.ValueTokenStartIndex = currentAttributeValue;
+                       currentAttributeValueToken.LineNumber = line;
+                       currentAttributeValueToken.LinePosition = column;
+
+                       bool incrementToken = false;
+                       bool isNewToken = true;
+                       bool loop = true;
+                       int ch = 0;
+                       while (loop) {
+                               ch = ReadChar ();
+                               if (ch == quoteChar)
+                                       break;
 
-                       while (PeekChar () != quoteChar) {
-                               int ch = ReadChar ();
+                               if (incrementToken) {
+                                       IncrementAttributeValueToken ();
+                                       currentAttributeValueToken.LineNumber = line;
+                                       currentAttributeValueToken.LinePosition = column;
+                                       incrementToken = false;
+                                       isNewToken = true;
+                               }
 
                                switch (ch)
                                {
                                case '<':
-                                       throw new XmlException ("attribute values cannot contain '<'");
-// expansion of entity now should be done at ResolveAttributeValue() method
-//                             case '&':
-//                                     ReadReference (true);
-//                                     break;
+                                       throw new XmlException (this as IXmlLineInfo,"attribute values cannot contain '<'");
                                case -1:
-                                       throw new XmlException ("unexpected end of file in an attribute value");
+                                       if (dummyQuoteChar < 0)
+                                               throw new XmlException (this as IXmlLineInfo,"unexpected end of file in an attribute value");
+                                       else    // Attribute value constructor.
+                                               loop = false;
+                                       break;
+                               case '&':
+                                       int startPosition = currentTagLength - 1;
+                                       if (PeekChar () == '#') {
+                                               ReadChar ();
+                                               ch = ReadCharacterReference ();
+                                               if (CharacterChecking && XmlChar.IsInvalid (ch))
+                                                       throw new XmlException (this as IXmlLineInfo,
+                                                               "Not allowed character was found.");
+                                               AppendValueChar (ch);
+                                               break;
+                                       }
+                                       // Check XML 1.0 section 3.1 WFC.
+                                       string entName = ReadName ();
+                                       Expect (';');
+                                       int predefined = XmlChar.GetPredefinedEntity (entName);
+                                       if (predefined < 0) {
+                                               CheckAttributeEntityReferenceWFC (entName);
+                                               currentAttributeValueToken.Value = CreateValueString ();
+                                               currentAttributeValueToken.NodeType = XmlNodeType.Text;
+                                               if (!isNewToken)
+                                                       IncrementAttributeValueToken ();
+                                               currentAttributeValueToken.Name = entName;
+                                               currentAttributeValueToken.Value = String.Empty;
+                                               currentAttributeValueToken.NodeType = XmlNodeType.EntityReference;
+                                               incrementToken = true;
+                                       }
+                                       else
+                                               AppendValueChar (predefined);
+                                       break;
                                default:
+                                       if (CharacterChecking && XmlChar.IsInvalid (ch))
+                                               throw new XmlException (this, "Invalid character was found.");
                                        AppendValueChar (ch);
                                        break;
                                }
+
+                               isNewToken = false;
                        }
+                       if (!incrementToken) {
+                               currentAttributeValueToken.Value = CreateValueString ();
+                               currentAttributeValueToken.NodeType = XmlNodeType.Text;
+                       }
+                       currentAttributeToken.ValueTokenEndIndex = currentAttributeValue;
+
+               }
+
+               private void CheckAttributeEntityReferenceWFC (string entName)
+               {
+                       DTDEntityDeclaration entDecl = 
+                               DTD == null ? null : DTD.EntityDecls [entName];
+                       if (DTD != null && resolver != null && entDecl == null)
+                               throw new XmlException (this, "Referenced entity does not exist.");
 
-                       ReadChar (); // quoteChar
-                       AppendValueChar (quoteChar);
+                       if (entDecl == null)
+                               return;
 
-                       return CreateValueString ();
+                       if (entDecl.HasExternalReference)
+                               throw new XmlException (this, "Reference to external entities is not allowed in the value of an attribute.");
+                       if (isStandalone && !entDecl.IsInternalSubset)
+                               throw new XmlException (this, "Reference to external entities is not allowed in the internal subset.");
+                       if (entDecl.EntityValue.IndexOf ('<') >= 0)
+                               throw new XmlException (this, "Attribute must not contain character '<' either directly or indirectly by way of entity references.");
                }
 
                // The reader is positioned on the first character
                // of the target.
                //
-               // Now it also reads XmlDeclaration, this method name became improper...
+               // It may be xml declaration or processing instruction.
                private void ReadProcessingInstruction ()
                {
                        string target = ReadName ();
-                       SkipWhitespace ();
+                       if (target == "xml") {
+                               ReadXmlDeclaration ();
+                               return;
+                       } else if (target.ToLower (CultureInfo.InvariantCulture) == "xml")
+                               throw new XmlException (this as IXmlLineInfo,
+                                       "Not allowed processing instruction name which starts with 'X', 'M', 'L' was found.");
 
-                       valueLength = 0;
+                       if (currentState == XmlNodeType.None)
+                               currentState = XmlNodeType.XmlDeclaration;
+
+                       if (!SkipWhitespace ())
+                               if (PeekChar () != '?')
+                                       throw new XmlException (this as IXmlLineInfo,
+                                               "Invalid processing instruction name was found.");
+
+                       ClearValueBuffer ();
 
                        while (PeekChar () != -1) {
                                int ch = ReadChar ();
@@ -1299,27 +2070,159 @@ namespace System.Xml
                                        break;
                                }
 
-                               AppendValueChar ((char)ch);
+                               if (CharacterChecking && XmlChar.IsInvalid (ch))
+                                       throw new XmlException (this, "Invalid character was found.");
+                               AppendValueChar (ch);
                        }
 
-/* for future use
-                       if(target == "xml") && parserContext.InputState != XmlParserInputState.Start)
-                               throw new XmlException("Xml declaration is not allowed here.");
-                       else {
-                               parserContext.InputState = XmlParserInputState.DTD; //for future use
-                       }
-*/
                        SetProperties (
-                               target == "xml" ?
-                               XmlNodeType.XmlDeclaration :
                                XmlNodeType.ProcessingInstruction, // nodeType
                                target, // name
                                false, // isEmptyElement
-                               CreateValueString (), // value
+                               null, // value: create only when required
                                true // clearAttributes
                        );
                }
 
+               // The reader is positioned after "<?xml "
+               private void ReadXmlDeclaration ()
+               {
+                       if (currentState != XmlNodeType.None) {
+                               throw new XmlException (this as IXmlLineInfo,
+                                       "XML declaration cannot appear in this state.");
+                       }
+                       currentState = XmlNodeType.XmlDeclaration;
+
+                       ClearAttributes ();
+
+                       ReadAttributes (true);  // They must have "version."
+                       string version = GetAttribute ("version");
+
+                       string message = null;
+
+                       if (attributeTokens [0].Name != "version" || version != "1.0")
+                               message = "Version 1.0 declaration is required in XML Declaration.";
+                       else if (attributeCount > 1 &&
+                                       (attributeTokens [1].Name != "encoding" &&
+                                       attributeTokens [1].Name != "standalone"))
+                               message = "Invalid Xml Declaration markup was found.";
+                       else if (attributeCount > 2 && attributeTokens [2].Name != "standalone")
+                               message = "Invalid Xml Declaration markup was found.";
+                       string sa = GetAttribute ("standalone");
+                       if (sa != null && sa != "yes" && sa != "no")
+                               message = "Only 'yes' or 'no' is allowed for standalone.";
+
+                       this.isStandalone = (sa == "yes");
+
+                       if (message != null)
+                               throw new XmlException (this as IXmlLineInfo, message);
+
+                       SetProperties (
+                               XmlNodeType.XmlDeclaration, // nodeType
+                               "xml", // name
+                               false, // isEmptyElement
+                               new string (currentTagBuffer, 6, currentTagLength - 6), // value
+                               false // clearAttributes
+                       );
+
+                       Expect ("?>");
+               }
+
+               internal void SkipTextDeclaration ()
+               {
+                       this.currentState = XmlNodeType.Element;
+
+                       if (PeekChar () != '<')
+                               return;
+
+                       ReadChar ();
+
+                       if (PeekChar () != '?') {
+                               peekCharsIndex = 0;
+                               return;
+                       }
+                       ReadChar ();
+
+                       while (peekCharsIndex < 6) {
+                               if (PeekChar () < 0)
+                                       break;
+                               else
+                                       ReadChar ();
+                       }
+                       if (new string (peekChars, 2, 4) != "xml ") {
+                               if (new string (peekChars, 2, 3).ToLower (CultureInfo.InvariantCulture) == "xml") {
+                                       throw new XmlException (this as IXmlLineInfo,
+                                               "Processing instruction name must not be character sequence 'X' 'M' 'L' with case insensitivity.");
+                               }
+                               peekCharsIndex = 0;
+                               return;
+                       }
+
+                       SkipWhitespace ();
+
+                       // version decl
+                       if (PeekChar () == 'v') {
+                               Expect ("version");
+                               ExpectAfterWhitespace ('=');
+                               SkipWhitespace ();
+                               int quoteChar = ReadChar ();
+                               char [] expect1_0 = new char [3];
+                               int versionLength = 0;
+                               switch (quoteChar) {
+                               case '\'':
+                               case '"':
+                                       while (PeekChar () != quoteChar) {
+                                               if (PeekChar () == -1)
+                                                       throw new XmlException (this as IXmlLineInfo,
+                                                               "Invalid version declaration inside text declaration.");
+                                               else if (versionLength == 3)
+                                                       throw new XmlException (this as IXmlLineInfo,
+                                                               "Invalid version number inside text declaration.");
+                                               else {
+                                                       expect1_0 [versionLength] = (char) ReadChar ();
+                                                       versionLength++;
+                                                       if (versionLength == 3 && new String (expect1_0) != "1.0")
+                                                               throw new XmlException (this as IXmlLineInfo,
+                                                                       "Invalid version number inside text declaration.");
+                                               }
+                                       }
+                                       ReadChar ();
+                                       SkipWhitespace ();
+                                       break;
+                               default:
+                                       throw new XmlException (this as IXmlLineInfo,
+                                               "Invalid version declaration inside text declaration.");
+                               }
+                       }
+
+                       if (PeekChar () == 'e') {
+                               Expect ("encoding");
+                               ExpectAfterWhitespace ('=');
+                               SkipWhitespace ();
+                               int quoteChar = ReadChar ();
+                               switch (quoteChar) {
+                               case '\'':
+                               case '"':
+                                       while (PeekChar () != quoteChar)
+                                               if (ReadChar () == -1)
+                                                       throw new XmlException (this as IXmlLineInfo,
+                                                               "Invalid encoding declaration inside text declaration.");
+                                       ReadChar ();
+                                       SkipWhitespace ();
+                                       break;
+                               default:
+                                       throw new XmlException (this as IXmlLineInfo,
+                                               "Invalid encoding declaration inside text declaration.");
+                               }
+                               // Encoding value should be checked inside XmlInputStream.
+                       }
+                       else
+                               throw new XmlException (this as IXmlLineInfo,
+                                       "Encoding declaration is mandatory in text declaration.");
+
+                       Expect ("?>");
+               }
+
                // The reader is positioned on the first character after
                // the leading '<!'.
                private void ReadDeclaration ()
@@ -1341,6 +2244,9 @@ namespace System.Xml
                                Expect ("DOCTYPE");
                                ReadDoctypeDecl ();
                                break;
+                       default:
+                               throw new XmlException (this as IXmlLineInfo,
+                                       "Unexpected declaration markup was found.");
                        }
                }
 
@@ -1348,7 +2254,10 @@ namespace System.Xml
                // the leading '<!--'.
                private void ReadComment ()
                {
-                       valueLength = 0;
+                       if (currentState == XmlNodeType.None)
+                               currentState = XmlNodeType.XmlDeclaration;
+
+                       ClearValueBuffer ();
 
                        while (PeekChar () != -1) {
                                int ch = ReadChar ();
@@ -1357,20 +2266,24 @@ namespace System.Xml
                                        ReadChar ();
 
                                        if (PeekChar () != '>')
-                                               throw new XmlException ("comments cannot contain '--'");
+                                               throw new XmlException (this as IXmlLineInfo,"comments cannot contain '--'");
 
                                        ReadChar ();
                                        break;
                                }
 
-                               AppendValueChar ((char)ch);
+                               if (XmlChar.IsInvalid (ch))
+                                       throw new XmlException (this as IXmlLineInfo,
+                                               "Not allowed character was found.");
+
+                               AppendValueChar (ch);
                        }
 
                        SetProperties (
                                XmlNodeType.Comment, // nodeType
                                String.Empty, // name
                                false, // isEmptyElement
-                               CreateValueString (), // value
+                               null, // value: create only when required
                                true // clearAttributes
                        );
                }
@@ -1379,10 +2292,18 @@ namespace System.Xml
                // the leading '<![CDATA['.
                private void ReadCDATA ()
                {
-                       valueLength = 0;
+                       if (currentState != XmlNodeType.Element)
+                               throw new XmlException (this as IXmlLineInfo,
+                                       "CDATA section cannot appear in this state.");
+
+                       ClearValueBuffer ();
 
+                       bool skip = false;
+                       int ch = 0;
                        while (PeekChar () != -1) {
-                               int ch = ReadChar ();
+                               if (!skip)
+                                       ch = ReadChar ();
+                               skip = false;
 
                                if (ch == ']' && PeekChar () == ']') {
                                        ch = ReadChar (); // ']'
@@ -1391,20 +2312,28 @@ namespace System.Xml
                                                ReadChar (); // '>'
                                                break;
                                        } else {
-                                               AppendValueChar (']');
-                                               AppendValueChar (']');
-                                               ch = ReadChar ();
+                                               skip = true;
                                        }
                                }
+                               if (normalization && ch == '\r') {
+                                       ch = PeekChar ();
+                                       if (ch != '\n')
+                                               // append '\n' instead of '\r'.
+                                               AppendValueChar ('\n');
+                                       // otherwise, discard '\r'.
+                                       continue;
+                               }
+                               if (CharacterChecking && XmlChar.IsInvalid (ch))
+                                       throw new XmlException (this, "Invalid character was found.");
 
-                               AppendValueChar ((char)ch);
+                               AppendValueChar (ch);
                        }
 
                        SetProperties (
                                XmlNodeType.CDATA, // nodeType
                                String.Empty, // name
                                false, // isEmptyElement
-                               CreateValueString (), // value
+                               null, // value: create only when required
                                true // clearAttributes
                        );
                }
@@ -1413,14 +2342,27 @@ namespace System.Xml
                // the leading '<!DOCTYPE'.
                private void ReadDoctypeDecl ()
                {
+                       if (prohibitDtd)
+                               throw new XmlException (this as IXmlLineInfo,
+                                       "Document Type Declaration (DTD) is prohibited in this XML.");
+                       switch (currentState) {
+                       case XmlNodeType.DocumentType:
+                       case XmlNodeType.Element:
+                       case XmlNodeType.EndElement:
+                               throw new XmlException (this as IXmlLineInfo,
+                                       "Document type cannot appear in this state.");
+                       }
+                       currentState = XmlNodeType.DocumentType;
+
                        string doctypeName = null;
-                       string publicId = String.Empty;
-                       string systemId = String.Empty;
+                       string publicId = null;
+                       string systemId = null;
+                       int intSubsetStartLine = 0;
+                       int intSubsetStartColumn = 0;
 
                        SkipWhitespace ();
                        doctypeName = ReadName ();
                        SkipWhitespace ();
-                       xmlBuffer.Length = 0;
                        switch(PeekChar ())
                        {
                        case 'S':
@@ -1428,7 +2370,9 @@ namespace System.Xml
                                break;
                        case 'P':
                                publicId = ReadPubidLiteral ();
-                               SkipWhitespace ();
+                               if (!SkipWhitespace ())
+                                       throw new XmlException (this as IXmlLineInfo,
+                                               "Whitespace is required between PUBLIC id and SYSTEM id.");
                                systemId = ReadSystemLiteral (false);
                                break;
                        }
@@ -1439,19 +2383,19 @@ namespace System.Xml
                        {
                                // read markupdecl etc. or end of decl
                                ReadChar ();
-                               xmlBuffer.Length = 0;
-                               saveToXmlBuffer = true;
-                               do {
-                                       ReadDTDInternalSubset ();
-                               } while(nodeType != XmlNodeType.None);
-                               xmlBuffer.Remove (xmlBuffer.Length - 1, 1);     // cut off ']'
-                               saveToXmlBuffer = false;
+                               intSubsetStartLine = this.LineNumber;
+                               intSubsetStartColumn = this.LinePosition;
+                               int startPos = currentTagLength;
+                               ReadInternalSubset ();
+                               int endPos = currentTagLength - 1;
+                               parserContext.InternalSubset = new string (currentTagBuffer, startPos, endPos - startPos);
                        }
                        // end of DOCTYPE decl.
-                       SkipWhitespace ();
-                       Expect ('>');
+                       ExpectAfterWhitespace ('>');
 
-                       parserContext.InternalSubset = xmlBuffer.ToString ();
+                       GenerateDTDObjectModel (doctypeName, publicId,
+                               systemId, parserContext.InternalSubset,
+                               intSubsetStartLine, intSubsetStartColumn);
 
                        // set properties for <!DOCTYPE> node
                        SetProperties (
@@ -1461,143 +2405,271 @@ namespace System.Xml
                                parserContext.InternalSubset, // value
                                true // clearAttributes
                                );
+
+                       if (publicId != null)
+                               AddAttribute ("PUBLIC", publicId);
+                       if (systemId != null)
+                               AddAttribute ("SYSTEM", systemId);
+                       currentAttribute = currentAttributeValue = -1;
                }
 
-               // Read any one of following:
-               //   elementdecl, AttlistDecl, EntityDecl, NotationDecl,
-               //   PI, Comment, Parameter Entity, or doctype termination char(']')
-               //
-               // returns a node of some nodeType or null, setting nodeType.
-               //       (if None then ']' was found.)
-               private void ReadDTDInternalSubset()
+               internal DTDObjectModel GenerateDTDObjectModel (string name, string publicId,
+                       string systemId, string internalSubset)
                {
-                       SkipWhitespace ();
-                       switch(ReadChar ())
+                       return GenerateDTDObjectModel (name, publicId, systemId, internalSubset, 0, 0);
+               }
+
+               internal DTDObjectModel GenerateDTDObjectModel (string name, string publicId,
+                       string systemId, string internalSubset, int intSubsetStartLine, int intSubsetStartColumn)
+               {
+                       // now compile DTD
+                       parserContext.Dtd = new DTDObjectModel (this.NameTable);        // merges both internal and external subsets in the meantime,
+                       DTD.BaseURI = BaseURI;
+                       DTD.Name = name;
+                       DTD.PublicId = publicId;
+                       DTD.SystemId = systemId;
+                       DTD.InternalSubset = internalSubset;
+                       DTD.XmlResolver = resolver;
+                       DTD.IsStandalone = isStandalone;
+                       DTD.LineNumber = line;
+                       DTD.LinePosition = column;
+
+                       DTDReader dr = new DTDReader (DTD, intSubsetStartLine, intSubsetStartColumn);
+                       dr.Normalization = this.normalization;
+#if DTD_HANDLE_EVENTS
+                       dr.ValidationEventHandler += new ValidationEventHandler (OnValidationEvent);
+#endif
+                       return dr.GenerateDTDObjectModel ();
+               }
+
+               private void OnValidationEvent (object o, ValidationEventArgs e)
+               {
+#if DTD_HANDLE_EVENTS
+                       if (ValidationEventHandler != null)
+                               // Override object as this.
+                               ValidationEventHandler (this, e);
+#endif
+               }
+
+               private enum DtdInputState
+               {
+                       Free = 1,
+                       ElementDecl,
+                       AttlistDecl,
+                       EntityDecl,
+                       NotationDecl,
+                       PI,
+                       Comment,
+                       InsideSingleQuoted,
+                       InsideDoubleQuoted,
+               }
+
+               private class DtdInputStateStack
+               {
+                       Stack intern = new Stack ();
+                       public DtdInputStateStack ()
                        {
-                       case ']':
-                               nodeType = XmlNodeType.None;
-                               break;
-                       case '%':
-                               string peName = ReadName ();
-                               Expect (';');
-                               nodeType = XmlNodeType.EntityReference; // It's chating a bit;-)
-                               break;
-                       case '<':
-                               switch(ReadChar ())
-                               {
-                               case '?':
-                                       ReadProcessingInstruction ();
+                               Push (DtdInputState.Free);
+                       }
+
+                       public DtdInputState Peek ()
+                       {
+                               return (DtdInputState) intern.Peek ();
+                       }
+
+                       public DtdInputState Pop ()
+                       {
+                               return (DtdInputState) intern.Pop ();
+                       }
+
+                       public void Push (DtdInputState val)
+                       {
+                               intern.Push (val);
+                       }
+               }
+
+
+               DtdInputStateStack stateStack = new DtdInputStateStack ();
+               DtdInputState State {
+                       get { return stateStack.Peek (); }
+               }
+
+               // Simply read but not generate any result.
+               private void ReadInternalSubset ()
+               {
+                       bool continueParse = true;
+
+                       while (continueParse) {
+                               switch (ReadChar ()) {
+                               case ']':
+                                       switch (State) {
+                                       case DtdInputState.Free:
+                                               continueParse = false;
+                                               break;
+                                       case DtdInputState.InsideDoubleQuoted:
+                                               continue;
+                                       case DtdInputState.InsideSingleQuoted:
+                                               continue;
+                                       default:
+                                               throw new XmlException (this as IXmlLineInfo,"unexpected end of file at DTD.");
+                                       }
                                        break;
-                               case '!':
-                                       switch(ReadChar ())
-                                       {
-                                       case '-':
-                                               Expect ('-');
-                                               ReadComment ();
+                               case -1:
+                                       throw new XmlException (this as IXmlLineInfo,"unexpected end of file at DTD.");
+                               case '<':
+                                       switch (State) {
+                                       case DtdInputState.InsideDoubleQuoted:
+                                       case DtdInputState.InsideSingleQuoted:
+                                       case DtdInputState.Comment:
+                                               continue;       // well-formed
+                                       }
+                                       int c = ReadChar ();
+                                       switch (c) {
+                                       case '?':
+                                               stateStack.Push (DtdInputState.PI);
                                                break;
-                                       case 'E':
-                                               switch(ReadChar ())
-                                               {
+                                       case '!':
+                                               switch (ReadChar ()) {
+                                               case 'E':
+                                                       switch (ReadChar ()) {
+                                                       case 'L':
+                                                               Expect ("EMENT");
+                                                               stateStack.Push (DtdInputState.ElementDecl);
+                                                               break;
+                                                       case 'N':
+                                                               Expect ("TITY");
+                                                               stateStack.Push (DtdInputState.EntityDecl);
+                                                               break;
+                                                       default:
+                                                               throw new XmlException (this as IXmlLineInfo,"unexpected token '<!E'.");
+                                                       }
+                                                       break;
+                                               case 'A':
+                                                       Expect ("TTLIST");
+                                                       stateStack.Push (DtdInputState.AttlistDecl);
+                                                       break;
                                                case 'N':
-                                                       Expect ("TITY");
-                                                       ReadEntityDecl ();
+                                                       Expect ("OTATION");
+                                                       stateStack.Push (DtdInputState.NotationDecl);
                                                        break;
-                                               case 'L':
-                                                       Expect ("EMENT");
-                                                       ReadElementDecl ();
+                                               case '-':
+                                                       Expect ("-");
+                                                       stateStack.Push (DtdInputState.Comment);
                                                        break;
-                                               default:
-                                                       throw new XmlException ("Syntax Error after '<!E' (ELEMENT or ENTITY must be found)");
                                                }
                                                break;
-                                       case 'A':
-                                               Expect ("TTLIST");
-                                               ReadAttListDecl ();
-                                               break;
-                                       case 'N':
-                                               Expect ("OTATION");
-                                               ReadNotationDecl ();
+                                       default:
+                                               throw new XmlException (this as IXmlLineInfo, String.Format ("unexpected '<{0}'.", (char) c));
+                                       }
+                                       break;
+                               case '\'':
+                                       if (State == DtdInputState.InsideSingleQuoted)
+                                               stateStack.Pop ();
+                                       else if (State != DtdInputState.InsideDoubleQuoted && State != DtdInputState.Comment)
+                                               stateStack.Push (DtdInputState.InsideSingleQuoted);
+                                       break;
+                               case '"':
+                                       if (State == DtdInputState.InsideDoubleQuoted)
+                                               stateStack.Pop ();
+                                       else if (State != DtdInputState.InsideSingleQuoted && State != DtdInputState.Comment)
+                                               stateStack.Push (DtdInputState.InsideDoubleQuoted);
+                                       break;
+                               case '>':
+                                       switch (State) {
+                                       case DtdInputState.ElementDecl:
+                                               goto case DtdInputState.NotationDecl;
+                                       case DtdInputState.AttlistDecl:
+                                               goto case DtdInputState.NotationDecl;
+                                       case DtdInputState.EntityDecl:
+                                               goto case DtdInputState.NotationDecl;
+                                       case DtdInputState.NotationDecl:
+                                               stateStack.Pop ();
                                                break;
+                                       case DtdInputState.InsideDoubleQuoted:
+                                       case DtdInputState.InsideSingleQuoted:
+                                       case DtdInputState.Comment:
+                                               continue;
                                        default:
-                                               throw new XmlException ("Syntax Error after '<!' characters.");
+                                               throw new XmlException (this as IXmlLineInfo,"unexpected token '>'");
                                        }
                                        break;
-                               default:
-                                       throw new XmlException ("Syntax Error after '<' character.");
+                               case '?':
+                                       if (State == DtdInputState.PI) {
+                                               if (ReadChar () == '>')
+                                                       stateStack.Pop ();
+                                       }
+                                       break;
+                               case '-':
+                                       if (State == DtdInputState.Comment) {
+                                               if (PeekChar () == '-') {
+                                                       ReadChar ();
+                                                       Expect ('>');
+                                                       stateStack.Pop ();
+                                               }
+                                       }
+                                       break;
+                               case '%':
+                                       if (State != DtdInputState.Free && State != DtdInputState.EntityDecl && State != DtdInputState.Comment && State != DtdInputState.InsideDoubleQuoted && State != DtdInputState.InsideSingleQuoted)
+                                               throw new XmlException (this as IXmlLineInfo,"Parameter Entity Reference cannot appear as a part of markupdecl (see XML spec 2.8).");
+                                       break;
                                }
-                               break;
-                       default:
-                               throw new XmlException ("Syntax Error inside doctypedecl markup.");
                        }
                }
 
-               // The reader is positioned on the head of the name.
-               private void ReadElementDecl()
-               {
-                       while(ReadChar () != '>');
-               }
-
-               private void ReadEntityDecl()
-               {
-                       while(ReadChar () != '>');
-               }
-
-               private void ReadAttListDecl()
-               {
-                       while(ReadChar () != '>');
-               }
-
-               private void ReadNotationDecl()
-               {
-                       while(ReadChar () != '>');
-               }
-               
                // The reader is positioned on the first 'S' of "SYSTEM".
                private string ReadSystemLiteral (bool expectSYSTEM)
                {
-                       if(expectSYSTEM)
+                       if(expectSYSTEM) {
                                Expect ("SYSTEM");
-                       SkipWhitespace ();
+                               if (!SkipWhitespace ())
+                                       throw new XmlException (this as IXmlLineInfo,
+                                               "Whitespace is required after 'SYSTEM'.");
+                       }
+                       else
+                               SkipWhitespace ();
                        int quoteChar = ReadChar ();    // apos or quot
-                       xmlBuffer.Length = 0;
-                       saveToXmlBuffer = true;
+                       int startPos = currentTagLength;
                        int c = 0;
-                       while(c != quoteChar) {
+                       ClearValueBuffer ();
+                       while (c != quoteChar) {
                                c = ReadChar ();
-                               if(c < 0) throw new XmlException ("Unexpected end of stream in ExternalID.");
+                               if (c < 0)
+                                       throw new XmlException (this as IXmlLineInfo,"Unexpected end of stream in ExternalID.");
+                               if (c != quoteChar)
+                                       AppendValueChar (c);
                        }
-                       saveToXmlBuffer = false;
-                       xmlBuffer.Remove (xmlBuffer.Length-1, 1);       // cut quoteChar
-                       return xmlBuffer.ToString ();
+                       return CreateValueString ();
                }
 
                private string ReadPubidLiteral()
                {
                        Expect ("PUBLIC");
-                       SkipWhitespace ();
+                       if (!SkipWhitespace ())
+                               throw new XmlException (this as IXmlLineInfo,
+                                       "Whitespace is required after 'PUBLIC'.");
                        int quoteChar = ReadChar ();
-                       xmlBuffer.Length = 0;
-                       saveToXmlBuffer = true;
+                       int startPos = currentTagLength;
                        int c = 0;
+                       ClearValueBuffer ();
                        while(c != quoteChar)
                        {
                                c = ReadChar ();
-                               if(c < 0) throw new XmlException ("Unexpected end of stream in ExternalID.");
+                               if(c < 0) throw new XmlException (this as IXmlLineInfo,"Unexpected end of stream in ExternalID.");
                                if(c != quoteChar && !XmlChar.IsPubidChar (c))
-                                       throw new XmlException("character '" + (char)c + "' not allowed for PUBLIC ID");
+                                       throw new XmlException (this as IXmlLineInfo,"character '" + (char) c + "' not allowed for PUBLIC ID");
+                               if (c != quoteChar)
+                                       AppendValueChar (c);
                        }
-                       ReadChar();     // skips quoteChar
-                       xmlBuffer.Remove (xmlBuffer.Length-1, 1);       // cut quoteChar
-                       saveToXmlBuffer = false;
-                       return xmlBuffer.ToString ();
+                       return CreateValueString ();
                }
 
                // The reader is positioned on the first character
                // of the name.
                private string ReadName ()
                {
-                       if (!XmlChar.IsFirstNameChar (PeekChar ()))
-                               throw new XmlException ("a name did not start with a legal character");
+                       int ch = PeekChar ();
+                       if (!XmlChar.IsFirstNameChar (ch))
+                               throw new XmlException (this as IXmlLineInfo,String.Format (CultureInfo.InvariantCulture, "a name did not start with a legal character {0} ({1})", ch, (char) ch));
 
                        nameLength = 0;
 
@@ -1617,12 +2689,12 @@ namespace System.Xml
                        int ch = ReadChar ();
 
                        if (ch != expected) {
-                               throw new XmlException (
-                                       String.Format (
+                               throw new XmlException (this as IXmlLineInfo,
+                                       String.Format (CultureInfo.InvariantCulture, 
                                                "expected '{0}' ({1:X}) but found '{2}' ({3:X})",
-                                               (char)expected,
+                                               (char) expected,
                                                expected,
-                                               (char)ch,
+                                               (char) ch,
                                                ch));
                        }
                }
@@ -1634,124 +2706,155 @@ namespace System.Xml
                                Expect (expected[i]);
                }
 
+               private void ExpectAfterWhitespace (char c)
+               {
+                       while (true) {
+                               int i = ReadChar ();
+                               if (i < 0x21 && XmlChar.IsWhitespace (i))
+                                       continue;
+                               if (c != i)
+                                       throw new XmlException (this, String.Format (CultureInfo.InvariantCulture, "Expected {0}, but found {1} [{2}]", c, (char) i, i));
+                               break;
+                       }
+               }
+
                // Does not consume the first non-whitespace character.
-               private void SkipWhitespace ()
+               private bool SkipWhitespace ()
                {
-                       //FIXME: Should not skip if whitespaceHandling == WhiteSpaceHandling.None
+                       bool skipped = XmlChar.IsWhitespace (PeekChar ());
+                       if (!skipped)
+                               return false;
                        while (XmlChar.IsWhitespace (PeekChar ()))
                                ReadChar ();
+                       return skipped;
                }
 
-               private bool ReadWhitespace ()
+               private void ReadWhitespace ()
                {
-                       valueLength = 0;
+                       if (currentState == XmlNodeType.None)
+                               currentState = XmlNodeType.XmlDeclaration;
+
+                       ClearValueBuffer ();
                        int ch = PeekChar ();
                        do {
                                AppendValueChar (ReadChar ());
                        } while ((ch = PeekChar ()) != -1 && XmlChar.IsWhitespace (ch));
 
-                       if (ch != -1 && ch != '<')
+                       if (currentState == XmlNodeType.Element && ch != -1 && ch != '<')
                                ReadText (false);
-                       else
-                               SetProperties (XmlNodeType.Whitespace,
+                       else {
+                               XmlNodeType nodeType = (this.XmlSpace == XmlSpace.Preserve) ?
+                                       XmlNodeType.SignificantWhitespace : XmlNodeType.Whitespace;
+                               SetProperties (nodeType,
                                               String.Empty,
                                               false,
-                                              CreateValueString (),
+                                              null, // value: create only when required
                                               true);
+                       }
 
-                       return (PeekChar () != -1);
+                       return;
                }
 
-               // read entity reference from attribute string and if parsable then return the value.
-               private string ReadAttributeValueEntityReference ()
+               // Since ReadBase64() is processed for every 4 chars, it does
+               // not handle '=' here.
+               private byte GetBase64Byte (char ch)
                {
-                       int endEntityPosition = attributeString.IndexOf(';',
-                               attributeStringCurrentPosition);
-                       string entityName = attributeString.Substring (attributeStringCurrentPosition + 1,
-                               endEntityPosition - attributeStringCurrentPosition - 1);
-
-                       attributeStringCurrentPosition = endEntityPosition + 1;
-
-                       if(entityName [0] == '#') {
-                               char c;
-                               // character entity
-                               if(entityName [1] == 'x') {
-                                       // hexadecimal
-                                       c = (char) int.Parse ("0" + entityName.Substring (2),
-                                               System.Globalization.NumberStyles.HexNumber);
-                               } else {
-                                       // decimal
-                                       c = (char) int.Parse (entityName.Substring (1));
-                               }
-                               return c.ToString();
-                       }
-                       else {
-                               switch(entityName)
-                               {
-                               case "lt": return "<";
-                               case "gt": return ">";
-                               case "amp": return "&";
-                               case "quot": return "\"";
-                               case "apos": return "'";
-                               default: return null;
-                               }
+                       switch (ch) {
+                       case '+':
+                               return 62;
+                       case '/':
+                               return 63;
+                       default:
+                               if (ch >= 'A' && ch <= 'Z')
+                                       return (byte) (ch - 'A');
+                               else if (ch >= 'a' && ch <= 'z')
+                                       return (byte) (ch - 'a' + 26);
+                               else if (ch >= '0' && ch <= '9')
+                                       return (byte) (ch - '0' + 52);
+                               else
+                                       throw new XmlException ("Invalid Base64 character was found.");
                        }
                }
 
-               private string ResolveAttributeValue (string unresolved)
+               // Returns -1 if it should throw an error.
+               private int ReadCharsInternal (char [] buffer, int offset, int length)
                {
-                       if(unresolved == null) return null;
-                       StringBuilder resolved = new StringBuilder();
-                       int pos = 0;
+                       if (IsEmptyElement) {
+                               Read ();
+                               return 0;
+                       }
 
-                       // trim start/end edge of quotation character.
-                       unresolved = unresolved.Substring (1, unresolved.Length - 2);
+                       if (offset < 0)
+                               throw new ArgumentOutOfRangeException ("offset", offset, "Offset must be non-negative integer.");
+                       else if (length < 0)
+                               throw new ArgumentOutOfRangeException ("length", length, "Length must be non-negative integer.");
+                       else if (buffer.Length < offset + length)
+                               throw new ArgumentOutOfRangeException ("buffer length is smaller than the sum of offset and length.");
 
-                       int next = unresolved.IndexOf ('&');
-                       if(next < 0)
-                               return unresolved;
+                       if (NodeType != XmlNodeType.Element)
+                               return 0;
 
-                       while(next >= 0) {
-                               if(pos < next)
-                                       resolved.Append (unresolved.Substring (pos, next - pos));// - 1);
-                               int endPos = unresolved.IndexOf (';', next+1);
-                               string entityName =
-                                       unresolved.Substring (next + 1, endPos - next - 1);
-                               if(entityName [0] == '#') {
-                                       char c;
-                                       // character entity
-                                       if(entityName [1] == 'x') {
-                                               // hexadecimal
-                                               c = (char) int.Parse ("0" + entityName.Substring (2),
-                                                       System.Globalization.NumberStyles.HexNumber);
-                                       } else {
-                                               // decimal
-                                               c = (char) int.Parse (entityName.Substring (1));
+                       shouldSkipUntilEndTag = true;
+
+                       int bufIndex = offset;
+                       for (int i = 0; i < length; i++) {
+                               int c = PeekChar ();
+                               switch (c) {
+                               case -1:
+                                       throw new XmlException (this as IXmlLineInfo, "Unexpected end of xml.");
+                               case '<':
+                                       ReadChar ();
+                                       if (PeekChar () != '/') {
+                                               buffer [bufIndex++] = '<';
+                                               continue;
                                        }
-                                       resolved.Append (c);
-                               } else {
-                                       switch(entityName) {
-                                       case "lt": resolved.Append ("<"); break;
-                                       case "gt": resolved.Append (">"); break;
-                                       case "amp": resolved.Append ("&"); break;
-                                       case "quot": resolved.Append ("\""); break;
-                                       case "apos": resolved.Append ("'"); break;
-                                       // With respect to "Value", MS document is helpless
-                                       // and the implemention returns inconsistent value
-                                       // (e.g. XML: "&ent; &amp;ent;" ---> Value: "&ent; &ent;".)
-                                       default: resolved.Append ("&" + entityName + ";"); break;
+                                       // Seems to skip immediate EndElement
+                                       Expect ('/');
+                                       if (depthUp) {
+                                               depth++;
+                                               depthUp = false;
+                                       }
+                                       ReadEndTag ();
+                                       shouldSkipUntilEndTag = false;
+                                       Read (); // move to the next node
+                                       return i;
+                               default:
+                                       ReadChar ();
+                                       if (c < Char.MaxValue)
+                                               buffer [bufIndex++] = (char) c;
+                                       else {
+                                               buffer [bufIndex++] = (char) (c / 0x10000 + 0xD800 - 1);
+                                               buffer [bufIndex++] = (char) (c % 0x10000 + 0xDC00);
                                        }
-                               }
-                               pos = endPos + 1;
-                               if(pos > unresolved.Length)
                                        break;
-                               next = unresolved.IndexOf('&', pos);
+                               }
                        }
-                       resolved.Append (unresolved.Substring(pos));
-
-                       return resolved.ToString();
+                       return length;
                }
 
+               private bool ReadUntilEndTag ()
+               {
+                       int ch;
+                       do {
+                               ch = ReadChar ();
+                               switch (ch) {
+                               case -1:
+                                       throw new XmlException (this as IXmlLineInfo,
+                                               "Unexpected end of xml.");
+                               case '<':
+                                       if (PeekChar () != '/')
+                                               continue;
+                                       ReadChar ();
+                                       string name = ReadName ();
+                                       if (name != elementNames [elementNameStackPos - 1])
+                                               continue;
+                                       Expect ('>');
+                                       depth--;
+                                       elementNames [--elementNameStackPos] = null;
+                                       return Read ();
+                               }
+                       } while (true);
+               }
                #endregion
        }
 }