2004-10-18 Atsushi Enomoto <atsushi@ximian.com>
[mono.git] / mcs / class / System.XML / System.Xml / XmlTextReader.cs
index 15888b8b7ab4dc0b5611c7a959ad7eb6cbeca63d..f1d5b59e8b04e5f2364e7c63c64d26bd4fe4522d 100644 (file)
@@ -9,12 +9,30 @@
 // (C) 2001, 2002 Jason Diamond  http://injektilo.org/
 //
 
-// FIXME:
 //
-//   NameTables aren't being used completely yet.
+// 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.
+//
+
+// FIXME:
 //
-//   Some thought needs to be given to performance. There's too many
-//   strings being allocated.
+//   Some thought needs to be given to performance.
 //
 //   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.Collections.Specialized;
+using System.Globalization;
 using System.IO;
+using System.Security.Policy;
 using System.Text;
 using System.Xml.Schema;
 using Mono.Xml;
-using Mono.Xml.Native;
 
 namespace System.Xml
 {
+#if NET_2_0
+       public class XmlTextReader : XmlReader,
+               IXmlLineInfo, IXmlNamespaceResolver
+#else
        public class XmlTextReader : XmlReader, IXmlLineInfo
+#endif
        {
                #region Constructors
 
@@ -75,8 +98,14 @@ namespace System.Xml
                }
 
                public XmlTextReader (string url, XmlNameTable nt)
-                       : this (url, new XmlStreamReader (url, null, null), 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)
@@ -129,13 +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 elementDepth + 2; // inside attribute value.
+                                       return nodeTypeMod + elementDepth + 2; // inside attribute value.
                                else if (currentAttribute >= 0)
-                                       return elementDepth + 1;
+                                       return nodeTypeMod + elementDepth + 1;
                                return elementDepth;
                        }
                }
