2002-12-28 Atsushi Enomoto <ginga@kit.hi-ho.ne.jp>
[mono.git] / mcs / class / System.XML / System.Xml / XmlTextReader.cs
index e385ba613bc257e0fc6a708e918f59852404cc38..5895b4b6572c36603d6de2a8d8f9c304b8dd7903 100644 (file)
@@ -1,11 +1,11 @@
-// -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
 //
-// System.Xml.XmlTextReader.cs
+// System.Xml.XmlTextReader
 //
 // Author:
 //   Jason Diamond (jason@injektilo.org)
+//   Adam Treat (manyoso@yahoo.com)
 //
-// (C) 2001 Jason Diamond  http://injektilo.org/
+// (C) 2001, 2002 Jason Diamond  http://injektilo.org/
 //
 
 // FIXME:
 //   instructions, and comments are OK.
 //
 //   It barfs on DOCTYPE declarations.
+//     => No barfing, but parsing is incomplete.
+//        DTD nodes are not still created.
 //
 //   There's also no checking being done for either well-formedness
 //   or validity.
 //
-//   ParserContext and NameTables aren't being used yet.
+//   NameTables aren't being used everywhere yet.
 //
 //   Some thought needs to be given to performance. There's too many
 //   strings being allocated.
 //
-//   None of the MoveTo methods have been implemented yet.
+//   Some of the MoveTo methods haven't been implemented yet.
 //
 //   LineNumber and LinePosition aren't being tracked.
 //
 //   xml:space, xml:lang, and xml:base aren't being tracked.
 //
-//   Depth isn't being tracked.
 
 using System;
 using System.Collections;
 using System.IO;
-using System.Net;
 using System.Text;
 
 namespace System.Xml
 {
        public class XmlTextReader : XmlReader, IXmlLineInfo
        {
-               // constructors
+               WhitespaceHandling whitespaceHandling = WhitespaceHandling.All;
+               #region Constructors
 
-               protected XmlTextReader()
+               protected XmlTextReader ()
                {
-                       Init();
                }
 
-               public XmlTextReader(Stream input)
+               public XmlTextReader (Stream input)
+                       : this (new StreamReader (input))
                {
-                       Init();
-                       reader = new StreamReader(
-                               input,
-                               Encoding.UTF8,
-                               true);
                }
 
-               public XmlTextReader(string url)
+               public XmlTextReader (string url)
+                       : this(url, new NameTable ())
                {
-                       Init();
-                       WebClient client = new WebClient();
-                       reader = new StreamReader(
-                               client.OpenRead(url),
-                               Encoding.UTF8,
-                               true);
                }
 
-               public XmlTextReader(TextReader input)
+               public XmlTextReader (TextReader input)
+                       : this (input, new NameTable ())
                {
-                       Init();
-                       reader = input;
                }
 
-               public XmlTextReader(Stream input, XmlNameTable nameTable)
-               {
-                       this.nameTable = nameTable;
+               protected XmlTextReader (XmlNameTable nt)
+                       : this (String.Empty, null, XmlNodeType.None, null)
+               {
+               }
 
-                       // TODO: implement me.
-                       throw new NotImplementedException();
+               public XmlTextReader (Stream input, XmlNameTable nt)
+                       : this(new StreamReader (input), nt)
+               {
                }
 
-               public XmlTextReader(string baseURI, Stream input)
+               public XmlTextReader (string url, Stream input)
+                       : this (url, new StreamReader (input))
                {
-                       // TODO: implement me.
-                       throw new NotImplementedException();
                }
 
-               public XmlTextReader(string baseURI, TextReader input)
+               public XmlTextReader (string url, TextReader input)
+                       : this (url, input, new NameTable ())
                {
-                       // TODO: implement me.
-                       throw new NotImplementedException();
                }
 
-               public XmlTextReader(string url, XmlNameTable nameTable)
+               [MonoTODO("Non-filename-url must be supported. Waiting for WebClient")]
+               public XmlTextReader (string url, XmlNameTable nt)
+                       // : this(url, new StreamReader ((Stream)new XmlUrlResolver ().GetEntity (new Uri (url), null, typeof(Stream))), nt)
+                       : this (url, new StreamReader (url), nt)
                {
-                       this.nameTable = nameTable;
-
-                       // TODO: implement me.
-                       throw new NotImplementedException();
                }
 
-               public XmlTextReader(
-                       TextReader input,
-                       XmlNameTable nameTable)
+               public XmlTextReader (TextReader input, XmlNameTable nt)
+                       : this(String.Empty, input, nt)
                {
-                       this.nameTable = nameTable;
-
-                       // TODO: implement me.
-                       throw new NotImplementedException();
                }
 
-               public XmlTextReader(
-                       Stream inputFragment,
-                       XmlNodeType fragmentType,
-                       XmlParserContext context)
+               public XmlTextReader (Stream xmlFragment, XmlNodeType fragType, XmlParserContext context)
+                       : this (String.Empty, new StreamReader (xmlFragment), fragType, context)
                {
-                       // TODO: implement me.
-                       throw new NotImplementedException();
                }
 
-               public XmlTextReader(
-                       string baseURI,
-                       Stream input,
-                       XmlNameTable nameTable)
+               public XmlTextReader (string url, Stream input, XmlNameTable nt)
+                       : this (url, new StreamReader (input), nt)
                {
-                       this.nameTable = nameTable;
+               }
 
-                       // TODO: implement me.
-                       throw new NotImplementedException();
+               public XmlTextReader (string url, TextReader input, XmlNameTable nt)
+                       : this (url, input, XmlNodeType.Document, new XmlParserContext (nt, new XmlNamespaceManager (nt), null, XmlSpace.None))
+               {
                }
 
-               public XmlTextReader(
-                       string baseURI,
-                       TextReader input,
-                       XmlNameTable nameTable)
+               [MonoTODO("TODO as same as private XmlTextReader(TextReader, XmlNodeType, XmlParserContext)")]
+               public XmlTextReader (string xmlFragment, XmlNodeType fragType, XmlParserContext context)
+                       : this (String.Empty, new StringReader (xmlFragment), fragType, context)
                {
-                       this.nameTable = nameTable;
-                       // TODO: implement me.
-                       throw new NotImplementedException();
                }
 
-               public XmlTextReader(
-                       string fragment,
-                       XmlNodeType fragmentType,
-                       XmlParserContext context)
+               // TODO still remains as described at head of this file,
+               // but it might not be TODO of the constructors...
+               XmlTextReader (string url, TextReader fragment, XmlNodeType fragType, XmlParserContext context)
                {
-                       // TODO: implement me.
-                       throw new NotImplementedException();
+                       this.SetReaderContext(url, context);
+                       this.SetReaderFragment(fragment, fragType);
                }
 
-               // properties
+               #endregion
+
+               #region Properties
 
                public override int AttributeCount
                {
-                       get
-                       {
-                               return attributes.Count;
-                       }
+                       get { return attributes.Count; }
                }
 
                public override string BaseURI
                {
-                       get
-                       {
-                               // TODO: implement me.
-                               return null;
-                       }
-               }
-
-               public override bool CanResolveEntity
-               {
-                       get
-                       {
-                               // XmlTextReaders don't resolve entities.
-                               return false;
-                       }
+                       get { return parserContext.BaseURI; }
                }
 
                public override int Depth
                {
-                       get
-                       {
-                               // TODO: implement me.
-                               return depth > 0 ? depth : 0;
+                       get {
+                               return elementDepth;
                        }
                }
 
                public Encoding Encoding
                {
-                       get
-                       {
-                               // TODO: implement me.
-                               return null;
-                       }
+                       get { return parserContext.Encoding; }
                }
 
                public override bool EOF
@@ -207,10 +161,7 @@ namespace System.Xml
 
                public override bool HasValue
                {
-                       get
-                       {
-                               return value != String.Empty;
-                       }
+                       get { return value != String.Empty;     }
                }
 
                public override bool IsDefault
@@ -224,370 +175,499 @@ namespace System.Xml
 
                public override bool IsEmptyElement
                {
-                       get
-                       {
-                               return isEmptyElement;
-                       }
+                       get { return isEmptyElement; }
                }
 
-               public override string this[int i]
+               public override string this [int i]
                {
-                       get
-                       {
-                               return GetAttribute(i);
-                       }
+                       get { return GetAttribute (i); }
                }
 
-               public override string this[string name]
+               public override string this [string name]
                {
-                       get
-                       {
-                               return GetAttribute(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);
-                       }
+                       get { return GetAttribute (localName, namespaceName); }
                }
 
                public int LineNumber
                {
-                       get
-                       {
-                               // TODO: implement me.
-                               return 0;
-                       }
+                       get { return line; }
                }
 
                public int LinePosition
                {
-                       get
-                       {
-                               // TODO: implement me.
-                               return 0;
-                       }
+                       get { return column; }
                }
 
                public override string LocalName
                {
-                       get
-                       {
-                               return localName;
-                       }
+                       get { return localName; }
                }
 
                public override string Name
                {
-                       get
-                       {
-                               return name;
-                       }
+                       get { return name; }
                }
 
+               [MonoTODO]
                public bool Namespaces
                {
-                       get
-                       {
-                               // TODO: implement me.
-                               return false;
-                       }
-
-                       set
-                       {
-                               // TODO: implement me.
-                       }
+                       get { throw new NotImplementedException (); }
+                       set { throw new NotImplementedException (); }
                }
 
                public override string NamespaceURI
                {
-                       get
-                       {
-                               return namespaceURI;
-                       }
+                       get { return namespaceURI; }
                }
 
                public override XmlNameTable NameTable
                {
-                       get
-                       {
-                               // TODO: implement me.
-                               return null;
-                       }
+                       get { return parserContext.NameTable; }
                }
 
                public override XmlNodeType NodeType
                {
-                       get
-                       {
-                               return nodeType;
-                       }
+                       get { return nodeType; }
                }
 
+               [MonoTODO]
                public bool Normalization
                {
-                       get
-                       {
-                               // TODO: implement me.
-                               return false;
-                       }
-
-                       set
-                       {
-                               // TODO: implement me.
-                       }
+                       get { throw new NotImplementedException (); }
+                       set { throw new NotImplementedException (); }
                }
 
                public override string Prefix
                {
-                       get
-                       {
-                               return prefix;
-                       }
+                       get { return prefix; }
                }
 
+               [MonoTODO]
                public override char QuoteChar
                {
-                       get
-                       {
-                               // TODO: implement me.
-                               return '"';
-                       }
+                       get { throw new NotImplementedException (); }
                }
 
                public override ReadState ReadState
                {
-                       get
-                       {
-                               return readState;
-                       }
+                       get { return readState; }
                }
 
                public override string Value
                {
-                       get
-                       {
-                               return value;
-                       }
+                       get { return value; }
                }
 
                public WhitespaceHandling WhitespaceHandling
                {
-                       get
-                       {
-                               // TODO: implement me.
-                               return WhitespaceHandling.All;
-                       }
-
-                       set
-                       {
-                               // TODO: implement me.
-                       }
+                       get { return whitespaceHandling; }
+                       set { whitespaceHandling = value; }
                }
 
+               [MonoTODO]
                public override string XmlLang
                {
-                       get
-                       {
-                               // TODO: implement me.
-                               return null;
-                       }
+                       get { throw new NotImplementedException (); }
                }
 
+               [MonoTODO]
                public XmlResolver XmlResolver
                {
-                       set
-                       {
-                               // TODO: implement me.
-                       }
+                       set { throw new NotImplementedException (); }
                }
 
+               [MonoTODO]
                public override XmlSpace XmlSpace
                {
-                       get
-                       {
-                               // TODO: implement me.
-                               return XmlSpace.Default;
-                       }
+                       get { throw new NotImplementedException (); }
                }
 
-               // methods
+               #endregion
+
+               #region Methods
 
-               public override void Close()
+               [MonoTODO]
+               public override void Close ()
                {
                        readState = ReadState.Closed;
                }
 
-               public override string GetAttribute(int i)
+               [MonoTODO]
+               public override string GetAttribute (int i)
                {
-                       // TODO: implement me.
-                       return null;
+                       if (i > attributes.Count)
+                               throw new ArgumentOutOfRangeException ("i is smaller than AttributeCount");
+                       else
+                               throw new NotImplementedException ();
                }
 
-               public override string GetAttribute(string name)
+               public override string GetAttribute (string name)
                {
-                       return (string)attributes[name];
+                       return attributes.ContainsKey (name) ?
+                               attributes [name] as string : String.Empty;
                }
 
-               public override string GetAttribute(
-                       string localName,
-                       string namespaceURI)
+               public override string GetAttribute (string localName, string namespaceURI)
                {
                        foreach (DictionaryEntry entry in attributes)
                        {
-                               string thisName = (string)entry.Key;
+                               string thisName = entry.Key as string;
 
-                               int indexOfColon = thisName.IndexOf(':');
+                               int indexOfColon = thisName.IndexOf (':');
 
-                               if (indexOfColon != -1)
-                               {
-                                       string thisLocalName = thisName.Substring(indexOfColon + 1);
+                               if (indexOfColon != -1) {
+                                       string thisLocalName = thisName.Substring (indexOfColon + 1);
 
-                                       if (localName == thisLocalName)
-                                       {
-                                               string thisPrefix = thisName.Substring(0, indexOfColon);
-                                               string thisNamespaceURI = LookupNamespace(thisPrefix);
+                                       if (localName == thisLocalName) {
+                                               string thisPrefix = thisName.Substring (0, indexOfColon);
+                                               string thisNamespaceURI = LookupNamespace (thisPrefix);
 
                                                if (namespaceURI == thisNamespaceURI)
-                                               {
-                                                       return (string)attributes[thisName];
-                                               }
+                                                       return attributes.ContainsKey (thisName) ?
+                                                               attributes [thisName] as string : String.Empty;
                                        }
-                               }
+                               } else if (localName == "xmlns" && namespaceURI == "http://www.w3.org/2000/xmlns/" && thisName == "xmlns")
+                                       return attributes.ContainsKey (thisName) ? 
+                                               attributes [thisName] as string : String.Empty;
                        }
 
                        return String.Empty;
                }
 
-               public TextReader GetRemainder()
+               [MonoTODO]
+               public TextReader GetRemainder ()
                {
-                       // TODO: implement me.
-                       return null;
+                       throw new NotImplementedException ();
                }
 
-               // Why does this use explicit interface implementation?
-               bool IXmlLineInfo.HasLineInfo()
+               [MonoTODO]
+               bool IXmlLineInfo.HasLineInfo ()
                {
-                       // TODO: implement me.
                        return false;
                }
 
-               public override string LookupNamespace(string prefix)
+               public override string LookupNamespace (string prefix)
                {
-                       return namespaceManager.LookupNamespace(prefix);
+                       return parserContext.NamespaceManager.LookupNamespace (prefix);
                }
 
-               public override void MoveToAttribute(int i)
+               [MonoTODO]
+               public override void MoveToAttribute (int i)
                {
-                       // TODO: implement me.
+                       throw new NotImplementedException ();
                }
 
-               public override bool MoveToAttribute(string name)
+               public override bool MoveToAttribute (string name)
                {
-                       // TODO: implement me.
-                       return false;
+                       MoveToElement ();
+                       bool match = false;
+
+                       if (attributes == null)
+                               return false;
+
+                       if (orderedAttributesEnumerator == null) {
+                               SaveProperties ();
+                               orderedAttributesEnumerator = orderedAttributes.GetEnumerator ();
+                       }
+
+                       while (orderedAttributesEnumerator.MoveNext ()) {
+                               if(name == orderedAttributesEnumerator.Current as string) {
+                                       match = true;
+                                       break;
+                               }
+                       }
+
+                       if (match) {
+                                       
+                               string value = attributes [name] as string;
+                               SetProperties (
+                                       XmlNodeType.Attribute, // nodeType
+                                       name, // name
+                                       false, // isEmptyElement
+                                       value, // value
+                                       false // clearAttributes
+                               );
+                       }
+                       
+                       return match;
                }
 
-               public override bool MoveToAttribute(
-                       string localName,
-                       string namespaceName)
+               [MonoTODO]
+               public override bool MoveToAttribute (string localName, string namespaceName)
                {
-                       // TODO: implement me.
-                       return false;
+                       throw new NotImplementedException ();
                }
 
-               public override bool MoveToElement()
+               public override bool MoveToElement ()
                {
-                       // TODO: implement me.
+                       if (orderedAttributesEnumerator != null) {
+                               orderedAttributesEnumerator = null;
+                               RestoreProperties ();
+                               return true;
+                       }
+
                        return false;
                }
 
-               public override bool MoveToFirstAttribute()
+               public override bool MoveToFirstAttribute ()
                {
-                       // TODO: implement me.
-                       return false;
+                       MoveToElement ();
+                       return MoveToNextAttribute ();
                }
 
-               public override bool MoveToNextAttribute()
+               public override bool MoveToNextAttribute ()
                {
-                       // TODO: implement me.
+                       if (attributes == null)
+                               return false;
+
+                       if (orderedAttributesEnumerator == null) {
+                               SaveProperties ();
+                               orderedAttributesEnumerator = orderedAttributes.GetEnumerator ();
+                       }
+
+                       if (orderedAttributesEnumerator.MoveNext ()) {
+                               string name = orderedAttributesEnumerator.Current as string;
+                               string value = attributes [name] as string;
+                               SetProperties (
+                                       XmlNodeType.Attribute, // nodeType
+                                       name, // name
+                                       false, // isEmptyElement
+                                       value, // value
+                                       false // clearAttributes
+                               );
+                               return true;
+                       }
+
                        return false;
                }
 
-               public override bool Read()
+               public override bool Read ()
                {
                        bool more = false;
 
                        readState = ReadState.Interactive;
 
-                       more = ReadContent();
+                       more = ReadContent ();
 
                        return more;
                }
 
-               public override bool ReadAttributeValue()
+               public override bool ReadAttributeValue ()
                {
-                       // TODO: implement me.
-                       return false;
+                       // reading attribute value phase now stopped
+                       if(attributeStringCurrentPosition < 0 ||
+                                       attributeString.Length < attributeStringCurrentPosition) {
+                               attributeStringCurrentPosition = 0;
+                               attributeString = String.Empty;
+                               return false;
+                       }
+
+                       // If not started, then initialize attributeString when parsing is at start.
+                       if(attributeStringCurrentPosition == 0)
+                               attributeString = value;
+
+                       bool returnEntity = false;
+                       value = String.Empty;
+                       int nextPosition = attributeString.IndexOf ('&',
+                               attributeStringCurrentPosition);
+
+                       // if attribute string starts from '&' then it may be (unparsable) entity reference.
+                       if(nextPosition == 0) {
+                               string parsed = ReadAttributeValueEntityReference ();
+                               if(parsed == null) {
+                                       // return entity (It is only this case to return entity reference.)
+                                       int endEntityPosition = attributeString.IndexOf (';',
+                                               attributeStringCurrentPosition);
+                                       SetProperties (XmlNodeType.EntityReference,
+                                               attributeString.Substring (attributeStringCurrentPosition + 1,
+                                               endEntityPosition - attributeStringCurrentPosition - 1),
+                                               false,
+                                               String.Empty,
+                                               false);
+                                       attributeStringCurrentPosition = endEntityPosition + 1;
+
+                                       return true;
+                               }
+                               else
+                                       value += parsed;
+                       }
+
+                       // Other case always set text node.
+                       while(!returnEntity) {
+                               nextPosition = attributeString.IndexOf ('&', attributeStringCurrentPosition);
+                               if(nextPosition < 0) {
+                                       // Reached to the end of value string.
+                                       value += attributeString.Substring (attributeStringCurrentPosition);
+                                       attributeStringCurrentPosition = -1;
+                                       break;
+                               } else if(nextPosition == attributeStringCurrentPosition) {
+                                       string parsed = ReadAttributeValueEntityReference ();
+                                       if(parsed != null)
+                                               value += parsed;
+                                       else {
+                                               // Found that an entity reference starts from this point.
+                                               // Then once stop to parse attribute value and then return text.
+                                               value += attributeString.Substring (attributeStringCurrentPosition,
+                                                       nextPosition - attributeStringCurrentPosition);
+                                               break;
+                                       }
+                               } else {
+                                       value += attributeString.Substring (attributeStringCurrentPosition,
+                                               nextPosition - attributeStringCurrentPosition);
+                                       attributeStringCurrentPosition = nextPosition;
+                                       break;
+                               }
+                       }
+
+                       SetProperties(XmlNodeType.Text,
+                               "#text",
+                               false,
+                               value,
+                               false);
+
+                       return true;
                }
 
-               public int ReadBase64(byte[] buffer, int offset, int length)
+               [MonoTODO]
+               public int ReadBase64 (byte [] buffer, int offset, int length)
                {
-                       // TODO: implement me.
-                       return 0;
+                       throw new NotImplementedException ();
                }
 
-               public int ReadBinHex(byte[] buffer, int offset, int length)
+               [MonoTODO]
+               public int ReadBinHex (byte [] buffer, int offset, int length)
                {
-                       // TODO: implement me.
-                       return 0;
+                       throw new NotImplementedException ();
                }
 
-               public int ReadChars(char[] buffer, int offset, int length)
+               [MonoTODO]
+               public int ReadChars (char [] buffer, int offset, int length)
                {
-                       // TODO: implement me.
-                       return 0;
+                       throw new NotImplementedException ();
                }
 
-               public override string ReadInnerXml()
+               [MonoTODO]
+               public override string ReadInnerXml ()
                {
-                       // TODO: implement me.
-                       return null;
+                       // Still need a Well Formedness check.
+                       // Will wait for Validating reader ;-)
+                       if (NodeType == XmlNodeType.Attribute) {
+                               return Value;
+                       } else {
+                               saveToXmlBuffer = true;
+                               string startname = this.Name;
+                               string endname = string.Empty;
+                               readState = ReadState.Interactive;
+
+                               while (startname != endname) {
+                                       ReadContent ();
+                                       endname = this.Name;
+                               }
+
+                               xmlBuffer.Replace (currentTag.ToString (), "");
+                               saveToXmlBuffer = false;
+                               string InnerXml = xmlBuffer.ToString ();
+                               xmlBuffer.Length = 0;
+                               return InnerXml;
+                       }
                }
 
-               public override string ReadOuterXml()
+               [MonoTODO]
+               public override string ReadOuterXml ()
                {
-                       // TODO: implement me.
-                       return null;
+                       if (NodeType == XmlNodeType.Attribute) {
+                               return Name + "=\"" + Value + "\"";
+                       } else {
+                               saveToXmlBuffer = true;
+                               xmlBuffer.Append (currentTag.ToString ());
+                               string startname = this.Name;
+                               string endname = string.Empty;
+                               readState = ReadState.Interactive;
+
+                               while (startname != endname) {
+                                       ReadContent ();
+                                       endname = this.Name;
+                               }
+                               saveToXmlBuffer = false;
+                               string OuterXml = xmlBuffer.ToString ();
+                               xmlBuffer.Length = 0;
+                               return OuterXml;
+                       }
                }
 
-               public override string ReadString()
+               [MonoTODO]
+               public override string ReadString ()
                {
-                       // TODO: implement me.
-                       return null;
+                       throw new NotImplementedException ();
                }
 
-               public override void ResolveEntity()
+               [MonoTODO]
+               public void ResetState ()
+               {
+                       throw new NotImplementedException ();
+               }
+
+               public override void ResolveEntity ()
                {
                        // XmlTextReaders don't resolve entities.
-                       throw new InvalidOperationException("XmlTextReaders don't resolve entities.");
+                       throw new InvalidOperationException ("XmlTextReaders don't resolve entities.");
                }
 
-               // privates
+               #endregion
+
+               #region Internals
+               internal string publicId;
+               internal string systemId;
+
+               internal void SetReaderContext (string url, XmlParserContext context)
+               {
+                       parserContext = context;
+                       parserContext.BaseURI = url;
+                       Init ();
+               }
+
+               internal void SetReaderFragment(TextReader fragment, XmlNodeType fragType)
+               {
+                       this.reader = fragment;
+                       can_seek = fragment != null && fragment.Peek () != -1;
+/*     for future use
+                       switch(fragType)
+                       {
+                       case XmlNodeType.Attribute:     // attribute content
+                               parserContext.InputState = XmlParserInputState.AttributeValue;
+                               break;
+                       case XmlNodeType.DocumentFragment:      // element content
+                               parserContext.InputState = XmlParserInputState.Content;
+                               break;
+                       case XmlNodeType.Element:       // one element
+                               parserContext.InputState = XmlParserInputState.StartTag;
+                               break;
+                       case XmlNodeType.Document:      // document content
+                               parserContext.InputState = XmlParserInputState.Start;
+                               break;
+                       default:
+                               throw new InvalidOperationException("setting this xml node type not allowed.");
+                       }
+*/
+               }
+               #endregion
+
+               #region Privates
+
+               private XmlParserContext parserContext;
 
                private TextReader reader;
                private ReadState readState;
 
                private int depth;
+               private int elementDepth;
                private bool depthDown;
 
-               private XmlNameTable nameTable;
-               private XmlNamespaceManager namespaceManager;
                private bool popScope;
 
                private XmlNodeType nodeType;
@@ -597,49 +677,76 @@ namespace System.Xml
                private string namespaceURI;
                private bool isEmptyElement;
                private string value;
+
+               private XmlNodeType saveNodeType;
+               private string saveName;
+               private string savePrefix;
+               private string saveLocalName;
+               private string saveNamespaceURI;
+               private bool saveIsEmptyElement;
+
                private Hashtable attributes;
+               private ArrayList orderedAttributes;
+               private IEnumerator orderedAttributesEnumerator;
 
                private bool returnEntityReference;
                private string entityReferenceName;
 
-               private char[] nameBuffer;
+               private char [] nameBuffer;
                private int nameLength;
                private int nameCapacity;
                private const int initialNameCapacity = 256;
 
-               private char[] valueBuffer;
+               private char [] valueBuffer;
                private int valueLength;
                private int valueCapacity;
                private const int initialValueCapacity = 8192;
 
-               private void Init()
-               {
-                       namespaceManager = new XmlNamespaceManager(nameTable);
-                       popScope = false;
+               private StringBuilder xmlBuffer; // This is for Read(Inner|Outer)Xml
+               private StringBuilder currentTag; // A buffer for ReadContent for ReadOuterXml
+               private bool saveToXmlBuffer;
+               private int line = 1;
+               private int column = 1;
+               private bool has_peek;
+               private bool can_seek;
+               private int peek_char;
 
+               private string attributeString = String.Empty;
+               private int attributeStringCurrentPosition;
+
+               private void Init ()
+               {
                        readState = ReadState.Initial;
 
-                       depth = -1;
+                       depth = 0;
                        depthDown = false;
 
+                       popScope = false;
+
                        nodeType = XmlNodeType.None;
                        name = String.Empty;
                        prefix = String.Empty;
                        localName = string.Empty;
                        isEmptyElement = false;
                        value = String.Empty;
-                       attributes = new Hashtable();
-                       
+
+                       attributes = new Hashtable ();
+                       orderedAttributes = new ArrayList ();
+                       orderedAttributesEnumerator = null;
+
                        returnEntityReference = false;
                        entityReferenceName = String.Empty;
 
-                       nameBuffer = new char[initialNameCapacity];
+                       nameBuffer = new char [initialNameCapacity];
                        nameLength = 0;
                        nameCapacity = initialNameCapacity;
 
-                       valueBuffer = new char[initialValueCapacity];
+                       valueBuffer = new char [initialValueCapacity];
                        valueLength = 0;
                        valueCapacity = initialValueCapacity;
+
+                       xmlBuffer = new StringBuilder ();
+                       currentTag = new StringBuilder ();
                }
 
                // Use this method rather than setting the properties
@@ -647,7 +754,7 @@ namespace System.Xml
                // be changed in harmony with each other. Maybe the
                // fields should be in a seperate class to help enforce
                // this.
-               private void SetProperties(
+               private void SetProperties (
                        XmlNodeType nodeType,
                        string name,
                        bool isEmptyElement,
@@ -658,108 +765,160 @@ namespace System.Xml
                        this.name = name;
                        this.isEmptyElement = isEmptyElement;
                        this.value = value;
+                       this.elementDepth = depth;
 
                        if (clearAttributes)
-                       {
-                               ClearAttributes();
-                       }
+                               ClearAttributes ();
 
-                       int indexOfColon = name.IndexOf(':');
+                       int indexOfColon = name.IndexOf (':');
 
-                       if (indexOfColon == -1)
-                       {
+                       if (indexOfColon == -1) {
                                prefix = String.Empty;
                                localName = name;
-                       }
-                       else
-                       {
-                               prefix = name.Substring(0, indexOfColon);
-                               localName = name.Substring(indexOfColon + 1);
+                       } else {
+                               prefix = name.Substring (0, indexOfColon);
+                               localName = name.Substring (indexOfColon + 1);
                        }
 
-                       namespaceURI = LookupNamespace(prefix);
+                       namespaceURI = LookupNamespace (prefix);
                }
 
-               private void AddAttribute(string name, string value)
+               private void SaveProperties ()
                {
-                       attributes.Add(name, value);
+                       saveNodeType = nodeType;
+                       saveName = name;
+                       savePrefix = prefix;
+                       saveLocalName = localName;
+                       saveNamespaceURI = namespaceURI;
+                       saveIsEmptyElement = isEmptyElement;
+                       // An element's value is always String.Empty.
                }
 
-               private void ClearAttributes()
+               private void RestoreProperties ()
                {
-                       if (attributes.Count > 0)
-                       {
-                               attributes.Clear();
+                       nodeType = saveNodeType;
+                       name = saveName;
+                       prefix = savePrefix;
+                       localName = saveLocalName;
+                       namespaceURI = saveNamespaceURI;
+                       isEmptyElement = saveIsEmptyElement;
+                       value = String.Empty;
+               }
+
+               private void AddAttribute (string name, string value)
+               {
+                       attributes.Add (name, value);
+                       orderedAttributes.Add (name);
+               }
+
+               private void ClearAttributes ()
+               {
+                       if (attributes.Count > 0) {
+                               attributes.Clear ();
+                               orderedAttributes.Clear ();
                        }
+
+                       orderedAttributesEnumerator = null;
                }
 
-               private int PeekChar()
+               private int PeekChar ()
                {
-                       return reader.Peek();
+                       if (can_seek)
+                               return reader.Peek ();
+
+                       if (has_peek)
+                               return peek_char;
+
+                       peek_char = reader.Read ();
+                       has_peek = true;
+                       return peek_char;
                }
 
-               private int ReadChar()
+               private int ReadChar ()
                {
-                       return reader.Read();
+                       int ch;
+                       if (has_peek) {
+                               ch = peek_char;
+                               has_peek = false;
+                       } else {
+                               ch = reader.Read ();
+                       }
+
+                       if (ch == '\n') {
+                               line++;
+                               column = 1;
+                       } else {
+                               column++;
+                       }
+                       if (saveToXmlBuffer) {
+                               xmlBuffer.Append ((char) ch);
+                       }
+                       currentTag.Append ((char) ch);
+                       return ch;
                }
 
                // 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()
+               private bool ReadContent ()
                {
-                       bool more = false;
-
-                       if (popScope)
-                       {
-                               namespaceManager.PopScope();
+                       currentTag.Length = 0;
+                       if (popScope) {
+                               parserContext.NamespaceManager.PopScope ();
                                popScope = false;
                        }
 
-                       if (depthDown)
-                       {
-                               --depth;
-                       }
-
-                       if (returnEntityReference)
-                       {
-                               ++depth;
-                               SetEntityReferenceProperties();
-                               more = true;
-                       }
-                       else
-                       {
-                               switch (PeekChar())
+                       if (returnEntityReference) {
+                               SetEntityReferenceProperties ();
+                       } else {
+                       switch (PeekChar ())
                                {
                                case '<':
-                                       ReadChar();
-                                       ReadTag();
-                                       more = true;
+                                       ReadChar ();
+                                       ReadTag ();
                                        break;
+                               case '\r':
+                                       if (whitespaceHandling == WhitespaceHandling.All ||
+                                           whitespaceHandling == WhitespaceHandling.Significant)
+                                               return ReadWhitespace ();
+
+                                       ReadChar ();
+                                       return ReadContent ();
+                               case '\n':
+                                       if (whitespaceHandling == WhitespaceHandling.All ||
+                                           whitespaceHandling == WhitespaceHandling.Significant)
+                                               return ReadWhitespace ();
+
+                                       ReadChar ();
+                                       return ReadContent ();
+                               case ' ':
+                                       if (whitespaceHandling == WhitespaceHandling.All ||
+                                           whitespaceHandling == WhitespaceHandling.Significant)
+                                               return ReadWhitespace ();
+
+                                       SkipWhitespace ();
+                                       return ReadContent ();
                                case -1:
                                        readState = ReadState.EndOfFile;
-                                       SetProperties(
+                                       SetProperties (
                                                XmlNodeType.None, // nodeType
                                                String.Empty, // name
                                                false, // isEmptyElement
                                                String.Empty, // value
                                                true // clearAttributes
                                        );
-                                       more = false;
                                        break;
                                default:
-                                       ReadText();
-                                       more = true;
+                                       ReadText (true);
                                        break;
                                }
                        }
-
-                       return more;
+                       return this.ReadState != ReadState.EndOfFile;
                }
 
-               private void SetEntityReferenceProperties()
+               private void SetEntityReferenceProperties ()
                {
-                       SetProperties(
+                       SetProperties (
                                XmlNodeType.EntityReference, // nodeType
                                entityReferenceName, // name
                                false, // isEmptyElement
@@ -772,77 +931,78 @@ namespace System.Xml
                }
 
                // The leading '<' has already been consumed.
-               private void ReadTag()
+               private void ReadTag ()
                {
-                       switch (PeekChar())
+                       switch (PeekChar ())
                        {
                        case '/':
-                               ReadChar();
-                               ReadEndTag();
+                               ReadChar ();
+                               ReadEndTag ();
                                break;
                        case '?':
-                               ReadChar();
-                               ReadProcessingInstruction();
+                               ReadChar ();
+                               ReadProcessingInstruction ();
                                break;
                        case '!':
-                               ReadChar();
-                               ReadDeclaration();
+                               ReadChar ();
+                               ReadDeclaration ();
                                break;
                        default:
-                               ReadStartTag();
+                               ReadStartTag ();
                                break;
                        }
                }
 
                // The leading '<' has already been consumed.
-               private void ReadStartTag()
+               private void ReadStartTag ()
                {
-                       namespaceManager.PushScope();
+                       parserContext.NamespaceManager.PushScope ();
 
-                       string name = ReadName();
-                       SkipWhitespace();
+                       string name = ReadName ();
+                       SkipWhitespace ();
 
                        bool isEmptyElement = false;
 
-                       ClearAttributes();
+                       ClearAttributes ();
 
-                       if (XmlChar.IsFirstNameChar(PeekChar()))
-                       {
-                               ReadAttributes();
-                       }
+                       if (XmlChar.IsFirstNameChar (PeekChar ()))
+                               ReadAttributes ();
 
-                       if (PeekChar() == '/')
-                       {
-                               ReadChar();
+                       if (PeekChar () == '/') {
+                               ReadChar ();
                                isEmptyElement = true;
                                depthDown = true;
                                popScope = true;
                        }
 
-                       Expect('>');
-
-                       ++depth;
+                       Expect ('>');
 
-                       SetProperties(
+                       SetProperties (
                                XmlNodeType.Element, // nodeType
                                name, // name
                                isEmptyElement, // isEmptyElement
                                String.Empty, // value
                                false // clearAttributes
                        );
+
+                       if (!depthDown)
+                               ++depth;
+                       else
+                               depthDown = false;
+
                }
 
                // The reader is positioned on the first character
                // of the element's name.
-               private void ReadEndTag()
+               private void ReadEndTag ()
                {
-                       string name = ReadName();
-                       SkipWhitespace();
-                       Expect('>');
+                       string name = ReadName ();
+                       SkipWhitespace ();
+                       Expect ('>');
 
                        --depth;
 
-                       SetProperties(
+                       SetProperties (
                                XmlNodeType.EndElement, // nodeType
                                name, // name
                                false, // isEmptyElement
@@ -853,95 +1013,76 @@ namespace System.Xml
                        popScope = true;
                }
 
-               private void AppendNameChar(int ch)
+               private void AppendNameChar (int ch)
                {
-                       CheckNameCapacity();
-                       nameBuffer[nameLength++] = (char)ch;
+                       CheckNameCapacity ();
+                       nameBuffer [nameLength++] = (char)ch;
                }
 
-               private void CheckNameCapacity()
+               private void CheckNameCapacity ()
                {
-                       if (nameLength == nameCapacity)
-                       {
+                       if (nameLength == nameCapacity) {
                                nameCapacity = nameCapacity * 2;
-                               char[] oldNameBuffer = nameBuffer;
-                               nameBuffer = new char[nameCapacity];
-                               Array.Copy(oldNameBuffer, nameBuffer, nameLength);
+                               char [] oldNameBuffer = nameBuffer;
+                               nameBuffer = new char [nameCapacity];
+                               Array.Copy (oldNameBuffer, nameBuffer, nameLength);
                        }
                }
 
-               private string CreateNameString()
+               private string CreateNameString ()
                {
-                       return new String(nameBuffer, 0, nameLength);
+                       return new String (nameBuffer, 0, nameLength);
                }
 
-               private void AppendValueChar(int ch)
+               private void AppendValueChar (int ch)
                {
-                       CheckValueCapacity();
-                       valueBuffer[valueLength++] = (char)ch;
+                       CheckValueCapacity ();
+                       valueBuffer [valueLength++] = (char)ch;
                }
 
-               private void CheckValueCapacity()
+               private void CheckValueCapacity ()
                {
-                       if (valueLength == valueCapacity)
-                       {
+                       if (valueLength == valueCapacity) {
                                valueCapacity = valueCapacity * 2;
-                               char[] oldValueBuffer = valueBuffer;
-                               valueBuffer = new char[valueCapacity];
-                               Array.Copy(oldValueBuffer, valueBuffer, valueLength);
+                               char [] oldValueBuffer = valueBuffer;
+                               valueBuffer = new char [valueCapacity];
+                               Array.Copy (oldValueBuffer, valueBuffer, valueLength);
                        }
                }
 
-               private string CreateValueString()
+               private string CreateValueString ()
                {
-                       return new String(valueBuffer, 0, valueLength);
+                       return new String (valueBuffer, 0, valueLength);
                }
 
                // The reader is positioned on the first character
                // of the text.
-               private void ReadText()
+               private void ReadText (bool cleanValue)
                {
-                       valueLength = 0;
+                       if (cleanValue)
+                               valueLength = 0;
 
-                       int ch = PeekChar();
+                       int ch = PeekChar ();
 
-                       while (ch != '<' && ch != -1)
-                       {
-                               if (ch == '&')
-                               {
-                                       ReadChar();
-
-                                       if (ReadReference(false))
-                                       {
+                       while (ch != '<' && ch != -1) {
+                               if (ch == '&') {
+                                       ReadChar ();
+                                       if (ReadReference (false))
                                                break;
-                                       }
-                               }
-                               else
-                               {
-                                       AppendValueChar(ReadChar());
-                               }
+                               } else
+                                       AppendValueChar (ReadChar ());
 
-                               ch = PeekChar();
-                       }
-
-                       if (returnEntityReference && valueLength == 0)
-                       {
-                               ++depth;
-                               SetEntityReferenceProperties();
+                               ch = PeekChar ();
                        }
-                       else
-                       {
-                               if (depth >= 0)
-                               {
-                                       ++depth;
-                                       depthDown = true;
-                               }
 
-                               SetProperties(
+                       if (returnEntityReference && valueLength == 0) {
+                               SetEntityReferenceProperties ();
+                       } else {
+                               SetProperties (
                                        XmlNodeType.Text, // nodeType
                                        String.Empty, // name
                                        false, // isEmptyElement
-                                       CreateValueString(), // value
+                                       CreateValueString (), // value
                                        true // clearAttributes
                                );
                        }
@@ -952,128 +1093,102 @@ 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 bool ReadReference (bool ignoreEntityReferences)
                {
-                       if (PeekChar() == '#')
-                       {
-                               ReadChar();
-                               ReadCharacterReference();
-                       }
-                       else
-                       {
-                               ReadEntityReference(ignoreEntityReferences);
-                       }
+                       if (PeekChar () == '#') {
+                               ReadChar ();
+                               ReadCharacterReference ();
+                       } else
+                               ReadEntityReference (ignoreEntityReferences);
 
                        return returnEntityReference;
                }
 
-               private void ReadCharacterReference()
+               private void ReadCharacterReference ()
                {
                        int value = 0;
 
-                       if (PeekChar() == 'x')
-                       {
-                               ReadChar();
+                       if (PeekChar () == 'x') {
+                               ReadChar ();
 
-                               while (PeekChar() != ';' && PeekChar() != -1)
-                               {
-                                       int ch = ReadChar();
+                               while (PeekChar () != ';' && PeekChar () != -1) {
+                                       int ch = ReadChar ();
 
                                        if (ch >= '0' && ch <= '9')
-                                       {
                                                value = (value << 4) + ch - '0';
-                                       }
                                        else if (ch >= 'A' && ch <= 'F')
-                                       {
                                                value = (value << 4) + ch - 'A' + 10;
-                                       }
                                        else if (ch >= 'a' && ch <= 'f')
-                                       {
                                                value = (value << 4) + ch - 'a' + 10;
-                                       }
                                        else
-                                       {
-                                               throw new Exception(
-                                                       String.Format(
+                                               throw new XmlException (
+                                                       String.Format (
                                                                "invalid hexadecimal digit: {0} (#x{1:X})",
                                                                (char)ch,
                                                                ch));
-                                       }
                                }
-                       }
-                       else
-                       {
-                               while (PeekChar() != ';' && PeekChar() != -1)
-                               {
-                                       int ch = ReadChar();
+                       } else {
+                               while (PeekChar () != ';' && PeekChar () != -1) {
+                                       int ch = ReadChar ();
 
                                        if (ch >= '0' && ch <= '9')
-                                       {
                                                value = value * 10 + ch - '0';
-                                       }
                                        else
-                                       {
-                                               throw new Exception(
-                                                       String.Format(
+                                               throw new XmlException (
+                                                       String.Format (
                                                                "invalid decimal digit: {0} (#x{1:X})",
                                                                (char)ch,
                                                                ch));
-                                       }
                                }
                        }
 
-                       ReadChar(); // ';'
+                       ReadChar (); // ';'
 
-                       AppendValueChar(value);
+                       AppendValueChar (value);
                }
 
-               private void ReadEntityReference(bool ignoreEntityReferences)
+               private void ReadEntityReference (bool ignoreEntityReferences)
                {
                        nameLength = 0;
 
-                       int ch = PeekChar();
+                       int ch = PeekChar ();
 
-                       while (ch != ';' && ch != -1)
-                       {
-                               AppendNameChar(ReadChar());
-                               ch = PeekChar();
+                       while (ch != ';' && ch != -1) {
+                               AppendNameChar (ReadChar ());
+                               ch = PeekChar ();
                        }
 
-                       Expect(';');
+                       Expect (';');
 
-                       string name = CreateNameString();
+                       string name = CreateNameString ();
 
                        switch (name)
                        {
                                case "lt":
-                                       AppendValueChar('<');
+                                       AppendValueChar ('<');
                                        break;
                                case "gt":
-                                       AppendValueChar('>');
+                                       AppendValueChar ('>');
                                        break;
                                case "amp":
-                                       AppendValueChar('&');
+                                       AppendValueChar ('&');
                                        break;
                                case "apos":
-                                       AppendValueChar('\'');
+                                       AppendValueChar ('\'');
                                        break;
                                case "quot":
-                                       AppendValueChar('"');
+                                       AppendValueChar ('"');
                                        break;
                                default:
-                                       if (ignoreEntityReferences)
-                                       {
-                                               AppendValueChar('&');
+                                       if (ignoreEntityReferences) {
+                                               AppendValueChar ('&');
 
-                                               foreach (char ch2 in name)
-                                               {
-                                                       AppendValueChar(ch2);
+                                               foreach (char ch2 in name) {
+                                                       AppendValueChar (ch2);
                                                }
 
-                                               AppendValueChar(';');
-                                       }
-                                       else
-                                       {
+                                               AppendValueChar (';');
+                                       } else {
                                                returnEntityReference = true;
                                                entityReferenceName = name;
                                        }
@@ -1083,247 +1198,527 @@ namespace System.Xml
 
                // The reader is positioned on the first character of
                // the attribute name.
-               private void ReadAttributes()
+               private void ReadAttributes ()
                {
-                       do
-                       {
-                               string name = ReadName();
-                               SkipWhitespace();
-                               Expect('=');
-                               SkipWhitespace();
-                               string value = ReadAttribute();
-                               SkipWhitespace();
+                       do {
+                               string name = ReadName ();
+                               SkipWhitespace ();
+                               Expect ('=');
+                               SkipWhitespace ();
+                               string value = ReadAttribute ();
+                               SkipWhitespace ();
 
                                if (name == "xmlns")
-                               {
-                                       namespaceManager.AddNamespace(String.Empty, value);
-                               }
-                               else if (name.StartsWith("xmlns:"))
-                               {
-                                       namespaceManager.AddNamespace(name.Substring(6), value);
-                               }
-                               else
-                               {
-                                       AddAttribute(name, value);
-                               }
-                       }
-                       while (PeekChar() != '/' && PeekChar() != '>' && PeekChar() != -1);
+                                       parserContext.NamespaceManager.AddNamespace (String.Empty, value);
+                               else if (name.StartsWith ("xmlns:"))
+                                       parserContext.NamespaceManager.AddNamespace (name.Substring (6), value);
+
+                               AddAttribute (name, value);
+                       } while (PeekChar () != '/' && PeekChar () != '>' && PeekChar () != -1);
                }
 
                // The reader is positioned on the quote character.
-               private string ReadAttribute()
+               private string ReadAttribute ()
                {
-                       int quoteChar = ReadChar();
+                       int quoteChar = ReadChar ();
 
                        if (quoteChar != '\'' && quoteChar != '\"')
-                       {
-                               throw new Exception("an attribute value was not quoted");
-                       }
+                               throw new XmlException ("an attribute value was not quoted");
 
                        valueLength = 0;
 
-                       while (PeekChar() != quoteChar)
-                       {
-                               int ch = ReadChar();
+                       while (PeekChar () != quoteChar) {
+                               int ch = ReadChar ();
 
                                switch (ch)
                                {
                                case '<':
-                                       throw new Exception("attribute values cannot contain '<'");
+                                       throw new XmlException ("attribute values cannot contain '<'");
                                case '&':
-                                       ReadReference(true);
+                                       ReadReference (true);
                                        break;
                                case -1:
-                                       throw new Exception("unexpected end of file in an attribute value");
+                                       throw new XmlException ("unexpected end of file in an attribute value");
                                default:
-                                       AppendValueChar(ch);
+                                       AppendValueChar (ch);
                                        break;
                                }
                        }
 
-                       ReadChar(); // quoteChar
+                       ReadChar (); // quoteChar
 
-                       return CreateValueString();
+                       return CreateValueString ();
                }
 
                // The reader is positioned on the first character
                // of the target.
-               private void ReadProcessingInstruction()
+               //
+               // Now it also reads XmlDeclaration, this method name became improper...
+               private void ReadProcessingInstruction ()
                {
-                       string target = ReadName();
-                       SkipWhitespace();
+                       string target = ReadName ();
+                       SkipWhitespace ();
 
                        valueLength = 0;
 
-                       while (PeekChar() != -1)
-                       {
-                               int ch = ReadChar();
+                       while (PeekChar () != -1) {
+                               int ch = ReadChar ();
 
-                               if (ch == '?' && PeekChar() == '>')
-                               {
-                                       ReadChar();
+                               if (ch == '?' && PeekChar () == '>') {
+                                       ReadChar ();
                                        break;
                                }
 
-                               AppendValueChar((char)ch);
+                               AppendValueChar ((char)ch);
                        }
 
-                       SetProperties(
+/* for future use
+                       if(target == "xml") && parserContext.InputState != XmlParserInputState.Start)
+                               throw new XmlException("Xml declaration is not allowed here.");
+                       else {
+                               parserContext.InputState = XmlParserInputState.DTD; //for future use
+                       }
+*/
+                       SetProperties (
+                               target == "xml" ?
+                               XmlNodeType.XmlDeclaration :
                                XmlNodeType.ProcessingInstruction, // nodeType
                                target, // name
                                false, // isEmptyElement
-                               CreateValueString(), // value
+                               CreateValueString (), // value
                                true // clearAttributes
                        );
                }
 
                // The reader is positioned on the first character after
                // the leading '<!'.
-               private void ReadDeclaration()
+               private void ReadDeclaration ()
                {
-                       int ch = PeekChar();
+                       int ch = PeekChar ();
 
                        switch (ch)
                        {
                        case '-':
-                               Expect('-');
-                               Expect('-');
-                               ReadComment();
+                               Expect ("--");
+                               ReadComment ();
                                break;
                        case '[':
-                               ReadChar();
-                               Expect('C');
-                               Expect('D');
-                               Expect('A');
-                               Expect('T');
-                               Expect('A');
-                               Expect('[');
-                               ReadCDATA();
+                               ReadChar ();
+                               Expect ("CDATA[");
+                               ReadCDATA ();
+                               break;
+                       case 'D':
+                               Expect ("DOCTYPE");
+                               ReadDoctypeDecl ();
                                break;
                        }
                }
 
                // The reader is positioned on the first character after
                // the leading '<!--'.
-               private void ReadComment()
+               private void ReadComment ()
                {
                        valueLength = 0;
 
-                       while (PeekChar() != -1)
-                       {
-                               int ch = ReadChar();
+                       while (PeekChar () != -1) {
+                               int ch = ReadChar ();
 
-                               if (ch == '-' && PeekChar() == '-')
-                               {
-                                       ReadChar();
+                               if (ch == '-' && PeekChar () == '-') {
+                                       ReadChar ();
 
-                                       if (PeekChar() != '>')
-                                       {
-                                               throw new Exception("comments cannot contain '--'");
-                                       }
+                                       if (PeekChar () != '>')
+                                               throw new XmlException ("comments cannot contain '--'");
 
-                                       ReadChar();
+                                       ReadChar ();
                                        break;
                                }
 
-                               AppendValueChar((char)ch);
+                               AppendValueChar ((char)ch);
                        }
 
-                       SetProperties(
+                       SetProperties (
                                XmlNodeType.Comment, // nodeType
                                String.Empty, // name
                                false, // isEmptyElement
-                               CreateValueString(), // value
+                               CreateValueString (), // value
                                true // clearAttributes
                        );
                }
 
                // The reader is positioned on the first character after
                // the leading '<![CDATA['.
-               private void ReadCDATA()
+               private void ReadCDATA ()
                {
                        valueLength = 0;
 
-                       while (PeekChar() != -1)
-                       {
-                               int ch = ReadChar();
+                       while (PeekChar () != -1) {
+                               int ch = ReadChar ();
 
-                               if (ch == ']' && PeekChar() == ']')
-                               {
-                                       ch = ReadChar(); // ']'
+                               if (ch == ']' && PeekChar () == ']') {
+                                       ch = ReadChar (); // ']'
 
-                                       if (PeekChar() == '>')
-                                       {
-                                               ReadChar(); // '>'
+                                       if (PeekChar () == '>') {
+                                               ReadChar (); // '>'
                                                break;
-                                       }
-                                       else
-                                       {
-                                               AppendValueChar(']');
-                                               AppendValueChar(']');
-                                               ch = ReadChar();
+                                       } else {
+                                               AppendValueChar (']');
+                                               AppendValueChar (']');
+                                               ch = ReadChar ();
                                        }
                                }
 
-                               AppendValueChar((char)ch);
+                               AppendValueChar ((char)ch);
                        }
 
-                       ++depth;
-
-                       SetProperties(
+                       SetProperties (
                                XmlNodeType.CDATA, // nodeType
                                String.Empty, // name
                                false, // isEmptyElement
-                               CreateValueString(), // value
+                               CreateValueString (), // value
                                true // clearAttributes
                        );
                }
 
-               // The reader is positioned on the first character
-               // of the name.
-               private string ReadName()
+               // The reader is positioned on the first character after
+               // the leading '<!DOCTYPE'.
+               private void ReadDoctypeDecl ()
                {
-                       if (!XmlChar.IsFirstNameChar(PeekChar()))
+                       string doctypeName = null;
+                       string publicId = String.Empty;
+                       string systemId = String.Empty;
+
+                       SkipWhitespace ();
+                       doctypeName = ReadName ();
+                       SkipWhitespace ();
+                       xmlBuffer.Length = 0;
+                       switch(PeekChar ())
                        {
-                               throw new Exception("a name did not start with a legal character");
+                       case 'S':
+                               systemId = ReadSystemLiteral (true);
+                               break;
+                       case 'P':
+                               publicId = ReadPubidLiteral ();
+                               SkipWhitespace ();
+                               systemId = ReadSystemLiteral (false);
+                               break;
                        }
+                       SkipWhitespace ();
 
-                       nameLength = 0;
 
-                       AppendNameChar(ReadChar());
+                       if(PeekChar () == '[')
+                       {
+                               // read markupdecl etc. or end of decl
+                               ReadChar ();
+                               xmlBuffer.Length = 0;
+                               saveToXmlBuffer = true;
+                               do {
+                                       ReadDTDInternalSubset ();
+                               } while(nodeType != XmlNodeType.None);
+                               xmlBuffer.Remove (xmlBuffer.Length - 1, 1);     // cut off ']'
+                               saveToXmlBuffer = false;
+                       }
+                       // end of DOCTYPE decl.
+                       SkipWhitespace ();
+                       Expect ('>');
+
+                       parserContext.InternalSubset = xmlBuffer.ToString ();
+
+                       // set properties for <!DOCTYPE> node
+                       SetProperties (
+                               XmlNodeType.DocumentType, // nodeType
+                               doctypeName, // name
+                               false, // isEmptyElement
+                               parserContext.InternalSubset, // value
+                               true // clearAttributes
+                               );
+               }
 
-                       while (XmlChar.IsNameChar(PeekChar()))
+               // Read any one of following:
+               //   elementdecl, AttlistDecl, EntityDecl, NotationDecl,
+               //   PI, Comment, Parameter Entity, or doctype termination char(']')
+               //
+               // returns a node of some nodeType or null, setting nodeType.
+               //       (if None then ']' was found.)
+               private void ReadDTDInternalSubset()
+               {
+                       SkipWhitespace ();
+                       switch(ReadChar ())
                        {
-                               AppendNameChar(ReadChar());
+                       case ']':
+                               nodeType = XmlNodeType.None;
+                               break;
+                       case '%':
+                               string peName = ReadName ();
+                               Expect (';');
+                               nodeType = XmlNodeType.EntityReference; // It's chating a bit;-)
+                               break;
+                       case '<':
+                               switch(ReadChar ())
+                               {
+                               case '?':
+                                       ReadProcessingInstruction ();
+                                       break;
+                               case '!':
+                                       switch(ReadChar ())
+                                       {
+                                       case '-':
+                                               Expect ('-');
+                                               ReadComment ();
+                                               break;
+                                       case 'E':
+                                               switch(ReadChar ())
+                                               {
+                                               case 'N':
+                                                       Expect ("TITY");
+                                                       ReadEntityDecl ();
+                                                       break;
+                                               case 'L':
+                                                       Expect ("EMENT");
+                                                       ReadElementDecl ();
+                                                       break;
+                                               default:
+                                                       throw new XmlException ("Syntax Error after '<!E' (ELEMENT or ENTITY must be found)");
+                                               }
+                                               break;
+                                       case 'A':
+                                               Expect ("TTLIST");
+                                               ReadAttListDecl ();
+                                               break;
+                                       case 'N':
+                                               Expect ("OTATION");
+                                               ReadNotationDecl ();
+                                               break;
+                                       default:
+                                               throw new XmlException ("Syntax Error after '<!' characters.");
+                                       }
+                                       break;
+                               default:
+                                       throw new XmlException ("Syntax Error after '<' character.");
+                               }
+                               break;
+                       default:
+                               throw new XmlException ("Syntax Error inside doctypedecl markup.");
                        }
+               }
+
+               // The reader is positioned on the head of the name.
+               private void ReadElementDecl()
+               {
+                       while(ReadChar () != '>');
+               }
 
-                       return CreateNameString();
+               private void ReadEntityDecl()
+               {
+                       while(ReadChar () != '>');
+               }
+
+               private void ReadAttListDecl()
+               {
+                       while(ReadChar () != '>');
+               }
+
+               private void ReadNotationDecl()
+               {
+                       while(ReadChar () != '>');
+               }
+               
+               // The reader is positioned on the first 'S' of "SYSTEM".
+               private string ReadSystemLiteral (bool expectSYSTEM)
+               {
+                       if(expectSYSTEM)
+                               Expect ("SYSTEM");
+                       SkipWhitespace ();
+                       int quoteChar = ReadChar ();    // apos or quot
+                       xmlBuffer.Length = 0;
+                       saveToXmlBuffer = true;
+                       int c = 0;
+                       while(c != quoteChar) {
+                               c = ReadChar ();
+                               if(c < 0) throw new XmlException ("Unexpected end of stream in ExternalID.");
+                       }
+                       saveToXmlBuffer = false;
+                       xmlBuffer.Remove (xmlBuffer.Length-1, 1);       // cut quoteChar
+                       return xmlBuffer.ToString ();
+               }
+
+               private string ReadPubidLiteral()
+               {
+                       Expect ("PUBLIC");
+                       SkipWhitespace ();
+                       int quoteChar = ReadChar ();
+                       xmlBuffer.Length = 0;
+                       saveToXmlBuffer = true;
+                       int c = 0;
+                       while(c != quoteChar)
+                       {
+                               c = ReadChar ();
+                               if(c < 0) throw new XmlException ("Unexpected end of stream in ExternalID.");
+                               if(c != quoteChar && !XmlChar.IsPubidChar (c))
+                                       throw new XmlException("character '" + (char)c + "' not allowed for PUBLIC ID");
+                       }
+                       ReadChar();     // skips quoteChar
+                       xmlBuffer.Remove (xmlBuffer.Length-1, 1);       // cut quoteChar
+                       saveToXmlBuffer = false;
+                       return xmlBuffer.ToString ();
+               }
+
+               // The reader is positioned on the first character
+               // of the name.
+               private string ReadName ()
+               {
+                       if (!XmlChar.IsFirstNameChar (PeekChar ()))
+                               throw new XmlException ("a name did not start with a legal character");
+
+                       nameLength = 0;
+
+                       AppendNameChar (ReadChar ());
+
+                       while (XmlChar.IsNameChar (PeekChar ())) {
+                               AppendNameChar (ReadChar ());
+                       }
+
+                       return CreateNameString ();
                }
 
                // Read the next character and compare it against the
                // specified character.
-               private void Expect(int expected)
+               private void Expect (int expected)
                {
-                       int ch = ReadChar();
+                       int ch = ReadChar ();
 
-                       if (ch != expected)
-                       {
-                               throw new Exception(String.Format(
-                                       "expected '{0}' ({1:X}) but found '{2}' ({3:X})",
-                                       (char)expected,
-                                       expected,
-                                       (char)ch,
-                                       ch));
+                       if (ch != expected) {
+                               throw new XmlException (
+                                       String.Format (
+                                               "expected '{0}' ({1:X}) but found '{2}' ({3:X})",
+                                               (char)expected,
+                                               expected,
+                                               (char)ch,
+                                               ch));
                        }
                }
 
+               private void Expect (string expected)
+               {
+                       int len = expected.Length;
+                       for(int i=0; i< len; i++)
+                               Expect (expected[i]);
+               }
+
                // Does not consume the first non-whitespace character.
-               private void SkipWhitespace()
+               private void SkipWhitespace ()
                {
-                       while (XmlChar.IsWhitespace(PeekChar()))
-                       {
-                               ReadChar();
+                       //FIXME: Should not skip if whitespaceHandling == WhiteSpaceHandling.None
+                       while (XmlChar.IsWhitespace (PeekChar ()))
+                               ReadChar ();
+               }
+
+               private bool ReadWhitespace ()
+               {
+                       valueLength = 0;
+                       int ch = PeekChar ();
+                       do {
+                               AppendValueChar (ReadChar ());
+                       } while ((ch = PeekChar ()) != -1 && XmlChar.IsWhitespace (ch));
+
+                       if (ch != -1 && ch != '<')
+                               ReadText (false);
+                       else
+                               SetProperties (XmlNodeType.Whitespace,
+                                              String.Empty,
+                                              false,
+                                              CreateValueString (),
+                                              true);
+
+                       return (PeekChar () != -1);
+               }
+
+               // read entity reference from attribute string and if parsable then return the value.
+               private string ReadAttributeValueEntityReference ()
+               {
+                       int endEntityPosition = attributeString.IndexOf(';',
+                               attributeStringCurrentPosition);
+                       string entityName = attributeString.Substring (attributeStringCurrentPosition + 1,
+                               endEntityPosition - attributeStringCurrentPosition - 1);
+
+                       attributeStringCurrentPosition = endEntityPosition + 1;
+
+                       if(entityName [0] == '#') {
+                               char c;
+                               // character entity
+                               if(entityName [1] == 'x') {
+                                       // hexadecimal
+                                       c = (char) int.Parse ("0" + entityName.Substring (2),
+                                               System.Globalization.NumberStyles.HexNumber);
+                               } else {
+                                       // decimal
+                                       c = (char) int.Parse (entityName.Substring (1));
+                               }
+                               return c.ToString();
                        }
+                       else {
+                               switch(entityName)
+                               {
+                               case "lt": return "<";
+                               case "gt": return ">";
+                               case "amp": return "&";
+                               case "quot": return "\"";
+                               case "apos": return "'";
+                               default: return null;
+                               }
+                       }
+               }
+
+               private string ResolveAttributeValue (string unresolved)
+               {
+                       if(unresolved == null) return null;
+                       StringBuilder resolved = new StringBuilder();
+                       int pos = 0;
+
+                       int next = unresolved.IndexOf ('&');
+                       if(next < 0)
+                               return unresolved;
+
+                       while(next >= 0) {
+                               if(pos < next)
+                                       resolved.Append (unresolved.Substring (pos, next - pos));// - 1);
+                               int endPos = unresolved.IndexOf (';', next+1);
+                               string entityName =
+                                       unresolved.Substring (next + 1, endPos - next - 1);
+                               if(entityName [0] == '#') {
+                                       char c;
+                                       // character entity
+                                       if(entityName [1] == 'x') {
+                                               // hexadecimal
+                                               c = (char) int.Parse ("0" + entityName.Substring (2),
+                                                       System.Globalization.NumberStyles.HexNumber);
+                                       } else {
+                                               // decimal
+                                               c = (char) int.Parse (entityName.Substring (1));
+                                       }
+                                       resolved.Append (c);
+                               } else {
+                                       switch(entityName) {
+                                       case "lt": resolved.Append ("<"); break;
+                                       case "gt": resolved.Append (">"); break;
+                                       case "amp": resolved.Append ("&"); break;
+                                       case "quot": resolved.Append ("\""); break;
+                                       case "apos": resolved.Append ("'"); break;
+                                       // With respect to "Value", MS document is helpless
+                                       // and the implemention returns inconsistent value
+                                       // (e.g. XML: "&ent; &amp;ent;" ---> Value: "&ent; &ent;".)
+                                       default: resolved.Append ("&" + entityName + ";"); break;
+                                       }
+                               }
+                               pos = endPos + 1;
+                               if(pos > unresolved.Length)
+                                       break;
+                               next = unresolved.IndexOf('&', pos);
+                       }
+                       resolved.Append (unresolved.Substring(pos));
+
+                       return resolved.ToString();
                }
+
+               #endregion
        }
 }