@@ -144,58 +192,51 @@ 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 { 
-                               if (this.valueBuilderAvailable)
-                                       return valueBuilder.Length != 0;
-                               else
-                                       return cursorToken.Value != null;
-                       }
+#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
-               {
+               public override bool IsDefault {
+                       // XmlTextReader does not expand default attributes.
+                       get { return false; }
+               }
+
+               public override bool IsEmptyElement {
                        get { return cursorToken.IsEmptyElement; }
                }
 
-               public override string this [int i]
-               {
+               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
-               {
+               public int LineNumber {
                        get {
                                if (useProceedingLineInfo)
                                        return line;
@@ -204,8 +245,7 @@ namespace System.Xml
                        }
                }
 
-               public int LinePosition
-               {
+               public int LinePosition {
                        get {
                                if (useProceedingLineInfo)
                                        return column;
@@ -214,18 +254,15 @@ namespace System.Xml
                        }
                }
 
-               public override string LocalName
-               {
+               public override string LocalName {
                        get { return cursorToken.LocalName; }
                }
 
-               public override string Name
-               {
+               public override string Name {
                        get { return cursorToken.Name; }
                }
 
-               public bool Namespaces
-               {
+               public bool Namespaces {
                        get { return namespaces; }
                        set { 
                                if (readState != ReadState.Initial)
@@ -234,66 +271,66 @@ namespace System.Xml
                        }
                }
 
-               public override string 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
-               {
+               public override XmlNodeType NodeType {
                        get { return cursorToken.NodeType; }
                }
 
-               [MonoTODO]
-               public bool Normalization
-               {
+               public bool Normalization {
                        get { return normalization; }
                        set { normalization = value; }
                }
 
-               public override string Prefix
-               {
+               public override string Prefix {
                        get { return cursorToken.Prefix; }
                }
 
-               public override char QuoteChar
-               {
+#if NET_2_0
+               public bool ProhibitDtd {
+                       get { return prohibitDtd; }
+                       set { prohibitDtd = value; }
+               }
+#endif
+
+               public override char QuoteChar {
                        get { return cursorToken.QuoteChar; }
                }
 
-               public override ReadState ReadState
-               {
+               public override ReadState ReadState {
                        get { return readState; }
                }
 
-               public override string Value
-               {
+#if NET_2_0
+               public override XmlReaderSettings Settings {
+                       get { return base.Settings; }
+               }
+#endif
+
+               public override string Value {
                        get { return cursorToken.Value != null ? cursorToken.Value : String.Empty; }
                }
 
-               public WhitespaceHandling WhitespaceHandling
-               {
+               public WhitespaceHandling WhitespaceHandling {
                        get { return whitespaceHandling; }
                        set { whitespaceHandling = value; }
                }
 
-               public override string XmlLang
-               {
+               public override string XmlLang {
                        get { return parserContext.XmlLang; }
                }
 
-               public XmlResolver XmlResolver
-               {
+               public XmlResolver XmlResolver {
                        set { resolver = value; }
                }
 
-               public override XmlSpace XmlSpace
-               {
+               public override XmlSpace XmlSpace {
                        get { return parserContext.XmlSpace; }
                }
 
@@ -308,11 +345,13 @@ namespace System.Xml
                        cursorToken.Clear ();
                        currentToken.Clear ();
                        attributeCount = 0;
+                       if (closeInput && reader != null)
+                               reader.Close ();
                }
 
                public override string GetAttribute (int i)
                {
-                       if (i > attributeCount)
+                       if (i >= attributeCount)
                                throw new ArgumentOutOfRangeException ("i is smaller than AttributeCount");
                        else {
                                return attributeTokens [i].Value;
@@ -353,39 +392,54 @@ namespace System.Xml
                        return attributeTokens [idx].Value;
                }
 
+#if NET_2_0
+               public IDictionary GetNamespacesInScope (XmlNamespaceScope scope)
+               {
+                       return parserContext.NamespaceManager.GetNamespacesInScope (scope);
+               }
+#endif
+
                public TextReader GetRemainder ()
                {
-                       StringBuilder sb = null;
-                       if (this.hasPeekChars) {
-                               sb = new StringBuilder ();
-                               int end = 0;
-                               for (; end < 6; end++)
-                                       if (peekChars [end] <= 0)
-                                               break;
-                               sb.Append (peekChars, 0, end);
-                       }
-                       if (has_peek && peek_char > 0) {
-                               if (sb != null)
-                                       sb.Append ((char) peek_char);
-                               else
-                                       return new StringReader (((char) peek_char) + reader.ReadToEnd ());
-                       }
-                       // As long as less memory consumptive...
-                       if (sb != null)
-                               return new StringReader (sb.ToString () + reader.ReadToEnd ());
-                       else
-                               return new StringReader (reader.ReadToEnd ());
+                       if (peekCharsIndex == peekCharsLength)
+                               return reader;
+                       return new StringReader (new string (peekChars, peekCharsIndex, peekCharsLength - peekCharsIndex) + reader.ReadToEnd ());
                }
 
+#if NET_2_0
+               public bool HasLineInfo ()
+#else
                bool IXmlLineInfo.HasLineInfo ()
+#endif
                {
                        return true;
                }
 
                public override string LookupNamespace (string prefix)
                {
-                       return parserContext.NamespaceManager.LookupNamespace (prefix);
+                       return LookupNamespace (prefix, false);
+               }
+
+#if NET_2_0
+               public override string LookupNamespace (string prefix, bool atomizedName)
+#else
+               internal override string LookupNamespace (string prefix, bool atomizedName)
+#endif
+               {
+                       return parserContext.NamespaceManager.LookupNamespace (prefix, atomizedName);
+               }
+
+#if NET_2_0
+               string IXmlNamespaceResolver.LookupPrefix (string ns)
+               {
+                       return LookupPrefix (ns, false);
+               }
+
+               public string LookupPrefix (string ns, bool atomizedName)
+               {
+                       return parserContext.NamespaceManager.LookupPrefix (ns, atomizedName);
                }
+#endif
 
                public override void MoveToAttribute (int i)
                {
@@ -484,19 +538,19 @@ namespace System.Xml
                        currentToken.Clear ();
 
                        // It was moved from end of ReadStartTag ().
-                       if (depthUp)
+                       if (depthUp) {
                                ++depth;
-                       depthUp = false;
+                               depthUp = false;
+                       }
 
                        if (shouldSkipUntilEndTag) {
                                shouldSkipUntilEndTag = false;
                                return ReadUntilEndTag ();
                        }
 
-                       more = ReadContent ();
+                       base64CacheStartsAt = -1;
 
-                       if (depth == 0 && !allowMultipleRoot && (IsEmptyElement || NodeType == XmlNodeType.EndElement))
-                               currentState = XmlNodeType.EndElement;
+                       more = ReadContent ();
 
                        if (!more && startNodeType == XmlNodeType.Document && currentState != XmlNodeType.EndElement)
                                throw new XmlException ("Document element did not appear.");
@@ -526,7 +580,14 @@ namespace System.Xml
                                return false;
                }
 
-               [MonoTODO ("It looks to keep incomplete byte block.")]
+               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)
@@ -536,31 +597,103 @@ namespace System.Xml
                        else if (buffer.Length < offset + length)
                                throw new ArgumentOutOfRangeException ("buffer length is smaller than the sum of offset and length.");
 
+                       if (length == 0)        // It does not raise an error.
+                               return 0;
+
+                       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;
+                               }
+                       }
+
+                       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);
 
-                       int bufIndex = offset;
-                       for (int i = 0; i < charsLength - 3; i += 4) {
-                               buffer [bufIndex] = (byte) (GetBase64Byte (chars [i]) << 2);
-                               if (i + 1 == charsLength)
+                       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;
+                               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;
-                               byte b = GetBase64Byte (chars [i + 1]);
-                               buffer [bufIndex] += (byte) (b >> 4);
-                               bufIndex++;
-                               buffer [bufIndex] = (byte) ((b & 0xf) << 4);
-                               if (i + 2 == charsLength)
+                               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;
-                               b = GetBase64Byte (chars [i + 2]);
-                               buffer [bufIndex] += (byte) (b >> 2);
-                               bufIndex++;
-                               buffer [bufIndex] = (byte) ((b & 3) << 6);
-                               if (i + 3 == charsLength)
+                               if ((i = SkipIgnorableBase64Chars (chars, charsLength, i)) == charsLength)
                                        break;
-                               buffer [bufIndex] += GetBase64Byte (chars [i + 3]);
-                               bufIndex++;
+                               work = GetBase64Byte (chars [i]);
+                               if (bufIndex < bufLast) {
+                                       buffer [bufIndex] += work;
+                                       bufIndex++;
+                               }
+                               else
+                                       base64Cache [2] += work;
                        }
-                       return (int) System.Math.Ceiling (4.0 / 3 * max);
+                       return System.Math.Min (bufLast - offset, bufIndex - offset);
                }
 
                public int ReadBinHex (byte [] buffer, int offset, int length)
@@ -572,27 +705,12 @@ namespace System.Xml
                        else if (buffer.Length < offset + length)
                                throw new ArgumentOutOfRangeException ("buffer length is smaller than the sum of offset and length.");
 
+                       if (length == 0)
+                               return 0;
+
                        char [] chars = new char [length * 2];
                        int charsLength = ReadChars (chars, 0, length * 2);
-                       int bufIndex = offset;
-                       for (int i = 0; i < charsLength - 1; i += 2) {
-                               buffer [bufIndex] = (chars [i] > '9' ?
-                                               (byte) (chars [i] - 'A' + 10) :
-                                               (byte) (chars [i] - '0'));
-                               buffer [bufIndex] <<= 4;
-                               buffer [bufIndex] += chars [i + 1] > '9' ?
-                                               (byte) (chars [i + 1] - 'A' + 10) : 
-                                               (byte) (chars [i + 1] - '0');
-                               bufIndex++;
-                       }
-                       if (charsLength %2 != 0)
-                               buffer [bufIndex++] = (byte)
-                                       ((chars [charsLength - 1] > '9' ?
-                                               (byte) (chars [charsLength - 1] - 'A' + 10) :
-                                               (byte) (chars [charsLength - 1] - '0'))
-                                       << 4);
-
-                       return bufIndex - offset;
+                       return XmlConvert.FromBinHexString (chars, offset, charsLength, buffer);
                }
 
                public int ReadChars (char [] buffer, int offset, int length)
@@ -600,110 +718,144 @@ namespace System.Xml
                        return ReadCharsInternal (buffer, offset, length);
                }
 
-#if NET_1_0
+#if NET_2_0
+               public override string ReadString ()
+               {
+                       return ReadStringInternal ();
+               }
+#elif NET_1_1
+#else
                public override string ReadInnerXml ()
                {
-                       if (readState != ReadState.Interactive)
-                               return String.Empty;
-
-                       switch (NodeType) {
-                       case XmlNodeType.Attribute:
-                               return value.Substring (1, value.Length - 2);
-                       case XmlNodeType.Element:
-                               if (IsEmptyElement)
-                                       return String.Empty;
-
-                               int startDepth = depth;
-
-                               if (innerXmlBuilder == null)
-                                       innerXmlBuilder = new StringBuilder ();
-                               innerXmlBuilder.Length = 0;
-                               bool loop = true;
-                               do {
-                                       Read ();
-                                       if (NodeType ==XmlNodeType.None)
-                                               throw new XmlException ("unexpected end of xml.");
-                                       else if (NodeType == XmlNodeType.EndElement && depth == startDepth) {
-                                               loop = false;
-                                               Read ();
-                                       }
-                                       else
-                                               innerXmlBuilder.Append (currentTag);
-                               } while (loop);
-                               string xml = innerXmlBuilder.ToString ();
-                               innerXmlBuilder.Length = 0;
-                               return xml;
-                       case XmlNodeType.None:
-                               // MS document is incorrect. Seems not to progress.
-                               return String.Empty;
-                       default:
-                               Read ();
-                               return String.Empty;
-                       }
+                       return ReadInnerXmlInternal ();
                }
 
                public override string ReadOuterXml ()
                {
-                       if (readState != ReadState.Interactive)
-                               return String.Empty;
-
-                       switch (NodeType) {
-                       case XmlNodeType.Attribute:
-                               // strictly incompatible with MS... (it holds spaces attribute between name, value and "=" char (very trivial).
-                               return String.Format ("{0}={1}{2}{1}", Name, QuoteChar, ReadInnerXml ());
-                       case XmlNodeType.Element:
-                               bool isEmpty = IsEmptyElement;
-                               string startTag = currentTag.ToString ();
-                               string name = Name;
-
-                               if (NodeType == XmlNodeType.Element && !isEmpty)
-                                       return String.Format ("{0}{1}</{2}>", startTag, ReadInnerXml (), name);
-                               else
-                                       return currentTag.ToString ();
-                       case XmlNodeType.None:
-                               // MS document is incorrect. Seems not to progress.
-                               return String.Empty;
-                       default:
-                               Read ();
-                               return String.Empty;
-                       }
+                       return ReadOuterXmlInternal ();
                }
-#endif
 
                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 override bool ReadValueAsBoolean ()
+               {
+                       return base.ReadValueAsBoolean ();
+               }
+
+               [MonoTODO]
+               public override DateTime ReadValueAsDateTime ()
+               {
+                       return base.ReadValueAsDateTime ();
+               }
+
+               [MonoTODO]
+               public override decimal ReadValueAsDecimal ()
+               {
+                       return base.ReadValueAsDecimal ();
+               }
+
+               [MonoTODO]
+               public override double ReadValueAsDouble ()
+               {
+                       return base.ReadValueAsDouble ();
+               }
+
+               [MonoTODO]
+               public override int ReadValueAsInt32 ()
+               {
+                       return base.ReadValueAsInt32 ();
+               }
+
+               [MonoTODO]
+               public override long ReadValueAsInt64 ()
+               {
+                       return base.ReadValueAsInt64 ();
+               }
+
+               [MonoTODO]
+               public override ICollection ReadValueAsList ()
+               {
+                       return base.ReadValueAsList ();
+               }
+
+               [MonoTODO]
+               public override float ReadValueAsSingle ()
+               {
+                       return base.ReadValueAsSingle ();
+               }
+
+               [MonoTODO]
+               public override string ReadValueAsString ()
+               {
+                       return ReadString ();
+               }
+
+               [MonoTODO]
+               public override object ReadValueAs (Type type)
+               {
+                       return base.ReadValueAs (type);
+               }
+
+               [MonoTODO]
+               public override object ReadValueAs (Type type, IXmlNamespaceResolver resolver)
+               {
+                       return base.ReadValueAs (type, resolver);
+               }
+#endif
+
                public override void ResolveEntity ()
                {
                        // 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
                // Parsed DTD Objects
+#if DTD_HANDLE_EVENTS
+               internal event ValidationEventHandler ValidationEventHandler;
+#endif
+
                internal DTDObjectModel DTD {
                        get { return parserContext.Dtd; }
                }
+
+               internal XmlResolver Resolver {
+                       get { return resolver; }
+               }
                #endregion
 
                #region Privates
                internal class XmlTokenInfo
                {
-                       public XmlTokenInfo (XmlTextReader xtr)
+                       public XmlTokenInfo (XmlTextReader xtr, bool isPrimaryToken)
                        {
+                               this.isPrimaryToken = isPrimaryToken;
                                Reader = xtr;
                                Clear ();
                        }
 
+                       bool isPrimaryToken;
                        string valueCache;
 
                        protected XmlTextReader Reader;
@@ -723,15 +875,19 @@ namespace System.Xml
                                get {
                                        if (valueCache != null)
                                                return valueCache;
-                                       else if (Reader.valueBuilderAvailable) {
-                                               valueCache = Reader.valueBuilder.ToString ();
+                                       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 valueCache;
-                               }
-                               set {
-                                       valueCache = value;
+                                       return null;
                                }
+                               set { valueCache = value; }
                        }
 
                        public virtual void Clear ()
@@ -747,28 +903,40 @@ namespace System.Xml
                        internal virtual void FillNames ()
                        {
                                if (Reader.Namespaces) {
-                                       int indexOfColon = Name.IndexOf (':');
+                                       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 {
-                                               Prefix = Reader.NameTable.Add (Name.Substring (0, indexOfColon));
-                                               LocalName = Reader.NameTable.Add (Name.Substring (indexOfColon + 1));
+                                               // 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 == string.Empty)
+                                               if (Prefix.Length == 0)
                                                        NamespaceURI = string.Empty;
                                                else
-                                                       NamespaceURI = Reader.LookupNamespace (Prefix);
+                                                       NamespaceURI = Reader.LookupNamespace (Prefix, true);
                                                break;
 
                                        case XmlNodeType.Element:
                                        case XmlNodeType.EndElement:
-                                               NamespaceURI = Reader.LookupNamespace (Prefix);
+                                               NamespaceURI = Reader.LookupNamespace (Prefix, true);
                                                break;
                                        default:
                                                NamespaceURI = "";
@@ -784,7 +952,7 @@ namespace System.Xml
                internal class XmlAttributeTokenInfo : XmlTokenInfo
                {
                        public XmlAttributeTokenInfo (XmlTextReader reader)
-                               : base (reader)
+                               : base (reader, false)
                        {
                                NodeType = XmlNodeType.Attribute;
                        }
@@ -792,40 +960,49 @@ namespace System.Xml
                        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.Text)
-                                                       valueCache = ti.Value;
-                                               else
+                                               if (ti.NodeType == XmlNodeType.EntityReference)
                                                        valueCache = String.Concat ("&", ti.Name, ";");
+                                               else
+                                                       valueCache = ti.Value;
+                                               if (cachedNormalization)
+                                                       NormalizeSpaces ();
                                                return valueCache;
                                        }
 
-                                       StringBuilder sb = new StringBuilder ();
+                                       tmpBuilder.Length = 0;
                                        for (int i = ValueTokenStartIndex; i <= ValueTokenEndIndex; i++) {
                                                XmlTokenInfo ti = Reader.attributeValueTokens [i];
                                                if (ti.NodeType == XmlNodeType.Text)
-                                                       sb.Append (ti.Value);
+                                                       tmpBuilder.Append (ti.Value);
                                                else {
-                                                       sb.Append ('&');
-                                                       sb.Append (ti.Name);
-                                                       sb.Append (';');
+                                                       tmpBuilder.Append ('&');
+                                                       tmpBuilder.Append (ti.Name);
+                                                       tmpBuilder.Append (';');
                                                }
                                        }
 
-                                       valueCache = sb.ToString ();
-
+                                       valueCache = tmpBuilder.ToString ();
+                                       if (cachedNormalization)
+                                               NormalizeSpaces ();
                                        return valueCache;
                                }
-                               set {
-                                       valueCache = value;
-                               }
+
+                               set { valueCache = value; }
                        }
 
                        public override void Clear ()
@@ -842,6 +1019,26 @@ namespace System.Xml
                                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 ();
+                       }
                }
 
                private XmlTokenInfo cursorToken;
@@ -863,42 +1060,45 @@ namespace System.Xml
                private bool depthUp;
 
                private bool popScope;
-               private Stack elementStack = new Stack();
+
+               private string [] elementNames;
+               int elementNameStackPos;
+
                private bool allowMultipleRoot;
 
                private bool isStandalone;
 
-               private StringBuilder valueBuilder;
-               private bool valueBuilderAvailable = false;
-
                private bool returnEntityReference;
                private string entityReferenceName;
 
                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 = 256;
 
-               private StringBuilder valueBuffer = new StringBuilder (512);
+               private char [] currentTagBuffer;
+               private int currentTagLength;
+               private int currentTagCapacity;
+               private const int initialCurrentTagCapacity = 256;
 
                private TextReader reader;
-               private bool can_seek;
-               private bool has_peek;
-               private int peek_char;
-               private bool hasPeekChars;
                private char [] peekChars;
                private int peekCharsIndex;
+               private int peekCharsLength;
+               private const int peekCharCapacity = 1024;
 
                private int line;
                private int column;
-               private StringBuilder currentTag = new StringBuilder ();
 
                private int currentLinkedNodeLineNumber;
                private int currentLinkedNodeLinePosition;
                private bool useProceedingLineInfo;
 
-               // A buffer for ReadContent for ReadOuterXml
-
                private XmlNodeType startNodeType;
                // State machine attribute.
                //      XmlDeclaration: after the first node.
@@ -909,6 +1109,8 @@ namespace System.Xml
 
                // 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;
@@ -916,9 +1118,14 @@ namespace System.Xml
                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);
+                       currentToken = new XmlTokenInfo (this, true);
                        cursorToken = currentToken;
                        currentAttribute = -1;
                        currentAttributeValue = -1;
@@ -932,10 +1139,10 @@ namespace System.Xml
                        depthUp = false;
 
                        popScope = allowMultipleRoot = false;
-                       elementStack.Clear ();
+                       elementNames = new string [10];
+                       elementNameStackPos = 0;
 
                        isStandalone = false;
-                       valueBuilderAvailable = false;
                        returnEntityReference = false;
                        entityReferenceName = String.Empty;
 
@@ -943,15 +1150,22 @@ namespace System.Xml
                        nameLength = 0;
                        nameCapacity = initialNameCapacity;
 
-                       can_seek = has_peek = false;
-                       peek_char = peekCharsIndex = 0;
-                       peekChars = new char [6];
+                       valueBuffer = new char [initialValueCapacity];
+                       valueLength = 0;
+                       valueCapacity = initialValueCapacity;
 
-                       line = 1;
-                       column = 0;
-                       currentTag.Length = 0;
+                       currentTagBuffer = new char [initialCurrentTagCapacity];
+                       currentTagLength = 0;
+                       currentTagCapacity = initialCurrentTagCapacity;
+
+                       peekCharsIndex = 0;
+                       peekCharsLength = 0;
+                       if (peekChars == null)
+                               peekChars = new char [peekCharCapacity];
 
-                       valueBuffer.Length = 0;
+                       line = 1;
+                       column = 1;
+                       currentTagLength = 0;
 
                        currentLinkedNodeLineNumber = currentLinkedNodeLinePosition = 0;
                        useProceedingLineInfo = false;
@@ -959,6 +1173,16 @@ namespace System.Xml
                        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)
@@ -973,17 +1197,24 @@ namespace System.Xml
                                        XmlSpace.None);
                        }
 
-                       if (url != null && url != String.Empty) {
-                               string path = Path.GetFullPath ("./a");
-                               Uri uri = new Uri (new Uri (path), url);
+                       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:
-                               fragment = new StringReader (fragment.ReadToEnd ().Replace ("\"", "&quot;"));
+                               reader = new StringReader (fragment.ReadToEnd ().Replace ("\"", "&quot;"));
                                break;
                        case XmlNodeType.Element:
                                currentState = XmlNodeType.Element;
@@ -994,9 +1225,30 @@ namespace System.Xml
                        default:
                                throw new XmlException (String.Format ("NodeType {0} is not allowed to create XmlTextReader.", fragType));
                        }
+               }
 
-                       reader = fragment;
+#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
@@ -1023,7 +1275,6 @@ namespace System.Xml
                        string value,
                        bool clearAttributes)
                {
-                       this.valueBuilderAvailable = false;
                        token.Clear ();
                        token.NodeType = nodeType;
                        token.Name = name;
@@ -1037,17 +1288,6 @@ namespace System.Xml
                        token.FillNames ();
                }
 
-               private void SetProperties (
-                       XmlNodeType nodeType,
-                       string name,
-                       bool isEmptyElement,
-                       bool clearAttributes,
-                       StringBuilder value) {
-                       SetProperties (nodeType, name, isEmptyElement, (string)null, clearAttributes);
-                       this.valueBuilderAvailable = true;
-                       this.valueBuilder = value;
-               }
-
                private void ClearAttributes ()
                {
                        for (int i = 0; i < attributeCount; i++)
@@ -1057,64 +1297,69 @@ namespace System.Xml
                        currentAttributeValue = -1;
                }
 
-               /*
                private int PeekChar ()
                {
-                       return currentInput.PeekChar ();
+                       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 ()
-               {
-                       return currentInput.ReadChar ();
-               }
-               */
-               public int PeekChar ()
-               {
-                       if (can_seek)
-                               return reader.Peek ();
-
-                       if (hasPeekChars)
-                               return peekChars [peekCharsIndex];
-
-                       if (has_peek)
-                               return peek_char;
-
-                       peek_char = reader.Read ();
-                       has_peek = true;
-                       return peek_char;
-               }
-
-               public int ReadChar ()
                {
                        int ch;
 
-                       if (hasPeekChars) {
-                               ch = peekChars [peekCharsIndex++];
-                               if (peekChars [peekCharsIndex] == 0)
-                                       hasPeekChars = false;
-                       } else 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++;
                        }
-                       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;
@@ -1123,39 +1368,43 @@ namespace System.Xml
                        if (returnEntityReference)
                                SetEntityReferenceProperties ();
                        else {
-                               switch (PeekChar ()) {
-                               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;
-                               case -1:
+                               int c = PeekChar ();
+                               if (c == -1) {
                                        readState = ReadState.EndOfFile;
+                                       ClearValueBuffer ();
                                        SetProperties (
                                                XmlNodeType.None, // nodeType
                                                String.Empty, // name
                                                false, // isEmptyElement
-                                               (string) null, // value
+                                               null, // value
                                                true // clearAttributes
                                        );
                                        if (depth > 0)
                                                throw new XmlException ("unexpected end of file. Current depth is " + depth);
 
                                        return false;
-                               default:
-                                       ReadText (true);
-                                       break;
+                               } 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;
@@ -1164,8 +1413,6 @@ namespace System.Xml
                private void SetEntityReferenceProperties ()
                {
                        DTDEntityDeclaration decl = DTD != null ? DTD.EntityDecls [entityReferenceName] : null;
-//                     if (DTD != null && resolver != null && decl == null)
-//                             throw new XmlException (this as IXmlLineInfo, "Entity declaration does not exist.");
                        if (this.isStandalone)
                                if (DTD == null || decl == null || !decl.IsInternalSubset)
                                        throw new XmlException (this as IXmlLineInfo,
@@ -1174,11 +1421,12 @@ namespace System.Xml
                                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) null, // value
+                               null, // value
                                true // clearAttributes
                        );
 
@@ -1214,11 +1462,14 @@ namespace System.Xml
                {
                        if (currentState == XmlNodeType.EndElement)
                                throw new XmlException (this as IXmlLineInfo,
-                                       "Element cannot appear in this state.");
+                                       "Multiple document element was detected.");
                        currentState = XmlNodeType.Element;
 
                        parserContext.NamespaceManager.PushScope ();
 
+                       currentLinkedNodeLineNumber = line;
+                       currentLinkedNodeLinePosition = column;
+
                        string name = ReadName ();
                        if (currentState == XmlNodeType.EndElement)
                                throw new XmlException (this as IXmlLineInfo,"document has terminated, cannot open new element");
@@ -1237,17 +1488,22 @@ namespace System.Xml
                                attributeTokens [i].FillNames ();
 
                        // quick name check
-                       for (int i = 0; i < attributeCount; i++)
+                       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)
-                               parserContext.BaseURI = baseUri;
+                       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;
@@ -1267,19 +1523,43 @@ namespace System.Xml
                        }
                        else {
                                depthUp = true;
-                               elementStack.Push (name);
+                               PushElementName (name);
                                parserContext.PushScope ();
                        }
 
                        Expect ('>');
-
                        SetProperties (
                                XmlNodeType.Element, // nodeType
                                name, // name
                                isEmptyElement, // isEmptyElement
-                               (string) null, // value
+                               null, // value
                                false // clearAttributes
                        );
+
+                       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
@@ -1290,16 +1570,18 @@ namespace System.Xml
                                throw new XmlException (this as IXmlLineInfo,
                                        "End tag cannot appear in this state.");
 
+                       currentLinkedNodeLineNumber = line;
+                       currentLinkedNodeLinePosition = column;
+
                        string name = ReadName ();
-                       if (elementStack.Count == 0)
+                       if (elementNameStackPos == 0)
                                throw new XmlException (this as IXmlLineInfo,"closing element without matching opening element");
-                       string expected = (string)elementStack.Pop();
+                       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 ();
 
-                       SkipWhitespace ();
-                       Expect ('>');
+                       ExpectAfterWhitespace ('>');
 
                        --depth;
 
@@ -1307,29 +1589,43 @@ namespace System.Xml
                                XmlNodeType.EndElement, // nodeType
                                name, // name
                                false, // isEmptyElement
-                               (string) null, // 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 parserContext.NameTable.Add (nameBuffer, 0, nameLength);
@@ -1337,17 +1633,66 @@ namespace System.Xml
 
                private void AppendValueChar (int ch)
                {
-                       valueBuffer.Append ((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 ExpandValueCapacity ()
+               {
+                       valueCapacity = valueCapacity * 2;
+                       char [] oldValueBuffer = valueBuffer;
+                       valueBuffer = new char [valueCapacity];
+                       Array.Copy (oldValueBuffer, valueBuffer, valueLength);
                }
 
                private string CreateValueString ()
                {
-                       return valueBuffer.ToString ();
+                       return new string (valueBuffer, 0, valueLength);
                }
-               
+
                private void ClearValueBuffer ()
                {
-                       valueBuffer.Length = 0;
+                       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
@@ -1362,34 +1707,44 @@ namespace System.Xml
                                ClearValueBuffer ();
 
                        int ch = PeekChar ();
-                       int previousCloseBracketLine = 0;
-                       int previousCloseBracketColumn = 0;
+                       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 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 (XmlConstructs.IsInvalid (ch))
-                                               throw new XmlException (this as IXmlLineInfo,
-                                                       "Not allowed character was found.");
-                                       AppendValueChar (ReadChar ());
-                                       if (ch == ']') {
-                                               if (previousCloseBracketColumn == LinePosition - 1 &&
-                                                       previousCloseBracketLine == LineNumber)
-                                                       if (PeekChar () == '>')
-                                                               throw new XmlException (this as IXmlLineInfo,
-                                                                       "Inside text content, character sequence ']]>' is not allowed.");
-                                               previousCloseBracketColumn = LinePosition;
-                                               previousCloseBracketLine = LineNumber;
-                                       }
+                                       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 && valueBuffer.Length == 0) {
+                       if (returnEntityReference && valueLength == 0) {
                                SetEntityReferenceProperties ();
                        } else {
                                XmlNodeType nodeType = notWhitespace ? XmlNodeType.Text :
@@ -1398,8 +1753,8 @@ namespace System.Xml
                                        nodeType, // nodeType
                                        String.Empty, // name
                                        false, // isEmptyElement
-                                       true, // clearAttributes
-                                       valueBuffer // value
+                                       null, // value: create only when required
+                                       true // clearAttributes
                                );
                        }
                }
@@ -1409,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;
 
@@ -1438,9 +1791,9 @@ namespace System.Xml
                                                value = (value << 4) + ch - 'a' + 10;
                                        else
                                                throw new XmlException (this as IXmlLineInfo,
-                                                       String.Format (
+                                                       String.Format (CultureInfo.InvariantCulture, 
                                                                "invalid hexadecimal digit: {0} (#x{1:X})",
-                                                               (char)ch,
+                                                               (char) ch,
                                                                ch));
                                }
                        } else {
@@ -1451,62 +1804,49 @@ namespace System.Xml
                                                value = value * 10 + ch - '0';
                                        else
                                                throw new XmlException (this as IXmlLineInfo,
-                                                       String.Format (
+                                                       String.Format (CultureInfo.InvariantCulture, 
                                                                "invalid decimal digit: {0} (#x{1:X})",
-                                                               (char)ch,
+                                                               (char) ch,
                                                                ch));
                                }
                        }
 
                        ReadChar (); // ';'
 
-                       // FIXME: how to handle such chars larger than 0xffff?
-                       if (value < 0xffff && !XmlConstructs.IsValid (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.");
-                       AppendValueChar (value);
+                                       "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 ();
-                       if (!XmlChar.IsName (name))
-                               throw new XmlException (this as IXmlLineInfo,
-                                       "Invalid entity reference name was found.");
-
-                       char predefined = XmlChar.GetPredefinedEntity (name);
-                       if (predefined != 0)
-                               AppendValueChar (predefined);
+                       int predefined = XmlChar.GetPredefinedEntity (name);
+                       if (predefined >= 0)
+                               return predefined;
                        else {
                                if (ignoreEntityReferences) {
                                        AppendValueChar ('&');
-
-                                       foreach (char ch2 in name) {
-                                               AppendValueChar (ch2);
-                                       }
-
+                                       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 (bool endsWithQuestion)
+               private void ReadAttributes (bool isXmlDecl)
                {
                        int peekChar = -1;
                        bool requireWhitespace = false;
@@ -1521,9 +1861,9 @@ namespace System.Xml
                                currentAttributeToken.LineNumber = line;
                                currentAttributeToken.LinePosition = column;
 
-                               currentAttributeToken.Name = ReadName ();
-                               SkipWhitespace ();
-                               Expect ('=');
+                               currentAttributeToken.LocalName = 
+                                       currentAttributeToken.Name = ReadName ();
+                               ExpectAfterWhitespace ('=');
                                SkipWhitespace ();
                                ReadAttributeValueTokens (-1);
                                attributeCount++;
@@ -1531,14 +1871,14 @@ namespace System.Xml
                                if (currentAttributeToken.Name == "xmlns")
                                        parserContext.NamespaceManager.AddNamespace (String.Empty, GetAttribute (currentAttribute));
                                else if (currentAttributeToken.Name.StartsWith ("xmlns:")) {
-                                       string nsPrefix = NameTable.Add (currentAttributeToken.Name.Substring (6));
+                                       string nsPrefix = currentAttributeToken.Name.Substring (6);
                                        parserContext.NamespaceManager.AddNamespace (nsPrefix, GetAttribute (currentAttribute));
                                }
 
                                if (!SkipWhitespace ())
                                        requireWhitespace = true;
                                peekChar = PeekChar ();
-                               if (endsWithQuestion) {
+                               if (isXmlDecl) {
                                        if (peekChar == '?')
                                                break;
                                }
@@ -1559,7 +1899,7 @@ namespace System.Xml
                        IncrementAttributeValueToken ();
                        XmlTokenInfo vti = attributeValueTokens [currentAttributeValue];
                        vti.Value = value;
-                       SetProperties (vti, XmlNodeType.Text, name, false, value, false);
+                       SetProperties (vti, XmlNodeType.Text, String.Empty, false, value, false);
                        attributeCount++;
                }
 
@@ -1588,11 +1928,12 @@ namespace System.Xml
                                attributeValueTokens = newArray;
                        }
                        if (attributeValueTokens [currentAttributeValue] == null)
-                               attributeValueTokens [currentAttributeValue] = new XmlTokenInfo (this);
+                               attributeValueTokens [currentAttributeValue] = new XmlTokenInfo (this, false);
                        currentAttributeValueToken = attributeValueTokens [currentAttributeValue];
                        currentAttributeValueToken.Clear ();
                }
 
+               // LAMESPEC: Orthodox XML reader should normalize attribute values
                private void ReadAttributeValueTokens (int dummyQuoteChar)
                {
                        int quoteChar = (dummyQuoteChar < 0) ? ReadChar () : dummyQuoteChar;
@@ -1609,7 +1950,12 @@ namespace System.Xml
                        bool incrementToken = false;
                        bool isNewToken = true;
                        bool loop = true;
-                       while (loop && PeekChar () != quoteChar) {
+                       int ch = 0;
+                       while (loop) {
+                               ch = ReadChar ();
+                               if (ch == quoteChar)
+                                       break;
+
                                if (incrementToken) {
                                        IncrementAttributeValueToken ();
                                        currentAttributeValueToken.LineNumber = line;
@@ -1618,8 +1964,6 @@ namespace System.Xml
                                        isNewToken = true;
                                }
 
-                               int ch = ReadChar ();
-
                                switch (ch)
                                {
                                case '<':
@@ -1631,30 +1975,22 @@ namespace System.Xml
                                                loop = false;
                                        break;
                                case '&':
-                                       int startPosition = currentTag.Length - 1;
+                                       int startPosition = currentTagLength - 1;
                                        if (PeekChar () == '#') {
                                                ReadChar ();
-                                               this.ReadCharacterReference ();
+                                               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) {
-                                               DTDEntityDeclaration entDecl = 
-                                                       DTD == null ? null : DTD.EntityDecls [entName];
-                                               if (DTD != null && resolver != null && entDecl == null)
-                                                       throw new XmlException (this as IXmlLineInfo, "Entity declaration does not exist.");
-                                               if (entDecl != null && entDecl.HasExternalReference)
-                                                       throw new XmlException (this as IXmlLineInfo,
-                                                               "Reference to external entities is not allowed in the value of an attribute.");
-                                               if (isStandalone && !entDecl.IsInternalSubset)
-                                                       throw new XmlException (this as IXmlLineInfo,
-                                                               "Reference to external entities is not allowed in the value of an attribute.");
-                                               if (entDecl != null && entDecl.EntityValue.IndexOf ('<') >= 0)
-                                                       throw new XmlException (this as IXmlLineInfo,
-                                                               "Attribute must not contain character '<' either directly or indirectly by way of entity references.");
+                                       if (predefined < 0) {
+                                               CheckAttributeEntityReferenceWFC (entName);
                                                currentAttributeValueToken.Value = CreateValueString ();
                                                currentAttributeValueToken.NodeType = XmlNodeType.Text;
                                                if (!isNewToken)
@@ -1668,6 +2004,8 @@ namespace System.Xml
                                                AppendValueChar (predefined);
                                        break;
                                default:
+                                       if (CharacterChecking && XmlChar.IsInvalid (ch))
+                                               throw new XmlException (this, "Invalid character was found.");
                                        AppendValueChar (ch);
                                        break;
                                }
@@ -1680,8 +2018,24 @@ namespace System.Xml
                        }
                        currentAttributeToken.ValueTokenEndIndex = currentAttributeValue;
 
-                       if (dummyQuoteChar < 0)
-                               ReadChar (); // quoteChar
+               }
+
+               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.");
+
+                       if (entDecl == null)
+                               return;
+
+                       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
@@ -1694,7 +2048,7 @@ namespace System.Xml
                        if (target == "xml") {
                                ReadXmlDeclaration ();
                                return;
-                       } else if (target.ToLower () == "xml")
+                       } 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.");
 
@@ -1716,15 +2070,17 @@ namespace System.Xml
                                        break;
                                }
 
-                               AppendValueChar ((char)ch);
+                               if (CharacterChecking && XmlChar.IsInvalid (ch))
+                                       throw new XmlException (this, "Invalid character was found.");
+                               AppendValueChar (ch);
                        }
 
                        SetProperties (
                                XmlNodeType.ProcessingInstruction, // nodeType
                                target, // name
                                false, // isEmptyElement
-                               true, // clearAttributes
-                               valueBuffer // value
+                               null, // value: create only when required
+                               true // clearAttributes
                        );
                }
 
@@ -1765,7 +2121,7 @@ namespace System.Xml
                                XmlNodeType.XmlDeclaration, // nodeType
                                "xml", // name
                                false, // isEmptyElement
-                               currentTag.ToString (6, currentTag.Length - 6), // value
+                               new string (currentTagBuffer, 6, currentTagLength - 6), // value
                                false // clearAttributes
                        );
 
@@ -1780,40 +2136,34 @@ namespace System.Xml
                                return;
 
                        ReadChar ();
-                       peekChars [0] = '<';
 
                        if (PeekChar () != '?') {
-                               hasPeekChars = true;
+                               peekCharsIndex = 0;
                                return;
                        }
                        ReadChar ();
-                       peekChars [1] = '?';
 
-                       for (int i = 2; i < 6; i++) {
-                               if (PeekChar () == 0)
+                       while (peekCharsIndex < 6) {
+                               if (PeekChar () < 0)
                                        break;
                                else
-                                       peekChars [i] = (char) ReadChar ();
+                                       ReadChar ();
                        }
                        if (new string (peekChars, 2, 4) != "xml ") {
-                               if (new string (peekChars, 2, 3).ToLower () == "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.");
                                }
-                               hasPeekChars = true;
+                               peekCharsIndex = 0;
                                return;
                        }
 
-                       for (int i = 0; i < 6; i++)
-                               peekChars [i] = '\0';
-
                        SkipWhitespace ();
 
                        // version decl
                        if (PeekChar () == 'v') {
                                Expect ("version");
-                               SkipWhitespace ();
-                               Expect ('=');
+                               ExpectAfterWhitespace ('=');
                                SkipWhitespace ();
                                int quoteChar = ReadChar ();
                                char [] expect1_0 = new char [3];
@@ -1847,8 +2197,7 @@ namespace System.Xml
 
                        if (PeekChar () == 'e') {
                                Expect ("encoding");
-                               SkipWhitespace ();
-                               Expect ('=');
+                               ExpectAfterWhitespace ('=');
                                SkipWhitespace ();
                                int quoteChar = ReadChar ();
                                switch (quoteChar) {
@@ -1923,19 +2272,19 @@ namespace System.Xml
                                        break;
                                }
 
-                               if (XmlConstructs.IsInvalid (ch))
+                               if (XmlChar.IsInvalid (ch))
                                        throw new XmlException (this as IXmlLineInfo,
                                                "Not allowed character was found.");
 
-                               AppendValueChar ((char)ch);
+                               AppendValueChar (ch);
                        }
 
                        SetProperties (
                                XmlNodeType.Comment, // nodeType
                                String.Empty, // name
                                false, // isEmptyElement
-                               true, // clearAttributes
-                               valueBuffer // value
+                               null, // value: create only when required
+                               true // clearAttributes
                        );
                }
 
@@ -1964,21 +2313,28 @@ namespace System.Xml
                                                break;
                                        } else {
                                                skip = true;
-//                                             AppendValueChar (']');
-//                                             AppendValueChar (']');
-//                                             ch = ReadChar ();
                                        }
                                }
+                               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
-                               true, // clearAttributes
-                               valueBuffer // value
+                               null, // value: create only when required
+                               true // clearAttributes
                        );
                }
 
@@ -1986,6 +2342,9 @@ 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:
@@ -2026,14 +2385,13 @@ namespace System.Xml
                                ReadChar ();
                                intSubsetStartLine = this.LineNumber;
                                intSubsetStartColumn = this.LinePosition;
-                               int startPos = currentTag.Length;
+                               int startPos = currentTagLength;
                                ReadInternalSubset ();
-                               int endPos = currentTag.Length - 1;
-                               parserContext.InternalSubset = currentTag.ToString (startPos, endPos - startPos);
+                               int endPos = currentTagLength - 1;
+                               parserContext.InternalSubset = new string (currentTagBuffer, startPos, endPos - startPos);
                        }
                        // end of DOCTYPE decl.
-                       SkipWhitespace ();
-                       Expect ('>');
+                       ExpectAfterWhitespace ('>');
 
                        GenerateDTDObjectModel (doctypeName, publicId,
                                systemId, parserContext.InternalSubset,
@@ -2052,6 +2410,7 @@ namespace System.Xml
                                AddAttribute ("PUBLIC", publicId);
                        if (systemId != null)
                                AddAttribute ("SYSTEM", systemId);
+                       currentAttribute = currentAttributeValue = -1;
                }
 
                internal DTDObjectModel GenerateDTDObjectModel (string name, string publicId,
@@ -2075,7 +2434,21 @@ namespace System.Xml
                        DTD.LineNumber = line;
                        DTD.LinePosition = column;
 
-                       return new DTDReader (DTD, intSubsetStartLine, intSubsetStartColumn).GenerateDTDObjectModel ();
+                       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
@@ -2144,10 +2517,14 @@ namespace System.Xml
                                case -1:
                                        throw new XmlException (this as IXmlLineInfo,"unexpected end of file at DTD.");
                                case '<':
-                                       if (State == DtdInputState.InsideDoubleQuoted ||
-                                               State == DtdInputState.InsideSingleQuoted)
+                                       switch (State) {
+                                       case DtdInputState.InsideDoubleQuoted:
+                                       case DtdInputState.InsideSingleQuoted:
+                                       case DtdInputState.Comment:
                                                continue;       // well-formed
-                                       switch (ReadChar ()) {
+                                       }
+                                       int c = ReadChar ();
+                                       switch (c) {
                                        case '?':
                                                stateStack.Push (DtdInputState.PI);
                                                break;
@@ -2182,7 +2559,7 @@ namespace System.Xml
                                                }
                                                break;
                                        default:
-                                               throw new XmlException (this as IXmlLineInfo,"unexpected '>'.");
+                                               throw new XmlException (this as IXmlLineInfo, String.Format ("unexpected '<{0}'.", (char) c));
                                        }
                                        break;
                                case '\'':
@@ -2209,9 +2586,7 @@ namespace System.Xml
                                                stateStack.Pop ();
                                                break;
                                        case DtdInputState.InsideDoubleQuoted:
-                                               continue;
                                        case DtdInputState.InsideSingleQuoted:
-                                               continue; // well-formed
                                        case DtdInputState.Comment:
                                                continue;
                                        default:
@@ -2253,7 +2628,7 @@ namespace System.Xml
                        else
                                SkipWhitespace ();
                        int quoteChar = ReadChar ();    // apos or quot
-                       int startPos = currentTag.Length;
+                       int startPos = currentTagLength;
                        int c = 0;
                        ClearValueBuffer ();
                        while (c != quoteChar) {
@@ -2263,7 +2638,7 @@ namespace System.Xml
                                if (c != quoteChar)
                                        AppendValueChar (c);
                        }
-                       return CreateValueString (); //currentTag.ToString (startPos, currentTag.Length - 1 - startPos);
+                       return CreateValueString ();
                }
 
                private string ReadPubidLiteral()
@@ -2273,7 +2648,7 @@ namespace System.Xml
                                throw new XmlException (this as IXmlLineInfo,
                                        "Whitespace is required after 'PUBLIC'.");
                        int quoteChar = ReadChar ();
-                       int startPos = currentTag.Length;
+                       int startPos = currentTagLength;
                        int c = 0;
                        ClearValueBuffer ();
                        while(c != quoteChar)
@@ -2281,38 +2656,20 @@ namespace System.Xml
                                c = ReadChar ();
                                if(c < 0) throw new XmlException (this as IXmlLineInfo,"Unexpected end of stream in ExternalID.");
                                if(c != quoteChar && !XmlChar.IsPubidChar (c))
-                                       throw new XmlException (this as IXmlLineInfo,"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);
                        }
-                       return CreateValueString (); //currentTag.ToString (startPos, currentTag.Length - 1 - startPos);
+                       return CreateValueString ();
                }
 
                // The reader is positioned on the first character
                // of the name.
                private string ReadName ()
-               {
-                       return ReadNameOrNmToken(false);
-               }
-
-               // The reader is positioned on the first character
-               // of the name.
-               private string ReadNmToken ()
-               {
-                       return ReadNameOrNmToken(true);
-               }
-
-               private string ReadNameOrNmToken (bool isNameToken)
                {
                        int ch = PeekChar ();
-                       if(isNameToken) {
-                               if (!XmlChar.IsNameChar ((char) ch))
-                                       throw new XmlException (this as IXmlLineInfo,String.Format ("a nmtoken did not start with a legal character {0} ({1})", ch, (char)ch));
-                       }
-                       else {
-                               if (!XmlChar.IsFirstNameChar (ch))
-                                       throw new XmlException (this as IXmlLineInfo,String.Format ("a name did not start with a legal character {0} ({1})", ch, (char)ch));
-                       }
+                       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;
 
@@ -2333,11 +2690,11 @@ namespace System.Xml
 
                        if (ch != expected) {
                                throw new XmlException (this as IXmlLineInfo,
-                                       String.Format (
+                                       String.Format (CultureInfo.InvariantCulture, 
                                                "expected '{0}' ({1:X}) but found '{2}' ({3:X})",
-                                               (char)expected,
+                                               (char) expected,
                                                expected,
-                                               (char)ch,
+                                               (char) ch,
                                                ch));
                        }
                }
@@ -2349,11 +2706,24 @@ 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 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;
@@ -2378,13 +2748,15 @@ namespace System.Xml
                                SetProperties (nodeType,
                                               String.Empty,
                                               false,
-                                              true,
-                                              valueBuffer);
+                                              null, // value: create only when required
+                                              true);
                        }
 
-                       return; // (PeekChar () != -1);
+                       return;
                }
 
+               // Since ReadBase64() is processed for every 4 chars, it does
+               // not handle '=' here.
                private byte GetBase64Byte (char ch)
                {
                        switch (ch) {
@@ -2392,8 +2764,6 @@ namespace System.Xml
                                return 62;
                        case '/':
                                return 63;
-                       case '=':
-                               return 0;
                        default:
                                if (ch >= 'A' && ch <= 'Z')
                                        return (byte) (ch - 'A');
@@ -2409,7 +2779,10 @@ namespace System.Xml
                // Returns -1 if it should throw an error.
                private int ReadCharsInternal (char [] buffer, int offset, int length)
                {
-                       shouldSkipUntilEndTag = true;
+                       if (IsEmptyElement) {
+                               Read ();
+                               return 0;
+                       }
 
                        if (offset < 0)
                                throw new ArgumentOutOfRangeException ("offset", offset, "Offset must be non-negative integer.");
@@ -2421,6 +2794,8 @@ namespace System.Xml
                        if (NodeType != XmlNodeType.Element)
                                return 0;
 
+                       shouldSkipUntilEndTag = true;
+
                        int bufIndex = offset;
                        for (int i = 0; i < length; i++) {
                                int c = PeekChar ();
@@ -2435,24 +2810,22 @@ namespace System.Xml
                                        }
                                        // Seems to skip immediate EndElement
                                        Expect ('/');
-                                       string name = ReadName ();
-                                       if (name != (string) this.elementStack.Peek ()) {
-                                               if (i + 1 < length) {
-                                                       buffer [bufIndex++] = '<';
-                                                       buffer [bufIndex++] = '/';
-                                               }
-                                               for (int n = 0; n < name.Length && i + n + 1 < length; n++)
-                                                       buffer [bufIndex++] = name [n];
-                                               continue;
+                                       if (depthUp) {
+                                               depth++;
+                                               depthUp = false;
                                        }
-                                       Expect ('>');
-                                       depth--;
-                                       this.elementStack.Pop ();
+                                       ReadEndTag ();
                                        shouldSkipUntilEndTag = false;
-                                       Read ();
+                                       Read (); // move to the next node
                                        return i;
                                default:
-                                       buffer [bufIndex++] = (char) ReadChar ();
+                                       ReadChar ();
+                                       if (c < Char.MaxValue)
+                                               buffer [bufIndex++] = (char) c;
+                                       else {
+                                               buffer [bufIndex++] = (char) (c / 0x10000 + 0xD800 - 1);
+                                               buffer [bufIndex++] = (char) (c % 0x10000 + 0xDC00);
+                                       }
                                        break;
                                }
                        }
@@ -2473,11 +2846,11 @@ namespace System.Xml
                                                continue;
                                        ReadChar ();
                                        string name = ReadName ();
-                                       if (name != (string) this.elementStack.Peek ())
+                                       if (name != elementNames [elementNameStackPos - 1])
                                                continue;
                                        Expect ('>');
                                        depth--;
-                                       this.elementStack.Pop ();
+                                       elementNames [--elementNameStackPos] = null;
                                        return Read ();
                                }
                        } while (true);