Switch from using HtmlAgilityPack 1.0 binary snapshot to HtmlAgilityPack 1.4~beta2...
authorJo Shields <directhex@mono-cvs.ximian.com>
Tue, 22 Dec 2009 16:52:26 +0000 (16:52 -0000)
committerJo Shields <directhex@mono-cvs.ximian.com>
Tue, 22 Dec 2009 16:52:26 +0000 (16:52 -0000)
svn path=/trunk/mono/; revision=148843

34 files changed:
docs/AgilityPack.dll [deleted file]
docs/ChangeLog
docs/HtmlAgilityPack/EncodingFoundException.cs [new file with mode: 0644]
docs/HtmlAgilityPack/HtmlAttribute.cs [new file with mode: 0644]
docs/HtmlAgilityPack/HtmlAttributeCollection.cs [new file with mode: 0644]
docs/HtmlAgilityPack/HtmlCmdLine.cs [new file with mode: 0644]
docs/HtmlAgilityPack/HtmlCommentNode.cs [new file with mode: 0644]
docs/HtmlAgilityPack/HtmlConsoleListener.cs [new file with mode: 0644]
docs/HtmlAgilityPack/HtmlDocument.cs [new file with mode: 0644]
docs/HtmlAgilityPack/HtmlElementFlag.cs [new file with mode: 0644]
docs/HtmlAgilityPack/HtmlEntity.cs [new file with mode: 0644]
docs/HtmlAgilityPack/HtmlNameTable.cs [new file with mode: 0644]
docs/HtmlAgilityPack/HtmlNode.cs [new file with mode: 0644]
docs/HtmlAgilityPack/HtmlNodeCollection.cs [new file with mode: 0644]
docs/HtmlAgilityPack/HtmlNodeNavigator.cs [new file with mode: 0644]
docs/HtmlAgilityPack/HtmlNodeType.cs [new file with mode: 0644]
docs/HtmlAgilityPack/HtmlParseError.cs [new file with mode: 0644]
docs/HtmlAgilityPack/HtmlParseErrorCode.cs [new file with mode: 0644]
docs/HtmlAgilityPack/HtmlTextNode.cs [new file with mode: 0644]
docs/HtmlAgilityPack/HtmlWeb.cs [new file with mode: 0644]
docs/HtmlAgilityPack/HtmlWebException.cs [new file with mode: 0644]
docs/HtmlAgilityPack/IOLibrary.cs [new file with mode: 0644]
docs/HtmlAgilityPack/MixedCodeDocument.cs [new file with mode: 0644]
docs/HtmlAgilityPack/MixedCodeDocumentCodeFragment.cs [new file with mode: 0644]
docs/HtmlAgilityPack/MixedCodeDocumentFragment.cs [new file with mode: 0644]
docs/HtmlAgilityPack/MixedCodeDocumentFragmentList.cs [new file with mode: 0644]
docs/HtmlAgilityPack/MixedCodeDocumentFragmentType.cs [new file with mode: 0644]
docs/HtmlAgilityPack/MixedCodeDocumentTextFragment.cs [new file with mode: 0644]
docs/HtmlAgilityPack/NameValuePair.cs [new file with mode: 0644]
docs/HtmlAgilityPack/NameValuePairList.cs [new file with mode: 0644]
docs/HtmlAgilityPack/crc32.cs [new file with mode: 0644]
docs/Makefile.am
docs/README
docs/docs.make

diff --git a/docs/AgilityPack.dll b/docs/AgilityPack.dll
deleted file mode 100755 (executable)
index 881836d..0000000
Binary files a/docs/AgilityPack.dll and /dev/null differ
index 20f2e861732df6342d717fda2ead2b0d17fbab15..69be5c9ebaa1c60a608d77d10a7ab898bf07f3a1 100644 (file)
@@ -1,3 +1,12 @@
+2009-12-22  Jo Shields  <directhex@apebox.org>
+
+       * HtmlAgilityPack/*: Bundle HtmlAgilityPack 1.4~beta2 from 
+          http://www.codeplex.com/htmlagilitypack in source form.
+
+       * AgilityPack.dll: Remove binary assembly, use source instead.
+
+       * docs.make Makefile.am README: Reflect above changes
+
 2009-02-12  Zoltan Varga  <vargaz@gmail.com>
 
        * Makefile.am (EXTRA_DIST): Remove removed files.
diff --git a/docs/HtmlAgilityPack/EncodingFoundException.cs b/docs/HtmlAgilityPack/EncodingFoundException.cs
new file mode 100644 (file)
index 0000000..bffdc02
--- /dev/null
@@ -0,0 +1,33 @@
+// HtmlAgilityPack V1.0 - Simon Mourier <simon underscore mourier at hotmail dot com>\r
+using System;\r
+using System.Text;\r
+\r
+namespace HtmlAgilityPack\r
+{\r
+    internal class EncodingFoundException : Exception\r
+    {\r
+        #region Fields\r
+\r
+        private Encoding _encoding;\r
+\r
+        #endregion\r
+\r
+        #region Constructors\r
+\r
+        internal EncodingFoundException(Encoding encoding)\r
+        {\r
+            _encoding = encoding;\r
+        }\r
+\r
+        #endregion\r
+\r
+        #region Properties\r
+\r
+        internal Encoding Encoding\r
+        {\r
+            get { return _encoding; }\r
+        }\r
+\r
+        #endregion\r
+    }\r
+}
\ No newline at end of file
diff --git a/docs/HtmlAgilityPack/HtmlAttribute.cs b/docs/HtmlAgilityPack/HtmlAttribute.cs
new file mode 100644 (file)
index 0000000..7a3de04
--- /dev/null
@@ -0,0 +1,260 @@
+// HtmlAgilityPack V1.0 - Simon Mourier <simon underscore mourier at hotmail dot com>\r
+\r
+#region\r
+\r
+using System;\r
+using System.Diagnostics;\r
+\r
+#endregion\r
+\r
+namespace HtmlAgilityPack\r
+{\r
+    /// <summary>\r
+    /// Represents an HTML attribute.\r
+    /// </summary>\r
+    [DebuggerDisplay("Name: {OriginalName}, Value: {Value}")]\r
+    public class HtmlAttribute : IComparable\r
+    {\r
+        #region Fields\r
+\r
+        private int _line;\r
+        internal int _lineposition;\r
+        internal string _name;\r
+        internal int _namelength;\r
+        internal int _namestartindex;\r
+        internal HtmlDocument _ownerdocument; // attribute can exists without a node\r
+        internal HtmlNode _ownernode;\r
+        private AttributeValueQuote _quoteType = AttributeValueQuote.DoubleQuote;\r
+        internal int _streamposition;\r
+        internal string _value;\r
+        internal int _valuelength;\r
+        internal int _valuestartindex;\r
+\r
+        #endregion\r
+\r
+        #region Constructors\r
+\r
+        internal HtmlAttribute(HtmlDocument ownerdocument)\r
+        {\r
+            _ownerdocument = ownerdocument;\r
+        }\r
+\r
+        #endregion\r
+\r
+        #region Properties\r
+\r
+        /// <summary>\r
+        /// Gets the line number of this attribute in the document.\r
+        /// </summary>\r
+        public int Line\r
+        {\r
+            get { return _line; }\r
+            internal set { _line = value; }\r
+        }\r
+\r
+        /// <summary>\r
+        /// Gets the column number of this attribute in the document.\r
+        /// </summary>\r
+        public int LinePosition\r
+        {\r
+            get { return _lineposition; }\r
+        }\r
+\r
+        /// <summary>\r
+        /// Gets the qualified name of the attribute.\r
+        /// </summary>\r
+        public string Name\r
+        {\r
+            get\r
+            {\r
+                if (_name == null)\r
+                {\r
+                    _name = _ownerdocument._text.Substring(_namestartindex, _namelength);\r
+                }\r
+                return _name.ToLower();\r
+            }\r
+            set\r
+            {\r
+                if (value == null)\r
+                {\r
+                    throw new ArgumentNullException("value");\r
+                }\r
+                _name = value;\r
+                if (_ownernode != null)\r
+                {\r
+                    _ownernode._innerchanged = true;\r
+                    _ownernode._outerchanged = true;\r
+                }\r
+            }\r
+        }\r
+\r
+        /// <summary>\r
+        /// Name of attribute with original case\r
+        /// </summary>\r
+        public string OriginalName\r
+        {\r
+            get { return _name; }\r
+        }\r
+\r
+        /// <summary>\r
+        /// Gets the HTML document to which this attribute belongs.\r
+        /// </summary>\r
+        public HtmlDocument OwnerDocument\r
+        {\r
+            get { return _ownerdocument; }\r
+        }\r
+\r
+        /// <summary>\r
+        /// Gets the HTML node to which this attribute belongs.\r
+        /// </summary>\r
+        public HtmlNode OwnerNode\r
+        {\r
+            get { return _ownernode; }\r
+        }\r
+\r
+        /// <summary>\r
+        /// Specifies what type of quote the data should be wrapped in\r
+        /// </summary>\r
+        public AttributeValueQuote QuoteType\r
+        {\r
+            get { return _quoteType; }\r
+            set { _quoteType = value; }\r
+        }\r
+\r
+        /// <summary>\r
+        /// Gets the stream position of this attribute in the document, relative to the start of the document.\r
+        /// </summary>\r
+        public int StreamPosition\r
+        {\r
+            get { return _streamposition; }\r
+        }\r
+\r
+        /// <summary>\r
+        /// Gets or sets the value of the attribute.\r
+        /// </summary>\r
+        public string Value\r
+        {\r
+            get\r
+            {\r
+                if (_value == null)\r
+                {\r
+                    _value = _ownerdocument._text.Substring(_valuestartindex, _valuelength);\r
+                }\r
+                return _value;\r
+            }\r
+            set\r
+            {\r
+                _value = value;\r
+                if (_ownernode != null)\r
+                {\r
+                    _ownernode._innerchanged = true;\r
+                    _ownernode._outerchanged = true;\r
+                }\r
+            }\r
+        }\r
+\r
+        internal string XmlName\r
+        {\r
+            get { return HtmlDocument.GetXmlName(Name); }\r
+        }\r
+\r
+        internal string XmlValue\r
+        {\r
+            get { return Value; }\r
+        }\r
+\r
+        /// <summary>\r
+        /// Gets a valid XPath string that points to this Attribute\r
+        /// </summary>\r
+        public string XPath\r
+        {\r
+            get\r
+            {\r
+                string basePath = (OwnerNode == null) ? "/" : OwnerNode.XPath + "/";\r
+                return basePath + GetRelativeXpath();\r
+            }\r
+        }\r
+\r
+        #endregion\r
+\r
+        #region IComparable Members\r
+\r
+        /// <summary>\r
+        /// Compares the current instance with another attribute. Comparison is based on attributes' name.\r
+        /// </summary>\r
+        /// <param name="obj">An attribute to compare with this instance.</param>\r
+        /// <returns>A 32-bit signed integer that indicates the relative order of the names comparison.</returns>\r
+        public int CompareTo(object obj)\r
+        {\r
+            HtmlAttribute att = obj as HtmlAttribute;\r
+            if (att == null)\r
+            {\r
+                throw new ArgumentException("obj");\r
+            }\r
+            return Name.CompareTo(att.Name);\r
+        }\r
+\r
+        #endregion\r
+\r
+        #region Public Methods\r
+\r
+        /// <summary>\r
+        /// Creates a duplicate of this attribute.\r
+        /// </summary>\r
+        /// <returns>The cloned attribute.</returns>\r
+        public HtmlAttribute Clone()\r
+        {\r
+            HtmlAttribute att = new HtmlAttribute(_ownerdocument);\r
+            att.Name = Name;\r
+            att.Value = Value;\r
+            return att;\r
+        }\r
+\r
+        /// <summary>\r
+        /// Removes this attribute from it's parents collection\r
+        /// </summary>\r
+        public void Remove()\r
+        {\r
+            _ownernode.Attributes.Remove(this);\r
+        }\r
+\r
+        #endregion\r
+\r
+        #region Private Methods\r
+\r
+        private string GetRelativeXpath()\r
+        {\r
+            if (OwnerNode == null)\r
+                return Name;\r
+\r
+            int i = 1;\r
+            foreach (HtmlAttribute node in OwnerNode.Attributes)\r
+            {\r
+                if (node.Name != Name) continue;\r
+\r
+                if (node == this)\r
+                    break;\r
+\r
+                i++;\r
+            }\r
+            return "@" + Name + "[" + i + "]";\r
+        }\r
+\r
+        #endregion\r
+    }\r
+\r
+    /// <summary>\r
+    /// An Enum representing different types of Quotes used for surrounding attribute values\r
+    /// </summary>\r
+    public enum AttributeValueQuote\r
+    {\r
+        /// <summary>\r
+        /// A single quote mark '\r
+        /// </summary>\r
+        SingleQuote,\r
+        /// <summary>\r
+        /// A double quote mark "\r
+        /// </summary>\r
+        DoubleQuote\r
+    }\r
+}
\ No newline at end of file
diff --git a/docs/HtmlAgilityPack/HtmlAttributeCollection.cs b/docs/HtmlAgilityPack/HtmlAttributeCollection.cs
new file mode 100644 (file)
index 0000000..07af997
--- /dev/null
@@ -0,0 +1,394 @@
+// HtmlAgilityPack V1.0 - Simon Mourier <simon underscore mourier at hotmail dot com>\r
+using System;\r
+using System.Collections;\r
+using System.Collections.Generic;\r
+\r
+namespace HtmlAgilityPack\r
+{\r
+    /// <summary>\r
+    /// Represents a combined list and collection of HTML nodes.\r
+    /// </summary>\r
+    public class HtmlAttributeCollection : IList<HtmlAttribute>\r
+    {\r
+        #region Fields\r
+\r
+        internal Dictionary<string, HtmlAttribute> Hashitems = new Dictionary<string, HtmlAttribute>();\r
+        private HtmlNode _ownernode;\r
+        private List<HtmlAttribute> items = new List<HtmlAttribute>();\r
+\r
+        #endregion\r
+\r
+        #region Constructors\r
+\r
+        internal HtmlAttributeCollection(HtmlNode ownernode)\r
+        {\r
+            _ownernode = ownernode;\r
+        }\r
+\r
+        #endregion\r
+\r
+        #region Properties\r
+\r
+        /// <summary>\r
+        /// Gets a given attribute from the list using its name.\r
+        /// </summary>\r
+        public HtmlAttribute this[string name]\r
+        {\r
+            get\r
+            {\r
+                if (name == null)\r
+                {\r
+                    throw new ArgumentNullException("name");\r
+                }\r
+                return Hashitems.ContainsKey(name.ToLower()) ? Hashitems[name.ToLower()] : null;\r
+            }\r
+            set { Append(value); }\r
+        }\r
+\r
+        #endregion\r
+\r
+        #region IList<HtmlAttribute> Members\r
+\r
+        /// <summary>\r
+        /// Gets the number of elements actually contained in the list.\r
+        /// </summary>\r
+        public int Count\r
+        {\r
+            get { return items.Count; }\r
+        }\r
+\r
+        /// <summary>\r
+        /// Gets readonly status of colelction\r
+        /// </summary>\r
+        public bool IsReadOnly\r
+        {\r
+            get { return false; }\r
+        }\r
+\r
+        /// <summary>\r
+        /// Gets the attribute at the specified index.\r
+        /// </summary>\r
+        public HtmlAttribute this[int index]\r
+        {\r
+            get { return items[index]; }\r
+            set { items[index] = value; }\r
+        }\r
+\r
+        /// <summary>\r
+        /// Adds supplied item to collection\r
+        /// </summary>\r
+        /// <param name="item"></param>\r
+        public void Add(HtmlAttribute item)\r
+        {\r
+            Append(item);\r
+        }\r
+\r
+        /// <summary>\r
+        /// Explicit clear\r
+        /// </summary>\r
+        void ICollection<HtmlAttribute>.Clear()\r
+        {\r
+            items.Clear();\r
+        }\r
+\r
+        /// <summary>\r
+        /// Retreives existence of supplied item\r
+        /// </summary>\r
+        /// <param name="item"></param>\r
+        /// <returns></returns>\r
+        public bool Contains(HtmlAttribute item)\r
+        {\r
+            return items.Contains(item);\r
+        }\r
+\r
+        /// <summary>\r
+        /// Copies collection to array\r
+        /// </summary>\r
+        /// <param name="array"></param>\r
+        /// <param name="arrayIndex"></param>\r
+        public void CopyTo(HtmlAttribute[] array, int arrayIndex)\r
+        {\r
+            items.CopyTo(array, arrayIndex);\r
+        }\r
+\r
+        /// <summary>\r
+        /// Get Explicit enumerator\r
+        /// </summary>\r
+        /// <returns></returns>\r
+        IEnumerator<HtmlAttribute> IEnumerable<HtmlAttribute>.GetEnumerator()\r
+        {\r
+            return items.GetEnumerator();\r
+        }\r
+\r
+        /// <summary>\r
+        /// Explicit non-generic enumerator\r
+        /// </summary>\r
+        /// <returns></returns>\r
+        IEnumerator IEnumerable.GetEnumerator()\r
+        {\r
+            return items.GetEnumerator();\r
+        }\r
+\r
+        /// <summary>\r
+        /// Retrieves the index for the supplied item, -1 if not found\r
+        /// </summary>\r
+        /// <param name="item"></param>\r
+        /// <returns></returns>\r
+        public int IndexOf(HtmlAttribute item)\r
+        {\r
+            return items.IndexOf(item);\r
+        }\r
+\r
+        /// <summary>\r
+        /// Inserts given item into collection at supplied index\r
+        /// </summary>\r
+        /// <param name="index"></param>\r
+        /// <param name="item"></param>\r
+        public void Insert(int index, HtmlAttribute item)\r
+        {\r
+            if (item == null)\r
+            {\r
+                throw new ArgumentNullException("item");\r
+            }\r
+\r
+            Hashitems[item.Name] = item;\r
+            item._ownernode = _ownernode;\r
+            items.Insert(index, item);\r
+\r
+            _ownernode._innerchanged = true;\r
+            _ownernode._outerchanged = true;\r
+        }\r
+\r
+        /// <summary>\r
+        /// Explicit collection remove\r
+        /// </summary>\r
+        /// <param name="item"></param>\r
+        /// <returns></returns>\r
+        bool ICollection<HtmlAttribute>.Remove(HtmlAttribute item)\r
+        {\r
+            return items.Remove(item);\r
+        }\r
+\r
+        /// <summary>\r
+        /// Removes the attribute at the specified index.\r
+        /// </summary>\r
+        /// <param name="index">The index of the attribute to remove.</param>\r
+        public void RemoveAt(int index)\r
+        {\r
+            HtmlAttribute att = items[index];\r
+            Hashitems.Remove(att.Name);\r
+            items.RemoveAt(index);\r
+\r
+            _ownernode._innerchanged = true;\r
+            _ownernode._outerchanged = true;\r
+        }\r
+\r
+        #endregion\r
+\r
+        #region Public Methods\r
+\r
+        /// <summary>\r
+        /// Adds a new attribute to the collection with the given values\r
+        /// </summary>\r
+        /// <param name="name"></param>\r
+        /// <param name="value"></param>\r
+        public void Add(string name, string value)\r
+        {\r
+            Append(name, value);\r
+        }\r
+\r
+        /// <summary>\r
+        /// Inserts the specified attribute as the last attribute in the collection.\r
+        /// </summary>\r
+        /// <param name="newAttribute">The attribute to insert. May not be null.</param>\r
+        /// <returns>The appended attribute.</returns>\r
+        public HtmlAttribute Append(HtmlAttribute newAttribute)\r
+        {\r
+            if (newAttribute == null)\r
+            {\r
+                throw new ArgumentNullException("newAttribute");\r
+            }\r
+\r
+            Hashitems[newAttribute.Name] = newAttribute;\r
+            newAttribute._ownernode = _ownernode;\r
+            items.Add(newAttribute);\r
+\r
+            _ownernode._innerchanged = true;\r
+            _ownernode._outerchanged = true;\r
+            return newAttribute;\r
+        }\r
+\r
+        /// <summary>\r
+        /// Creates and inserts a new attribute as the last attribute in the collection.\r
+        /// </summary>\r
+        /// <param name="name">The name of the attribute to insert.</param>\r
+        /// <returns>The appended attribute.</returns>\r
+        public HtmlAttribute Append(string name)\r
+        {\r
+            HtmlAttribute att = _ownernode._ownerdocument.CreateAttribute(name);\r
+            return Append(att);\r
+        }\r
+\r
+        /// <summary>\r
+        /// Creates and inserts a new attribute as the last attribute in the collection.\r
+        /// </summary>\r
+        /// <param name="name">The name of the attribute to insert.</param>\r
+        /// <param name="value">The value of the attribute to insert.</param>\r
+        /// <returns>The appended attribute.</returns>\r
+        public HtmlAttribute Append(string name, string value)\r
+        {\r
+            HtmlAttribute att = _ownernode._ownerdocument.CreateAttribute(name, value);\r
+            return Append(att);\r
+        }\r
+\r
+        /// <summary>\r
+        /// Checks for existance of attribute with given name\r
+        /// </summary>\r
+        /// <param name="name"></param>\r
+        /// <returns></returns>\r
+        public bool Contains(string name)\r
+        {\r
+            for (int i = 0; i < items.Count; i++)\r
+            {\r
+                if (items[i].Name.Equals(name.ToLower()))\r
+                    return true;\r
+            }\r
+            return false;\r
+        }\r
+\r
+        /// <summary>\r
+        /// Inserts the specified attribute as the first node in the collection.\r
+        /// </summary>\r
+        /// <param name="newAttribute">The attribute to insert. May not be null.</param>\r
+        /// <returns>The prepended attribute.</returns>\r
+        public HtmlAttribute Prepend(HtmlAttribute newAttribute)\r
+        {\r
+            Insert(0, newAttribute);\r
+            return newAttribute;\r
+        }\r
+\r
+        /// <summary>\r
+        /// Removes a given attribute from the list.\r
+        /// </summary>\r
+        /// <param name="attribute">The attribute to remove. May not be null.</param>\r
+        public void Remove(HtmlAttribute attribute)\r
+        {\r
+            if (attribute == null)\r
+            {\r
+                throw new ArgumentNullException("attribute");\r
+            }\r
+            int index = GetAttributeIndex(attribute);\r
+            if (index == -1)\r
+            {\r
+                throw new IndexOutOfRangeException();\r
+            }\r
+            RemoveAt(index);\r
+        }\r
+\r
+        /// <summary>\r
+        /// Removes an attribute from the list, using its name. If there are more than one attributes with this name, they will all be removed.\r
+        /// </summary>\r
+        /// <param name="name">The attribute's name. May not be null.</param>\r
+        public void Remove(string name)\r
+        {\r
+            if (name == null)\r
+            {\r
+                throw new ArgumentNullException("name");\r
+            }\r
+\r
+            string lname = name.ToLower();\r
+            for (int i = 0; i < items.Count; i++)\r
+            {\r
+                HtmlAttribute att = items[i];\r
+                if (att.Name == lname)\r
+                {\r
+                    RemoveAt(i);\r
+                }\r
+            }\r
+        }\r
+\r
+        /// <summary>\r
+        /// Remove all attributes in the list.\r
+        /// </summary>\r
+        public void RemoveAll()\r
+        {\r
+            Hashitems.Clear();\r
+            items.Clear();\r
+\r
+            _ownernode._innerchanged = true;\r
+            _ownernode._outerchanged = true;\r
+        }\r
+\r
+        #endregion\r
+\r
+        #region LINQ Methods\r
+\r
+        /// <summary>\r
+        /// Returns all attributes with specified name. Handles case insentivity\r
+        /// </summary>\r
+        /// <param name="attributeName">Name of the attribute</param>\r
+        /// <returns></returns>\r
+        public IEnumerable<HtmlAttribute> AttributesWithName(string attributeName)\r
+        {\r
+            attributeName = attributeName.ToLower();\r
+            for (int i = 0; i < items.Count; i++)\r
+            {\r
+                if (items[i].Name.Equals(attributeName))\r
+                    yield return items[i];\r
+            }\r
+        }\r
+\r
+        /// <summary>\r
+        /// Removes all attributes from the collection\r
+        /// </summary>\r
+        public void Remove()\r
+        {\r
+            foreach (HtmlAttribute item in items)\r
+                item.Remove();\r
+        }\r
+\r
+        #endregion\r
+\r
+        #region Internal Methods\r
+\r
+        /// <summary>\r
+        /// Clears the attribute collection\r
+        /// </summary>\r
+        internal void Clear()\r
+        {\r
+            Hashitems.Clear();\r
+            items.Clear();\r
+        }\r
+\r
+        internal int GetAttributeIndex(HtmlAttribute attribute)\r
+        {\r
+            if (attribute == null)\r
+            {\r
+                throw new ArgumentNullException("attribute");\r
+            }\r
+            for (int i = 0; i < items.Count; i++)\r
+            {\r
+                if ((items[i]) == attribute)\r
+                    return i;\r
+            }\r
+            return -1;\r
+        }\r
+\r
+        internal int GetAttributeIndex(string name)\r
+        {\r
+            if (name == null)\r
+            {\r
+                throw new ArgumentNullException("name");\r
+            }\r
+            string lname = name.ToLower();\r
+            for (int i = 0; i < items.Count; i++)\r
+            {\r
+                if ((items[i]).Name == lname)\r
+                    return i;\r
+            }\r
+            return -1;\r
+        }\r
+\r
+        #endregion\r
+    }\r
+}
\ No newline at end of file
diff --git a/docs/HtmlAgilityPack/HtmlCmdLine.cs b/docs/HtmlAgilityPack/HtmlCmdLine.cs
new file mode 100644 (file)
index 0000000..1421765
--- /dev/null
@@ -0,0 +1,142 @@
+// HtmlAgilityPack V1.0 - Simon Mourier <simon underscore mourier at hotmail dot com>\r
+using System;\r
+\r
+namespace HtmlAgilityPack\r
+{\r
+    internal class HtmlCmdLine\r
+    {\r
+        #region Static Members\r
+\r
+        internal static bool Help;\r
+\r
+        #endregion\r
+\r
+        #region Constructors\r
+\r
+        static HtmlCmdLine()\r
+        {\r
+            Help = false;\r
+            ParseArgs();\r
+        }\r
+\r
+        #endregion\r
+\r
+        #region Internal Methods\r
+\r
+        internal static string GetOption(string name, string def)\r
+        {\r
+            string p = def;\r
+            string[] args = Environment.GetCommandLineArgs();\r
+            for (int i = 1; i < args.Length; i++)\r
+            {\r
+                GetStringArg(args[i], name, ref p);\r
+            }\r
+            return p;\r
+        }\r
+\r
+        internal static string GetOption(int index, string def)\r
+        {\r
+            string p = def;\r
+            string[] args = Environment.GetCommandLineArgs();\r
+            int j = 0;\r
+            for (int i = 1; i < args.Length; i++)\r
+            {\r
+                if (GetStringArg(args[i], ref p))\r
+                {\r
+                    if (index == j)\r
+                        return p;\r
+                    else\r
+                        p = def;\r
+                    j++;\r
+                }\r
+            }\r
+            return p;\r
+        }\r
+\r
+        internal static bool GetOption(string name, bool def)\r
+        {\r
+            bool p = def;\r
+            string[] args = Environment.GetCommandLineArgs();\r
+            for (int i = 1; i < args.Length; i++)\r
+            {\r
+                GetBoolArg(args[i], name, ref p);\r
+            }\r
+            return p;\r
+        }\r
+\r
+        internal static int GetOption(string name, int def)\r
+        {\r
+            int p = def;\r
+            string[] args = Environment.GetCommandLineArgs();\r
+            for (int i = 1; i < args.Length; i++)\r
+            {\r
+                GetIntArg(args[i], name, ref p);\r
+            }\r
+            return p;\r
+        }\r
+\r
+        #endregion\r
+\r
+        #region Private Methods\r
+\r
+        private static void GetBoolArg(string Arg, string Name, ref bool ArgValue)\r
+        {\r
+            if (Arg.Length < (Name.Length + 1)) // -name is 1 more than name\r
+                return;\r
+            if (('/' != Arg[0]) && ('-' != Arg[0])) // not a param\r
+                return;\r
+            if (Arg.Substring(1, Name.Length).ToLower() == Name.ToLower())\r
+                ArgValue = true;\r
+        }\r
+\r
+        private static void GetIntArg(string Arg, string Name, ref int ArgValue)\r
+        {\r
+            if (Arg.Length < (Name.Length + 3)) // -name:12 is 3 more than name\r
+                return;\r
+            if (('/' != Arg[0]) && ('-' != Arg[0])) // not a param\r
+                return;\r
+            if (Arg.Substring(1, Name.Length).ToLower() == Name.ToLower())\r
+            {\r
+                try\r
+                {\r
+                    ArgValue = Convert.ToInt32(Arg.Substring(Name.Length + 2, Arg.Length - Name.Length - 2));\r
+                }\r
+                catch\r
+                {\r
+                }\r
+            }\r
+        }\r
+\r
+        private static bool GetStringArg(string Arg, ref string ArgValue)\r
+        {\r
+            if (('/' == Arg[0]) || ('-' == Arg[0]))\r
+                return false;\r
+            ArgValue = Arg;\r
+            return true;\r
+        }\r
+\r
+        private static void GetStringArg(string Arg, string Name, ref string ArgValue)\r
+        {\r
+            if (Arg.Length < (Name.Length + 3)) // -name:x is 3 more than name\r
+                return;\r
+            if (('/' != Arg[0]) && ('-' != Arg[0])) // not a param\r
+                return;\r
+            if (Arg.Substring(1, Name.Length).ToLower() == Name.ToLower())\r
+                ArgValue = Arg.Substring(Name.Length + 2, Arg.Length - Name.Length - 2);\r
+        }\r
+\r
+        private static void ParseArgs()\r
+        {\r
+            string[] args = Environment.GetCommandLineArgs();\r
+            for (int i = 1; i < args.Length; i++)\r
+            {\r
+                // help\r
+                GetBoolArg(args[i], "?", ref Help);\r
+                GetBoolArg(args[i], "h", ref Help);\r
+                GetBoolArg(args[i], "help", ref Help);\r
+            }\r
+        }\r
+\r
+        #endregion\r
+    }\r
+}
\ No newline at end of file
diff --git a/docs/HtmlAgilityPack/HtmlCommentNode.cs b/docs/HtmlAgilityPack/HtmlCommentNode.cs
new file mode 100644 (file)
index 0000000..1091dcb
--- /dev/null
@@ -0,0 +1,76 @@
+// HtmlAgilityPack V1.0 - Simon Mourier <simon underscore mourier at hotmail dot com>\r
+namespace HtmlAgilityPack\r
+{\r
+    /// <summary>\r
+    /// Represents an HTML comment.\r
+    /// </summary>\r
+    public class HtmlCommentNode : HtmlNode\r
+    {\r
+        #region Fields\r
+\r
+        private string _comment;\r
+\r
+        #endregion\r
+\r
+        #region Constructors\r
+\r
+        internal HtmlCommentNode(HtmlDocument ownerdocument, int index)\r
+            :\r
+                base(HtmlNodeType.Comment, ownerdocument, index)\r
+        {\r
+        }\r
+\r
+        #endregion\r
+\r
+        #region Properties\r
+\r
+        /// <summary>\r
+        /// Gets or Sets the comment text of the node.\r
+        /// </summary>\r
+        public string Comment\r
+        {\r
+            get\r
+            {\r
+                if (_comment == null)\r
+                {\r
+                    return base.InnerHtml;\r
+                }\r
+                return _comment;\r
+            }\r
+            set { _comment = value; }\r
+        }\r
+\r
+        /// <summary>\r
+        /// Gets or Sets the HTML between the start and end tags of the object. In the case of a text node, it is equals to OuterHtml.\r
+        /// </summary>\r
+        public override string InnerHtml\r
+        {\r
+            get\r
+            {\r
+                if (_comment == null)\r
+                {\r
+                    return base.InnerHtml;\r
+                }\r
+                return _comment;\r
+            }\r
+            set { _comment = value; }\r
+        }\r
+\r
+        /// <summary>\r
+        /// Gets or Sets the object and its content in HTML.\r
+        /// </summary>\r
+        public override string OuterHtml\r
+        {\r
+            get\r
+            {\r
+                if (_comment == null)\r
+                {\r
+                    return base.OuterHtml;\r
+                }\r
+                return "<!--" + _comment + "-->";\r
+            }\r
+        }\r
+\r
+        #endregion\r
+    }\r
+}
\ No newline at end of file
diff --git a/docs/HtmlAgilityPack/HtmlConsoleListener.cs b/docs/HtmlAgilityPack/HtmlConsoleListener.cs
new file mode 100644 (file)
index 0000000..bd14a7a
--- /dev/null
@@ -0,0 +1,33 @@
+// HtmlAgilityPack V1.0 - Simon Mourier <simon underscore mourier at hotmail dot com>\r
+using System;\r
+using System.Diagnostics;\r
+\r
+namespace HtmlAgilityPack\r
+{\r
+    internal class HtmlConsoleListener : TraceListener\r
+    {\r
+        #region Public Methods\r
+\r
+        public override void Write(string Message)\r
+        {\r
+            Write(Message, "");\r
+        }\r
+\r
+        public override void Write(string Message, string Category)\r
+        {\r
+            Console.Write("T:" + Category + ": " + Message);\r
+        }\r
+\r
+        public override void WriteLine(string Message)\r
+        {\r
+            Write(Message + "\n");\r
+        }\r
+\r
+        public override void WriteLine(string Message, string Category)\r
+        {\r
+            Write(Message + "\n", Category);\r
+        }\r
+\r
+        #endregion\r
+    }\r
+}
\ No newline at end of file
diff --git a/docs/HtmlAgilityPack/HtmlDocument.cs b/docs/HtmlAgilityPack/HtmlDocument.cs
new file mode 100644 (file)
index 0000000..7233da0
--- /dev/null
@@ -0,0 +1,1962 @@
+// HtmlAgilityPack V1.0 - Simon Mourier <simon underscore mourier at hotmail dot com>\r
+using System;\r
+using System.Collections;\r
+using System.Collections.Generic;\r
+using System.IO;\r
+using System.Text;\r
+using System.Text.RegularExpressions;\r
+using System.Xml;\r
+using System.Xml.XPath;\r
+\r
+namespace HtmlAgilityPack\r
+{\r
+    /// <summary>\r
+    /// Represents a complete HTML document.\r
+    /// </summary>\r
+    public class HtmlDocument : IXPathNavigable\r
+    {\r
+        #region Fields\r
+\r
+        private int _c;\r
+        private Crc32 _crc32;\r
+        private HtmlAttribute _currentattribute;\r
+        private HtmlNode _currentnode;\r
+        private Encoding _declaredencoding;\r
+        private HtmlNode _documentnode;\r
+        private bool _fullcomment;\r
+        private int _index;\r
+        internal Hashtable _lastnodes = new Hashtable();\r
+        private HtmlNode _lastparentnode;\r
+        private int _line;\r
+        private int _lineposition, _maxlineposition;\r
+        internal Hashtable _nodesid;\r
+        private ParseState _oldstate;\r
+        private bool _onlyDetectEncoding;\r
+        internal Hashtable _openednodes;\r
+        private List<HtmlParseError> _parseerrors = new List<HtmlParseError>();\r
+        private string _remainder;\r
+        private int _remainderOffset;\r
+        private ParseState _state;\r
+        private Encoding _streamencoding;\r
+        internal string _text;\r
+\r
+        // public props\r
+\r
+        /// <summary>\r
+        /// Adds Debugging attributes to node. Default is false.\r
+        /// </summary>\r
+        public bool OptionAddDebuggingAttributes;\r
+\r
+        /// <summary>\r
+        /// Defines if closing for non closed nodes must be done at the end or directly in the document.\r
+        /// Setting this to true can actually change how browsers render the page. Default is false.\r
+        /// </summary>\r
+        public bool OptionAutoCloseOnEnd; // close errors at the end\r
+\r
+        /// <summary>\r
+        /// Defines if non closed nodes will be checked at the end of parsing. Default is true.\r
+        /// </summary>\r
+        public bool OptionCheckSyntax = true;\r
+\r
+        /// <summary>\r
+        /// Defines if a checksum must be computed for the document while parsing. Default is false.\r
+        /// </summary>\r
+        public bool OptionComputeChecksum;\r
+\r
+        /// <summary>\r
+        /// Defines the default stream encoding to use. Default is System.Text.Encoding.Default.\r
+        /// </summary>\r
+        public Encoding OptionDefaultStreamEncoding = Encoding.Default;\r
+\r
+        /// <summary>\r
+        /// Defines if source text must be extracted while parsing errors.\r
+        /// If the document has a lot of errors, or cascading errors, parsing performance can be dramatically affected if set to true.\r
+        /// Default is false.\r
+        /// </summary>\r
+        public bool OptionExtractErrorSourceText;\r
+\r
+        // turning this on can dramatically slow performance if a lot of errors are detected\r
+\r
+        /// <summary>\r
+        /// Defines the maximum length of source text or parse errors. Default is 100.\r
+        /// </summary>\r
+        public int OptionExtractErrorSourceTextMaxLength = 100;\r
+\r
+        /// <summary>\r
+        /// Defines if LI, TR, TH, TD tags must be partially fixed when nesting errors are detected. Default is false.\r
+        /// </summary>\r
+        public bool OptionFixNestedTags; // fix li, tr, th, td tags\r
+\r
+        /// <summary>\r
+        /// Defines if output must conform to XML, instead of HTML.\r
+        /// </summary>\r
+        public bool OptionOutputAsXml;\r
+\r
+        /// <summary>\r
+        /// Defines if attribute value output must be optimized (not bound with double quotes if it is possible). Default is false.\r
+        /// </summary>\r
+        public bool OptionOutputOptimizeAttributeValues;\r
+\r
+        /// <summary>\r
+        /// Defines if name must be output with it's original case. Useful for asp.net tags and attributes\r
+        /// </summary>\r
+        public bool OptionOutputOriginalCase;\r
+\r
+        /// <summary>\r
+        /// Defines if name must be output in uppercase. Default is false.\r
+        /// </summary>\r
+        public bool OptionOutputUpperCase;\r
+\r
+        /// <summary>\r
+        /// Defines if declared encoding must be read from the document.\r
+        /// Declared encoding is determined using the meta http-equiv="content-type" content="text/html;charset=XXXXX" html node.\r
+        /// Default is true.\r
+        /// </summary>\r
+        public bool OptionReadEncoding = true;\r
+\r
+        /// <summary>\r
+        /// Defines the name of a node that will throw the StopperNodeException when found as an end node. Default is null.\r
+        /// </summary>\r
+        public string OptionStopperNodeName;\r
+\r
+        /// <summary>\r
+        /// Defines if the 'id' attribute must be specifically used. Default is true.\r
+        /// </summary>\r
+        public bool OptionUseIdAttribute = true;\r
+\r
+        /// <summary>\r
+        /// Defines if empty nodes must be written as closed during output. Default is false.\r
+        /// </summary>\r
+        public bool OptionWriteEmptyNodes;\r
+\r
+        #endregion\r
+\r
+        #region Static Members\r
+\r
+        internal static readonly string HtmlExceptionRefNotChild = "Reference node must be a child of this node";\r
+\r
+        internal static readonly string HtmlExceptionUseIdAttributeFalse =\r
+            "You need to set UseIdAttribute property to true to enable this feature";\r
+\r
+        #endregion\r
+\r
+        #region Constructors\r
+\r
+        /// <summary>\r
+        /// Creates an instance of an HTML document.\r
+        /// </summary>\r
+        public HtmlDocument()\r
+        {\r
+            _documentnode = CreateNode(HtmlNodeType.Document, 0);\r
+        }\r
+\r
+        #endregion\r
+\r
+        #region Properties\r
+\r
+        /// <summary>\r
+        /// Gets the document CRC32 checksum if OptionComputeChecksum was set to true before parsing, 0 otherwise.\r
+        /// </summary>\r
+        public int CheckSum\r
+        {\r
+            get\r
+            {\r
+                if (_crc32 == null)\r
+                {\r
+                    return 0;\r
+                }\r
+                else\r
+                {\r
+                    return (int) _crc32.CheckSum;\r
+                }\r
+            }\r
+        }\r
+\r
+        /// <summary>\r
+        /// Gets the document's declared encoding.\r
+        /// Declared encoding is determined using the meta http-equiv="content-type" content="text/html;charset=XXXXX" html node.\r
+        /// </summary>\r
+        public Encoding DeclaredEncoding\r
+        {\r
+            get { return _declaredencoding; }\r
+        }\r
+\r
+        /// <summary>\r
+        /// Gets the root node of the document.\r
+        /// </summary>\r
+        public HtmlNode DocumentNode\r
+        {\r
+            get { return _documentnode; }\r
+        }\r
+\r
+        /// <summary>\r
+        /// Gets the document's output encoding.\r
+        /// </summary>\r
+        public Encoding Encoding\r
+        {\r
+            get { return GetOutEncoding(); }\r
+        }\r
+\r
+        /// <summary>\r
+        /// Gets a list of parse errors found in the document.\r
+        /// </summary>\r
+        public IEnumerable<HtmlParseError> ParseErrors\r
+        {\r
+            get { return _parseerrors; }\r
+        }\r
+\r
+        /// <summary>\r
+        /// Gets the remaining text.\r
+        /// Will always be null if OptionStopperNodeName is null.\r
+        /// </summary>\r
+        public string Remainder\r
+        {\r
+            get { return _remainder; }\r
+        }\r
+\r
+        /// <summary>\r
+        /// Gets the offset of Remainder in the original Html text.\r
+        /// If OptionStopperNodeName is null, this will return the length of the original Html text.\r
+        /// </summary>\r
+        public int RemainderOffset\r
+        {\r
+            get { return _remainderOffset; }\r
+        }\r
+\r
+        /// <summary>\r
+        /// Gets the document's stream encoding.\r
+        /// </summary>\r
+        public Encoding StreamEncoding\r
+        {\r
+            get { return _streamencoding; }\r
+        }\r
+\r
+        #endregion\r
+\r
+        #region IXPathNavigable Members\r
+\r
+        /// <summary>\r
+        /// Creates a new XPathNavigator object for navigating this HTML document.\r
+        /// </summary>\r
+        /// <returns>An XPathNavigator object. The XPathNavigator is positioned on the root of the document.</returns>\r
+        public XPathNavigator CreateNavigator()\r
+        {\r
+            return new HtmlNodeNavigator(this, _documentnode);\r
+        }\r
+\r
+        #endregion\r
+\r
+        #region Public Methods\r
+\r
+        /// <summary>\r
+        /// Gets a valid XML name.\r
+        /// </summary>\r
+        /// <param name="name">Any text.</param>\r
+        /// <returns>A string that is a valid XML name.</returns>\r
+        public static string GetXmlName(string name)\r
+        {\r
+            string xmlname = string.Empty;\r
+            bool nameisok = true;\r
+            for (int i = 0; i < name.Length; i++)\r
+            {\r
+                // names are lcase\r
+                // note: we are very limited here, too much?\r
+                if (((name[i] >= 'a') && (name[i] <= 'z')) ||\r
+                    ((name[i] >= '0') && (name[i] <= '9')) ||\r
+                    //                                 (name[i]==':') || (name[i]=='_') || (name[i]=='-') || (name[i]=='.')) // these are bads in fact\r
+                    (name[i] == '_') || (name[i] == '-') || (name[i] == '.'))\r
+                {\r
+                    xmlname += name[i];\r
+                }\r
+                else\r
+                {\r
+                    nameisok = false;\r
+                    byte[] bytes = Encoding.UTF8.GetBytes(new char[] {name[i]});\r
+                    for (int j = 0; j < bytes.Length; j++)\r
+                    {\r
+                        xmlname += bytes[j].ToString("x2");\r
+                    }\r
+                    xmlname += "_";\r
+                }\r
+            }\r
+            if (nameisok)\r
+            {\r
+                return xmlname;\r
+            }\r
+            return "_" + xmlname;\r
+        }\r
+\r
+        /// <summary>\r
+        /// Applies HTML encoding to a specified string.\r
+        /// </summary>\r
+        /// <param name="html">The input string to encode. May not be null.</param>\r
+        /// <returns>The encoded string.</returns>\r
+        public static string HtmlEncode(string html)\r
+        {\r
+            if (html == null)\r
+            {\r
+                throw new ArgumentNullException("html");\r
+            }\r
+            // replace & by &amp; but only once!\r
+            Regex rx = new Regex("&(?!(amp;)|(lt;)|(gt;)|(quot;))", RegexOptions.IgnoreCase);\r
+            return rx.Replace(html, "&amp;").Replace("<", "&lt;").Replace(">", "&gt;").Replace("\"", "&quot;");\r
+        }\r
+\r
+        /// <summary>\r
+        /// Determines if the specified character is considered as a whitespace character.\r
+        /// </summary>\r
+        /// <param name="c">The character to check.</param>\r
+        /// <returns>true if if the specified character is considered as a whitespace character.</returns>\r
+        public static bool IsWhiteSpace(int c)\r
+        {\r
+            if ((c == 10) || (c == 13) || (c == 32) || (c == 9))\r
+            {\r
+                return true;\r
+            }\r
+            return false;\r
+        }\r
+\r
+        /// <summary>\r
+        /// Creates an HTML attribute with the specified name.\r
+        /// </summary>\r
+        /// <param name="name">The name of the attribute. May not be null.</param>\r
+        /// <returns>The new HTML attribute.</returns>\r
+        public HtmlAttribute CreateAttribute(string name)\r
+        {\r
+            if (name == null)\r
+            {\r
+                throw new ArgumentNullException("name");\r
+            }\r
+            HtmlAttribute att = CreateAttribute();\r
+            att.Name = name;\r
+            return att;\r
+        }\r
+\r
+        /// <summary>\r
+        /// Creates an HTML attribute with the specified name.\r
+        /// </summary>\r
+        /// <param name="name">The name of the attribute. May not be null.</param>\r
+        /// <param name="value">The value of the attribute.</param>\r
+        /// <returns>The new HTML attribute.</returns>\r
+        public HtmlAttribute CreateAttribute(string name, string value)\r
+        {\r
+            if (name == null)\r
+            {\r
+                throw new ArgumentNullException("name");\r
+            }\r
+            HtmlAttribute att = CreateAttribute(name);\r
+            att.Value = value;\r
+            return att;\r
+        }\r
+\r
+        /// <summary>\r
+        /// Creates an HTML comment node.\r
+        /// </summary>\r
+        /// <returns>The new HTML comment node.</returns>\r
+        public HtmlCommentNode CreateComment()\r
+        {\r
+            return (HtmlCommentNode) CreateNode(HtmlNodeType.Comment);\r
+        }\r
+\r
+        /// <summary>\r
+        /// Creates an HTML comment node with the specified comment text.\r
+        /// </summary>\r
+        /// <param name="comment">The comment text. May not be null.</param>\r
+        /// <returns>The new HTML comment node.</returns>\r
+        public HtmlCommentNode CreateComment(string comment)\r
+        {\r
+            if (comment == null)\r
+            {\r
+                throw new ArgumentNullException("comment");\r
+            }\r
+            HtmlCommentNode c = CreateComment();\r
+            c.Comment = comment;\r
+            return c;\r
+        }\r
+\r
+        /// <summary>\r
+        /// Creates an HTML element node with the specified name.\r
+        /// </summary>\r
+        /// <param name="name">The qualified name of the element. May not be null.</param>\r
+        /// <returns>The new HTML node.</returns>\r
+        public HtmlNode CreateElement(string name)\r
+        {\r
+            if (name == null)\r
+            {\r
+                throw new ArgumentNullException("name");\r
+            }\r
+            HtmlNode node = CreateNode(HtmlNodeType.Element);\r
+            node.Name = name;\r
+            return node;\r
+        }\r
+\r
+        /// <summary>\r
+        /// Creates an HTML text node.\r
+        /// </summary>\r
+        /// <returns>The new HTML text node.</returns>\r
+        public HtmlTextNode CreateTextNode()\r
+        {\r
+            return (HtmlTextNode) CreateNode(HtmlNodeType.Text);\r
+        }\r
+\r
+        /// <summary>\r
+        /// Creates an HTML text node with the specified text.\r
+        /// </summary>\r
+        /// <param name="text">The text of the node. May not be null.</param>\r
+        /// <returns>The new HTML text node.</returns>\r
+        public HtmlTextNode CreateTextNode(string text)\r
+        {\r
+            if (text == null)\r
+            {\r
+                throw new ArgumentNullException("text");\r
+            }\r
+            HtmlTextNode t = CreateTextNode();\r
+            t.Text = text;\r
+            return t;\r
+        }\r
+\r
+        /// <summary>\r
+        /// Detects the encoding of an HTML stream.\r
+        /// </summary>\r
+        /// <param name="stream">The input stream. May not be null.</param>\r
+        /// <returns>The detected encoding.</returns>\r
+        public Encoding DetectEncoding(Stream stream)\r
+        {\r
+            if (stream == null)\r
+            {\r
+                throw new ArgumentNullException("stream");\r
+            }\r
+            return DetectEncoding(new StreamReader(stream));\r
+        }\r
+\r
+        /// <summary>\r
+        /// Detects the encoding of an HTML file.\r
+        /// </summary>\r
+        /// <param name="path">Path for the file containing the HTML document to detect. May not be null.</param>\r
+        /// <returns>The detected encoding.</returns>\r
+        public Encoding DetectEncoding(string path)\r
+        {\r
+            if (path == null)\r
+            {\r
+                throw new ArgumentNullException("path");\r
+            }\r
+            StreamReader sr = new StreamReader(path, OptionDefaultStreamEncoding);\r
+            Encoding encoding = DetectEncoding(sr);\r
+            sr.Close();\r
+            return encoding;\r
+        }\r
+\r
+        /// <summary>\r
+        /// Detects the encoding of an HTML text provided on a TextReader.\r
+        /// </summary>\r
+        /// <param name="reader">The TextReader used to feed the HTML. May not be null.</param>\r
+        /// <returns>The detected encoding.</returns>\r
+        public Encoding DetectEncoding(TextReader reader)\r
+        {\r
+            if (reader == null)\r
+            {\r
+                throw new ArgumentNullException("reader");\r
+            }\r
+            _onlyDetectEncoding = true;\r
+            if (OptionCheckSyntax)\r
+            {\r
+                _openednodes = new Hashtable();\r
+            }\r
+            else\r
+            {\r
+                _openednodes = null;\r
+            }\r
+\r
+            if (OptionUseIdAttribute)\r
+            {\r
+                _nodesid = new Hashtable();\r
+            }\r
+            else\r
+            {\r
+                _nodesid = null;\r
+            }\r
+\r
+            StreamReader sr = reader as StreamReader;\r
+            if (sr != null)\r
+            {\r
+                _streamencoding = sr.CurrentEncoding;\r
+            }\r
+            else\r
+            {\r
+                _streamencoding = null;\r
+            }\r
+            _declaredencoding = null;\r
+\r
+            _text = reader.ReadToEnd();\r
+            _documentnode = CreateNode(HtmlNodeType.Document, 0);\r
+\r
+            // this is almost a hack, but it allows us not to muck with the original parsing code\r
+            try\r
+            {\r
+                Parse();\r
+            }\r
+            catch (EncodingFoundException ex)\r
+            {\r
+                return ex.Encoding;\r
+            }\r
+            return null;\r
+        }\r
+\r
+        /// <summary>\r
+        /// Detects the encoding of an HTML document from a file first, and then loads the file.\r
+        /// </summary>\r
+        /// <param name="path">The complete file path to be read.</param>\r
+        public void DetectEncodingAndLoad(string path)\r
+        {\r
+            DetectEncodingAndLoad(path, true);\r
+        }\r
+\r
+        /// <summary>\r
+        /// Detects the encoding of an HTML document from a file first, and then loads the file.\r
+        /// </summary>\r
+        /// <param name="path">The complete file path to be read. May not be null.</param>\r
+        /// <param name="detectEncoding">true to detect encoding, false otherwise.</param>\r
+        public void DetectEncodingAndLoad(string path, bool detectEncoding)\r
+        {\r
+            if (path == null)\r
+            {\r
+                throw new ArgumentNullException("path");\r
+            }\r
+            Encoding enc;\r
+            if (detectEncoding)\r
+            {\r
+                enc = DetectEncoding(path);\r
+            }\r
+            else\r
+            {\r
+                enc = null;\r
+            }\r
+\r
+            if (enc == null)\r
+            {\r
+                Load(path);\r
+            }\r
+            else\r
+            {\r
+                Load(path, enc);\r
+            }\r
+        }\r
+\r
+        /// <summary>\r
+        /// Detects the encoding of an HTML text.\r
+        /// </summary>\r
+        /// <param name="html">The input html text. May not be null.</param>\r
+        /// <returns>The detected encoding.</returns>\r
+        public Encoding DetectEncodingHtml(string html)\r
+        {\r
+            if (html == null)\r
+            {\r
+                throw new ArgumentNullException("html");\r
+            }\r
+            StringReader sr = new StringReader(html);\r
+            Encoding encoding = DetectEncoding(sr);\r
+            sr.Close();\r
+            return encoding;\r
+        }\r
+\r
+        /// <summary>\r
+        /// Gets the HTML node with the specified 'id' attribute value.\r
+        /// </summary>\r
+        /// <param name="id">The attribute id to match. May not be null.</param>\r
+        /// <returns>The HTML node with the matching id or null if not found.</returns>\r
+        public HtmlNode GetElementbyId(string id)\r
+        {\r
+            if (id == null)\r
+            {\r
+                throw new ArgumentNullException("id");\r
+            }\r
+            if (_nodesid == null)\r
+            {\r
+                throw new Exception(HtmlExceptionUseIdAttributeFalse);\r
+            }\r
+\r
+            return _nodesid[id.ToLower()] as HtmlNode;\r
+        }\r
+\r
+        /// <summary>\r
+        /// Loads an HTML document from a stream.\r
+        /// </summary>\r
+        /// <param name="stream">The input stream.</param>\r
+        public void Load(Stream stream)\r
+        {\r
+            Load(new StreamReader(stream, OptionDefaultStreamEncoding));\r
+        }\r
+\r
+        /// <summary>\r
+        /// Loads an HTML document from a stream.\r
+        /// </summary>\r
+        /// <param name="stream">The input stream.</param>\r
+        /// <param name="detectEncodingFromByteOrderMarks">Indicates whether to look for byte order marks at the beginning of the stream.</param>\r
+        public void Load(Stream stream, bool detectEncodingFromByteOrderMarks)\r
+        {\r
+            Load(new StreamReader(stream, detectEncodingFromByteOrderMarks));\r
+        }\r
+\r
+        /// <summary>\r
+        /// Loads an HTML document from a stream.\r
+        /// </summary>\r
+        /// <param name="stream">The input stream.</param>\r
+        /// <param name="encoding">The character encoding to use.</param>\r
+        public void Load(Stream stream, Encoding encoding)\r
+        {\r
+            Load(new StreamReader(stream, encoding));\r
+        }\r
+\r
+        /// <summary>\r
+        /// Loads an HTML document from a stream.\r
+        /// </summary>\r
+        /// <param name="stream">The input stream.</param>\r
+        /// <param name="encoding">The character encoding to use.</param>\r
+        /// <param name="detectEncodingFromByteOrderMarks">Indicates whether to look for byte order marks at the beginning of the stream.</param>\r
+        public void Load(Stream stream, Encoding encoding, bool detectEncodingFromByteOrderMarks)\r
+        {\r
+            Load(new StreamReader(stream, encoding, detectEncodingFromByteOrderMarks));\r
+        }\r
+\r
+        /// <summary>\r
+        /// Loads an HTML document from a stream.\r
+        /// </summary>\r
+        /// <param name="stream">The input stream.</param>\r
+        /// <param name="encoding">The character encoding to use.</param>\r
+        /// <param name="detectEncodingFromByteOrderMarks">Indicates whether to look for byte order marks at the beginning of the stream.</param>\r
+        /// <param name="buffersize">The minimum buffer size.</param>\r
+        public void Load(Stream stream, Encoding encoding, bool detectEncodingFromByteOrderMarks, int buffersize)\r
+        {\r
+            Load(new StreamReader(stream, encoding, detectEncodingFromByteOrderMarks, buffersize));\r
+        }\r
+\r
+        /// <summary>\r
+        /// Loads an HTML document from a file.\r
+        /// </summary>\r
+        /// <param name="path">The complete file path to be read. May not be null.</param>\r
+        public void Load(string path)\r
+        {\r
+            if (path == null)\r
+            {\r
+                throw new ArgumentNullException("path");\r
+            }\r
+            StreamReader sr = new StreamReader(path, OptionDefaultStreamEncoding);\r
+            Load(sr);\r
+            sr.Close();\r
+        }\r
+\r
+        /// <summary>\r
+        /// Loads an HTML document from a file.\r
+        /// </summary>\r
+        /// <param name="path">The complete file path to be read. May not be null.</param>\r
+        /// <param name="detectEncodingFromByteOrderMarks">Indicates whether to look for byte order marks at the beginning of the file.</param>\r
+        public void Load(string path, bool detectEncodingFromByteOrderMarks)\r
+        {\r
+            if (path == null)\r
+            {\r
+                throw new ArgumentNullException("path");\r
+            }\r
+            StreamReader sr = new StreamReader(path, detectEncodingFromByteOrderMarks);\r
+            Load(sr);\r
+            sr.Close();\r
+        }\r
+\r
+        /// <summary>\r
+        /// Loads an HTML document from a file.\r
+        /// </summary>\r
+        /// <param name="path">The complete file path to be read. May not be null.</param>\r
+        /// <param name="encoding">The character encoding to use. May not be null.</param>\r
+        public void Load(string path, Encoding encoding)\r
+        {\r
+            if (path == null)\r
+            {\r
+                throw new ArgumentNullException("path");\r
+            }\r
+            if (encoding == null)\r
+            {\r
+                throw new ArgumentNullException("encoding");\r
+            }\r
+            StreamReader sr = new StreamReader(path, encoding);\r
+            Load(sr);\r
+            sr.Close();\r
+        }\r
+\r
+        /// <summary>\r
+        /// Loads an HTML document from a file.\r
+        /// </summary>\r
+        /// <param name="path">The complete file path to be read. May not be null.</param>\r
+        /// <param name="encoding">The character encoding to use. May not be null.</param>\r
+        /// <param name="detectEncodingFromByteOrderMarks">Indicates whether to look for byte order marks at the beginning of the file.</param>\r
+        public void Load(string path, Encoding encoding, bool detectEncodingFromByteOrderMarks)\r
+        {\r
+            if (path == null)\r
+            {\r
+                throw new ArgumentNullException("path");\r
+            }\r
+            if (encoding == null)\r
+            {\r
+                throw new ArgumentNullException("encoding");\r
+            }\r
+            StreamReader sr = new StreamReader(path, encoding, detectEncodingFromByteOrderMarks);\r
+            Load(sr);\r
+            sr.Close();\r
+        }\r
+\r
+        /// <summary>\r
+        /// Loads an HTML document from a file.\r
+        /// </summary>\r
+        /// <param name="path">The complete file path to be read. May not be null.</param>\r
+        /// <param name="encoding">The character encoding to use. May not be null.</param>\r
+        /// <param name="detectEncodingFromByteOrderMarks">Indicates whether to look for byte order marks at the beginning of the file.</param>\r
+        /// <param name="buffersize">The minimum buffer size.</param>\r
+        public void Load(string path, Encoding encoding, bool detectEncodingFromByteOrderMarks, int buffersize)\r
+        {\r
+            if (path == null)\r
+            {\r
+                throw new ArgumentNullException("path");\r
+            }\r
+            if (encoding == null)\r
+            {\r
+                throw new ArgumentNullException("encoding");\r
+            }\r
+            StreamReader sr = new StreamReader(path, encoding, detectEncodingFromByteOrderMarks, buffersize);\r
+            Load(sr);\r
+            sr.Close();\r
+        }\r
+\r
+        /// <summary>\r
+        /// Loads the HTML document from the specified TextReader.\r
+        /// </summary>\r
+        /// <param name="reader">The TextReader used to feed the HTML data into the document. May not be null.</param>\r
+        public void Load(TextReader reader)\r
+        {\r
+            // all Load methods pass down to this one\r
+            if (reader == null)\r
+            {\r
+                throw new ArgumentNullException("reader");\r
+            }\r
+\r
+            _onlyDetectEncoding = false;\r
+\r
+            if (OptionCheckSyntax)\r
+            {\r
+                _openednodes = new Hashtable();\r
+            }\r
+            else\r
+            {\r
+                _openednodes = null;\r
+            }\r
+\r
+            if (OptionUseIdAttribute)\r
+            {\r
+                _nodesid = new Hashtable();\r
+            }\r
+            else\r
+            {\r
+                _nodesid = null;\r
+            }\r
+\r
+            StreamReader sr = reader as StreamReader;\r
+            if (sr != null)\r
+            {\r
+                try\r
+                {\r
+                    // trigger bom read if needed\r
+                    sr.Peek();\r
+                }\r
+                    // ReSharper disable EmptyGeneralCatchClause\r
+                catch (Exception)\r
+                    // ReSharper restore EmptyGeneralCatchClause\r
+                {\r
+                    // void on purpose\r
+                }\r
+                _streamencoding = sr.CurrentEncoding;\r
+            }\r
+            else\r
+            {\r
+                _streamencoding = null;\r
+            }\r
+            _declaredencoding = null;\r
+\r
+            _text = reader.ReadToEnd();\r
+            _documentnode = CreateNode(HtmlNodeType.Document, 0);\r
+            Parse();\r
+\r
+            if (OptionCheckSyntax)\r
+            {\r
+                foreach (HtmlNode node in _openednodes.Values)\r
+                {\r
+                    if (!node._starttag) // already reported\r
+                    {\r
+                        continue;\r
+                    }\r
+\r
+                    string html;\r
+                    if (OptionExtractErrorSourceText)\r
+                    {\r
+                        html = node.OuterHtml;\r
+                        if (html.Length > OptionExtractErrorSourceTextMaxLength)\r
+                        {\r
+                            html = html.Substring(0, OptionExtractErrorSourceTextMaxLength);\r
+                        }\r
+                    }\r
+                    else\r
+                    {\r
+                        html = string.Empty;\r
+                    }\r
+                    AddError(\r
+                        HtmlParseErrorCode.TagNotClosed,\r
+                        node._line, node._lineposition,\r
+                        node._streamposition, html,\r
+                        "End tag </" + node.Name + "> was not found");\r
+                }\r
+\r
+                // we don't need this anymore\r
+                _openednodes.Clear();\r
+            }\r
+        }\r
+\r
+        /// <summary>\r
+        /// Loads the HTML document from the specified string.\r
+        /// </summary>\r
+        /// <param name="html">String containing the HTML document to load. May not be null.</param>\r
+        public void LoadHtml(string html)\r
+        {\r
+            if (html == null)\r
+            {\r
+                throw new ArgumentNullException("html");\r
+            }\r
+            StringReader sr = new StringReader(html);\r
+            Load(sr);\r
+            sr.Close();\r
+        }\r
+\r
+        /// <summary>\r
+        /// Saves the HTML document to the specified stream.\r
+        /// </summary>\r
+        /// <param name="outStream">The stream to which you want to save.</param>\r
+        public void Save(Stream outStream)\r
+        {\r
+            StreamWriter sw = new StreamWriter(outStream, GetOutEncoding());\r
+            Save(sw);\r
+        }\r
+\r
+        /// <summary>\r
+        /// Saves the HTML document to the specified stream.\r
+        /// </summary>\r
+        /// <param name="outStream">The stream to which you want to save. May not be null.</param>\r
+        /// <param name="encoding">The character encoding to use. May not be null.</param>\r
+        public void Save(Stream outStream, Encoding encoding)\r
+        {\r
+            if (outStream == null)\r
+            {\r
+                throw new ArgumentNullException("outStream");\r
+            }\r
+            if (encoding == null)\r
+            {\r
+                throw new ArgumentNullException("encoding");\r
+            }\r
+            StreamWriter sw = new StreamWriter(outStream, encoding);\r
+            Save(sw);\r
+        }\r
+\r
+        /// <summary>\r
+        /// Saves the mixed document to the specified file.\r
+        /// </summary>\r
+        /// <param name="filename">The location of the file where you want to save the document.</param>\r
+        public void Save(string filename)\r
+        {\r
+            StreamWriter sw = new StreamWriter(filename, false, GetOutEncoding());\r
+            Save(sw);\r
+            sw.Close();\r
+        }\r
+\r
+        /// <summary>\r
+        /// Saves the mixed document to the specified file.\r
+        /// </summary>\r
+        /// <param name="filename">The location of the file where you want to save the document. May not be null.</param>\r
+        /// <param name="encoding">The character encoding to use. May not be null.</param>\r
+        public void Save(string filename, Encoding encoding)\r
+        {\r
+            if (filename == null)\r
+            {\r
+                throw new ArgumentNullException("filename");\r
+            }\r
+            if (encoding == null)\r
+            {\r
+                throw new ArgumentNullException("encoding");\r
+            }\r
+            StreamWriter sw = new StreamWriter(filename, false, encoding);\r
+            Save(sw);\r
+            sw.Close();\r
+        }\r
+\r
+        /// <summary>\r
+        /// Saves the HTML document to the specified StreamWriter.\r
+        /// </summary>\r
+        /// <param name="writer">The StreamWriter to which you want to save.</param>\r
+        public void Save(StreamWriter writer)\r
+        {\r
+            Save((TextWriter) writer);\r
+        }\r
+\r
+        /// <summary>\r
+        /// Saves the HTML document to the specified TextWriter.\r
+        /// </summary>\r
+        /// <param name="writer">The TextWriter to which you want to save. May not be null.</param>\r
+        public void Save(TextWriter writer)\r
+        {\r
+            if (writer == null)\r
+            {\r
+                throw new ArgumentNullException("writer");\r
+            }\r
+            DocumentNode.WriteTo(writer);\r
+        }\r
+\r
+        /// <summary>\r
+        /// Saves the HTML document to the specified XmlWriter.\r
+        /// </summary>\r
+        /// <param name="writer">The XmlWriter to which you want to save.</param>\r
+        public void Save(XmlWriter writer)\r
+        {\r
+            DocumentNode.WriteTo(writer);\r
+            writer.Flush();\r
+        }\r
+\r
+        #endregion\r
+\r
+        #region Internal Methods\r
+\r
+        internal HtmlAttribute CreateAttribute()\r
+        {\r
+            return new HtmlAttribute(this);\r
+        }\r
+\r
+        internal HtmlNode CreateNode(HtmlNodeType type)\r
+        {\r
+            return CreateNode(type, -1);\r
+        }\r
+\r
+        internal HtmlNode CreateNode(HtmlNodeType type, int index)\r
+        {\r
+            switch (type)\r
+            {\r
+                case HtmlNodeType.Comment:\r
+                    return new HtmlCommentNode(this, index);\r
+\r
+                case HtmlNodeType.Text:\r
+                    return new HtmlTextNode(this, index);\r
+\r
+                default:\r
+                    return new HtmlNode(type, this, index);\r
+            }\r
+        }\r
+\r
+        internal Encoding GetOutEncoding()\r
+        {\r
+            // when unspecified, use the stream encoding first\r
+            if (_declaredencoding != null)\r
+            {\r
+                return _declaredencoding;\r
+            }\r
+            else\r
+            {\r
+                if (_streamencoding != null)\r
+                {\r
+                    return _streamencoding;\r
+                }\r
+            }\r
+            return OptionDefaultStreamEncoding;\r
+        }\r
+\r
+        internal HtmlNode GetXmlDeclaration()\r
+        {\r
+            if (!_documentnode.HasChildNodes)\r
+            {\r
+                return null;\r
+            }\r
+\r
+            foreach (HtmlNode node in _documentnode._childnodes)\r
+            {\r
+                if (node.Name == "?xml") // it's ok, names are case sensitive\r
+                {\r
+                    return node;\r
+                }\r
+            }\r
+            return null;\r
+        }\r
+\r
+        internal void SetIdForNode(HtmlNode node, string id)\r
+        {\r
+            if (!OptionUseIdAttribute)\r
+            {\r
+                return;\r
+            }\r
+\r
+            if ((_nodesid == null) || (id == null))\r
+            {\r
+                return;\r
+            }\r
+\r
+            if (node == null)\r
+            {\r
+                _nodesid.Remove(id.ToLower());\r
+            }\r
+            else\r
+            {\r
+                _nodesid[id.ToLower()] = node;\r
+            }\r
+        }\r
+\r
+        internal void UpdateLastParentNode()\r
+        {\r
+            do\r
+            {\r
+                if (_lastparentnode.Closed)\r
+                {\r
+                    _lastparentnode = _lastparentnode.ParentNode;\r
+                }\r
+            } while ((_lastparentnode != null) && (_lastparentnode.Closed));\r
+            if (_lastparentnode == null)\r
+            {\r
+                _lastparentnode = _documentnode;\r
+            }\r
+        }\r
+\r
+        #endregion\r
+\r
+        #region Private Methods\r
+\r
+        private HtmlParseError AddError(\r
+            HtmlParseErrorCode code,\r
+            int line,\r
+            int linePosition,\r
+            int streamPosition,\r
+            string sourceText,\r
+            string reason)\r
+        {\r
+            HtmlParseError err = new HtmlParseError(code, line, linePosition, streamPosition, sourceText, reason);\r
+            _parseerrors.Add(err);\r
+            return err;\r
+        }\r
+\r
+        private void CloseCurrentNode()\r
+        {\r
+            if (_currentnode.Closed) // text or document are by def closed\r
+                return;\r
+\r
+            bool error = false;\r
+\r
+            // find last node of this kind\r
+            HtmlNode prev = (HtmlNode) _lastnodes[_currentnode.Name];\r
+            if (prev == null)\r
+            {\r
+                if (HtmlNode.IsClosedElement(_currentnode.Name))\r
+                {\r
+                    // </br> will be seen as <br>\r
+                    _currentnode.CloseNode(_currentnode);\r
+\r
+                    // add to parent node\r
+                    if (_lastparentnode != null)\r
+                    {\r
+                        HtmlNode foundNode = null;\r
+                        Stack futureChild = new Stack();\r
+                        for (HtmlNode node = _lastparentnode.LastChild; node != null; node = node.PreviousSibling)\r
+                        {\r
+                            if ((node.Name == _currentnode.Name) && (!node.HasChildNodes))\r
+                            {\r
+                                foundNode = node;\r
+                                break;\r
+                            }\r
+                            futureChild.Push(node);\r
+                        }\r
+                        if (foundNode != null)\r
+                        {\r
+                            HtmlNode node = null;\r
+                            while (futureChild.Count != 0)\r
+                            {\r
+                                node = (HtmlNode) futureChild.Pop();\r
+                                _lastparentnode.RemoveChild(node);\r
+                                foundNode.AppendChild(node);\r
+                            }\r
+                        }\r
+                        else\r
+                        {\r
+                            _lastparentnode.AppendChild(_currentnode);\r
+                        }\r
+                    }\r
+                }\r
+                else\r
+                {\r
+                    // node has no parent\r
+                    // node is not a closed node\r
+\r
+                    if (HtmlNode.CanOverlapElement(_currentnode.Name))\r
+                    {\r
+                        // this is a hack: add it as a text node\r
+                        HtmlNode closenode = CreateNode(HtmlNodeType.Text, _currentnode._outerstartindex);\r
+                        closenode._outerlength = _currentnode._outerlength;\r
+                        ((HtmlTextNode) closenode).Text = ((HtmlTextNode) closenode).Text.ToLower();\r
+                        if (_lastparentnode != null)\r
+                        {\r
+                            _lastparentnode.AppendChild(closenode);\r
+                        }\r
+                    }\r
+                    else\r
+                    {\r
+                        if (HtmlNode.IsEmptyElement(_currentnode.Name))\r
+                        {\r
+                            AddError(\r
+                                HtmlParseErrorCode.EndTagNotRequired,\r
+                                _currentnode._line, _currentnode._lineposition,\r
+                                _currentnode._streamposition, _currentnode.OuterHtml,\r
+                                "End tag </" + _currentnode.Name + "> is not required");\r
+                        }\r
+                        else\r
+                        {\r
+                            // node cannot overlap, node is not empty\r
+                            AddError(\r
+                                HtmlParseErrorCode.TagNotOpened,\r
+                                _currentnode._line, _currentnode._lineposition,\r
+                                _currentnode._streamposition, _currentnode.OuterHtml,\r
+                                "Start tag <" + _currentnode.Name + "> was not found");\r
+                            error = true;\r
+                        }\r
+                    }\r
+                }\r
+            }\r
+            else\r
+            {\r
+                if (OptionFixNestedTags)\r
+                {\r
+                    if (FindResetterNodes(prev, GetResetters(_currentnode.Name)))\r
+                    {\r
+                        AddError(\r
+                            HtmlParseErrorCode.EndTagInvalidHere,\r
+                            _currentnode._line, _currentnode._lineposition,\r
+                            _currentnode._streamposition, _currentnode.OuterHtml,\r
+                            "End tag </" + _currentnode.Name + "> invalid here");\r
+                        error = true;\r
+                    }\r
+                }\r
+\r
+                if (!error)\r
+                {\r
+                    _lastnodes[_currentnode.Name] = prev._prevwithsamename;\r
+                    prev.CloseNode(_currentnode);\r
+                }\r
+            }\r
+\r
+\r
+            // we close this node, get grandparent\r
+            if (!error)\r
+            {\r
+                if ((_lastparentnode != null) &&\r
+                    ((!HtmlNode.IsClosedElement(_currentnode.Name)) ||\r
+                     (_currentnode._starttag)))\r
+                {\r
+                    UpdateLastParentNode();\r
+                }\r
+            }\r
+        }\r
+\r
+        private string CurrentAttributeName()\r
+        {\r
+            return _text.Substring(_currentattribute._namestartindex, _currentattribute._namelength);\r
+        }\r
+\r
+        private string CurrentAttributeValue()\r
+        {\r
+            return _text.Substring(_currentattribute._valuestartindex, _currentattribute._valuelength);\r
+        }\r
+\r
+        private string CurrentNodeInner()\r
+        {\r
+            return _text.Substring(_currentnode._innerstartindex, _currentnode._innerlength);\r
+        }\r
+\r
+        private string CurrentNodeName()\r
+        {\r
+            return _text.Substring(_currentnode._namestartindex, _currentnode._namelength);\r
+        }\r
+\r
+        private string CurrentNodeOuter()\r
+        {\r
+            return _text.Substring(_currentnode._outerstartindex, _currentnode._outerlength);\r
+        }\r
+\r
+\r
+        private void DecrementPosition()\r
+        {\r
+            _index--;\r
+            if (_lineposition == 1)\r
+            {\r
+                _lineposition = _maxlineposition;\r
+                _line--;\r
+            }\r
+            else\r
+            {\r
+                _lineposition--;\r
+            }\r
+        }\r
+\r
+        private HtmlNode FindResetterNode(HtmlNode node, string name)\r
+        {\r
+            HtmlNode resetter = (HtmlNode) _lastnodes[name];\r
+            if (resetter == null)\r
+                return null;\r
+            if (resetter.Closed)\r
+            {\r
+                return null;\r
+            }\r
+            if (resetter._streamposition < node._streamposition)\r
+            {\r
+                return null;\r
+            }\r
+            return resetter;\r
+        }\r
+\r
+        private bool FindResetterNodes(HtmlNode node, string[] names)\r
+        {\r
+            if (names == null)\r
+            {\r
+                return false;\r
+            }\r
+            for (int i = 0; i < names.Length; i++)\r
+            {\r
+                if (FindResetterNode(node, names[i]) != null)\r
+                {\r
+                    return true;\r
+                }\r
+            }\r
+            return false;\r
+        }\r
+\r
+        private void FixNestedTag(string name, string[] resetters)\r
+        {\r
+            if (resetters == null)\r
+                return;\r
+\r
+            HtmlNode prev;\r
+\r
+            // if we find a previous unclosed same name node, without a resetter node between, we must close it\r
+            prev = (HtmlNode) _lastnodes[name];\r
+            if ((prev != null) && (!prev.Closed))\r
+            {\r
+                // try to find a resetter node, if found, we do nothing\r
+                if (FindResetterNodes(prev, resetters))\r
+                {\r
+                    return;\r
+                }\r
+\r
+                // ok we need to close the prev now\r
+                // create a fake closer node\r
+                HtmlNode close = new HtmlNode(prev.NodeType, this, -1);\r
+                close._endnode = close;\r
+                prev.CloseNode(close);\r
+            }\r
+        }\r
+\r
+        private void FixNestedTags()\r
+        {\r
+            // we are only interested by start tags, not closing tags\r
+            if (!_currentnode._starttag)\r
+                return;\r
+\r
+            string name = CurrentNodeName();\r
+            FixNestedTag(name, GetResetters(name));\r
+        }\r
+\r
+        private string[] GetResetters(string name)\r
+        {\r
+            switch (name)\r
+            {\r
+                case "li":\r
+                    return new string[] {"ul"};\r
+\r
+                case "tr":\r
+                    return new string[] {"table"};\r
+\r
+                case "th":\r
+                case "td":\r
+                    return new string[] {"tr", "table"};\r
+\r
+                default:\r
+                    return null;\r
+            }\r
+        }\r
+\r
+        private void IncrementPosition()\r
+        {\r
+            if (_crc32 != null)\r
+            {\r
+                // REVIEW: should we add some checksum code in DecrementPosition too?\r
+                _crc32.AddToCRC32(_c);\r
+            }\r
+\r
+            _index++;\r
+            _maxlineposition = _lineposition;\r
+            if (_c == 10)\r
+            {\r
+                _lineposition = 1;\r
+                _line++;\r
+            }\r
+            else\r
+            {\r
+                _lineposition++;\r
+            }\r
+        }\r
+\r
+        private bool NewCheck()\r
+        {\r
+            if (_c != '<')\r
+            {\r
+                return false;\r
+            }\r
+            if (_index < _text.Length)\r
+            {\r
+                if (_text[_index] == '%')\r
+                {\r
+                    switch (_state)\r
+                    {\r
+                        case ParseState.AttributeAfterEquals:\r
+                            PushAttributeValueStart(_index - 1);\r
+                            break;\r
+\r
+                        case ParseState.BetweenAttributes:\r
+                            PushAttributeNameStart(_index - 1);\r
+                            break;\r
+\r
+                        case ParseState.WhichTag:\r
+                            PushNodeNameStart(true, _index - 1);\r
+                            _state = ParseState.Tag;\r
+                            break;\r
+                    }\r
+                    _oldstate = _state;\r
+                    _state = ParseState.ServerSideCode;\r
+                    return true;\r
+                }\r
+            }\r
+\r
+            if (!PushNodeEnd(_index - 1, true))\r
+            {\r
+                // stop parsing\r
+                _index = _text.Length;\r
+                return true;\r
+            }\r
+            _state = ParseState.WhichTag;\r
+            if ((_index - 1) <= (_text.Length - 2))\r
+            {\r
+                if (_text[_index] == '!')\r
+                {\r
+                    PushNodeStart(HtmlNodeType.Comment, _index - 1);\r
+                    PushNodeNameStart(true, _index);\r
+                    PushNodeNameEnd(_index + 1);\r
+                    _state = ParseState.Comment;\r
+                    if (_index < (_text.Length - 2))\r
+                    {\r
+                        if ((_text[_index + 1] == '-') &&\r
+                            (_text[_index + 2] == '-'))\r
+                        {\r
+                            _fullcomment = true;\r
+                        }\r
+                        else\r
+                        {\r
+                            _fullcomment = false;\r
+                        }\r
+                    }\r
+                    return true;\r
+                }\r
+            }\r
+            PushNodeStart(HtmlNodeType.Element, _index - 1);\r
+            return true;\r
+        }\r
+\r
+        private void Parse()\r
+        {\r
+            int lastquote = 0;\r
+            if (OptionComputeChecksum)\r
+            {\r
+                _crc32 = new Crc32();\r
+            }\r
+\r
+            _lastnodes = new Hashtable();\r
+            _c = 0;\r
+            _fullcomment = false;\r
+            _parseerrors = new List<HtmlParseError>();\r
+            _line = 1;\r
+            _lineposition = 1;\r
+            _maxlineposition = 1;\r
+\r
+            _state = ParseState.Text;\r
+            _oldstate = _state;\r
+            _documentnode._innerlength = _text.Length;\r
+            _documentnode._outerlength = _text.Length;\r
+            _remainderOffset = _text.Length;\r
+\r
+            _lastparentnode = _documentnode;\r
+            _currentnode = CreateNode(HtmlNodeType.Text, 0);\r
+            _currentattribute = null;\r
+\r
+            _index = 0;\r
+            PushNodeStart(HtmlNodeType.Text, 0);\r
+            while (_index < _text.Length)\r
+            {\r
+                _c = _text[_index];\r
+                IncrementPosition();\r
+\r
+                switch (_state)\r
+                {\r
+                    case ParseState.Text:\r
+                        if (NewCheck())\r
+                            continue;\r
+                        break;\r
+\r
+                    case ParseState.WhichTag:\r
+                        if (NewCheck())\r
+                            continue;\r
+                        if (_c == '/')\r
+                        {\r
+                            PushNodeNameStart(false, _index);\r
+                        }\r
+                        else\r
+                        {\r
+                            PushNodeNameStart(true, _index - 1);\r
+                            DecrementPosition();\r
+                        }\r
+                        _state = ParseState.Tag;\r
+                        break;\r
+\r
+                    case ParseState.Tag:\r
+                        if (NewCheck())\r
+                            continue;\r
+                        if (IsWhiteSpace(_c))\r
+                        {\r
+                            PushNodeNameEnd(_index - 1);\r
+                            if (_state != ParseState.Tag)\r
+                                continue;\r
+                            _state = ParseState.BetweenAttributes;\r
+                            continue;\r
+                        }\r
+                        if (_c == '/')\r
+                        {\r
+                            PushNodeNameEnd(_index - 1);\r
+                            if (_state != ParseState.Tag)\r
+                                continue;\r
+                            _state = ParseState.EmptyTag;\r
+                            continue;\r
+                        }\r
+                        if (_c == '>')\r
+                        {\r
+                            PushNodeNameEnd(_index - 1);\r
+                            if (_state != ParseState.Tag)\r
+                                continue;\r
+                            if (!PushNodeEnd(_index, false))\r
+                            {\r
+                                // stop parsing\r
+                                _index = _text.Length;\r
+                                break;\r
+                            }\r
+                            if (_state != ParseState.Tag)\r
+                                continue;\r
+                            _state = ParseState.Text;\r
+                            PushNodeStart(HtmlNodeType.Text, _index);\r
+                        }\r
+                        break;\r
+\r
+                    case ParseState.BetweenAttributes:\r
+                        if (NewCheck())\r
+                            continue;\r
+\r
+                        if (IsWhiteSpace(_c))\r
+                            continue;\r
+\r
+                        if ((_c == '/') || (_c == '?'))\r
+                        {\r
+                            _state = ParseState.EmptyTag;\r
+                            continue;\r
+                        }\r
+\r
+                        if (_c == '>')\r
+                        {\r
+                            if (!PushNodeEnd(_index, false))\r
+                            {\r
+                                // stop parsing\r
+                                _index = _text.Length;\r
+                                break;\r
+                            }\r
+\r
+                            if (_state != ParseState.BetweenAttributes)\r
+                                continue;\r
+                            _state = ParseState.Text;\r
+                            PushNodeStart(HtmlNodeType.Text, _index);\r
+                            continue;\r
+                        }\r
+\r
+                        PushAttributeNameStart(_index - 1);\r
+                        _state = ParseState.AttributeName;\r
+                        break;\r
+\r
+                    case ParseState.EmptyTag:\r
+                        if (NewCheck())\r
+                            continue;\r
+\r
+                        if (_c == '>')\r
+                        {\r
+                            if (!PushNodeEnd(_index, true))\r
+                            {\r
+                                // stop parsing\r
+                                _index = _text.Length;\r
+                                break;\r
+                            }\r
+\r
+                            if (_state != ParseState.EmptyTag)\r
+                                continue;\r
+                            _state = ParseState.Text;\r
+                            PushNodeStart(HtmlNodeType.Text, _index);\r
+                            continue;\r
+                        }\r
+                        _state = ParseState.BetweenAttributes;\r
+                        break;\r
+\r
+                    case ParseState.AttributeName:\r
+                        if (NewCheck())\r
+                            continue;\r
+\r
+                        if (IsWhiteSpace(_c))\r
+                        {\r
+                            PushAttributeNameEnd(_index - 1);\r
+                            _state = ParseState.AttributeBeforeEquals;\r
+                            continue;\r
+                        }\r
+                        if (_c == '=')\r
+                        {\r
+                            PushAttributeNameEnd(_index - 1);\r
+                            _state = ParseState.AttributeAfterEquals;\r
+                            continue;\r
+                        }\r
+                        if (_c == '>')\r
+                        {\r
+                            PushAttributeNameEnd(_index - 1);\r
+                            if (!PushNodeEnd(_index, false))\r
+                            {\r
+                                // stop parsing\r
+                                _index = _text.Length;\r
+                                break;\r
+                            }\r
+                            if (_state != ParseState.AttributeName)\r
+                                continue;\r
+                            _state = ParseState.Text;\r
+                            PushNodeStart(HtmlNodeType.Text, _index);\r
+                            continue;\r
+                        }\r
+                        break;\r
+\r
+                    case ParseState.AttributeBeforeEquals:\r
+                        if (NewCheck())\r
+                            continue;\r
+\r
+                        if (IsWhiteSpace(_c))\r
+                            continue;\r
+                        if (_c == '>')\r
+                        {\r
+                            if (!PushNodeEnd(_index, false))\r
+                            {\r
+                                // stop parsing\r
+                                _index = _text.Length;\r
+                                break;\r
+                            }\r
+                            if (_state != ParseState.AttributeBeforeEquals)\r
+                                continue;\r
+                            _state = ParseState.Text;\r
+                            PushNodeStart(HtmlNodeType.Text, _index);\r
+                            continue;\r
+                        }\r
+                        if (_c == '=')\r
+                        {\r
+                            _state = ParseState.AttributeAfterEquals;\r
+                            continue;\r
+                        }\r
+                        // no equals, no whitespace, it's a new attrribute starting\r
+                        _state = ParseState.BetweenAttributes;\r
+                        DecrementPosition();\r
+                        break;\r
+\r
+                    case ParseState.AttributeAfterEquals:\r
+                        if (NewCheck())\r
+                            continue;\r
+\r
+                        if (IsWhiteSpace(_c))\r
+                            continue;\r
+\r
+                        if ((_c == '\'') || (_c == '"'))\r
+                        {\r
+                            _state = ParseState.QuotedAttributeValue;\r
+                            PushAttributeValueStart(_index, _c);\r
+                            lastquote = _c;\r
+                            continue;\r
+                        }\r
+                        if (_c == '>')\r
+                        {\r
+                            if (!PushNodeEnd(_index, false))\r
+                            {\r
+                                // stop parsing\r
+                                _index = _text.Length;\r
+                                break;\r
+                            }\r
+                            if (_state != ParseState.AttributeAfterEquals)\r
+                                continue;\r
+                            _state = ParseState.Text;\r
+                            PushNodeStart(HtmlNodeType.Text, _index);\r
+                            continue;\r
+                        }\r
+                        PushAttributeValueStart(_index - 1);\r
+                        _state = ParseState.AttributeValue;\r
+                        break;\r
+\r
+                    case ParseState.AttributeValue:\r
+                        if (NewCheck())\r
+                            continue;\r
+\r
+                        if (IsWhiteSpace(_c))\r
+                        {\r
+                            PushAttributeValueEnd(_index - 1);\r
+                            _state = ParseState.BetweenAttributes;\r
+                            continue;\r
+                        }\r
+\r
+                        if (_c == '>')\r
+                        {\r
+                            PushAttributeValueEnd(_index - 1);\r
+                            if (!PushNodeEnd(_index, false))\r
+                            {\r
+                                // stop parsing\r
+                                _index = _text.Length;\r
+                                break;\r
+                            }\r
+                            if (_state != ParseState.AttributeValue)\r
+                                continue;\r
+                            _state = ParseState.Text;\r
+                            PushNodeStart(HtmlNodeType.Text, _index);\r
+                            continue;\r
+                        }\r
+                        break;\r
+\r
+                    case ParseState.QuotedAttributeValue:\r
+                        if (_c == lastquote)\r
+                        {\r
+                            PushAttributeValueEnd(_index - 1);\r
+                            _state = ParseState.BetweenAttributes;\r
+                            continue;\r
+                        }\r
+                        if (_c == '<')\r
+                        {\r
+                            if (_index < _text.Length)\r
+                            {\r
+                                if (_text[_index] == '%')\r
+                                {\r
+                                    _oldstate = _state;\r
+                                    _state = ParseState.ServerSideCode;\r
+                                    continue;\r
+                                }\r
+                            }\r
+                        }\r
+                        break;\r
+\r
+                    case ParseState.Comment:\r
+                        if (_c == '>')\r
+                        {\r
+                            if (_fullcomment)\r
+                            {\r
+                                if ((_text[_index - 2] != '-') ||\r
+                                    (_text[_index - 3] != '-'))\r
+                                {\r
+                                    continue;\r
+                                }\r
+                            }\r
+                            if (!PushNodeEnd(_index, false))\r
+                            {\r
+                                // stop parsing\r
+                                _index = _text.Length;\r
+                                break;\r
+                            }\r
+                            _state = ParseState.Text;\r
+                            PushNodeStart(HtmlNodeType.Text, _index);\r
+                            continue;\r
+                        }\r
+                        break;\r
+\r
+                    case ParseState.ServerSideCode:\r
+                        if (_c == '%')\r
+                        {\r
+                            if (_index < _text.Length)\r
+                            {\r
+                                if (_text[_index] == '>')\r
+                                {\r
+                                    switch (_oldstate)\r
+                                    {\r
+                                        case ParseState.AttributeAfterEquals:\r
+                                            _state = ParseState.AttributeValue;\r
+                                            break;\r
+\r
+                                        case ParseState.BetweenAttributes:\r
+                                            PushAttributeNameEnd(_index + 1);\r
+                                            _state = ParseState.BetweenAttributes;\r
+                                            break;\r
+\r
+                                        default:\r
+                                            _state = _oldstate;\r
+                                            break;\r
+                                    }\r
+                                    IncrementPosition();\r
+                                }\r
+                            }\r
+                        }\r
+                        break;\r
+\r
+                    case ParseState.PcData:\r
+                        // look for </tag + 1 char\r
+\r
+                        // check buffer end\r
+                        if ((_currentnode._namelength + 3) <= (_text.Length - (_index - 1)))\r
+                        {\r
+                            if (string.Compare(_text.Substring(_index - 1, _currentnode._namelength + 2),\r
+                                               "</" + _currentnode.Name, true) == 0)\r
+                            {\r
+                                int c = _text[_index - 1 + 2 + _currentnode.Name.Length];\r
+                                if ((c == '>') || (IsWhiteSpace(c)))\r
+                                {\r
+                                    // add the script as a text node\r
+                                    HtmlNode script = CreateNode(HtmlNodeType.Text,\r
+                                                                 _currentnode._outerstartindex +\r
+                                                                 _currentnode._outerlength);\r
+                                    script._outerlength = _index - 1 - script._outerstartindex;\r
+                                    _currentnode.AppendChild(script);\r
+\r
+\r
+                                    PushNodeStart(HtmlNodeType.Element, _index - 1);\r
+                                    PushNodeNameStart(false, _index - 1 + 2);\r
+                                    _state = ParseState.Tag;\r
+                                    IncrementPosition();\r
+                                }\r
+                            }\r
+                        }\r
+                        break;\r
+                }\r
+            }\r
+\r
+            // finish the current work\r
+            if (_currentnode._namestartindex > 0)\r
+            {\r
+                PushNodeNameEnd(_index);\r
+            }\r
+            PushNodeEnd(_index, false);\r
+\r
+            // we don't need this anymore\r
+            _lastnodes.Clear();\r
+        }\r
+\r
+        private void PushAttributeNameEnd(int index)\r
+        {\r
+            _currentattribute._namelength = index - _currentattribute._namestartindex;\r
+            _currentnode.Attributes.Append(_currentattribute);\r
+        }\r
+\r
+        private void PushAttributeNameStart(int index)\r
+        {\r
+            _currentattribute = CreateAttribute();\r
+            _currentattribute._namestartindex = index;\r
+            _currentattribute.Line = _line;\r
+            _currentattribute._lineposition = _lineposition;\r
+            _currentattribute._streamposition = index;\r
+        }\r
+\r
+        private void PushAttributeValueEnd(int index)\r
+        {\r
+            _currentattribute._valuelength = index - _currentattribute._valuestartindex;\r
+        }\r
+\r
+        private void PushAttributeValueStart(int index)\r
+        {\r
+            PushAttributeValueStart(index, 0);\r
+        }\r
+\r
+        private void PushAttributeValueStart(int index, int quote)\r
+        {\r
+            _currentattribute._valuestartindex = index;\r
+            if (quote == '\'')\r
+                _currentattribute.QuoteType = AttributeValueQuote.SingleQuote;\r
+        }\r
+\r
+        private bool PushNodeEnd(int index, bool close)\r
+        {\r
+            _currentnode._outerlength = index - _currentnode._outerstartindex;\r
+\r
+            if ((_currentnode._nodetype == HtmlNodeType.Text) ||\r
+                (_currentnode._nodetype == HtmlNodeType.Comment))\r
+            {\r
+                // forget about void nodes\r
+                if (_currentnode._outerlength > 0)\r
+                {\r
+                    _currentnode._innerlength = _currentnode._outerlength;\r
+                    _currentnode._innerstartindex = _currentnode._outerstartindex;\r
+                    if (_lastparentnode != null)\r
+                    {\r
+                        _lastparentnode.AppendChild(_currentnode);\r
+                    }\r
+                }\r
+            }\r
+            else\r
+            {\r
+                if ((_currentnode._starttag) && (_lastparentnode != _currentnode))\r
+                {\r
+                    // add to parent node\r
+                    if (_lastparentnode != null)\r
+                    {\r
+                        _lastparentnode.AppendChild(_currentnode);\r
+                    }\r
+\r
+                    ReadDocumentEncoding(_currentnode);\r
+\r
+                    // remember last node of this kind\r
+                    HtmlNode prev = (HtmlNode) _lastnodes[_currentnode.Name];\r
+                    _currentnode._prevwithsamename = prev;\r
+                    _lastnodes[_currentnode.Name] = _currentnode;\r
+\r
+                    // change parent?\r
+                    if ((_currentnode.NodeType == HtmlNodeType.Document) ||\r
+                        (_currentnode.NodeType == HtmlNodeType.Element))\r
+                    {\r
+                        _lastparentnode = _currentnode;\r
+                    }\r
+\r
+                    if (HtmlNode.IsCDataElement(CurrentNodeName()))\r
+                    {\r
+                        _state = ParseState.PcData;\r
+                        return true;\r
+                    }\r
+\r
+                    if ((HtmlNode.IsClosedElement(_currentnode.Name)) ||\r
+                        (HtmlNode.IsEmptyElement(_currentnode.Name)))\r
+                    {\r
+                        close = true;\r
+                    }\r
+                }\r
+            }\r
+\r
+            if ((close) || (!_currentnode._starttag))\r
+            {\r
+                if ((OptionStopperNodeName != null) && (_remainder == null) &&\r
+                    (string.Compare(_currentnode.Name, OptionStopperNodeName, true) == 0))\r
+                {\r
+                    _remainderOffset = index;\r
+                    _remainder = _text.Substring(_remainderOffset);\r
+                    CloseCurrentNode();\r
+                    return false; // stop parsing\r
+                }\r
+                CloseCurrentNode();\r
+            }\r
+            return true;\r
+        }\r
+\r
+        private void PushNodeNameEnd(int index)\r
+        {\r
+            _currentnode._namelength = index - _currentnode._namestartindex;\r
+            if (OptionFixNestedTags)\r
+            {\r
+                FixNestedTags();\r
+            }\r
+        }\r
+\r
+        private void PushNodeNameStart(bool starttag, int index)\r
+        {\r
+            _currentnode._starttag = starttag;\r
+            _currentnode._namestartindex = index;\r
+        }\r
+\r
+        private void PushNodeStart(HtmlNodeType type, int index)\r
+        {\r
+            _currentnode = CreateNode(type, index);\r
+            _currentnode._line = _line;\r
+            _currentnode._lineposition = _lineposition;\r
+            if (type == HtmlNodeType.Element)\r
+            {\r
+                _currentnode._lineposition--;\r
+            }\r
+            _currentnode._streamposition = index;\r
+        }\r
+\r
+        private void ReadDocumentEncoding(HtmlNode node)\r
+        {\r
+            if (!OptionReadEncoding)\r
+                return;\r
+            // format is \r
+            // <meta http-equiv="content-type" content="text/html;charset=iso-8859-1" />\r
+\r
+            // when we append a child, we are in node end, so attributes are already populated\r
+            if (node._namelength == 4) // quick check, avoids string alloc\r
+            {\r
+                if (node.Name == "meta") // all nodes names are lowercase\r
+                {\r
+                    HtmlAttribute att = node.Attributes["http-equiv"];\r
+                    if (att != null)\r
+                    {\r
+                        if (string.Compare(att.Value, "content-type", true) == 0)\r
+                        {\r
+                            HtmlAttribute content = node.Attributes["content"];\r
+                            if (content != null)\r
+                            {\r
+                                string charset = NameValuePairList.GetNameValuePairsValue(content.Value, "charset");\r
+                                if (charset != null && (charset = charset.Trim()).Length > 0)\r
+                                {\r
+                                    _declaredencoding = Encoding.GetEncoding(charset.Trim());\r
+                                    if (_onlyDetectEncoding)\r
+                                    {\r
+                                        throw new EncodingFoundException(_declaredencoding);\r
+                                    }\r
+\r
+                                    if (_streamencoding != null)\r
+                                    {\r
+                                        if (_declaredencoding.WindowsCodePage != _streamencoding.WindowsCodePage)\r
+                                        {\r
+                                            AddError(\r
+                                                HtmlParseErrorCode.CharsetMismatch,\r
+                                                _line, _lineposition,\r
+                                                _index, node.OuterHtml,\r
+                                                "Encoding mismatch between StreamEncoding: " +\r
+                                                _streamencoding.WebName + " and DeclaredEncoding: " +\r
+                                                _declaredencoding.WebName);\r
+                                        }\r
+                                    }\r
+                                }\r
+                            }\r
+                        }\r
+                    }\r
+                }\r
+            }\r
+        }\r
+\r
+        #endregion\r
+\r
+        #region Nested type: ParseState\r
+\r
+        private enum ParseState\r
+        {\r
+            Text,\r
+            WhichTag,\r
+            Tag,\r
+            BetweenAttributes,\r
+            EmptyTag,\r
+            AttributeName,\r
+            AttributeBeforeEquals,\r
+            AttributeAfterEquals,\r
+            AttributeValue,\r
+            Comment,\r
+            QuotedAttributeValue,\r
+            ServerSideCode,\r
+            PcData\r
+        }\r
+\r
+        #endregion\r
+    }\r
+}
\ No newline at end of file
diff --git a/docs/HtmlAgilityPack/HtmlElementFlag.cs b/docs/HtmlAgilityPack/HtmlElementFlag.cs
new file mode 100644 (file)
index 0000000..01232cd
--- /dev/null
@@ -0,0 +1,32 @@
+// HtmlAgilityPack V1.0 - Simon Mourier <simon underscore mourier at hotmail dot com>\r
+using System;\r
+\r
+namespace HtmlAgilityPack\r
+{\r
+    /// <summary>\r
+    /// Flags that describe the behavior of an Element node.\r
+    /// </summary>\r
+    [Flags]\r
+    public enum HtmlElementFlag\r
+    {\r
+        /// <summary>\r
+        /// The node is a CDATA node.\r
+        /// </summary>\r
+        CData = 1,\r
+\r
+        /// <summary>\r
+        /// The node is empty. META or IMG are example of such nodes.\r
+        /// </summary>\r
+        Empty = 2,\r
+\r
+        /// <summary>\r
+        /// The node will automatically be closed during parsing.\r
+        /// </summary>\r
+        Closed = 4,\r
+\r
+        /// <summary>\r
+        /// The node can overlap.\r
+        /// </summary>\r
+        CanOverlap = 8\r
+    }\r
+}
\ No newline at end of file
diff --git a/docs/HtmlAgilityPack/HtmlEntity.cs b/docs/HtmlAgilityPack/HtmlEntity.cs
new file mode 100644 (file)
index 0000000..b79404d
--- /dev/null
@@ -0,0 +1,826 @@
+// HtmlAgilityPack V1.0 - Simon Mourier <simon underscore mourier at hotmail dot com>\r
+using System;\r
+using System.Collections;\r
+using System.Text;\r
+\r
+namespace HtmlAgilityPack\r
+{\r
+    /// <summary>\r
+    /// A utility class to replace special characters by entities and vice-versa.\r
+    /// Follows HTML 4.0 specification found at http://www.w3.org/TR/html4/sgml/entities.html\r
+    /// </summary>\r
+    public class HtmlEntity\r
+    {\r
+        #region Static Members\r
+\r
+        private static readonly int _maxEntitySize;\r
+        private static Hashtable _entityName;\r
+        private static Hashtable _entityValue;\r
+\r
+        /// <summary>\r
+        /// A collection of entities indexed by name.\r
+        /// </summary>\r
+        public static Hashtable EntityName\r
+        {\r
+            get { return _entityName; }\r
+        }\r
+\r
+        /// <summary>\r
+        /// A collection of entities indexed by value.\r
+        /// </summary>\r
+        public static Hashtable EntityValue\r
+        {\r
+            get { return _entityValue; }\r
+        }\r
+\r
+        #endregion\r
+\r
+        #region Constructors\r
+\r
+        static HtmlEntity()\r
+        {\r
+            _entityName = new Hashtable();\r
+            _entityValue = new Hashtable();\r
+\r
+            #region Entities Definition\r
+\r
+            _entityValue.Add("nbsp", 160); // no-break space = non-breaking space, U+00A0 ISOnum \r
+            _entityName.Add(160, "nbsp");\r
+            _entityValue.Add("iexcl", 161); // inverted exclamation mark, U+00A1 ISOnum \r
+            _entityName.Add(161, "iexcl");\r
+            _entityValue.Add("cent", 162); // cent sign, U+00A2 ISOnum \r
+            _entityName.Add(162, "cent");\r
+            _entityValue.Add("pound", 163); // pound sign, U+00A3 ISOnum \r
+            _entityName.Add(163, "pound");\r
+            _entityValue.Add("curren", 164); // currency sign, U+00A4 ISOnum \r
+            _entityName.Add(164, "curren");\r
+            _entityValue.Add("yen", 165); // yen sign = yuan sign, U+00A5 ISOnum \r
+            _entityName.Add(165, "yen");\r
+            _entityValue.Add("brvbar", 166); // broken bar = broken vertical bar, U+00A6 ISOnum \r
+            _entityName.Add(166, "brvbar");\r
+            _entityValue.Add("sect", 167); // section sign, U+00A7 ISOnum \r
+            _entityName.Add(167, "sect");\r
+            _entityValue.Add("uml", 168); // diaeresis = spacing diaeresis, U+00A8 ISOdia \r
+            _entityName.Add(168, "uml");\r
+            _entityValue.Add("copy", 169); // copyright sign, U+00A9 ISOnum \r
+            _entityName.Add(169, "copy");\r
+            _entityValue.Add("ordf", 170); // feminine ordinal indicator, U+00AA ISOnum \r
+            _entityName.Add(170, "ordf");\r
+            _entityValue.Add("laquo", 171);\r
+                // left-pointing double angle quotation mark = left pointing guillemet, U+00AB ISOnum \r
+            _entityName.Add(171, "laquo");\r
+            _entityValue.Add("not", 172); // not sign, U+00AC ISOnum \r
+            _entityName.Add(172, "not");\r
+            _entityValue.Add("shy", 173); // soft hyphen = discretionary hyphen, U+00AD ISOnum \r
+            _entityName.Add(173, "shy");\r
+            _entityValue.Add("reg", 174); // registered sign = registered trade mark sign, U+00AE ISOnum \r
+            _entityName.Add(174, "reg");\r
+            _entityValue.Add("macr", 175); // macron = spacing macron = overline = APL overbar, U+00AF ISOdia \r
+            _entityName.Add(175, "macr");\r
+            _entityValue.Add("deg", 176); // degree sign, U+00B0 ISOnum \r
+            _entityName.Add(176, "deg");\r
+            _entityValue.Add("plusmn", 177); // plus-minus sign = plus-or-minus sign, U+00B1 ISOnum \r
+            _entityName.Add(177, "plusmn");\r
+            _entityValue.Add("sup2", 178); // superscript two = superscript digit two = squared, U+00B2 ISOnum \r
+            _entityName.Add(178, "sup2");\r
+            _entityValue.Add("sup3", 179); // superscript three = superscript digit three = cubed, U+00B3 ISOnum \r
+            _entityName.Add(179, "sup3");\r
+            _entityValue.Add("acute", 180); // acute accent = spacing acute, U+00B4 ISOdia \r
+            _entityName.Add(180, "acute");\r
+            _entityValue.Add("micro", 181); // micro sign, U+00B5 ISOnum \r
+            _entityName.Add(181, "micro");\r
+            _entityValue.Add("para", 182); // pilcrow sign = paragraph sign, U+00B6 ISOnum \r
+            _entityName.Add(182, "para");\r
+            _entityValue.Add("middot", 183); // middle dot = Georgian comma = Greek middle dot, U+00B7 ISOnum \r
+            _entityName.Add(183, "middot");\r
+            _entityValue.Add("cedil", 184); // cedilla = spacing cedilla, U+00B8 ISOdia \r
+            _entityName.Add(184, "cedil");\r
+            _entityValue.Add("sup1", 185); // superscript one = superscript digit one, U+00B9 ISOnum \r
+            _entityName.Add(185, "sup1");\r
+            _entityValue.Add("ordm", 186); // masculine ordinal indicator, U+00BA ISOnum \r
+            _entityName.Add(186, "ordm");\r
+            _entityValue.Add("raquo", 187);\r
+                // right-pointing double angle quotation mark = right pointing guillemet, U+00BB ISOnum \r
+            _entityName.Add(187, "raquo");\r
+            _entityValue.Add("frac14", 188); // vulgar fraction one quarter = fraction one quarter, U+00BC ISOnum \r
+            _entityName.Add(188, "frac14");\r
+            _entityValue.Add("frac12", 189); // vulgar fraction one half = fraction one half, U+00BD ISOnum \r
+            _entityName.Add(189, "frac12");\r
+            _entityValue.Add("frac34", 190); // vulgar fraction three quarters = fraction three quarters, U+00BE ISOnum \r
+            _entityName.Add(190, "frac34");\r
+            _entityValue.Add("iquest", 191); // inverted question mark = turned question mark, U+00BF ISOnum \r
+            _entityName.Add(191, "iquest");\r
+            _entityValue.Add("Agrave", 192);\r
+                // latin capital letter A with grave = latin capital letter A grave, U+00C0 ISOlat1 \r
+            _entityName.Add(192, "Agrave");\r
+            _entityValue.Add("Aacute", 193); // latin capital letter A with acute, U+00C1 ISOlat1 \r
+            _entityName.Add(193, "Aacute");\r
+            _entityValue.Add("Acirc", 194); // latin capital letter A with circumflex, U+00C2 ISOlat1 \r
+            _entityName.Add(194, "Acirc");\r
+            _entityValue.Add("Atilde", 195); // latin capital letter A with tilde, U+00C3 ISOlat1 \r
+            _entityName.Add(195, "Atilde");\r
+            _entityValue.Add("Auml", 196); // latin capital letter A with diaeresis, U+00C4 ISOlat1 \r
+            _entityName.Add(196, "Auml");\r
+            _entityValue.Add("Aring", 197);\r
+                // latin capital letter A with ring above = latin capital letter A ring, U+00C5 ISOlat1 \r
+            _entityName.Add(197, "Aring");\r
+            _entityValue.Add("AElig", 198); // latin capital letter AE = latin capital ligature AE, U+00C6 ISOlat1 \r
+            _entityName.Add(198, "AElig");\r
+            _entityValue.Add("Ccedil", 199); // latin capital letter C with cedilla, U+00C7 ISOlat1 \r
+            _entityName.Add(199, "Ccedil");\r
+            _entityValue.Add("Egrave", 200); // latin capital letter E with grave, U+00C8 ISOlat1 \r
+            _entityName.Add(200, "Egrave");\r
+            _entityValue.Add("Eacute", 201); // latin capital letter E with acute, U+00C9 ISOlat1 \r
+            _entityName.Add(201, "Eacute");\r
+            _entityValue.Add("Ecirc", 202); // latin capital letter E with circumflex, U+00CA ISOlat1 \r
+            _entityName.Add(202, "Ecirc");\r
+            _entityValue.Add("Euml", 203); // latin capital letter E with diaeresis, U+00CB ISOlat1 \r
+            _entityName.Add(203, "Euml");\r
+            _entityValue.Add("Igrave", 204); // latin capital letter I with grave, U+00CC ISOlat1 \r
+            _entityName.Add(204, "Igrave");\r
+            _entityValue.Add("Iacute", 205); // latin capital letter I with acute, U+00CD ISOlat1 \r
+            _entityName.Add(205, "Iacute");\r
+            _entityValue.Add("Icirc", 206); // latin capital letter I with circumflex, U+00CE ISOlat1 \r
+            _entityName.Add(206, "Icirc");\r
+            _entityValue.Add("Iuml", 207); // latin capital letter I with diaeresis, U+00CF ISOlat1 \r
+            _entityName.Add(207, "Iuml");\r
+            _entityValue.Add("ETH", 208); // latin capital letter ETH, U+00D0 ISOlat1 \r
+            _entityName.Add(208, "ETH");\r
+            _entityValue.Add("Ntilde", 209); // latin capital letter N with tilde, U+00D1 ISOlat1 \r
+            _entityName.Add(209, "Ntilde");\r
+            _entityValue.Add("Ograve", 210); // latin capital letter O with grave, U+00D2 ISOlat1 \r
+            _entityName.Add(210, "Ograve");\r
+            _entityValue.Add("Oacute", 211); // latin capital letter O with acute, U+00D3 ISOlat1 \r
+            _entityName.Add(211, "Oacute");\r
+            _entityValue.Add("Ocirc", 212); // latin capital letter O with circumflex, U+00D4 ISOlat1 \r
+            _entityName.Add(212, "Ocirc");\r
+            _entityValue.Add("Otilde", 213); // latin capital letter O with tilde, U+00D5 ISOlat1 \r
+            _entityName.Add(213, "Otilde");\r
+            _entityValue.Add("Ouml", 214); // latin capital letter O with diaeresis, U+00D6 ISOlat1 \r
+            _entityName.Add(214, "Ouml");\r
+            _entityValue.Add("times", 215); // multiplication sign, U+00D7 ISOnum \r
+            _entityName.Add(215, "times");\r
+            _entityValue.Add("Oslash", 216);\r
+                // latin capital letter O with stroke = latin capital letter O slash, U+00D8 ISOlat1 \r
+            _entityName.Add(216, "Oslash");\r
+            _entityValue.Add("Ugrave", 217); // latin capital letter U with grave, U+00D9 ISOlat1 \r
+            _entityName.Add(217, "Ugrave");\r
+            _entityValue.Add("Uacute", 218); // latin capital letter U with acute, U+00DA ISOlat1 \r
+            _entityName.Add(218, "Uacute");\r
+            _entityValue.Add("Ucirc", 219); // latin capital letter U with circumflex, U+00DB ISOlat1 \r
+            _entityName.Add(219, "Ucirc");\r
+            _entityValue.Add("Uuml", 220); // latin capital letter U with diaeresis, U+00DC ISOlat1 \r
+            _entityName.Add(220, "Uuml");\r
+            _entityValue.Add("Yacute", 221); // latin capital letter Y with acute, U+00DD ISOlat1 \r
+            _entityName.Add(221, "Yacute");\r
+            _entityValue.Add("THORN", 222); // latin capital letter THORN, U+00DE ISOlat1 \r
+            _entityName.Add(222, "THORN");\r
+            _entityValue.Add("szlig", 223); // latin small letter sharp s = ess-zed, U+00DF ISOlat1 \r
+            _entityName.Add(223, "szlig");\r
+            _entityValue.Add("agrave", 224);\r
+                // latin small letter a with grave = latin small letter a grave, U+00E0 ISOlat1 \r
+            _entityName.Add(224, "agrave");\r
+            _entityValue.Add("aacute", 225); // latin small letter a with acute, U+00E1 ISOlat1 \r
+            _entityName.Add(225, "aacute");\r
+            _entityValue.Add("acirc", 226); // latin small letter a with circumflex, U+00E2 ISOlat1 \r
+            _entityName.Add(226, "acirc");\r
+            _entityValue.Add("atilde", 227); // latin small letter a with tilde, U+00E3 ISOlat1 \r
+            _entityName.Add(227, "atilde");\r
+            _entityValue.Add("auml", 228); // latin small letter a with diaeresis, U+00E4 ISOlat1 \r
+            _entityName.Add(228, "auml");\r
+            _entityValue.Add("aring", 229);\r
+                // latin small letter a with ring above = latin small letter a ring, U+00E5 ISOlat1 \r
+            _entityName.Add(229, "aring");\r
+            _entityValue.Add("aelig", 230); // latin small letter ae = latin small ligature ae, U+00E6 ISOlat1 \r
+            _entityName.Add(230, "aelig");\r
+            _entityValue.Add("ccedil", 231); // latin small letter c with cedilla, U+00E7 ISOlat1 \r
+            _entityName.Add(231, "ccedil");\r
+            _entityValue.Add("egrave", 232); // latin small letter e with grave, U+00E8 ISOlat1 \r
+            _entityName.Add(232, "egrave");\r
+            _entityValue.Add("eacute", 233); // latin small letter e with acute, U+00E9 ISOlat1 \r
+            _entityName.Add(233, "eacute");\r
+            _entityValue.Add("ecirc", 234); // latin small letter e with circumflex, U+00EA ISOlat1 \r
+            _entityName.Add(234, "ecirc");\r
+            _entityValue.Add("euml", 235); // latin small letter e with diaeresis, U+00EB ISOlat1 \r
+            _entityName.Add(235, "euml");\r
+            _entityValue.Add("igrave", 236); // latin small letter i with grave, U+00EC ISOlat1 \r
+            _entityName.Add(236, "igrave");\r
+            _entityValue.Add("iacute", 237); // latin small letter i with acute, U+00ED ISOlat1 \r
+            _entityName.Add(237, "iacute");\r
+            _entityValue.Add("icirc", 238); // latin small letter i with circumflex, U+00EE ISOlat1 \r
+            _entityName.Add(238, "icirc");\r
+            _entityValue.Add("iuml", 239); // latin small letter i with diaeresis, U+00EF ISOlat1 \r
+            _entityName.Add(239, "iuml");\r
+            _entityValue.Add("eth", 240); // latin small letter eth, U+00F0 ISOlat1 \r
+            _entityName.Add(240, "eth");\r
+            _entityValue.Add("ntilde", 241); // latin small letter n with tilde, U+00F1 ISOlat1 \r
+            _entityName.Add(241, "ntilde");\r
+            _entityValue.Add("ograve", 242); // latin small letter o with grave, U+00F2 ISOlat1 \r
+            _entityName.Add(242, "ograve");\r
+            _entityValue.Add("oacute", 243); // latin small letter o with acute, U+00F3 ISOlat1 \r
+            _entityName.Add(243, "oacute");\r
+            _entityValue.Add("ocirc", 244); // latin small letter o with circumflex, U+00F4 ISOlat1 \r
+            _entityName.Add(244, "ocirc");\r
+            _entityValue.Add("otilde", 245); // latin small letter o with tilde, U+00F5 ISOlat1 \r
+            _entityName.Add(245, "otilde");\r
+            _entityValue.Add("ouml", 246); // latin small letter o with diaeresis, U+00F6 ISOlat1 \r
+            _entityName.Add(246, "ouml");\r
+            _entityValue.Add("divide", 247); // division sign, U+00F7 ISOnum \r
+            _entityName.Add(247, "divide");\r
+            _entityValue.Add("oslash", 248);\r
+                // latin small letter o with stroke, = latin small letter o slash, U+00F8 ISOlat1 \r
+            _entityName.Add(248, "oslash");\r
+            _entityValue.Add("ugrave", 249); // latin small letter u with grave, U+00F9 ISOlat1 \r
+            _entityName.Add(249, "ugrave");\r
+            _entityValue.Add("uacute", 250); // latin small letter u with acute, U+00FA ISOlat1 \r
+            _entityName.Add(250, "uacute");\r
+            _entityValue.Add("ucirc", 251); // latin small letter u with circumflex, U+00FB ISOlat1 \r
+            _entityName.Add(251, "ucirc");\r
+            _entityValue.Add("uuml", 252); // latin small letter u with diaeresis, U+00FC ISOlat1 \r
+            _entityName.Add(252, "uuml");\r
+            _entityValue.Add("yacute", 253); // latin small letter y with acute, U+00FD ISOlat1 \r
+            _entityName.Add(253, "yacute");\r
+            _entityValue.Add("thorn", 254); // latin small letter thorn, U+00FE ISOlat1 \r
+            _entityName.Add(254, "thorn");\r
+            _entityValue.Add("yuml", 255); // latin small letter y with diaeresis, U+00FF ISOlat1 \r
+            _entityName.Add(255, "yuml");\r
+            _entityValue.Add("fnof", 402); // latin small f with hook = function = florin, U+0192 ISOtech \r
+            _entityName.Add(402, "fnof");\r
+            _entityValue.Add("Alpha", 913); // greek capital letter alpha, U+0391 \r
+            _entityName.Add(913, "Alpha");\r
+            _entityValue.Add("Beta", 914); // greek capital letter beta, U+0392 \r
+            _entityName.Add(914, "Beta");\r
+            _entityValue.Add("Gamma", 915); // greek capital letter gamma, U+0393 ISOgrk3 \r
+            _entityName.Add(915, "Gamma");\r
+            _entityValue.Add("Delta", 916); // greek capital letter delta, U+0394 ISOgrk3 \r
+            _entityName.Add(916, "Delta");\r
+            _entityValue.Add("Epsilon", 917); // greek capital letter epsilon, U+0395 \r
+            _entityName.Add(917, "Epsilon");\r
+            _entityValue.Add("Zeta", 918); // greek capital letter zeta, U+0396 \r
+            _entityName.Add(918, "Zeta");\r
+            _entityValue.Add("Eta", 919); // greek capital letter eta, U+0397 \r
+            _entityName.Add(919, "Eta");\r
+            _entityValue.Add("Theta", 920); // greek capital letter theta, U+0398 ISOgrk3 \r
+            _entityName.Add(920, "Theta");\r
+            _entityValue.Add("Iota", 921); // greek capital letter iota, U+0399 \r
+            _entityName.Add(921, "Iota");\r
+            _entityValue.Add("Kappa", 922); // greek capital letter kappa, U+039A \r
+            _entityName.Add(922, "Kappa");\r
+            _entityValue.Add("Lambda", 923); // greek capital letter lambda, U+039B ISOgrk3 \r
+            _entityName.Add(923, "Lambda");\r
+            _entityValue.Add("Mu", 924); // greek capital letter mu, U+039C \r
+            _entityName.Add(924, "Mu");\r
+            _entityValue.Add("Nu", 925); // greek capital letter nu, U+039D \r
+            _entityName.Add(925, "Nu");\r
+            _entityValue.Add("Xi", 926); // greek capital letter xi, U+039E ISOgrk3 \r
+            _entityName.Add(926, "Xi");\r
+            _entityValue.Add("Omicron", 927); // greek capital letter omicron, U+039F \r
+            _entityName.Add(927, "Omicron");\r
+            _entityValue.Add("Pi", 928); // greek capital letter pi, U+03A0 ISOgrk3 \r
+            _entityName.Add(928, "Pi");\r
+            _entityValue.Add("Rho", 929); // greek capital letter rho, U+03A1 \r
+            _entityName.Add(929, "Rho");\r
+            _entityValue.Add("Sigma", 931); // greek capital letter sigma, U+03A3 ISOgrk3 \r
+            _entityName.Add(931, "Sigma");\r
+            _entityValue.Add("Tau", 932); // greek capital letter tau, U+03A4 \r
+            _entityName.Add(932, "Tau");\r
+            _entityValue.Add("Upsilon", 933); // greek capital letter upsilon, U+03A5 ISOgrk3 \r
+            _entityName.Add(933, "Upsilon");\r
+            _entityValue.Add("Phi", 934); // greek capital letter phi, U+03A6 ISOgrk3 \r
+            _entityName.Add(934, "Phi");\r
+            _entityValue.Add("Chi", 935); // greek capital letter chi, U+03A7 \r
+            _entityName.Add(935, "Chi");\r
+            _entityValue.Add("Psi", 936); // greek capital letter psi, U+03A8 ISOgrk3 \r
+            _entityName.Add(936, "Psi");\r
+            _entityValue.Add("Omega", 937); // greek capital letter omega, U+03A9 ISOgrk3 \r
+            _entityName.Add(937, "Omega");\r
+            _entityValue.Add("alpha", 945); // greek small letter alpha, U+03B1 ISOgrk3 \r
+            _entityName.Add(945, "alpha");\r
+            _entityValue.Add("beta", 946); // greek small letter beta, U+03B2 ISOgrk3 \r
+            _entityName.Add(946, "beta");\r
+            _entityValue.Add("gamma", 947); // greek small letter gamma, U+03B3 ISOgrk3 \r
+            _entityName.Add(947, "gamma");\r
+            _entityValue.Add("delta", 948); // greek small letter delta, U+03B4 ISOgrk3 \r
+            _entityName.Add(948, "delta");\r
+            _entityValue.Add("epsilon", 949); // greek small letter epsilon, U+03B5 ISOgrk3 \r
+            _entityName.Add(949, "epsilon");\r
+            _entityValue.Add("zeta", 950); // greek small letter zeta, U+03B6 ISOgrk3 \r
+            _entityName.Add(950, "zeta");\r
+            _entityValue.Add("eta", 951); // greek small letter eta, U+03B7 ISOgrk3 \r
+            _entityName.Add(951, "eta");\r
+            _entityValue.Add("theta", 952); // greek small letter theta, U+03B8 ISOgrk3 \r
+            _entityName.Add(952, "theta");\r
+            _entityValue.Add("iota", 953); // greek small letter iota, U+03B9 ISOgrk3 \r
+            _entityName.Add(953, "iota");\r
+            _entityValue.Add("kappa", 954); // greek small letter kappa, U+03BA ISOgrk3 \r
+            _entityName.Add(954, "kappa");\r
+            _entityValue.Add("lambda", 955); // greek small letter lambda, U+03BB ISOgrk3 \r
+            _entityName.Add(955, "lambda");\r
+            _entityValue.Add("mu", 956); // greek small letter mu, U+03BC ISOgrk3 \r
+            _entityName.Add(956, "mu");\r
+            _entityValue.Add("nu", 957); // greek small letter nu, U+03BD ISOgrk3 \r
+            _entityName.Add(957, "nu");\r
+            _entityValue.Add("xi", 958); // greek small letter xi, U+03BE ISOgrk3 \r
+            _entityName.Add(958, "xi");\r
+            _entityValue.Add("omicron", 959); // greek small letter omicron, U+03BF NEW \r
+            _entityName.Add(959, "omicron");\r
+            _entityValue.Add("pi", 960); // greek small letter pi, U+03C0 ISOgrk3 \r
+            _entityName.Add(960, "pi");\r
+            _entityValue.Add("rho", 961); // greek small letter rho, U+03C1 ISOgrk3 \r
+            _entityName.Add(961, "rho");\r
+            _entityValue.Add("sigmaf", 962); // greek small letter final sigma, U+03C2 ISOgrk3 \r
+            _entityName.Add(962, "sigmaf");\r
+            _entityValue.Add("sigma", 963); // greek small letter sigma, U+03C3 ISOgrk3 \r
+            _entityName.Add(963, "sigma");\r
+            _entityValue.Add("tau", 964); // greek small letter tau, U+03C4 ISOgrk3 \r
+            _entityName.Add(964, "tau");\r
+            _entityValue.Add("upsilon", 965); // greek small letter upsilon, U+03C5 ISOgrk3 \r
+            _entityName.Add(965, "upsilon");\r
+            _entityValue.Add("phi", 966); // greek small letter phi, U+03C6 ISOgrk3 \r
+            _entityName.Add(966, "phi");\r
+            _entityValue.Add("chi", 967); // greek small letter chi, U+03C7 ISOgrk3 \r
+            _entityName.Add(967, "chi");\r
+            _entityValue.Add("psi", 968); // greek small letter psi, U+03C8 ISOgrk3 \r
+            _entityName.Add(968, "psi");\r
+            _entityValue.Add("omega", 969); // greek small letter omega, U+03C9 ISOgrk3 \r
+            _entityName.Add(969, "omega");\r
+            _entityValue.Add("thetasym", 977); // greek small letter theta symbol, U+03D1 NEW \r
+            _entityName.Add(977, "thetasym");\r
+            _entityValue.Add("upsih", 978); // greek upsilon with hook symbol, U+03D2 NEW \r
+            _entityName.Add(978, "upsih");\r
+            _entityValue.Add("piv", 982); // greek pi symbol, U+03D6 ISOgrk3 \r
+            _entityName.Add(982, "piv");\r
+            _entityValue.Add("bull", 8226); // bullet = black small circle, U+2022 ISOpub \r
+            _entityName.Add(8226, "bull");\r
+            _entityValue.Add("hellip", 8230); // horizontal ellipsis = three dot leader, U+2026 ISOpub \r
+            _entityName.Add(8230, "hellip");\r
+            _entityValue.Add("prime", 8242); // prime = minutes = feet, U+2032 ISOtech \r
+            _entityName.Add(8242, "prime");\r
+            _entityValue.Add("Prime", 8243); // double prime = seconds = inches, U+2033 ISOtech \r
+            _entityName.Add(8243, "Prime");\r
+            _entityValue.Add("oline", 8254); // overline = spacing overscore, U+203E NEW \r
+            _entityName.Add(8254, "oline");\r
+            _entityValue.Add("frasl", 8260); // fraction slash, U+2044 NEW \r
+            _entityName.Add(8260, "frasl");\r
+            _entityValue.Add("weierp", 8472); // script capital P = power set = Weierstrass p, U+2118 ISOamso \r
+            _entityName.Add(8472, "weierp");\r
+            _entityValue.Add("image", 8465); // blackletter capital I = imaginary part, U+2111 ISOamso \r
+            _entityName.Add(8465, "image");\r
+            _entityValue.Add("real", 8476); // blackletter capital R = real part symbol, U+211C ISOamso \r
+            _entityName.Add(8476, "real");\r
+            _entityValue.Add("trade", 8482); // trade mark sign, U+2122 ISOnum \r
+            _entityName.Add(8482, "trade");\r
+            _entityValue.Add("alefsym", 8501); // alef symbol = first transfinite cardinal, U+2135 NEW \r
+            _entityName.Add(8501, "alefsym");\r
+            _entityValue.Add("larr", 8592); // leftwards arrow, U+2190 ISOnum \r
+            _entityName.Add(8592, "larr");\r
+            _entityValue.Add("uarr", 8593); // upwards arrow, U+2191 ISOnum\r
+            _entityName.Add(8593, "uarr");\r
+            _entityValue.Add("rarr", 8594); // rightwards arrow, U+2192 ISOnum \r
+            _entityName.Add(8594, "rarr");\r
+            _entityValue.Add("darr", 8595); // downwards arrow, U+2193 ISOnum \r
+            _entityName.Add(8595, "darr");\r
+            _entityValue.Add("harr", 8596); // left right arrow, U+2194 ISOamsa \r
+            _entityName.Add(8596, "harr");\r
+            _entityValue.Add("crarr", 8629); // downwards arrow with corner leftwards = carriage return, U+21B5 NEW \r
+            _entityName.Add(8629, "crarr");\r
+            _entityValue.Add("lArr", 8656); // leftwards double arrow, U+21D0 ISOtech \r
+            _entityName.Add(8656, "lArr");\r
+            _entityValue.Add("uArr", 8657); // upwards double arrow, U+21D1 ISOamsa \r
+            _entityName.Add(8657, "uArr");\r
+            _entityValue.Add("rArr", 8658); // rightwards double arrow, U+21D2 ISOtech \r
+            _entityName.Add(8658, "rArr");\r
+            _entityValue.Add("dArr", 8659); // downwards double arrow, U+21D3 ISOamsa \r
+            _entityName.Add(8659, "dArr");\r
+            _entityValue.Add("hArr", 8660); // left right double arrow, U+21D4 ISOamsa \r
+            _entityName.Add(8660, "hArr");\r
+            _entityValue.Add("forall", 8704); // for all, U+2200 ISOtech \r
+            _entityName.Add(8704, "forall");\r
+            _entityValue.Add("part", 8706); // partial differential, U+2202 ISOtech \r
+            _entityName.Add(8706, "part");\r
+            _entityValue.Add("exist", 8707); // there exists, U+2203 ISOtech \r
+            _entityName.Add(8707, "exist");\r
+            _entityValue.Add("empty", 8709); // empty set = null set = diameter, U+2205 ISOamso \r
+            _entityName.Add(8709, "empty");\r
+            _entityValue.Add("nabla", 8711); // nabla = backward difference, U+2207 ISOtech \r
+            _entityName.Add(8711, "nabla");\r
+            _entityValue.Add("isin", 8712); // element of, U+2208 ISOtech \r
+            _entityName.Add(8712, "isin");\r
+            _entityValue.Add("notin", 8713); // not an element of, U+2209 ISOtech \r
+            _entityName.Add(8713, "notin");\r
+            _entityValue.Add("ni", 8715); // contains as member, U+220B ISOtech \r
+            _entityName.Add(8715, "ni");\r
+            _entityValue.Add("prod", 8719); // n-ary product = product sign, U+220F ISOamsb \r
+            _entityName.Add(8719, "prod");\r
+            _entityValue.Add("sum", 8721); // n-ary sumation, U+2211 ISOamsb \r
+            _entityName.Add(8721, "sum");\r
+            _entityValue.Add("minus", 8722); // minus sign, U+2212 ISOtech \r
+            _entityName.Add(8722, "minus");\r
+            _entityValue.Add("lowast", 8727); // asterisk operator, U+2217 ISOtech \r
+            _entityName.Add(8727, "lowast");\r
+            _entityValue.Add("radic", 8730); // square root = radical sign, U+221A ISOtech \r
+            _entityName.Add(8730, "radic");\r
+            _entityValue.Add("prop", 8733); // proportional to, U+221D ISOtech \r
+            _entityName.Add(8733, "prop");\r
+            _entityValue.Add("infin", 8734); // infinity, U+221E ISOtech \r
+            _entityName.Add(8734, "infin");\r
+            _entityValue.Add("ang", 8736); // angle, U+2220 ISOamso \r
+            _entityName.Add(8736, "ang");\r
+            _entityValue.Add("and", 8743); // logical and = wedge, U+2227 ISOtech \r
+            _entityName.Add(8743, "and");\r
+            _entityValue.Add("or", 8744); // logical or = vee, U+2228 ISOtech \r
+            _entityName.Add(8744, "or");\r
+            _entityValue.Add("cap", 8745); // intersection = cap, U+2229 ISOtech \r
+            _entityName.Add(8745, "cap");\r
+            _entityValue.Add("cup", 8746); // union = cup, U+222A ISOtech \r
+            _entityName.Add(8746, "cup");\r
+            _entityValue.Add("int", 8747); // integral, U+222B ISOtech \r
+            _entityName.Add(8747, "int");\r
+            _entityValue.Add("there4", 8756); // therefore, U+2234 ISOtech \r
+            _entityName.Add(8756, "there4");\r
+            _entityValue.Add("sim", 8764); // tilde operator = varies with = similar to, U+223C ISOtech \r
+            _entityName.Add(8764, "sim");\r
+            _entityValue.Add("cong", 8773); // approximately equal to, U+2245 ISOtech \r
+            _entityName.Add(8773, "cong");\r
+            _entityValue.Add("asymp", 8776); // almost equal to = asymptotic to, U+2248 ISOamsr \r
+            _entityName.Add(8776, "asymp");\r
+            _entityValue.Add("ne", 8800); // not equal to, U+2260 ISOtech \r
+            _entityName.Add(8800, "ne");\r
+            _entityValue.Add("equiv", 8801); // identical to, U+2261 ISOtech \r
+            _entityName.Add(8801, "equiv");\r
+            _entityValue.Add("le", 8804); // less-than or equal to, U+2264 ISOtech \r
+            _entityName.Add(8804, "le");\r
+            _entityValue.Add("ge", 8805); // greater-than or equal to, U+2265 ISOtech \r
+            _entityName.Add(8805, "ge");\r
+            _entityValue.Add("sub", 8834); // subset of, U+2282 ISOtech \r
+            _entityName.Add(8834, "sub");\r
+            _entityValue.Add("sup", 8835); // superset of, U+2283 ISOtech \r
+            _entityName.Add(8835, "sup");\r
+            _entityValue.Add("nsub", 8836); // not a subset of, U+2284 ISOamsn \r
+            _entityName.Add(8836, "nsub");\r
+            _entityValue.Add("sube", 8838); // subset of or equal to, U+2286 ISOtech \r
+            _entityName.Add(8838, "sube");\r
+            _entityValue.Add("supe", 8839); // superset of or equal to, U+2287 ISOtech \r
+            _entityName.Add(8839, "supe");\r
+            _entityValue.Add("oplus", 8853); // circled plus = direct sum, U+2295 ISOamsb \r
+            _entityName.Add(8853, "oplus");\r
+            _entityValue.Add("otimes", 8855); // circled times = vector product, U+2297 ISOamsb \r
+            _entityName.Add(8855, "otimes");\r
+            _entityValue.Add("perp", 8869); // up tack = orthogonal to = perpendicular, U+22A5 ISOtech \r
+            _entityName.Add(8869, "perp");\r
+            _entityValue.Add("sdot", 8901); // dot operator, U+22C5 ISOamsb \r
+            _entityName.Add(8901, "sdot");\r
+            _entityValue.Add("lceil", 8968); // left ceiling = apl upstile, U+2308 ISOamsc \r
+            _entityName.Add(8968, "lceil");\r
+            _entityValue.Add("rceil", 8969); // right ceiling, U+2309 ISOamsc \r
+            _entityName.Add(8969, "rceil");\r
+            _entityValue.Add("lfloor", 8970); // left floor = apl downstile, U+230A ISOamsc \r
+            _entityName.Add(8970, "lfloor");\r
+            _entityValue.Add("rfloor", 8971); // right floor, U+230B ISOamsc \r
+            _entityName.Add(8971, "rfloor");\r
+            _entityValue.Add("lang", 9001); // left-pointing angle bracket = bra, U+2329 ISOtech \r
+            _entityName.Add(9001, "lang");\r
+            _entityValue.Add("rang", 9002); // right-pointing angle bracket = ket, U+232A ISOtech \r
+            _entityName.Add(9002, "rang");\r
+            _entityValue.Add("loz", 9674); // lozenge, U+25CA ISOpub \r
+            _entityName.Add(9674, "loz");\r
+            _entityValue.Add("spades", 9824); // black spade suit, U+2660 ISOpub \r
+            _entityName.Add(9824, "spades");\r
+            _entityValue.Add("clubs", 9827); // black club suit = shamrock, U+2663 ISOpub \r
+            _entityName.Add(9827, "clubs");\r
+            _entityValue.Add("hearts", 9829); // black heart suit = valentine, U+2665 ISOpub \r
+            _entityName.Add(9829, "hearts");\r
+            _entityValue.Add("diams", 9830); // black diamond suit, U+2666 ISOpub \r
+            _entityName.Add(9830, "diams");\r
+            _entityValue.Add("quot", 34); // quotation mark = APL quote, U+0022 ISOnum \r
+            _entityName.Add(34, "quot");\r
+            _entityValue.Add("amp", 38); // ampersand, U+0026 ISOnum \r
+            _entityName.Add(38, "amp");\r
+            _entityValue.Add("lt", 60); // less-than sign, U+003C ISOnum \r
+            _entityName.Add(60, "lt");\r
+            _entityValue.Add("gt", 62); // greater-than sign, U+003E ISOnum \r
+            _entityName.Add(62, "gt");\r
+            _entityValue.Add("OElig", 338); // latin capital ligature OE, U+0152 ISOlat2 \r
+            _entityName.Add(338, "OElig");\r
+            _entityValue.Add("oelig", 339); // latin small ligature oe, U+0153 ISOlat2 \r
+            _entityName.Add(339, "oelig");\r
+            _entityValue.Add("Scaron", 352); // latin capital letter S with caron, U+0160 ISOlat2 \r
+            _entityName.Add(352, "Scaron");\r
+            _entityValue.Add("scaron", 353); // latin small letter s with caron, U+0161 ISOlat2 \r
+            _entityName.Add(353, "scaron");\r
+            _entityValue.Add("Yuml", 376); // latin capital letter Y with diaeresis, U+0178 ISOlat2 \r
+            _entityName.Add(376, "Yuml");\r
+            _entityValue.Add("circ", 710); // modifier letter circumflex accent, U+02C6 ISOpub \r
+            _entityName.Add(710, "circ");\r
+            _entityValue.Add("tilde", 732); // small tilde, U+02DC ISOdia \r
+            _entityName.Add(732, "tilde");\r
+            _entityValue.Add("ensp", 8194); // en space, U+2002 ISOpub \r
+            _entityName.Add(8194, "ensp");\r
+            _entityValue.Add("emsp", 8195); // em space, U+2003 ISOpub \r
+            _entityName.Add(8195, "emsp");\r
+            _entityValue.Add("thinsp", 8201); // thin space, U+2009 ISOpub \r
+            _entityName.Add(8201, "thinsp");\r
+            _entityValue.Add("zwnj", 8204); // zero width non-joiner, U+200C NEW RFC 2070 \r
+            _entityName.Add(8204, "zwnj");\r
+            _entityValue.Add("zwj", 8205); // zero width joiner, U+200D NEW RFC 2070 \r
+            _entityName.Add(8205, "zwj");\r
+            _entityValue.Add("lrm", 8206); // left-to-right mark, U+200E NEW RFC 2070 \r
+            _entityName.Add(8206, "lrm");\r
+            _entityValue.Add("rlm", 8207); // right-to-left mark, U+200F NEW RFC 2070 \r
+            _entityName.Add(8207, "rlm");\r
+            _entityValue.Add("ndash", 8211); // en dash, U+2013 ISOpub \r
+            _entityName.Add(8211, "ndash");\r
+            _entityValue.Add("mdash", 8212); // em dash, U+2014 ISOpub \r
+            _entityName.Add(8212, "mdash");\r
+            _entityValue.Add("lsquo", 8216); // left single quotation mark, U+2018 ISOnum \r
+            _entityName.Add(8216, "lsquo");\r
+            _entityValue.Add("rsquo", 8217); // right single quotation mark, U+2019 ISOnum \r
+            _entityName.Add(8217, "rsquo");\r
+            _entityValue.Add("sbquo", 8218); // single low-9 quotation mark, U+201A NEW \r
+            _entityName.Add(8218, "sbquo");\r
+            _entityValue.Add("ldquo", 8220); // left double quotation mark, U+201C ISOnum \r
+            _entityName.Add(8220, "ldquo");\r
+            _entityValue.Add("rdquo", 8221); // right double quotation mark, U+201D ISOnum \r
+            _entityName.Add(8221, "rdquo");\r
+            _entityValue.Add("bdquo", 8222); // double low-9 quotation mark, U+201E NEW \r
+            _entityName.Add(8222, "bdquo");\r
+            _entityValue.Add("dagger", 8224); // dagger, U+2020 ISOpub \r
+            _entityName.Add(8224, "dagger");\r
+            _entityValue.Add("Dagger", 8225); // double dagger, U+2021 ISOpub \r
+            _entityName.Add(8225, "Dagger");\r
+            _entityValue.Add("permil", 8240); // per mille sign, U+2030 ISOtech \r
+            _entityName.Add(8240, "permil");\r
+            _entityValue.Add("lsaquo", 8249); // single left-pointing angle quotation mark, U+2039 ISO proposed \r
+            _entityName.Add(8249, "lsaquo");\r
+            _entityValue.Add("rsaquo", 8250); // single right-pointing angle quotation mark, U+203A ISO proposed \r
+            _entityName.Add(8250, "rsaquo");\r
+            _entityValue.Add("euro", 8364); // euro sign, U+20AC NEW \r
+            _entityName.Add(8364, "euro");\r
+\r
+            _maxEntitySize = 8 + 1; // we add the # char\r
+\r
+            #endregion\r
+        }\r
+\r
+        private HtmlEntity()\r
+        {\r
+        }\r
+\r
+        #endregion\r
+\r
+        #region Public Methods\r
+\r
+        /// <summary>\r
+        /// Replace known entities by characters.\r
+        /// </summary>\r
+        /// <param name="text">The source text.</param>\r
+        /// <returns>The result text.</returns>\r
+        public static string DeEntitize(string text)\r
+        {\r
+            if (text == null)\r
+                return null;\r
+\r
+            if (text.Length == 0)\r
+                return text;\r
+\r
+            StringBuilder sb = new StringBuilder(text.Length);\r
+            ParseState state = ParseState.Text;\r
+            StringBuilder entity = new StringBuilder(10);\r
+\r
+            for (int i = 0; i < text.Length; i++)\r
+            {\r
+                switch (state)\r
+                {\r
+                    case ParseState.Text:\r
+                        switch (text[i])\r
+                        {\r
+                            case '&':\r
+                                state = ParseState.EntityStart;\r
+                                break;\r
+\r
+                            default:\r
+                                sb.Append(text[i]);\r
+                                break;\r
+                        }\r
+                        break;\r
+\r
+                    case ParseState.EntityStart:\r
+                        switch (text[i])\r
+                        {\r
+                            case ';':\r
+                                if (entity.Length == 0)\r
+                                {\r
+                                    sb.Append("&;");\r
+                                }\r
+                                else\r
+                                {\r
+                                    if (entity[0] == '#')\r
+                                    {\r
+                                        string e = entity.ToString();\r
+                                        try\r
+                                        {\r
+                                            int code = Convert.ToInt32(e.Substring(1, e.Length - 1));\r
+                                            sb.Append(Convert.ToChar(code));\r
+                                        }\r
+                                        catch\r
+                                        {\r
+                                            sb.Append("&#" + e + ";");\r
+                                        }\r
+                                    }\r
+                                    else\r
+                                    {\r
+                                        // named entity?\r
+                                        int code;\r
+                                        object o = _entityValue[entity.ToString()];\r
+                                        if (o == null)\r
+                                        {\r
+                                            // nope\r
+                                            sb.Append("&" + entity + ";");\r
+                                        }\r
+                                        else\r
+                                        {\r
+                                            // we found one\r
+                                            code = (int) o;\r
+                                            sb.Append(Convert.ToChar(code));\r
+                                        }\r
+                                    }\r
+                                    entity.Remove(0, entity.Length);\r
+                                }\r
+                                state = ParseState.Text;\r
+                                break;\r
+\r
+                            case '&':\r
+                                // new entity start without end, it was not an entity...\r
+                                sb.Append("&" + entity);\r
+                                entity.Remove(0, entity.Length);\r
+                                break;\r
+\r
+                            default:\r
+                                entity.Append(text[i]);\r
+                                if (entity.Length > _maxEntitySize)\r
+                                {\r
+                                    // unknown stuff, just don't touch it\r
+                                    state = ParseState.Text;\r
+                                    sb.Append("&" + entity);\r
+                                    entity.Remove(0, entity.Length);\r
+                                }\r
+                                break;\r
+                        }\r
+                        break;\r
+                }\r
+            }\r
+\r
+            // finish the work\r
+            if (state == ParseState.EntityStart)\r
+            {\r
+                sb.Append("&" + entity);\r
+            }\r
+            return sb.ToString();\r
+        }\r
+\r
+        /// <summary>\r
+        /// Clone and entitize an HtmlNode. This will affect attribute values and nodes' text. It will also entitize all child nodes.\r
+        /// </summary>\r
+        /// <param name="node">The node to entitize.</param>\r
+        /// <returns>An entitized cloned node.</returns>\r
+        public static HtmlNode Entitize(HtmlNode node)\r
+        {\r
+            if (node == null)\r
+            {\r
+                throw new ArgumentNullException("node");\r
+            }\r
+            HtmlNode result = node.CloneNode(true);\r
+            if (result.HasAttributes)\r
+                Entitize(result.Attributes);\r
+\r
+            if (result.HasChildNodes)\r
+            {\r
+                Entitize(result.ChildNodes);\r
+            }\r
+            else\r
+            {\r
+                if (result.NodeType == HtmlNodeType.Text)\r
+                {\r
+                    ((HtmlTextNode) result).Text = Entitize(((HtmlTextNode) result).Text, true, true);\r
+                }\r
+            }\r
+            return result;\r
+        }\r
+\r
+\r
+        /// <summary>\r
+        /// Replace characters above 127 by entities.\r
+        /// </summary>\r
+        /// <param name="text">The source text.</param>\r
+        /// <returns>The result text.</returns>\r
+        public static string Entitize(string text)\r
+        {\r
+            return Entitize(text, true);\r
+        }\r
+\r
+        /// <summary>\r
+        /// Replace characters above 127 by entities.\r
+        /// </summary>\r
+        /// <param name="text">The source text.</param>\r
+        /// <param name="useNames">If set to false, the function will not use known entities name. Default is true.</param>\r
+        /// <returns>The result text.</returns>\r
+        public static string Entitize(string text, bool useNames)\r
+        {\r
+            return Entitize(text, useNames, false);\r
+        }\r
+\r
+        /// <summary>\r
+        /// Replace characters above 127 by entities.\r
+        /// </summary>\r
+        /// <param name="text">The source text.</param>\r
+        /// <param name="useNames">If set to false, the function will not use known entities name. Default is true.</param>\r
+        /// <param name="entitizeQuotAmpAndLtGt">If set to true, the [quote], [ampersand], [lower than] and [greather than] characters will be entitized.</param>\r
+        /// <returns>The result text</returns>\r
+        public static string Entitize(string text, bool useNames, bool entitizeQuotAmpAndLtGt)\r
+//             _entityValue.Add("quot", 34);   // quotation mark = APL quote, U+0022 ISOnum \r
+//             _entityName.Add(34, "quot");\r
+//             _entityValue.Add("amp", 38);    // ampersand, U+0026 ISOnum \r
+//             _entityName.Add(38, "amp");\r
+//             _entityValue.Add("lt", 60);     // less-than sign, U+003C ISOnum \r
+//             _entityName.Add(60, "lt");\r
+//             _entityValue.Add("gt", 62);     // greater-than sign, U+003E ISOnum \r
+//             _entityName.Add(62, "gt");\r
+        {\r
+            if (text == null)\r
+                return null;\r
+\r
+            if (text.Length == 0)\r
+                return text;\r
+\r
+            StringBuilder sb = new StringBuilder(text.Length);\r
+            for (int i = 0; i < text.Length; i++)\r
+            {\r
+                int code = text[i];\r
+                if ((code > 127) ||\r
+                    (entitizeQuotAmpAndLtGt && ((code == 34) || (code == 38) || (code == 60) || (code == 62))))\r
+                {\r
+                    string entity = _entityName[code] as string;\r
+                    if ((entity == null) || (!useNames))\r
+                    {\r
+                        sb.Append("&#" + code + ";");\r
+                    }\r
+                    else\r
+                    {\r
+                        sb.Append("&" + entity + ";");\r
+                    }\r
+                }\r
+                else\r
+                {\r
+                    sb.Append(text[i]);\r
+                }\r
+            }\r
+\r
+            return sb.ToString();\r
+        }\r
+\r
+        #endregion\r
+\r
+        #region Private Methods\r
+\r
+        private static void Entitize(HtmlAttributeCollection collection)\r
+        {\r
+            foreach (HtmlAttribute at in collection)\r
+            {\r
+                at.Value = Entitize(at.Value);\r
+            }\r
+        }\r
+\r
+        private static void Entitize(HtmlNodeCollection collection)\r
+        {\r
+            foreach (HtmlNode node in collection)\r
+            {\r
+                if (node.HasAttributes)\r
+                    Entitize(node.Attributes);\r
+\r
+                if (node.HasChildNodes)\r
+                {\r
+                    Entitize(node.ChildNodes);\r
+                }\r
+                else\r
+                {\r
+                    if (node.NodeType == HtmlNodeType.Text)\r
+                    {\r
+                        ((HtmlTextNode) node).Text = Entitize(((HtmlTextNode) node).Text, true, true);\r
+                    }\r
+                }\r
+            }\r
+        }\r
+\r
+        #endregion\r
+\r
+        #region Nested type: ParseState\r
+\r
+        private enum ParseState\r
+        {\r
+            Text,\r
+            EntityStart\r
+        }\r
+\r
+        #endregion\r
+    }\r
+}
\ No newline at end of file
diff --git a/docs/HtmlAgilityPack/HtmlNameTable.cs b/docs/HtmlAgilityPack/HtmlNameTable.cs
new file mode 100644 (file)
index 0000000..2b9ffd3
--- /dev/null
@@ -0,0 +1,52 @@
+// HtmlAgilityPack V1.0 - Simon Mourier <simon underscore mourier at hotmail dot com>\r
+using System.Xml;\r
+\r
+namespace HtmlAgilityPack\r
+{\r
+    internal class HtmlNameTable : XmlNameTable\r
+    {\r
+        #region Fields\r
+\r
+        private NameTable _nametable = new NameTable();\r
+\r
+        #endregion\r
+\r
+        #region Public Methods\r
+\r
+        public override string Add(string array)\r
+        {\r
+            return _nametable.Add(array);\r
+        }\r
+\r
+        public override string Add(char[] array, int offset, int length)\r
+        {\r
+            return _nametable.Add(array, offset, length);\r
+        }\r
+\r
+        public override string Get(string array)\r
+        {\r
+            return _nametable.Get(array);\r
+        }\r
+\r
+        public override string Get(char[] array, int offset, int length)\r
+        {\r
+            return _nametable.Get(array, offset, length);\r
+        }\r
+\r
+        #endregion\r
+\r
+        #region Internal Methods\r
+\r
+        internal string GetOrAdd(string array)\r
+        {\r
+            string s = Get(array);\r
+            if (s == null)\r
+            {\r
+                return Add(array);\r
+            }\r
+            return s;\r
+        }\r
+\r
+        #endregion\r
+    }\r
+}
\ No newline at end of file
diff --git a/docs/HtmlAgilityPack/HtmlNode.cs b/docs/HtmlAgilityPack/HtmlNode.cs
new file mode 100644 (file)
index 0000000..ecc915e
--- /dev/null
@@ -0,0 +1,1996 @@
+// HtmlAgilityPack V1.0 - Simon Mourier <simon underscore mourier at hotmail dot com>\r
+using System;\r
+using System.Collections;\r
+using System.Collections.Generic;\r
+using System.Diagnostics;\r
+using System.IO;\r
+using System.Xml;\r
+using System.Xml.XPath;\r
+\r
+namespace HtmlAgilityPack\r
+{\r
+    /// <summary>\r
+    /// Represents an HTML node.\r
+    /// </summary>\r
+    [DebuggerDisplay("Name: {OriginalName}}")]\r
+    public class HtmlNode : IXPathNavigable\r
+    {\r
+        #region Fields\r
+\r
+        internal HtmlAttributeCollection _attributes;\r
+        internal HtmlNodeCollection _childnodes;\r
+        internal HtmlNode _endnode;\r
+\r
+        internal bool _innerchanged;\r
+        internal string _innerhtml;\r
+        internal int _innerlength;\r
+        internal int _innerstartindex;\r
+        internal int _line;\r
+        internal int _lineposition;\r
+        private string _name;\r
+        internal int _namelength;\r
+        internal int _namestartindex;\r
+        internal HtmlNode _nextnode;\r
+        internal HtmlNodeType _nodetype;\r
+        internal bool _outerchanged;\r
+        internal string _outerhtml;\r
+        internal int _outerlength;\r
+        internal int _outerstartindex;\r
+        internal HtmlDocument _ownerdocument;\r
+        internal HtmlNode _parentnode;\r
+        internal HtmlNode _prevnode;\r
+        internal HtmlNode _prevwithsamename;\r
+        internal bool _starttag;\r
+        internal int _streamposition;\r
+\r
+        #endregion\r
+\r
+        #region Static Members\r
+\r
+        /// <summary>\r
+        /// Gets the name of a comment node. It is actually defined as '#comment'.\r
+        /// </summary>\r
+        public static readonly string HtmlNodeTypeNameComment = "#comment";\r
+\r
+        /// <summary>\r
+        /// Gets the name of the document node. It is actually defined as '#document'.\r
+        /// </summary>\r
+        public static readonly string HtmlNodeTypeNameDocument = "#document";\r
+\r
+        /// <summary>\r
+        /// Gets the name of a text node. It is actually defined as '#text'.\r
+        /// </summary>\r
+        public static readonly string HtmlNodeTypeNameText = "#text";\r
+\r
+        /// <summary>\r
+        /// Gets a collection of flags that define specific behaviors for specific element nodes.\r
+        /// The table contains a DictionaryEntry list with the lowercase tag name as the Key, and a combination of HtmlElementFlags as the Value.\r
+        /// </summary>\r
+        public static Hashtable ElementsFlags;\r
+\r
+        #endregion\r
+\r
+        #region Constructors\r
+\r
+        /// <summary>\r
+        /// Initialize HtmlNode. Builds a list of all tags that have special allowances\r
+        /// </summary>\r
+        static HtmlNode()\r
+        {\r
+            // tags whose content may be anything\r
+            ElementsFlags = new Hashtable();\r
+            ElementsFlags.Add("script", HtmlElementFlag.CData);\r
+            ElementsFlags.Add("style", HtmlElementFlag.CData);\r
+            ElementsFlags.Add("noxhtml", HtmlElementFlag.CData);\r
+\r
+            // tags that can not contain other tags\r
+            ElementsFlags.Add("base", HtmlElementFlag.Empty);\r
+            ElementsFlags.Add("link", HtmlElementFlag.Empty);\r
+            ElementsFlags.Add("meta", HtmlElementFlag.Empty);\r
+            ElementsFlags.Add("isindex", HtmlElementFlag.Empty);\r
+            ElementsFlags.Add("hr", HtmlElementFlag.Empty);\r
+            ElementsFlags.Add("col", HtmlElementFlag.Empty);\r
+            ElementsFlags.Add("img", HtmlElementFlag.Empty);\r
+            ElementsFlags.Add("param", HtmlElementFlag.Empty);\r
+            ElementsFlags.Add("embed", HtmlElementFlag.Empty);\r
+            ElementsFlags.Add("frame", HtmlElementFlag.Empty);\r
+            ElementsFlags.Add("wbr", HtmlElementFlag.Empty);\r
+            ElementsFlags.Add("bgsound", HtmlElementFlag.Empty);\r
+            ElementsFlags.Add("spacer", HtmlElementFlag.Empty);\r
+            ElementsFlags.Add("keygen", HtmlElementFlag.Empty);\r
+            ElementsFlags.Add("area", HtmlElementFlag.Empty);\r
+            ElementsFlags.Add("input", HtmlElementFlag.Empty);\r
+            ElementsFlags.Add("basefont", HtmlElementFlag.Empty);\r
+\r
+            ElementsFlags.Add("form", HtmlElementFlag.CanOverlap | HtmlElementFlag.Empty);\r
+\r
+            // they sometimes contain, and sometimes they don 't...\r
+            ElementsFlags.Add("option", HtmlElementFlag.Empty);\r
+\r
+            // tag whose closing tag is equivalent to open tag:\r
+            // <p>bla</p>bla will be transformed into <p>bla</p>bla\r
+            // <p>bla<p>bla will be transformed into <p>bla<p>bla and not <p>bla></p><p>bla</p> or <p>bla<p>bla</p></p>\r
+            //<br> see above\r
+            ElementsFlags.Add("br", HtmlElementFlag.Empty | HtmlElementFlag.Closed);\r
+            ElementsFlags.Add("p", HtmlElementFlag.Empty | HtmlElementFlag.Closed);\r
+        }\r
+\r
+        /// <summary>\r
+        /// Initializes HtmlNode, providing type, owner and where it exists in a collection\r
+        /// </summary>\r
+        /// <param name="type"></param>\r
+        /// <param name="ownerdocument"></param>\r
+        /// <param name="index"></param>\r
+        public HtmlNode(HtmlNodeType type, HtmlDocument ownerdocument, int index)\r
+        {\r
+            _nodetype = type;\r
+            _ownerdocument = ownerdocument;\r
+            _outerstartindex = index;\r
+\r
+            switch (type)\r
+            {\r
+                case HtmlNodeType.Comment:\r
+                    Name = HtmlNodeTypeNameComment;\r
+                    _endnode = this;\r
+                    break;\r
+\r
+                case HtmlNodeType.Document:\r
+                    Name = HtmlNodeTypeNameDocument;\r
+                    _endnode = this;\r
+                    break;\r
+\r
+                case HtmlNodeType.Text:\r
+                    Name = HtmlNodeTypeNameText;\r
+                    _endnode = this;\r
+                    break;\r
+            }\r
+\r
+            if (_ownerdocument._openednodes != null)\r
+            {\r
+                if (!Closed)\r
+                {\r
+                    // we use the index as the key\r
+\r
+                    // -1 means the node comes from public\r
+                    if (-1 != index)\r
+                    {\r
+                        _ownerdocument._openednodes.Add(index, this);\r
+                    }\r
+                }\r
+            }\r
+\r
+            if ((-1 != index) || (type == HtmlNodeType.Comment) || (type == HtmlNodeType.Text)) return;\r
+            // innerhtml and outerhtml must be calculated\r
+            _outerchanged = true;\r
+            _innerchanged = true;\r
+        }\r
+\r
+        #endregion\r
+\r
+        #region Properties\r
+\r
+        /// <summary>\r
+        /// Gets the collection of HTML attributes for this node. May not be null.\r
+        /// </summary>\r
+        public HtmlAttributeCollection Attributes\r
+        {\r
+            get\r
+            {\r
+                if (!HasAttributes)\r
+                {\r
+                    _attributes = new HtmlAttributeCollection(this);\r
+                }\r
+                return _attributes;\r
+            }\r
+            internal set { _attributes = value; }\r
+        }\r
+\r
+        /// <summary>\r
+        /// Gets all the children of the node.\r
+        /// </summary>\r
+        public HtmlNodeCollection ChildNodes\r
+        {\r
+            get\r
+            {\r
+                if (_childnodes == null)\r
+                {\r
+                    _childnodes = new HtmlNodeCollection(this);\r
+                }\r
+                return _childnodes;\r
+            }\r
+            internal set { _childnodes = value; }\r
+        }\r
+\r
+        /// <summary>\r
+        /// Gets a value indicating if this node has been closed or not.\r
+        /// </summary>\r
+        public bool Closed\r
+        {\r
+            get { return (_endnode != null); }\r
+        }\r
+\r
+        /// <summary>\r
+        /// Gets the collection of HTML attributes for the closing tag. May not be null.\r
+        /// </summary>\r
+        public HtmlAttributeCollection ClosingAttributes\r
+        {\r
+            get\r
+            {\r
+                if (!HasClosingAttributes)\r
+                {\r
+                    return new HtmlAttributeCollection(this);\r
+                }\r
+                return _endnode.Attributes;\r
+            }\r
+        }\r
+\r
+        internal HtmlNode EndNode\r
+        {\r
+            get { return _endnode; }\r
+        }\r
+\r
+        /// <summary>\r
+        /// Gets the first child of the node.\r
+        /// </summary>\r
+        public HtmlNode FirstChild\r
+        {\r
+            get\r
+            {\r
+                if (!HasChildNodes)\r
+                {\r
+                    return null;\r
+                }\r
+                return _childnodes[0];\r
+            }\r
+        }\r
+\r
+        /// <summary>\r
+        /// Gets a value indicating whether the current node has any attributes.\r
+        /// </summary>\r
+        public bool HasAttributes\r
+        {\r
+            get\r
+            {\r
+                if (_attributes == null)\r
+                {\r
+                    return false;\r
+                }\r
+\r
+                if (_attributes.Count <= 0)\r
+                {\r
+                    return false;\r
+                }\r
+                return true;\r
+            }\r
+        }\r
+\r
+        /// <summary>\r
+        /// Gets a value indicating whether this node has any child nodes.\r
+        /// </summary>\r
+        public bool HasChildNodes\r
+        {\r
+            get\r
+            {\r
+                if (_childnodes == null)\r
+                {\r
+                    return false;\r
+                }\r
+\r
+                if (_childnodes.Count <= 0)\r
+                {\r
+                    return false;\r
+                }\r
+                return true;\r
+            }\r
+        }\r
+\r
+        /// <summary>\r
+        /// Gets a value indicating whether the current node has any attributes on the closing tag.\r
+        /// </summary>\r
+        public bool HasClosingAttributes\r
+        {\r
+            get\r
+            {\r
+                if ((_endnode == null) || (_endnode == this))\r
+                {\r
+                    return false;\r
+                }\r
+\r
+                if (_endnode._attributes == null)\r
+                {\r
+                    return false;\r
+                }\r
+\r
+                if (_endnode._attributes.Count <= 0)\r
+                {\r
+                    return false;\r
+                }\r
+                return true;\r
+            }\r
+        }\r
+\r
+        /// <summary>\r
+        /// Gets or sets the value of the 'id' HTML attribute. The document must have been parsed using the OptionUseIdAttribute set to true.\r
+        /// </summary>\r
+        public string Id\r
+        {\r
+            get\r
+            {\r
+                if (_ownerdocument._nodesid == null)\r
+                {\r
+                    throw new Exception(HtmlDocument.HtmlExceptionUseIdAttributeFalse);\r
+                }\r
+                return GetId();\r
+            }\r
+            set\r
+            {\r
+                if (_ownerdocument._nodesid == null)\r
+                {\r
+                    throw new Exception(HtmlDocument.HtmlExceptionUseIdAttributeFalse);\r
+                }\r
+\r
+                if (value == null)\r
+                {\r
+                    throw new ArgumentNullException("value");\r
+                }\r
+                SetId(value);\r
+            }\r
+        }\r
+\r
+        /// <summary>\r
+        /// Gets or Sets the HTML between the start and end tags of the object.\r
+        /// </summary>\r
+        public virtual string InnerHtml\r
+        {\r
+            get\r
+            {\r
+                if (_innerchanged)\r
+                {\r
+                    _innerhtml = WriteContentTo();\r
+                    _innerchanged = false;\r
+                    return _innerhtml;\r
+                }\r
+                if (_innerhtml != null)\r
+                {\r
+                    return _innerhtml;\r
+                }\r
+\r
+                if (_innerstartindex < 0)\r
+                {\r
+                    return string.Empty;\r
+                }\r
+\r
+                return _ownerdocument._text.Substring(_innerstartindex, _innerlength);\r
+            }\r
+            set\r
+            {\r
+                HtmlDocument doc = new HtmlDocument();\r
+                doc.LoadHtml(value);\r
+\r
+                RemoveAllChildren();\r
+                AppendChildren(doc.DocumentNode.ChildNodes);\r
+            }\r
+        }\r
+\r
+        /// <summary>\r
+        /// Gets or Sets the text between the start and end tags of the object.\r
+        /// </summary>\r
+        public virtual string InnerText\r
+        {\r
+            get\r
+            {\r
+                if (_nodetype == HtmlNodeType.Text)\r
+                {\r
+                    return ((HtmlTextNode) this).Text;\r
+                }\r
+\r
+                if (_nodetype == HtmlNodeType.Comment)\r
+                {\r
+                    return ((HtmlCommentNode) this).Comment;\r
+                }\r
+\r
+                // note: right now, this method is *slow*, because we recompute everything.\r
+                // it could be optimised like innerhtml\r
+                if (!HasChildNodes)\r
+                {\r
+                    return string.Empty;\r
+                }\r
+\r
+                string s = null;\r
+                foreach (HtmlNode node in ChildNodes)\r
+                {\r
+                    s += node.InnerText;\r
+                }\r
+                return s;\r
+            }\r
+        }\r
+\r
+        /// <summary>\r
+        /// Gets the last child of the node.\r
+        /// </summary>\r
+        public HtmlNode LastChild\r
+        {\r
+            get\r
+            {\r
+                return !HasChildNodes ? null : _childnodes[_childnodes.Count - 1];\r
+            }\r
+        }\r
+\r
+        /// <summary>\r
+        /// Gets the line number of this node in the document.\r
+        /// </summary>\r
+        public int Line\r
+        {\r
+            get { return _line; }\r
+            internal set { _line = value; }\r
+        }\r
+\r
+        /// <summary>\r
+        /// Gets the column number of this node in the document.\r
+        /// </summary>\r
+        public int LinePosition\r
+        {\r
+            get { return _lineposition; }\r
+            internal set { _lineposition = value; }\r
+        }\r
+\r
+        /// <summary>\r
+        /// Gets or sets this node's name.\r
+        /// </summary>\r
+        public string Name\r
+        {\r
+            get\r
+            {\r
+                if (_name == null)\r
+                {\r
+                    Name = _ownerdocument._text.Substring(_namestartindex, _namelength);\r
+                }\r
+                return _name != null ? _name.ToLower() : string.Empty;\r
+            }\r
+            set { _name = value; }\r
+        }\r
+\r
+        /// <summary>\r
+        /// Gets the HTML node immediately following this element.\r
+        /// </summary>\r
+        public HtmlNode NextSibling\r
+        {\r
+            get { return _nextnode; }\r
+            internal set { _nextnode = value; }\r
+        }\r
+\r
+        /// <summary>\r
+        /// Gets the type of this node.\r
+        /// </summary>\r
+        public HtmlNodeType NodeType\r
+        {\r
+            get { return _nodetype; }\r
+            internal set { _nodetype = value; }\r
+        }\r
+\r
+        /// <summary>\r
+        /// The original unaltered name of the tag\r
+        /// </summary>\r
+        public string OriginalName\r
+        {\r
+            get { return _name; }\r
+        }\r
+\r
+        /// <summary>\r
+        /// Gets or Sets the object and its content in HTML.\r
+        /// </summary>\r
+        public virtual string OuterHtml\r
+        {\r
+            get\r
+            {\r
+                if (_outerchanged)\r
+                {\r
+                    _outerhtml = WriteTo();\r
+                    _outerchanged = false;\r
+                    return _outerhtml;\r
+                }\r
+\r
+                if (_outerhtml != null)\r
+                {\r
+                    return _outerhtml;\r
+                }\r
+\r
+                if (_outerstartindex < 0)\r
+                {\r
+                    return string.Empty;\r
+                }\r
+\r
+                return _ownerdocument._text.Substring(_outerstartindex, _outerlength);\r
+            }\r
+        }\r
+\r
+        /// <summary>\r
+        /// Gets the <see cref="HtmlDocument"/> to which this node belongs.\r
+        /// </summary>\r
+        public HtmlDocument OwnerDocument\r
+        {\r
+            get { return _ownerdocument; }\r
+            internal set { _ownerdocument = value; }\r
+        }\r
+\r
+        /// <summary>\r
+        /// Gets the parent of this node (for nodes that can have parents).\r
+        /// </summary>\r
+        public HtmlNode ParentNode\r
+        {\r
+            get { return _parentnode; }\r
+            internal set { _parentnode = value; }\r
+        }\r
+\r
+        /// <summary>\r
+        /// Gets the node immediately preceding this node.\r
+        /// </summary>\r
+        public HtmlNode PreviousSibling\r
+        {\r
+            get { return _prevnode; }\r
+            internal set { _prevnode = value; }\r
+        }\r
+\r
+        /// <summary>\r
+        /// Gets the stream position of this node in the document, relative to the start of the document.\r
+        /// </summary>\r
+        public int StreamPosition\r
+        {\r
+            get { return _streamposition; }\r
+        }\r
+\r
+        /// <summary>\r
+        /// Gets a valid XPath string that points to this node\r
+        /// </summary>\r
+        public string XPath\r
+        {\r
+            get\r
+            {\r
+                string basePath = (ParentNode == null || ParentNode.NodeType == HtmlNodeType.Document)\r
+                                      ? "/"\r
+                                      : ParentNode.XPath + "/";\r
+                return basePath + GetRelativeXpath();\r
+            }\r
+        }\r
+\r
+        #endregion\r
+\r
+        #region IXPathNavigable Members\r
+\r
+        /// <summary>\r
+        /// Creates a new XPathNavigator object for navigating this HTML node.\r
+        /// </summary>\r
+        /// <returns>An XPathNavigator object. The XPathNavigator is positioned on the node from which the method was called. It is not positioned on the root of the document.</returns>\r
+        public XPathNavigator CreateNavigator()\r
+        {\r
+            return new HtmlNodeNavigator(_ownerdocument, this);\r
+        }\r
+\r
+        #endregion\r
+\r
+        #region Public Methods\r
+\r
+        /// <summary>\r
+        /// Determines if an element node can be kept overlapped.\r
+        /// </summary>\r
+        /// <param name="name">The name of the element node to check. May not be <c>null</c>.</param>\r
+        /// <returns>true if the name is the name of an element node that can be kept overlapped, <c>false</c> otherwise.</returns>\r
+        public static bool CanOverlapElement(string name)\r
+        {\r
+            if (name == null)\r
+            {\r
+                throw new ArgumentNullException("name");\r
+            }\r
+\r
+            object flag = ElementsFlags[name.ToLower()];\r
+            if (flag == null)\r
+            {\r
+                return false;\r
+            }\r
+            return (((HtmlElementFlag) flag) & HtmlElementFlag.CanOverlap) != 0;\r
+        }\r
+\r
+        /// <summary>\r
+        /// Creates an HTML node from a string representing literal HTML.\r
+        /// </summary>\r
+        /// <param name="html">The HTML text.</param>\r
+        /// <returns>The newly created node instance.</returns>\r
+        public static HtmlNode CreateNode(string html)\r
+        {\r
+            // REVIEW: this is *not* optimum...\r
+            HtmlDocument doc = new HtmlDocument();\r
+            doc.LoadHtml(html);\r
+            return doc.DocumentNode.FirstChild;\r
+        }\r
+\r
+        /// <summary>\r
+        /// Determines if an element node is a CDATA element node.\r
+        /// </summary>\r
+        /// <param name="name">The name of the element node to check. May not be null.</param>\r
+        /// <returns>true if the name is the name of a CDATA element node, false otherwise.</returns>\r
+        public static bool IsCDataElement(string name)\r
+        {\r
+            if (name == null)\r
+            {\r
+                throw new ArgumentNullException("name");\r
+            }\r
+\r
+            object flag = ElementsFlags[name.ToLower()];\r
+            if (flag == null)\r
+            {\r
+                return false;\r
+            }\r
+            return (((HtmlElementFlag) flag) & HtmlElementFlag.CData) != 0;\r
+        }\r
+\r
+        /// <summary>\r
+        /// Determines if an element node is closed.\r
+        /// </summary>\r
+        /// <param name="name">The name of the element node to check. May not be null.</param>\r
+        /// <returns>true if the name is the name of a closed element node, false otherwise.</returns>\r
+        public static bool IsClosedElement(string name)\r
+        {\r
+            if (name == null)\r
+            {\r
+                throw new ArgumentNullException("name");\r
+            }\r
+\r
+            object flag = ElementsFlags[name.ToLower()];\r
+            if (flag == null)\r
+            {\r
+                return false;\r
+            }\r
+            return (((HtmlElementFlag) flag) & HtmlElementFlag.Closed) != 0;\r
+        }\r
+\r
+        /// <summary>\r
+        /// Determines if an element node is defined as empty.\r
+        /// </summary>\r
+        /// <param name="name">The name of the element node to check. May not be null.</param>\r
+        /// <returns>true if the name is the name of an empty element node, false otherwise.</returns>\r
+        public static bool IsEmptyElement(string name)\r
+        {\r
+            if (name == null)\r
+            {\r
+                throw new ArgumentNullException("name");\r
+            }\r
+\r
+            if (name.Length == 0)\r
+            {\r
+                return true;\r
+            }\r
+\r
+            // <!DOCTYPE ...\r
+            if ('!' == name[0])\r
+            {\r
+                return true;\r
+            }\r
+\r
+            // <?xml ...\r
+            if ('?' == name[0])\r
+            {\r
+                return true;\r
+            }\r
+\r
+            object flag = ElementsFlags[name.ToLower()];\r
+            if (flag == null)\r
+            {\r
+                return false;\r
+            }\r
+            return (((HtmlElementFlag) flag) & HtmlElementFlag.Empty) != 0;\r
+        }\r
+\r
+        /// <summary>\r
+        /// Determines if a text corresponds to the closing tag of an node that can be kept overlapped.\r
+        /// </summary>\r
+        /// <param name="text">The text to check. May not be null.</param>\r
+        /// <returns>true or false.</returns>\r
+        public static bool IsOverlappedClosingElement(string text)\r
+        {\r
+            if (text == null)\r
+            {\r
+                throw new ArgumentNullException("text");\r
+            }\r
+            // min is </x>: 4\r
+            if (text.Length <= 4)\r
+                return false;\r
+\r
+            if ((text[0] != '<') ||\r
+                (text[text.Length - 1] != '>') ||\r
+                (text[1] != '/'))\r
+                return false;\r
+\r
+            string name = text.Substring(2, text.Length - 3);\r
+            return CanOverlapElement(name);\r
+        }\r
+\r
+        /// <summary>\r
+        /// Returns a collection of all ancestor nodes of this element.\r
+        /// </summary>\r
+        /// <returns></returns>\r
+        public IEnumerable<HtmlNode> Ancestors()\r
+        {\r
+            HtmlNode node = ParentNode;\r
+            while (node.ParentNode != null)\r
+            {\r
+                yield return node.ParentNode;\r
+                node = node.ParentNode;\r
+            }\r
+        }\r
+\r
+        /// <summary>\r
+        /// Get Ancestors with matching name\r
+        /// </summary>\r
+        /// <param name="name"></param>\r
+        /// <returns></returns>\r
+        public IEnumerable<HtmlNode> Ancestors(string name)\r
+        {\r
+            for (HtmlNode n = ParentNode; n != null; n = n.ParentNode)\r
+                if (n.Name == name)\r
+                    yield return n;\r
+        }\r
+\r
+        /// <summary>\r
+        /// Returns a collection of all ancestor nodes of this element.\r
+        /// </summary>\r
+        /// <returns></returns>\r
+        public IEnumerable<HtmlNode> AncestorsAndSelf()\r
+        {\r
+            for (HtmlNode n = this; n != null; n = n.ParentNode)\r
+                yield return n;\r
+        }\r
+\r
+        /// <summary>\r
+        /// Gets all anscestor nodes and the current node\r
+        /// </summary>\r
+        /// <param name="name"></param>\r
+        /// <returns></returns>\r
+        public IEnumerable<HtmlNode> AncestorsAndSelf(string name)\r
+        {\r
+            for (HtmlNode n = this; n != null; n = n.ParentNode)\r
+                if (n.Name == name)\r
+                    yield return n;\r
+        }\r
+\r
+        /// <summary>\r
+        /// Adds the specified node to the end of the list of children of this node.\r
+        /// </summary>\r
+        /// <param name="newChild">The node to add. May not be null.</param>\r
+        /// <returns>The node added.</returns>\r
+        public HtmlNode AppendChild(HtmlNode newChild)\r
+        {\r
+            if (newChild == null)\r
+            {\r
+                throw new ArgumentNullException("newChild");\r
+            }\r
+\r
+            ChildNodes.Append(newChild);\r
+            _ownerdocument.SetIdForNode(newChild, newChild.GetId());\r
+            _outerchanged = true;\r
+            _innerchanged = true;\r
+            return newChild;\r
+        }\r
+\r
+        /// <summary>\r
+        /// Adds the specified node to the end of the list of children of this node.\r
+        /// </summary>\r
+        /// <param name="newChildren">The node list to add. May not be null.</param>\r
+        public void AppendChildren(HtmlNodeCollection newChildren)\r
+        {\r
+            if (newChildren == null)\r
+                throw new ArgumentNullException("newChildrend");\r
+\r
+            foreach (HtmlNode newChild in newChildren)\r
+            {\r
+                AppendChild(newChild);\r
+            }\r
+        }\r
+\r
+        /// <summary>\r
+        /// Gets all Attributes with name\r
+        /// </summary>\r
+        /// <param name="name"></param>\r
+        /// <returns></returns>\r
+        public IEnumerable<HtmlAttribute> ChildAttributes(string name)\r
+        {\r
+            return Attributes.AttributesWithName(name);\r
+        }\r
+\r
+        /// <summary>\r
+        /// Creates a duplicate of the node\r
+        /// </summary>\r
+        /// <returns></returns>\r
+        public HtmlNode Clone()\r
+        {\r
+            return CloneNode(true);\r
+        }\r
+\r
+        /// <summary>\r
+        /// Creates a duplicate of the node and changes its name at the same time.\r
+        /// </summary>\r
+        /// <param name="newName">The new name of the cloned node. May not be <c>null</c>.</param>\r
+        /// <returns>The cloned node.</returns>\r
+        public HtmlNode CloneNode(string newName)\r
+        {\r
+            return CloneNode(newName, true);\r
+        }\r
+\r
+        /// <summary>\r
+        /// Creates a duplicate of the node and changes its name at the same time.\r
+        /// </summary>\r
+        /// <param name="newName">The new name of the cloned node. May not be null.</param>\r
+        /// <param name="deep">true to recursively clone the subtree under the specified node; false to clone only the node itself.</param>\r
+        /// <returns>The cloned node.</returns>\r
+        public HtmlNode CloneNode(string newName, bool deep)\r
+        {\r
+            if (newName == null)\r
+            {\r
+                throw new ArgumentNullException("newName");\r
+            }\r
+\r
+            HtmlNode node = CloneNode(deep);\r
+            node.Name = newName;\r
+            return node;\r
+        }\r
+\r
+        /// <summary>\r
+        /// Creates a duplicate of the node.\r
+        /// </summary>\r
+        /// <param name="deep">true to recursively clone the subtree under the specified node; false to clone only the node itself.</param>\r
+        /// <returns>The cloned node.</returns>\r
+        public HtmlNode CloneNode(bool deep)\r
+        {\r
+            HtmlNode node = _ownerdocument.CreateNode(_nodetype);\r
+            node.Name = Name;\r
+\r
+            switch (_nodetype)\r
+            {\r
+                case HtmlNodeType.Comment:\r
+                    ((HtmlCommentNode) node).Comment = ((HtmlCommentNode) this).Comment;\r
+                    return node;\r
+\r
+                case HtmlNodeType.Text:\r
+                    ((HtmlTextNode) node).Text = ((HtmlTextNode) this).Text;\r
+                    return node;\r
+            }\r
+\r
+            // attributes\r
+            if (HasAttributes)\r
+            {\r
+                foreach (HtmlAttribute att in _attributes)\r
+                {\r
+                    HtmlAttribute newatt = att.Clone();\r
+                    node.Attributes.Append(newatt);\r
+                }\r
+            }\r
+\r
+            // closing attributes\r
+            if (HasClosingAttributes)\r
+            {\r
+                node._endnode = _endnode.CloneNode(false);\r
+                foreach (HtmlAttribute att in _endnode._attributes)\r
+                {\r
+                    HtmlAttribute newatt = att.Clone();\r
+                    node._endnode._attributes.Append(newatt);\r
+                }\r
+            }\r
+            if (!deep)\r
+            {\r
+                return node;\r
+            }\r
+\r
+            if (!HasChildNodes)\r
+            {\r
+                return node;\r
+            }\r
+\r
+            // child nodes\r
+            foreach (HtmlNode child in _childnodes)\r
+            {\r
+                HtmlNode newchild = child.Clone();\r
+                node.AppendChild(newchild);\r
+            }\r
+            return node;\r
+        }\r
+\r
+        /// <summary>\r
+        /// Creates a duplicate of the node and the subtree under it.\r
+        /// </summary>\r
+        /// <param name="node">The node to duplicate. May not be <c>null</c>.</param>\r
+        public void CopyFrom(HtmlNode node)\r
+        {\r
+            CopyFrom(node, true);\r
+        }\r
+\r
+        /// <summary>\r
+        /// Creates a duplicate of the node.\r
+        /// </summary>\r
+        /// <param name="node">The node to duplicate. May not be <c>null</c>.</param>\r
+        /// <param name="deep">true to recursively clone the subtree under the specified node, false to clone only the node itself.</param>\r
+        public void CopyFrom(HtmlNode node, bool deep)\r
+        {\r
+            if (node == null)\r
+            {\r
+                throw new ArgumentNullException("node");\r
+            }\r
+\r
+            Attributes.RemoveAll();\r
+            if (node.HasAttributes)\r
+            {\r
+                foreach (HtmlAttribute att in node.Attributes)\r
+                {\r
+                    SetAttributeValue(att.Name, att.Value);\r
+                }\r
+            }\r
+\r
+            if (!deep)\r
+            {\r
+                RemoveAllChildren();\r
+                if (node.HasChildNodes)\r
+                {\r
+                    foreach (HtmlNode child in node.ChildNodes)\r
+                    {\r
+                        AppendChild(child.CloneNode(true));\r
+                    }\r
+                }\r
+            }\r
+        }\r
+\r
+        /// <summary>\r
+        /// Creates an XPathNavigator using the root of this document.\r
+        /// </summary>\r
+        /// <returns></returns>\r
+        public XPathNavigator CreateRootNavigator()\r
+        {\r
+            return new HtmlNodeNavigator(_ownerdocument, _ownerdocument.DocumentNode);\r
+        }\r
+\r
+        /// <summary>\r
+        /// Gets all Descendant nodes for this node and each of child nodes\r
+        /// </summary>\r
+        /// <returns></returns>\r
+        public IEnumerable<HtmlNode> DescendantNodes()\r
+        {\r
+            foreach (HtmlNode node in ChildNodes)\r
+            {\r
+                yield return node;\r
+                foreach (HtmlNode descendant in node.DescendantNodes())\r
+                    yield return descendant;\r
+            }\r
+        }\r
+\r
+        /// <summary>\r
+        /// Returns a collection of all descendant nodes of this element, in document order\r
+        /// </summary>\r
+        /// <returns></returns>\r
+        public IEnumerable<HtmlNode> DescendantNodesAndSelf()\r
+        {\r
+            return DescendantsAndSelf();\r
+        }\r
+\r
+        /// <summary>\r
+        /// Gets all Descendant nodes in enumerated list\r
+        /// </summary>\r
+        /// <returns></returns>\r
+        public IEnumerable<HtmlNode> Descendants()\r
+        {\r
+            foreach (HtmlNode node in DescendantNodes())\r
+            {\r
+                yield return node;\r
+            }\r
+        }\r
+\r
+        /// <summary>\r
+        /// Get all descendant nodes with matching name\r
+        /// </summary>\r
+        /// <param name="name"></param>\r
+        /// <returns></returns>\r
+        public IEnumerable<HtmlNode> Descendants(string name)\r
+        {\r
+            foreach (HtmlNode node in Descendants())\r
+                if (node.Name == name)\r
+                    yield return node;\r
+        }\r
+\r
+        /// <summary>\r
+        /// Returns a collection of all descendant nodes of this element, in document order\r
+        /// </summary>\r
+        /// <returns></returns>\r
+        public IEnumerable<HtmlNode> DescendantsAndSelf()\r
+        {\r
+            yield return this;\r
+            foreach (HtmlNode n in DescendantNodes())\r
+            {\r
+                HtmlNode el = n;\r
+                if (el != null)\r
+                    yield return el;\r
+            }\r
+        }\r
+\r
+        /// <summary>\r
+        /// Gets all descendant nodes including this node\r
+        /// </summary>\r
+        /// <param name="name"></param>\r
+        /// <returns></returns>\r
+        public IEnumerable<HtmlNode> DescendantsAndSelf(string name)\r
+        {\r
+            yield return this;\r
+            foreach (HtmlNode node in Descendants())\r
+                if (node.Name == name)\r
+                    yield return node;\r
+        }\r
+\r
+        /// <summary>\r
+        /// Gets first generation child node matching name\r
+        /// </summary>\r
+        /// <param name="name"></param>\r
+        /// <returns></returns>\r
+        public HtmlNode Element(string name)\r
+        {\r
+            foreach (HtmlNode node in ChildNodes)\r
+                if (node.Name == name)\r
+                    return node;\r
+            return null;\r
+        }\r
+\r
+        /// <summary>\r
+        /// Gets matching first generation child nodes matching name\r
+        /// </summary>\r
+        /// <param name="name"></param>\r
+        /// <returns></returns>\r
+        public IEnumerable<HtmlNode> Elements(string name)\r
+        {\r
+            foreach (HtmlNode node in ChildNodes)\r
+                if (node.Name == name)\r
+                    yield return node;\r
+        }\r
+\r
+        /// <summary>\r
+        /// Helper method to get the value of an attribute of this node. If the attribute is not found, the default value will be returned.\r
+        /// </summary>\r
+        /// <param name="name">The name of the attribute to get. May not be <c>null</c>.</param>\r
+        /// <param name="def">The default value to return if not found.</param>\r
+        /// <returns>The value of the attribute if found, the default value if not found.</returns>\r
+        public string GetAttributeValue(string name, string def)\r
+        {\r
+            if (name == null)\r
+            {\r
+                throw new ArgumentNullException("name");\r
+            }\r
+\r
+            if (!HasAttributes)\r
+            {\r
+                return def;\r
+            }\r
+            HtmlAttribute att = Attributes[name];\r
+            if (att == null)\r
+            {\r
+                return def;\r
+            }\r
+            return att.Value;\r
+        }\r
+\r
+        /// <summary>\r
+        /// Helper method to get the value of an attribute of this node. If the attribute is not found, the default value will be returned.\r
+        /// </summary>\r
+        /// <param name="name">The name of the attribute to get. May not be <c>null</c>.</param>\r
+        /// <param name="def">The default value to return if not found.</param>\r
+        /// <returns>The value of the attribute if found, the default value if not found.</returns>\r
+        public int GetAttributeValue(string name, int def)\r
+        {\r
+            if (name == null)\r
+            {\r
+                throw new ArgumentNullException("name");\r
+            }\r
+\r
+            if (!HasAttributes)\r
+            {\r
+                return def;\r
+            }\r
+            HtmlAttribute att = Attributes[name];\r
+            if (att == null)\r
+            {\r
+                return def;\r
+            }\r
+            try\r
+            {\r
+                return Convert.ToInt32(att.Value);\r
+            }\r
+            catch\r
+            {\r
+                return def;\r
+            }\r
+        }\r
+\r
+        /// <summary>\r
+        /// Helper method to get the value of an attribute of this node. If the attribute is not found, the default value will be returned.\r
+        /// </summary>\r
+        /// <param name="name">The name of the attribute to get. May not be <c>null</c>.</param>\r
+        /// <param name="def">The default value to return if not found.</param>\r
+        /// <returns>The value of the attribute if found, the default value if not found.</returns>\r
+        public bool GetAttributeValue(string name, bool def)\r
+        {\r
+            if (name == null)\r
+            {\r
+                throw new ArgumentNullException("name");\r
+            }\r
+\r
+            if (!HasAttributes)\r
+            {\r
+                return def;\r
+            }\r
+            HtmlAttribute att = Attributes[name];\r
+            if (att == null)\r
+            {\r
+                return def;\r
+            }\r
+            try\r
+            {\r
+                return Convert.ToBoolean(att.Value);\r
+            }\r
+            catch\r
+            {\r
+                return def;\r
+            }\r
+        }\r
+\r
+        /// <summary>\r
+        /// Inserts the specified node immediately after the specified reference node.\r
+        /// </summary>\r
+        /// <param name="newChild">The node to insert. May not be <c>null</c>.</param>\r
+        /// <param name="refChild">The node that is the reference node. The newNode is placed after the refNode.</param>\r
+        /// <returns>The node being inserted.</returns>\r
+        public HtmlNode InsertAfter(HtmlNode newChild, HtmlNode refChild)\r
+        {\r
+            if (newChild == null)\r
+            {\r
+                throw new ArgumentNullException("newChild");\r
+            }\r
+\r
+            if (refChild == null)\r
+            {\r
+                return PrependChild(newChild);\r
+            }\r
+\r
+            if (newChild == refChild)\r
+            {\r
+                return newChild;\r
+            }\r
+\r
+            int index = -1;\r
+\r
+            if (_childnodes != null)\r
+            {\r
+                index = _childnodes[refChild];\r
+            }\r
+            if (index == -1)\r
+            {\r
+                throw new ArgumentException(HtmlDocument.HtmlExceptionRefNotChild);\r
+            }\r
+\r
+            if (_childnodes != null) _childnodes.Insert(index + 1, newChild);\r
+\r
+            _ownerdocument.SetIdForNode(newChild, newChild.GetId());\r
+            _outerchanged = true;\r
+            _innerchanged = true;\r
+            return newChild;\r
+        }\r
+\r
+        /// <summary>\r
+        /// Inserts the specified node immediately before the specified reference node.\r
+        /// </summary>\r
+        /// <param name="newChild">The node to insert. May not be <c>null</c>.</param>\r
+        /// <param name="refChild">The node that is the reference node. The newChild is placed before this node.</param>\r
+        /// <returns>The node being inserted.</returns>\r
+        public HtmlNode InsertBefore(HtmlNode newChild, HtmlNode refChild)\r
+        {\r
+            if (newChild == null)\r
+            {\r
+                throw new ArgumentNullException("newChild");\r
+            }\r
+\r
+            if (refChild == null)\r
+            {\r
+                return AppendChild(newChild);\r
+            }\r
+\r
+            if (newChild == refChild)\r
+            {\r
+                return newChild;\r
+            }\r
+\r
+            int index = -1;\r
+\r
+            if (_childnodes != null)\r
+            {\r
+                index = _childnodes[refChild];\r
+            }\r
+\r
+            if (index == -1)\r
+            {\r
+                throw new ArgumentException(HtmlDocument.HtmlExceptionRefNotChild);\r
+            }\r
+\r
+            if (_childnodes != null) _childnodes.Insert(index, newChild);\r
+\r
+            _ownerdocument.SetIdForNode(newChild, newChild.GetId());\r
+            _outerchanged = true;\r
+            _innerchanged = true;\r
+            return newChild;\r
+        }\r
+\r
+        /// <summary>\r
+        /// Adds the specified node to the beginning of the list of children of this node.\r
+        /// </summary>\r
+        /// <param name="newChild">The node to add. May not be <c>null</c>.</param>\r
+        /// <returns>The node added.</returns>\r
+        public HtmlNode PrependChild(HtmlNode newChild)\r
+        {\r
+            if (newChild == null)\r
+            {\r
+                throw new ArgumentNullException("newChild");\r
+            }\r
+            ChildNodes.Prepend(newChild);\r
+            _ownerdocument.SetIdForNode(newChild, newChild.GetId());\r
+            _outerchanged = true;\r
+            _innerchanged = true;\r
+            return newChild;\r
+        }\r
+\r
+        /// <summary>\r
+        /// Adds the specified node list to the beginning of the list of children of this node.\r
+        /// </summary>\r
+        /// <param name="newChildren">The node list to add. May not be <c>null</c>.</param>\r
+        public void PrependChildren(HtmlNodeCollection newChildren)\r
+        {\r
+            if (newChildren == null)\r
+            {\r
+                throw new ArgumentNullException("newChildren");\r
+            }\r
+\r
+            foreach (HtmlNode newChild in newChildren)\r
+            {\r
+                PrependChild(newChild);\r
+            }\r
+        }\r
+\r
+        /// <summary>\r
+        /// Removes node from parent collection\r
+        /// </summary>\r
+        public void Remove()\r
+        {\r
+            if (ParentNode != null)\r
+                ParentNode.ChildNodes.Remove(this);\r
+        }\r
+\r
+        /// <summary>\r
+        /// Removes all the children and/or attributes of the current node.\r
+        /// </summary>\r
+        public void RemoveAll()\r
+        {\r
+            RemoveAllChildren();\r
+\r
+            if (HasAttributes)\r
+            {\r
+                _attributes.Clear();\r
+            }\r
+\r
+            if ((_endnode != null) && (_endnode != this))\r
+            {\r
+                if (_endnode._attributes != null)\r
+                {\r
+                    _endnode._attributes.Clear();\r
+                }\r
+            }\r
+            _outerchanged = true;\r
+            _innerchanged = true;\r
+        }\r
+\r
+        /// <summary>\r
+        /// Removes all the children of the current node.\r
+        /// </summary>\r
+        public void RemoveAllChildren()\r
+        {\r
+            if (!HasChildNodes)\r
+            {\r
+                return;\r
+            }\r
+\r
+            if (_ownerdocument.OptionUseIdAttribute)\r
+            {\r
+                // remove nodes from id list\r
+                foreach (HtmlNode node in _childnodes)\r
+                {\r
+                    _ownerdocument.SetIdForNode(null, node.GetId());\r
+                }\r
+            }\r
+            _childnodes.Clear();\r
+            _outerchanged = true;\r
+            _innerchanged = true;\r
+        }\r
+\r
+        /// <summary>\r
+        /// Removes the specified child node.\r
+        /// </summary>\r
+        /// <param name="oldChild">The node being removed. May not be <c>null</c>.</param>\r
+        /// <returns>The node removed.</returns>\r
+        public HtmlNode RemoveChild(HtmlNode oldChild)\r
+        {\r
+            if (oldChild == null)\r
+            {\r
+                throw new ArgumentNullException("oldChild");\r
+            }\r
+\r
+            int index = -1;\r
+\r
+            if (_childnodes != null)\r
+            {\r
+                index = _childnodes[oldChild];\r
+            }\r
+\r
+            if (index == -1)\r
+            {\r
+                throw new ArgumentException(HtmlDocument.HtmlExceptionRefNotChild);\r
+            }\r
+\r
+            if (_childnodes != null)\r
+                _childnodes.Remove(index);\r
+\r
+            _ownerdocument.SetIdForNode(null, oldChild.GetId());\r
+            _outerchanged = true;\r
+            _innerchanged = true;\r
+            return oldChild;\r
+        }\r
+\r
+        /// <summary>\r
+        /// Removes the specified child node.\r
+        /// </summary>\r
+        /// <param name="oldChild">The node being removed. May not be <c>null</c>.</param>\r
+        /// <param name="keepGrandChildren">true to keep grand children of the node, false otherwise.</param>\r
+        /// <returns>The node removed.</returns>\r
+        public HtmlNode RemoveChild(HtmlNode oldChild, bool keepGrandChildren)\r
+        {\r
+            if (oldChild == null)\r
+            {\r
+                throw new ArgumentNullException("oldChild");\r
+            }\r
+\r
+            if ((oldChild._childnodes != null) && keepGrandChildren)\r
+            {\r
+                // get prev sibling\r
+                HtmlNode prev = oldChild.PreviousSibling;\r
+\r
+                // reroute grand children to ourselves\r
+                foreach (HtmlNode grandchild in oldChild._childnodes)\r
+                {\r
+                    InsertAfter(grandchild, prev);\r
+                }\r
+            }\r
+            RemoveChild(oldChild);\r
+            _outerchanged = true;\r
+            _innerchanged = true;\r
+            return oldChild;\r
+        }\r
+\r
+        /// <summary>\r
+        /// Replaces the child node oldChild with newChild node.\r
+        /// </summary>\r
+        /// <param name="newChild">The new node to put in the child list.</param>\r
+        /// <param name="oldChild">The node being replaced in the list.</param>\r
+        /// <returns>The node replaced.</returns>\r
+        public HtmlNode ReplaceChild(HtmlNode newChild, HtmlNode oldChild)\r
+        {\r
+            if (newChild == null)\r
+            {\r
+                return RemoveChild(oldChild);\r
+            }\r
+\r
+            if (oldChild == null)\r
+            {\r
+                return AppendChild(newChild);\r
+            }\r
+\r
+            int index = -1;\r
+\r
+            if (_childnodes != null)\r
+            {\r
+                index = _childnodes[oldChild];\r
+            }\r
+\r
+            if (index == -1)\r
+            {\r
+                throw new ArgumentException(HtmlDocument.HtmlExceptionRefNotChild);\r
+            }\r
+\r
+            if (_childnodes != null) _childnodes.Replace(index, newChild);\r
+\r
+            _ownerdocument.SetIdForNode(null, oldChild.GetId());\r
+            _ownerdocument.SetIdForNode(newChild, newChild.GetId());\r
+            _outerchanged = true;\r
+            _innerchanged = true;\r
+            return newChild;\r
+        }\r
+\r
+        /// <summary>\r
+        /// Selects a list of nodes matching the <see cref="XPath"/> expression.\r
+        /// </summary>\r
+        /// <param name="xpath">The XPath expression.</param>\r
+        /// <returns>An <see cref="HtmlNodeCollection"/> containing a collection of nodes matching the <see cref="XPath"/> query, or <c>null</c> if no node matched the XPath expression.</returns>\r
+        public HtmlNodeCollection SelectNodes(string xpath)\r
+        {\r
+            HtmlNodeCollection list = new HtmlNodeCollection(null);\r
+\r
+            HtmlNodeNavigator nav = new HtmlNodeNavigator(_ownerdocument, this);\r
+            XPathNodeIterator it = nav.Select(xpath);\r
+            while (it.MoveNext())\r
+            {\r
+                HtmlNodeNavigator n = (HtmlNodeNavigator) it.Current;\r
+                list.Add(n.CurrentNode);\r
+            }\r
+            if (list.Count == 0)\r
+            {\r
+                return null;\r
+            }\r
+            return list;\r
+        }\r
+\r
+        /// <summary>\r
+        /// Selects the first XmlNode that matches the XPath expression.\r
+        /// </summary>\r
+        /// <param name="xpath">The XPath expression. May not be null.</param>\r
+        /// <returns>The first <see cref="HtmlNode"/> that matches the XPath query or a null reference if no matching node was found.</returns>\r
+        public HtmlNode SelectSingleNode(string xpath)\r
+        {\r
+            if (xpath == null)\r
+            {\r
+                throw new ArgumentNullException("xpath");\r
+            }\r
+\r
+            HtmlNodeNavigator nav = new HtmlNodeNavigator(_ownerdocument, this);\r
+            XPathNodeIterator it = nav.Select(xpath);\r
+            if (!it.MoveNext())\r
+            {\r
+                return null;\r
+            }\r
+\r
+            HtmlNodeNavigator node = (HtmlNodeNavigator) it.Current;\r
+            return node.CurrentNode;\r
+        }\r
+\r
+        /// <summary>\r
+        /// Helper method to set the value of an attribute of this node. If the attribute is not found, it will be created automatically.\r
+        /// </summary>\r
+        /// <param name="name">The name of the attribute to set. May not be null.</param>\r
+        /// <param name="value">The value for the attribute.</param>\r
+        /// <returns>The corresponding attribute instance.</returns>\r
+        public HtmlAttribute SetAttributeValue(string name, string value)\r
+        {\r
+            if (name == null)\r
+            {\r
+                throw new ArgumentNullException("name");\r
+            }\r
+            HtmlAttribute att = Attributes[name];\r
+            if (att == null)\r
+            {\r
+                return Attributes.Append(_ownerdocument.CreateAttribute(name, value));\r
+            }\r
+            att.Value = value;\r
+            return att;\r
+        }\r
+\r
+        /// <summary>\r
+        /// Saves all the children of the node to the specified TextWriter.\r
+        /// </summary>\r
+        /// <param name="outText">The TextWriter to which you want to save.</param>\r
+        public void WriteContentTo(TextWriter outText)\r
+        {\r
+            if (_childnodes == null)\r
+            {\r
+                return;\r
+            }\r
+\r
+            foreach (HtmlNode node in _childnodes)\r
+            {\r
+                node.WriteTo(outText);\r
+            }\r
+        }\r
+\r
+        /// <summary>\r
+        /// Saves all the children of the node to a string.\r
+        /// </summary>\r
+        /// <returns>The saved string.</returns>\r
+        public string WriteContentTo()\r
+        {\r
+            StringWriter sw = new StringWriter();\r
+            WriteContentTo(sw);\r
+            sw.Flush();\r
+            return sw.ToString();\r
+        }\r
+\r
+        /// <summary>\r
+        /// Saves the current node to the specified TextWriter.\r
+        /// </summary>\r
+        /// <param name="outText">The TextWriter to which you want to save.</param>\r
+        public void WriteTo(TextWriter outText)\r
+        {\r
+            string html;\r
+            switch (_nodetype)\r
+            {\r
+                case HtmlNodeType.Comment:\r
+                    html = ((HtmlCommentNode) this).Comment;\r
+                    if (_ownerdocument.OptionOutputAsXml)\r
+                    {\r
+                        outText.Write("<!--" + GetXmlComment((HtmlCommentNode) this) + " -->");\r
+                    }\r
+                    else\r
+                    {\r
+                        outText.Write(html);\r
+                    }\r
+                    break;\r
+\r
+                case HtmlNodeType.Document:\r
+                    if (_ownerdocument.OptionOutputAsXml)\r
+                    {\r
+                        outText.Write("<?xml version=\"1.0\" encoding=\"" + _ownerdocument.GetOutEncoding().BodyName +\r
+                                      "\"?>");\r
+\r
+                        // check there is a root element\r
+                        if (_ownerdocument.DocumentNode.HasChildNodes)\r
+                        {\r
+                            int rootnodes = _ownerdocument.DocumentNode._childnodes.Count;\r
+                            if (rootnodes > 0)\r
+                            {\r
+                                HtmlNode xml = _ownerdocument.GetXmlDeclaration();\r
+                                if (xml != null)\r
+                                {\r
+                                    rootnodes --;\r
+                                }\r
+\r
+                                if (rootnodes > 1)\r
+                                {\r
+                                    if (_ownerdocument.OptionOutputUpperCase)\r
+                                    {\r
+                                        outText.Write("<SPAN>");\r
+                                        WriteContentTo(outText);\r
+                                        outText.Write("</SPAN>");\r
+                                    }\r
+                                    else\r
+                                    {\r
+                                        outText.Write("<span>");\r
+                                        WriteContentTo(outText);\r
+                                        outText.Write("</span>");\r
+                                    }\r
+                                    break;\r
+                                }\r
+                            }\r
+                        }\r
+                    }\r
+                    WriteContentTo(outText);\r
+                    break;\r
+\r
+                case HtmlNodeType.Text:\r
+                    html = ((HtmlTextNode) this).Text;\r
+                    if (_ownerdocument.OptionOutputAsXml)\r
+                    {\r
+                        outText.Write(HtmlDocument.HtmlEncode(html));\r
+                    }\r
+                    else\r
+                    {\r
+                        outText.Write(html);\r
+                    }\r
+                    break;\r
+\r
+                case HtmlNodeType.Element:\r
+                    string name;\r
+                    if (_ownerdocument.OptionOutputUpperCase)\r
+                    {\r
+                        name = Name.ToUpper();\r
+                    }\r
+                    else\r
+                    {\r
+                        name = Name;\r
+                    }\r
+\r
+                    if (_ownerdocument.OptionOutputOriginalCase)\r
+                        name = OriginalName;\r
+\r
+                    if (_ownerdocument.OptionOutputAsXml)\r
+                    {\r
+                        if (name.Length > 0)\r
+                        {\r
+                            if (name[0] == '?')\r
+                            {\r
+                                // forget this one, it's been done at the document level\r
+                                break;\r
+                            }\r
+\r
+                            if (name.Trim().Length == 0)\r
+                            {\r
+                                break;\r
+                            }\r
+                            name = HtmlDocument.GetXmlName(name);\r
+                        }\r
+                        else\r
+                        {\r
+                            break;\r
+                        }\r
+                    }\r
+\r
+                    outText.Write("<" + name);\r
+                    WriteAttributes(outText, false);\r
+\r
+                    if (!HasChildNodes)\r
+                    {\r
+                        if (IsEmptyElement(Name))\r
+                        {\r
+                            if ((_ownerdocument.OptionWriteEmptyNodes) || (_ownerdocument.OptionOutputAsXml))\r
+                            {\r
+                                outText.Write(" />");\r
+                            }\r
+                            else\r
+                            {\r
+                                if (Name.Length > 0)\r
+                                {\r
+                                    if (Name[0] == '?')\r
+                                    {\r
+                                        outText.Write("?");\r
+                                    }\r
+                                }\r
+\r
+                                outText.Write(">");\r
+                            }\r
+                        }\r
+                        else\r
+                        {\r
+                            outText.Write("></" + name + ">");\r
+                        }\r
+                    }\r
+                    else\r
+                    {\r
+                        outText.Write(">");\r
+                        bool cdata = false;\r
+                        if (_ownerdocument.OptionOutputAsXml)\r
+                        {\r
+                            if (IsCDataElement(Name))\r
+                            {\r
+                                // this code and the following tries to output things as nicely as possible for old browsers.\r
+                                cdata = true;\r
+                                outText.Write("\r\n//<![CDATA[\r\n");\r
+                            }\r
+                        }\r
+\r
+                        if (cdata)\r
+                        {\r
+                            if (HasChildNodes)\r
+                            {\r
+                                // child must be a text\r
+                                ChildNodes[0].WriteTo(outText);\r
+                            }\r
+                            outText.Write("\r\n//]]>//\r\n");\r
+                        }\r
+                        else\r
+                        {\r
+                            WriteContentTo(outText);\r
+                        }\r
+\r
+                        outText.Write("</" + name);\r
+                        if (!_ownerdocument.OptionOutputAsXml)\r
+                        {\r
+                            WriteAttributes(outText, true);\r
+                        }\r
+                        outText.Write(">");\r
+                    }\r
+                    break;\r
+            }\r
+        }\r
+\r
+        /// <summary>\r
+        /// Saves the current node to the specified XmlWriter.\r
+        /// </summary>\r
+        /// <param name="writer">The XmlWriter to which you want to save.</param>\r
+        public void WriteTo(XmlWriter writer)\r
+        {\r
+            switch (_nodetype)\r
+            {\r
+                case HtmlNodeType.Comment:\r
+                    writer.WriteComment(GetXmlComment((HtmlCommentNode) this));\r
+                    break;\r
+\r
+                case HtmlNodeType.Document:\r
+                    writer.WriteProcessingInstruction("xml",\r
+                                                      "version=\"1.0\" encoding=\"" +\r
+                                                      _ownerdocument.GetOutEncoding().BodyName + "\"");\r
+                    if (HasChildNodes)\r
+                    {\r
+                        foreach (HtmlNode subnode in ChildNodes)\r
+                        {\r
+                            subnode.WriteTo(writer);\r
+                        }\r
+                    }\r
+                    break;\r
+\r
+                case HtmlNodeType.Text:\r
+                    string html = ((HtmlTextNode) this).Text;\r
+                    writer.WriteString(html);\r
+                    break;\r
+\r
+                case HtmlNodeType.Element:\r
+                    string name = _ownerdocument.OptionOutputUpperCase ? Name.ToUpper() : Name;\r
+\r
+                    if (_ownerdocument.OptionOutputOriginalCase)\r
+                        name = OriginalName;\r
+\r
+                    writer.WriteStartElement(name);\r
+                    WriteAttributes(writer, this);\r
+\r
+                    if (HasChildNodes)\r
+                    {\r
+                        foreach (HtmlNode subnode in ChildNodes)\r
+                        {\r
+                            subnode.WriteTo(writer);\r
+                        }\r
+                    }\r
+                    writer.WriteEndElement();\r
+                    break;\r
+            }\r
+        }\r
+\r
+        /// <summary>\r
+        /// Saves the current node to a string.\r
+        /// </summary>\r
+        /// <returns>The saved string.</returns>\r
+        public string WriteTo()\r
+        {\r
+            using (StringWriter sw = new StringWriter())\r
+            {\r
+                WriteTo(sw);\r
+                sw.Flush();\r
+                return sw.ToString();\r
+            }\r
+        }\r
+\r
+        #endregion\r
+\r
+        #region Internal Methods\r
+\r
+        internal static string GetXmlComment(HtmlCommentNode comment)\r
+        {\r
+            string s = comment.Comment;\r
+            return s.Substring(4, s.Length - 7).Replace("--", " - -");\r
+        }\r
+\r
+        internal static void WriteAttributes(XmlWriter writer, HtmlNode node)\r
+        {\r
+            if (!node.HasAttributes)\r
+            {\r
+                return;\r
+            }\r
+            // we use Hashitems to make sure attributes are written only once\r
+            foreach (HtmlAttribute att in node.Attributes.Hashitems.Values)\r
+            {\r
+                writer.WriteAttributeString(att.XmlName, att.Value);\r
+            }\r
+        }\r
+\r
+        internal void CloseNode(HtmlNode endnode)\r
+        {\r
+            if (!_ownerdocument.OptionAutoCloseOnEnd)\r
+            {\r
+                // close all children\r
+                if (_childnodes != null)\r
+                {\r
+                    foreach (HtmlNode child in _childnodes)\r
+                    {\r
+                        if (child.Closed)\r
+                            continue;\r
+\r
+                        // create a fake closer node\r
+                        HtmlNode close = new HtmlNode(NodeType, _ownerdocument, -1);\r
+                        close._endnode = close;\r
+                        child.CloseNode(close);\r
+                    }\r
+                }\r
+            }\r
+\r
+            if (!Closed)\r
+            {\r
+                _endnode = endnode;\r
+\r
+                if (_ownerdocument._openednodes != null)\r
+                {\r
+                    _ownerdocument._openednodes.Remove(_outerstartindex);\r
+                }\r
+\r
+                HtmlNode self = _ownerdocument._lastnodes[Name] as HtmlNode;\r
+                if (self == this)\r
+                {\r
+                    _ownerdocument._lastnodes.Remove(Name);\r
+                    _ownerdocument.UpdateLastParentNode();\r
+                }\r
+\r
+                if (endnode == this)\r
+                    return;\r
+\r
+                // create an inner section\r
+                _innerstartindex = _outerstartindex + _outerlength;\r
+                _innerlength = endnode._outerstartindex - _innerstartindex;\r
+\r
+                // update full length\r
+                _outerlength = (endnode._outerstartindex + endnode._outerlength) - _outerstartindex;\r
+            }\r
+        }\r
+\r
+        internal string GetId()\r
+        {\r
+            HtmlAttribute att = Attributes["id"];\r
+            if (att == null)\r
+            {\r
+                return null;\r
+            }\r
+            return att.Value;\r
+        }\r
+\r
+        internal void SetId(string id)\r
+        {\r
+            HtmlAttribute att = Attributes["id"];\r
+            if (att == null)\r
+            {\r
+                att = _ownerdocument.CreateAttribute("id");\r
+            }\r
+            att.Value = id;\r
+            _ownerdocument.SetIdForNode(this, att.Value);\r
+            _outerchanged = true;\r
+        }\r
+\r
+        internal void WriteAttribute(TextWriter outText, HtmlAttribute att)\r
+        {\r
+            string name;\r
+            string quote = att.QuoteType == AttributeValueQuote.DoubleQuote ? "\"" : "'";\r
+            if (_ownerdocument.OptionOutputAsXml)\r
+            {\r
+                if (_ownerdocument.OptionOutputUpperCase)\r
+                {\r
+                    name = att.XmlName.ToUpper();\r
+                }\r
+                else\r
+                {\r
+                    name = att.XmlName;\r
+                }\r
+                if (_ownerdocument.OptionOutputOriginalCase)\r
+                    name = att.OriginalName;\r
+\r
+                outText.Write(" " + name + "=" + quote + HtmlDocument.HtmlEncode(att.XmlValue) + quote);\r
+            }\r
+            else\r
+            {\r
+                if (_ownerdocument.OptionOutputUpperCase)\r
+                {\r
+                    name = att.Name.ToUpper();\r
+                }\r
+                else\r
+                {\r
+                    name = att.Name;\r
+                }\r
+\r
+                if (att.Name.Length >= 4)\r
+                {\r
+                    if ((att.Name[0] == '<') && (att.Name[1] == '%') &&\r
+                        (att.Name[att.Name.Length - 1] == '>') && (att.Name[att.Name.Length - 2] == '%'))\r
+                    {\r
+                        outText.Write(" " + name);\r
+                        return;\r
+                    }\r
+                }\r
+                if (_ownerdocument.OptionOutputOptimizeAttributeValues)\r
+                {\r
+                    if (att.Value.IndexOfAny(new Char[] {(char) 10, (char) 13, (char) 9, ' '}) < 0)\r
+                    {\r
+                        outText.Write(" " + name + "=" + att.Value);\r
+                    }\r
+                    else\r
+                    {\r
+                        outText.Write(" " + name + "=" + quote + att.Value + quote);\r
+                    }\r
+                }\r
+                else\r
+                {\r
+                    outText.Write(" " + name + "=" + quote + att.Value + quote);\r
+                }\r
+            }\r
+        }\r
+\r
+        internal void WriteAttributes(TextWriter outText, bool closing)\r
+        {\r
+            if (_ownerdocument.OptionOutputAsXml)\r
+            {\r
+                if (_attributes == null)\r
+                {\r
+                    return;\r
+                }\r
+                // we use Hashitems to make sure attributes are written only once\r
+                foreach (HtmlAttribute att in _attributes.Hashitems.Values)\r
+                {\r
+                    WriteAttribute(outText, att);\r
+                }\r
+                return;\r
+            }\r
+\r
+            if (!closing)\r
+            {\r
+                if (_attributes != null)\r
+                {\r
+                    foreach (HtmlAttribute att in _attributes)\r
+                    {\r
+                        WriteAttribute(outText, att);\r
+                    }\r
+                }\r
+                if (_ownerdocument.OptionAddDebuggingAttributes)\r
+                {\r
+                    WriteAttribute(outText, _ownerdocument.CreateAttribute("_closed", Closed.ToString()));\r
+                    WriteAttribute(outText, _ownerdocument.CreateAttribute("_children", ChildNodes.Count.ToString()));\r
+\r
+                    int i = 0;\r
+                    foreach (HtmlNode n in ChildNodes)\r
+                    {\r
+                        WriteAttribute(outText, _ownerdocument.CreateAttribute("_child_" + i,\r
+                                                                               n.Name));\r
+                        i++;\r
+                    }\r
+                }\r
+            }\r
+            else\r
+            {\r
+                if (_endnode == null)\r
+                {\r
+                    return;\r
+                }\r
+\r
+                if (_endnode._attributes == null)\r
+                {\r
+                    return;\r
+                }\r
+\r
+                if (_endnode == this)\r
+                {\r
+                    return;\r
+                }\r
+\r
+                foreach (HtmlAttribute att in _endnode._attributes)\r
+                {\r
+                    WriteAttribute(outText, att);\r
+                }\r
+                if (_ownerdocument.OptionAddDebuggingAttributes)\r
+                {\r
+                    WriteAttribute(outText, _ownerdocument.CreateAttribute("_closed", Closed.ToString()));\r
+                    WriteAttribute(outText, _ownerdocument.CreateAttribute("_children", ChildNodes.Count.ToString()));\r
+                }\r
+            }\r
+        }\r
+\r
+        #endregion\r
+\r
+        #region Private Methods\r
+\r
+        private string GetRelativeXpath()\r
+        {\r
+            if (ParentNode == null)\r
+                return Name;\r
+            if (NodeType == HtmlNodeType.Document)\r
+                return string.Empty;\r
+\r
+            int i = 1;\r
+            foreach (HtmlNode node in ParentNode.ChildNodes)\r
+            {\r
+                if (node.Name != Name) continue;\r
+\r
+                if (node == this)\r
+                    break;\r
+\r
+                i++;\r
+            }\r
+            return Name + "[" + i + "]";\r
+        }\r
+\r
+        #endregion\r
+    }\r
+}
\ No newline at end of file
diff --git a/docs/HtmlAgilityPack/HtmlNodeCollection.cs b/docs/HtmlAgilityPack/HtmlNodeCollection.cs
new file mode 100644 (file)
index 0000000..379e370
--- /dev/null
@@ -0,0 +1,512 @@
+// HtmlAgilityPack V1.0 - Simon Mourier <simon underscore mourier at hotmail dot com>\r
+using System;\r
+using System.Collections;\r
+using System.Collections.Generic;\r
+\r
+namespace HtmlAgilityPack\r
+{\r
+    /// <summary>\r
+    /// Represents a combined list and collection of HTML nodes.\r
+    /// </summary>\r
+    public class HtmlNodeCollection : IList<HtmlNode>\r
+    {\r
+        #region Fields\r
+\r
+        private readonly HtmlNode _parentnode;\r
+        private readonly List<HtmlNode> _items = new List<HtmlNode>();\r
+\r
+        #endregion\r
+\r
+        #region Constructors\r
+\r
+        /// <summary>\r
+        /// Initialize the HtmlNodeCollection with the base parent node\r
+        /// </summary>\r
+        /// <param name="parentnode">The base node of the collection</param>\r
+        public HtmlNodeCollection(HtmlNode parentnode)\r
+        {\r
+            _parentnode = parentnode; // may be null\r
+        }\r
+\r
+        #endregion\r
+\r
+        #region Properties\r
+\r
+        /// <summary>\r
+        /// Gets a given node from the list.\r
+        /// </summary>\r
+        public int this[HtmlNode node]\r
+        {\r
+            get\r
+            {\r
+                int index = GetNodeIndex(node);\r
+                if (index == -1)\r
+                {\r
+                    throw new ArgumentOutOfRangeException("node",\r
+                                                          "Node \"" + node.CloneNode(false).OuterHtml +\r
+                                                          "\" was not found in the collection");\r
+                }\r
+                return index;\r
+            }\r
+        }\r
+\r
+        /// <summary>\r
+        /// Get node with tag name\r
+        /// </summary>\r
+        /// <param name="nodeName"></param>\r
+        /// <returns></returns>\r
+        public HtmlNode this[string nodeName]\r
+        {\r
+            get\r
+            {\r
+                nodeName = nodeName.ToLower();\r
+                for (int i = 0; i < _items.Count; i++)\r
+                    if (_items[i].Equals(nodeName))\r
+                        return _items[i];\r
+\r
+                return null;\r
+            }\r
+        }\r
+\r
+        #endregion\r
+\r
+        #region IList<HtmlNode> Members\r
+\r
+        /// <summary>\r
+        /// Gets the number of elements actually contained in the list.\r
+        /// </summary>\r
+        public int Count\r
+        {\r
+            get { return _items.Count; }\r
+        }\r
+\r
+        /// <summary>\r
+        /// Is collection read only\r
+        /// </summary>\r
+        public bool IsReadOnly\r
+        {\r
+            get { return false; }\r
+        }\r
+\r
+        /// <summary>\r
+        /// Gets the node at the specified index.\r
+        /// </summary>\r
+        public HtmlNode this[int index]\r
+        {\r
+            get { return _items[index]; }\r
+            set { _items[index] = value; }\r
+        }\r
+\r
+        /// <summary>\r
+        /// Add node to the collection\r
+        /// </summary>\r
+        /// <param name="node"></param>\r
+        public void Add(HtmlNode node)\r
+        {\r
+            _items.Add(node);\r
+        }\r
+\r
+        /// <summary>\r
+        /// Clears out the collection of HtmlNodes. Removes each nodes reference to parentnode, nextnode and prevnode\r
+        /// </summary>\r
+        public void Clear()\r
+        {\r
+            foreach (HtmlNode node in _items)\r
+            {\r
+                node.ParentNode = null;\r
+                node.NextSibling = null;\r
+                node.PreviousSibling = null;\r
+            }\r
+            _items.Clear();\r
+        }\r
+\r
+        /// <summary>\r
+        /// Gets existence of node in collection\r
+        /// </summary>\r
+        /// <param name="item"></param>\r
+        /// <returns></returns>\r
+        public bool Contains(HtmlNode item)\r
+        {\r
+            return _items.Contains(item);\r
+        }\r
+\r
+        /// <summary>\r
+        /// Copy collection to array\r
+        /// </summary>\r
+        /// <param name="array"></param>\r
+        /// <param name="arrayIndex"></param>\r
+        public void CopyTo(HtmlNode[] array, int arrayIndex)\r
+        {\r
+            _items.CopyTo(array, arrayIndex);\r
+        }\r
+\r
+        /// <summary>\r
+        /// Get Enumerator\r
+        /// </summary>\r
+        /// <returns></returns>\r
+        IEnumerator<HtmlNode> IEnumerable<HtmlNode>.GetEnumerator()\r
+        {\r
+            return _items.GetEnumerator();\r
+        }\r
+\r
+        /// <summary>\r
+        /// Get Explicit Enumerator\r
+        /// </summary>\r
+        /// <returns></returns>\r
+        IEnumerator IEnumerable.GetEnumerator()\r
+        {\r
+            return _items.GetEnumerator();\r
+        }\r
+\r
+        /// <summary>\r
+        /// Get index of node\r
+        /// </summary>\r
+        /// <param name="item"></param>\r
+        /// <returns></returns>\r
+        public int IndexOf(HtmlNode item)\r
+        {\r
+            return _items.IndexOf(item);\r
+        }\r
+\r
+        /// <summary>\r
+        /// Insert node at index\r
+        /// </summary>\r
+        /// <param name="index"></param>\r
+        /// <param name="node"></param>\r
+        public void Insert(int index, HtmlNode node)\r
+        {\r
+            HtmlNode next = null;\r
+            HtmlNode prev = null;\r
+\r
+            if (index > 0)\r
+            {\r
+                prev = _items[index - 1];\r
+            }\r
+\r
+            if (index < _items.Count)\r
+            {\r
+                next = _items[index];\r
+            }\r
+\r
+            _items.Insert(index, node);\r
+\r
+            if (prev != null)\r
+            {\r
+                if (node == prev)\r
+                {\r
+                    throw new InvalidProgramException("Unexpected error.");\r
+                }\r
+                prev._nextnode = node;\r
+            }\r
+\r
+            if (next != null)\r
+            {\r
+                next._prevnode = node;\r
+            }\r
+\r
+            node._prevnode = prev;\r
+            if (next == node)\r
+            {\r
+                throw new InvalidProgramException("Unexpected error.");\r
+            }\r
+            node._nextnode = next;\r
+            node._parentnode = _parentnode;\r
+        }\r
+\r
+        /// <summary>\r
+        /// Remove node\r
+        /// </summary>\r
+        /// <param name="item"></param>\r
+        /// <returns></returns>\r
+        public bool Remove(HtmlNode item)\r
+        {\r
+            int i = _items.IndexOf(item);\r
+            RemoveAt(i);\r
+            return true;\r
+        }\r
+\r
+        /// <summary>\r
+        /// Remove <see cref="HtmlNode"/> at index\r
+        /// </summary>\r
+        /// <param name="index"></param>\r
+        public void RemoveAt(int index)\r
+        {\r
+            HtmlNode next = null;\r
+            HtmlNode prev = null;\r
+            HtmlNode oldnode = _items[index];\r
+\r
+            if (index > 0)\r
+            {\r
+                prev = _items[index - 1];\r
+            }\r
+\r
+            if (index < (_items.Count - 1))\r
+            {\r
+                next = _items[index + 1];\r
+            }\r
+\r
+            _items.RemoveAt(index);\r
+\r
+            if (prev != null)\r
+            {\r
+                if (next == prev)\r
+                {\r
+                    throw new InvalidProgramException("Unexpected error.");\r
+                }\r
+                prev._nextnode = next;\r
+            }\r
+\r
+            if (next != null)\r
+            {\r
+                next._prevnode = prev;\r
+            }\r
+\r
+            oldnode._prevnode = null;\r
+            oldnode._nextnode = null;\r
+            oldnode._parentnode = null;\r
+        }\r
+\r
+        #endregion\r
+\r
+        #region Public Methods\r
+\r
+        /// <summary>\r
+        /// Get first instance of node in supplied collection\r
+        /// </summary>\r
+        /// <param name="items"></param>\r
+        /// <param name="name"></param>\r
+        /// <returns></returns>\r
+        public static HtmlNode FindFirst(HtmlNodeCollection items, string name)\r
+        {\r
+            foreach (HtmlNode node in items)\r
+            {\r
+                if (node.Name.ToLower().Contains(name))\r
+                    return node;\r
+                if (node.HasChildNodes)\r
+                {\r
+                    HtmlNode returnNode = FindFirst(node.ChildNodes, name);\r
+                    if (returnNode != null)\r
+                        return returnNode;\r
+                }\r
+            }\r
+            return null;\r
+        }\r
+\r
+        /// <summary>\r
+        /// Add node to the end of the collection\r
+        /// </summary>\r
+        /// <param name="node"></param>\r
+        public void Append(HtmlNode node)\r
+        {\r
+            HtmlNode last = null;\r
+            if (_items.Count > 0)\r
+            {\r
+                last = _items[_items.Count - 1];\r
+            }\r
+\r
+            _items.Add(node);\r
+            node._prevnode = last;\r
+            node._nextnode = null;\r
+            node._parentnode = _parentnode;\r
+            if (last != null)\r
+            {\r
+                if (last == node)\r
+                {\r
+                    throw new InvalidProgramException("Unexpected error.");\r
+                }\r
+                last._nextnode = node;\r
+            }\r
+        }\r
+\r
+        /// <summary>\r
+        /// Get first instance of node with name\r
+        /// </summary>\r
+        /// <param name="name"></param>\r
+        /// <returns></returns>\r
+        public HtmlNode FindFirst(string name)\r
+        {\r
+            return FindFirst(this, name);\r
+        }\r
+\r
+        /// <summary>\r
+        /// Get index of node\r
+        /// </summary>\r
+        /// <param name="node"></param>\r
+        /// <returns></returns>\r
+        public int GetNodeIndex(HtmlNode node)\r
+        {\r
+            // TODO: should we rewrite this? what would be the key of a node?\r
+            for (int i = 0; i < _items.Count; i++)\r
+            {\r
+                if (node == (_items[i]))\r
+                {\r
+                    return i;\r
+                }\r
+            }\r
+            return -1;\r
+        }\r
+\r
+        /// <summary>\r
+        /// Add node to the beginning of the collection\r
+        /// </summary>\r
+        /// <param name="node"></param>\r
+        public void Prepend(HtmlNode node)\r
+        {\r
+            HtmlNode first = null;\r
+            if (_items.Count > 0)\r
+            {\r
+                first = _items[0];\r
+            }\r
+\r
+            _items.Insert(0, node);\r
+\r
+            if (node == first)\r
+            {\r
+                throw new InvalidProgramException("Unexpected error.");\r
+            }\r
+            node._nextnode = first;\r
+            node._prevnode = null;\r
+            node._parentnode = _parentnode;\r
+            if (first != null)\r
+            {\r
+                first._prevnode = node;\r
+            }\r
+        }\r
+\r
+        /// <summary>\r
+        /// Remove node at index\r
+        /// </summary>\r
+        /// <param name="index"></param>\r
+        /// <returns></returns>\r
+        public bool Remove(int index)\r
+        {\r
+            RemoveAt(index);\r
+            return true;\r
+        }\r
+\r
+        /// <summary>\r
+        /// Replace node at index\r
+        /// </summary>\r
+        /// <param name="index"></param>\r
+        /// <param name="node"></param>\r
+        public void Replace(int index, HtmlNode node)\r
+        {\r
+            HtmlNode next = null;\r
+            HtmlNode prev = null;\r
+            HtmlNode oldnode = _items[index];\r
+\r
+            if (index > 0)\r
+            {\r
+                prev = _items[index - 1];\r
+            }\r
+\r
+            if (index < (_items.Count - 1))\r
+            {\r
+                next = _items[index + 1];\r
+            }\r
+\r
+            _items[index] = node;\r
+\r
+            if (prev != null)\r
+            {\r
+                if (node == prev)\r
+                {\r
+                    throw new InvalidProgramException("Unexpected error.");\r
+                }\r
+                prev._nextnode = node;\r
+            }\r
+\r
+            if (next != null)\r
+            {\r
+                next._prevnode = node;\r
+            }\r
+\r
+            node._prevnode = prev;\r
+\r
+            if (next == node)\r
+            {\r
+                throw new InvalidProgramException("Unexpected error.");\r
+            }\r
+\r
+            node._nextnode = next;\r
+            node._parentnode = _parentnode;\r
+\r
+            oldnode._prevnode = null;\r
+            oldnode._nextnode = null;\r
+            oldnode._parentnode = null;\r
+        }\r
+\r
+        #endregion\r
+\r
+        #region LINQ Methods\r
+\r
+        /// <summary>\r
+        /// Get all node descended from this collection\r
+        /// </summary>\r
+        /// <returns></returns>\r
+        public IEnumerable<HtmlNode> DescendantNodes()\r
+        {\r
+            foreach (HtmlNode item in _items)\r
+                foreach (HtmlNode n in item.DescendantNodes())\r
+                    yield return n;\r
+        }\r
+\r
+        /// <summary>\r
+        /// Get all node descended from this collection\r
+        /// </summary>\r
+        /// <returns></returns>\r
+        public IEnumerable<HtmlNode> Descendants()\r
+        {\r
+            foreach (HtmlNode item in _items)\r
+                foreach (HtmlNode n in item.Descendants())\r
+                    yield return n;\r
+        }\r
+\r
+        /// <summary>\r
+        /// Get all node descended from this collection with matching name\r
+        /// </summary>\r
+        /// <returns></returns>\r
+        public IEnumerable<HtmlNode> Descendants(string name)\r
+        {\r
+            foreach (HtmlNode item in _items)\r
+                foreach (HtmlNode n in item.Descendants(name))\r
+                    yield return n;\r
+        }\r
+\r
+        /// <summary>\r
+        /// Gets all first generation elements in collection\r
+        /// </summary>\r
+        /// <returns></returns>\r
+        public IEnumerable<HtmlNode> Elements()\r
+        {\r
+            foreach (HtmlNode item in _items)\r
+                foreach (HtmlNode n in item.ChildNodes)\r
+                    yield return n;\r
+        }\r
+\r
+        /// <summary>\r
+        /// Gets all first generation elements matching name\r
+        /// </summary>\r
+        /// <param name="name"></param>\r
+        /// <returns></returns>\r
+        public IEnumerable<HtmlNode> Elements(string name)\r
+        {\r
+            foreach (HtmlNode item in _items)\r
+                foreach (HtmlNode n in item.Elements(name))\r
+                    yield return n;\r
+        }\r
+\r
+        /// <summary>\r
+        /// All first generation nodes in collection\r
+        /// </summary>\r
+        /// <returns></returns>\r
+        public IEnumerable<HtmlNode> Nodes()\r
+        {\r
+            foreach (HtmlNode item in _items)\r
+                foreach (HtmlNode n in item.ChildNodes)\r
+                    yield return n;\r
+        }\r
+\r
+        #endregion\r
+    }\r
+}
\ No newline at end of file
diff --git a/docs/HtmlAgilityPack/HtmlNodeNavigator.cs b/docs/HtmlAgilityPack/HtmlNodeNavigator.cs
new file mode 100644 (file)
index 0000000..78375ed
--- /dev/null
@@ -0,0 +1,768 @@
+// HtmlAgilityPack V1.0 - Simon Mourier <simon underscore mourier at hotmail dot com>\r
+using System;\r
+using System.Diagnostics;\r
+using System.IO;\r
+using System.Text;\r
+using System.Xml;\r
+using System.Xml.XPath;\r
+\r
+namespace HtmlAgilityPack\r
+{\r
+    /// <summary>\r
+    /// Represents an HTML navigator on an HTML document seen as a data store.\r
+    /// </summary>\r
+    public class HtmlNodeNavigator : XPathNavigator\r
+    {\r
+        #region Fields\r
+\r
+        private int _attindex;\r
+        private HtmlNode _currentnode;\r
+        private HtmlDocument _doc = new HtmlDocument();\r
+        private HtmlNameTable _nametable = new HtmlNameTable();\r
+\r
+        internal bool Trace;\r
+\r
+        #endregion\r
+\r
+        #region Constructors\r
+\r
+        internal HtmlNodeNavigator()\r
+        {\r
+            Reset();\r
+        }\r
+\r
+        internal HtmlNodeNavigator(HtmlDocument doc, HtmlNode currentNode)\r
+        {\r
+            if (currentNode == null)\r
+            {\r
+                throw new ArgumentNullException("currentNode");\r
+            }\r
+            if (currentNode.OwnerDocument != doc)\r
+            {\r
+                throw new ArgumentException(HtmlDocument.HtmlExceptionRefNotChild);\r
+            }\r
+            InternalTrace(null);\r
+\r
+            _doc = doc;\r
+            Reset();\r
+            _currentnode = currentNode;\r
+        }\r
+\r
+        private HtmlNodeNavigator(HtmlNodeNavigator nav)\r
+        {\r
+            if (nav == null)\r
+            {\r
+                throw new ArgumentNullException("nav");\r
+            }\r
+            InternalTrace(null);\r
+\r
+            _doc = nav._doc;\r
+            _currentnode = nav._currentnode;\r
+            _attindex = nav._attindex;\r
+            _nametable = nav._nametable; // REVIEW: should we do this?\r
+        }\r
+\r
+        /// <summary>\r
+        /// Initializes a new instance of the HtmlNavigator and loads an HTML document from a stream.\r
+        /// </summary>\r
+        /// <param name="stream">The input stream.</param>\r
+        public HtmlNodeNavigator(Stream stream)\r
+        {\r
+            _doc.Load(stream);\r
+            Reset();\r
+        }\r
+\r
+        /// <summary>\r
+        /// Initializes a new instance of the HtmlNavigator and loads an HTML document from a stream.\r
+        /// </summary>\r
+        /// <param name="stream">The input stream.</param>\r
+        /// <param name="detectEncodingFromByteOrderMarks">Indicates whether to look for byte order marks at the beginning of the stream.</param>\r
+        public HtmlNodeNavigator(Stream stream, bool detectEncodingFromByteOrderMarks)\r
+        {\r
+            _doc.Load(stream, detectEncodingFromByteOrderMarks);\r
+            Reset();\r
+        }\r
+\r
+        /// <summary>\r
+        /// Initializes a new instance of the HtmlNavigator and loads an HTML document from a stream.\r
+        /// </summary>\r
+        /// <param name="stream">The input stream.</param>\r
+        /// <param name="encoding">The character encoding to use.</param>\r
+        public HtmlNodeNavigator(Stream stream, Encoding encoding)\r
+        {\r
+            _doc.Load(stream, encoding);\r
+            Reset();\r
+        }\r
+\r
+        /// <summary>\r
+        /// Initializes a new instance of the HtmlNavigator and loads an HTML document from a stream.\r
+        /// </summary>\r
+        /// <param name="stream">The input stream.</param>\r
+        /// <param name="encoding">The character encoding to use.</param>\r
+        /// <param name="detectEncodingFromByteOrderMarks">Indicates whether to look for byte order marks at the beginning of the stream.</param>\r
+        public HtmlNodeNavigator(Stream stream, Encoding encoding, bool detectEncodingFromByteOrderMarks)\r
+        {\r
+            _doc.Load(stream, encoding, detectEncodingFromByteOrderMarks);\r
+            Reset();\r
+        }\r
+\r
+        /// <summary>\r
+        /// Initializes a new instance of the HtmlNavigator and loads an HTML document from a stream.\r
+        /// </summary>\r
+        /// <param name="stream">The input stream.</param>\r
+        /// <param name="encoding">The character encoding to use.</param>\r
+        /// <param name="detectEncodingFromByteOrderMarks">Indicates whether to look for byte order marks at the beginning of the stream.</param>\r
+        /// <param name="buffersize">The minimum buffer size.</param>\r
+        public HtmlNodeNavigator(Stream stream, Encoding encoding, bool detectEncodingFromByteOrderMarks, int buffersize)\r
+        {\r
+            _doc.Load(stream, encoding, detectEncodingFromByteOrderMarks, buffersize);\r
+            Reset();\r
+        }\r
+\r
+        /// <summary>\r
+        /// Initializes a new instance of the HtmlNavigator and loads an HTML document from a TextReader.\r
+        /// </summary>\r
+        /// <param name="reader">The TextReader used to feed the HTML data into the document.</param>\r
+        public HtmlNodeNavigator(TextReader reader)\r
+        {\r
+            _doc.Load(reader);\r
+            Reset();\r
+        }\r
+\r
+        /// <summary>\r
+        /// Initializes a new instance of the HtmlNavigator and loads an HTML document from a file.\r
+        /// </summary>\r
+        /// <param name="path">The complete file path to be read.</param>\r
+        public HtmlNodeNavigator(string path)\r
+        {\r
+            _doc.Load(path);\r
+            Reset();\r
+        }\r
+\r
+        /// <summary>\r
+        /// Initializes a new instance of the HtmlNavigator and loads an HTML document from a file.\r
+        /// </summary>\r
+        /// <param name="path">The complete file path to be read.</param>\r
+        /// <param name="detectEncodingFromByteOrderMarks">Indicates whether to look for byte order marks at the beginning of the file.</param>\r
+        public HtmlNodeNavigator(string path, bool detectEncodingFromByteOrderMarks)\r
+        {\r
+            _doc.Load(path, detectEncodingFromByteOrderMarks);\r
+            Reset();\r
+        }\r
+\r
+        /// <summary>\r
+        /// Initializes a new instance of the HtmlNavigator and loads an HTML document from a file.\r
+        /// </summary>\r
+        /// <param name="path">The complete file path to be read.</param>\r
+        /// <param name="encoding">The character encoding to use.</param>\r
+        public HtmlNodeNavigator(string path, Encoding encoding)\r
+        {\r
+            _doc.Load(path, encoding);\r
+            Reset();\r
+        }\r
+\r
+        /// <summary>\r
+        /// Initializes a new instance of the HtmlNavigator and loads an HTML document from a file.\r
+        /// </summary>\r
+        /// <param name="path">The complete file path to be read.</param>\r
+        /// <param name="encoding">The character encoding to use.</param>\r
+        /// <param name="detectEncodingFromByteOrderMarks">Indicates whether to look for byte order marks at the beginning of the file.</param>\r
+        public HtmlNodeNavigator(string path, Encoding encoding, bool detectEncodingFromByteOrderMarks)\r
+        {\r
+            _doc.Load(path, encoding, detectEncodingFromByteOrderMarks);\r
+            Reset();\r
+        }\r
+\r
+        /// <summary>\r
+        /// Initializes a new instance of the HtmlNavigator and loads an HTML document from a file.\r
+        /// </summary>\r
+        /// <param name="path">The complete file path to be read.</param>\r
+        /// <param name="encoding">The character encoding to use.</param>\r
+        /// <param name="detectEncodingFromByteOrderMarks">Indicates whether to look for byte order marks at the beginning of the file.</param>\r
+        /// <param name="buffersize">The minimum buffer size.</param>\r
+        public HtmlNodeNavigator(string path, Encoding encoding, bool detectEncodingFromByteOrderMarks, int buffersize)\r
+        {\r
+            _doc.Load(path, encoding, detectEncodingFromByteOrderMarks, buffersize);\r
+            Reset();\r
+        }\r
+\r
+        #endregion\r
+\r
+        #region Properties\r
+\r
+        /// <summary>\r
+        /// Gets the base URI for the current node.\r
+        /// Always returns string.Empty in the case of HtmlNavigator implementation.\r
+        /// </summary>\r
+        public override string BaseURI\r
+        {\r
+            get\r
+            {\r
+                InternalTrace(">");\r
+                return _nametable.GetOrAdd(string.Empty);\r
+            }\r
+        }\r
+\r
+        /// <summary>\r
+        /// Gets the current HTML document.\r
+        /// </summary>\r
+        public HtmlDocument CurrentDocument\r
+        {\r
+            get { return _doc; }\r
+        }\r
+\r
+        /// <summary>\r
+        /// Gets the current HTML node.\r
+        /// </summary>\r
+        public HtmlNode CurrentNode\r
+        {\r
+            get { return _currentnode; }\r
+        }\r
+\r
+        /// <summary>\r
+        /// Gets a value indicating whether the current node has child nodes.\r
+        /// </summary>\r
+        public override bool HasAttributes\r
+        {\r
+            get\r
+            {\r
+                InternalTrace(">" + (_currentnode.Attributes.Count > 0));\r
+                return (_currentnode.Attributes.Count > 0);\r
+            }\r
+        }\r
+\r
+        /// <summary>\r
+        /// Gets a value indicating whether the current node has child nodes.\r
+        /// </summary>\r
+        public override bool HasChildren\r
+        {\r
+            get\r
+            {\r
+                InternalTrace(">" + (_currentnode.ChildNodes.Count > 0));\r
+                return (_currentnode.ChildNodes.Count > 0);\r
+            }\r
+        }\r
+\r
+        /// <summary>\r
+        /// Gets a value indicating whether the current node is an empty element.\r
+        /// </summary>\r
+        public override bool IsEmptyElement\r
+        {\r
+            get\r
+            {\r
+                InternalTrace(">" + !HasChildren);\r
+                // REVIEW: is this ok?\r
+                return !HasChildren;\r
+            }\r
+        }\r
+\r
+        /// <summary>\r
+        /// Gets the name of the current HTML node without the namespace prefix.\r
+        /// </summary>\r
+        public override string LocalName\r
+        {\r
+            get\r
+            {\r
+                if (_attindex != -1)\r
+                {\r
+                    InternalTrace("att>" + _currentnode.Attributes[_attindex].Name);\r
+                    return _nametable.GetOrAdd(_currentnode.Attributes[_attindex].Name);\r
+                }\r
+                InternalTrace("node>" + _currentnode.Name);\r
+                return _nametable.GetOrAdd(_currentnode.Name);\r
+            }\r
+        }\r
+\r
+        /// <summary>\r
+        /// Gets the qualified name of the current node.\r
+        /// </summary>\r
+        public override string Name\r
+        {\r
+            get\r
+            {\r
+                InternalTrace(">" + _currentnode.Name);\r
+                return _nametable.GetOrAdd(_currentnode.Name);\r
+            }\r
+        }\r
+\r
+        /// <summary>\r
+        /// Gets the namespace URI (as defined in the W3C Namespace Specification) of the current node.\r
+        /// Always returns string.Empty in the case of HtmlNavigator implementation.\r
+        /// </summary>\r
+        public override string NamespaceURI\r
+        {\r
+            get\r
+            {\r
+                InternalTrace(">");\r
+                return _nametable.GetOrAdd(string.Empty);\r
+            }\r
+        }\r
+\r
+        /// <summary>\r
+        /// Gets the <see cref="XmlNameTable"/> associated with this implementation.\r
+        /// </summary>\r
+        public override XmlNameTable NameTable\r
+        {\r
+            get\r
+            {\r
+                InternalTrace(null);\r
+                return _nametable;\r
+            }\r
+        }\r
+\r
+        /// <summary>\r
+        /// Gets the type of the current node.\r
+        /// </summary>\r
+        public override XPathNodeType NodeType\r
+        {\r
+            get\r
+            {\r
+                switch (_currentnode.NodeType)\r
+                {\r
+                    case HtmlNodeType.Comment:\r
+                        InternalTrace(">" + XPathNodeType.Comment);\r
+                        return XPathNodeType.Comment;\r
+\r
+                    case HtmlNodeType.Document:\r
+                        InternalTrace(">" + XPathNodeType.Root);\r
+                        return XPathNodeType.Root;\r
+\r
+                    case HtmlNodeType.Text:\r
+                        InternalTrace(">" + XPathNodeType.Text);\r
+                        return XPathNodeType.Text;\r
+\r
+                    case HtmlNodeType.Element:\r
+                        {\r
+                            if (_attindex != -1)\r
+                            {\r
+                                InternalTrace(">" + XPathNodeType.Attribute);\r
+                                return XPathNodeType.Attribute;\r
+                            }\r
+                            InternalTrace(">" + XPathNodeType.Element);\r
+                            return XPathNodeType.Element;\r
+                        }\r
+\r
+                    default:\r
+                        throw new NotImplementedException("Internal error: Unhandled HtmlNodeType: " +\r
+                                                          _currentnode.NodeType);\r
+                }\r
+            }\r
+        }\r
+\r
+        /// <summary>\r
+        /// Gets the prefix associated with the current node.\r
+        /// Always returns string.Empty in the case of HtmlNavigator implementation.\r
+        /// </summary>\r
+        public override string Prefix\r
+        {\r
+            get\r
+            {\r
+                InternalTrace(null);\r
+                return _nametable.GetOrAdd(string.Empty);\r
+            }\r
+        }\r
+\r
+        /// <summary>\r
+        /// Gets the text value of the current node.\r
+        /// </summary>\r
+        public override string Value\r
+        {\r
+            get\r
+            {\r
+                InternalTrace("nt=" + _currentnode.NodeType);\r
+                switch (_currentnode.NodeType)\r
+                {\r
+                    case HtmlNodeType.Comment:\r
+                        InternalTrace(">" + ((HtmlCommentNode) _currentnode).Comment);\r
+                        return ((HtmlCommentNode) _currentnode).Comment;\r
+\r
+                    case HtmlNodeType.Document:\r
+                        InternalTrace(">");\r
+                        return "";\r
+\r
+                    case HtmlNodeType.Text:\r
+                        InternalTrace(">" + ((HtmlTextNode) _currentnode).Text);\r
+                        return ((HtmlTextNode) _currentnode).Text;\r
+\r
+                    case HtmlNodeType.Element:\r
+                        {\r
+                            if (_attindex != -1)\r
+                            {\r
+                                InternalTrace(">" + _currentnode.Attributes[_attindex].Value);\r
+                                return _currentnode.Attributes[_attindex].Value;\r
+                            }\r
+                            return _currentnode.InnerText;\r
+                        }\r
+\r
+                    default:\r
+                        throw new NotImplementedException("Internal error: Unhandled HtmlNodeType: " +\r
+                                                          _currentnode.NodeType);\r
+                }\r
+            }\r
+        }\r
+\r
+        /// <summary>\r
+        /// Gets the xml:lang scope for the current node.\r
+        /// Always returns string.Empty in the case of HtmlNavigator implementation.\r
+        /// </summary>\r
+        public override string XmlLang\r
+        {\r
+            get\r
+            {\r
+                InternalTrace(null);\r
+                return _nametable.GetOrAdd(string.Empty);\r
+            }\r
+        }\r
+\r
+        #endregion\r
+\r
+        #region Public Methods\r
+\r
+        /// <summary>\r
+        /// Creates a new HtmlNavigator positioned at the same node as this HtmlNavigator.\r
+        /// </summary>\r
+        /// <returns>A new HtmlNavigator object positioned at the same node as the original HtmlNavigator.</returns>\r
+        public override XPathNavigator Clone()\r
+        {\r
+            InternalTrace(null);\r
+            return new HtmlNodeNavigator(this);\r
+        }\r
+\r
+        /// <summary>\r
+        /// Gets the value of the HTML attribute with the specified LocalName and NamespaceURI.\r
+        /// </summary>\r
+        /// <param name="localName">The local name of the HTML attribute.</param>\r
+        /// <param name="namespaceURI">The namespace URI of the attribute. Unsupported with the HtmlNavigator implementation.</param>\r
+        /// <returns>The value of the specified HTML attribute. String.Empty or null if a matching attribute is not found or if the navigator is not positioned on an element node.</returns>\r
+        public override string GetAttribute(string localName, string namespaceURI)\r
+        {\r
+            InternalTrace("localName=" + localName + ", namespaceURI=" + namespaceURI);\r
+            HtmlAttribute att = _currentnode.Attributes[localName];\r
+            if (att == null)\r
+            {\r
+                InternalTrace(">null");\r
+                return null;\r
+            }\r
+            InternalTrace(">" + att.Value);\r
+            return att.Value;\r
+        }\r
+\r
+        /// <summary>\r
+        /// Returns the value of the namespace node corresponding to the specified local name.\r
+        /// Always returns string.Empty for the HtmlNavigator implementation.\r
+        /// </summary>\r
+        /// <param name="name">The local name of the namespace node.</param>\r
+        /// <returns>Always returns string.Empty for the HtmlNavigator implementation.</returns>\r
+        public override string GetNamespace(string name)\r
+        {\r
+            InternalTrace("name=" + name);\r
+            return string.Empty;\r
+        }\r
+\r
+        /// <summary>\r
+        /// Determines whether the current HtmlNavigator is at the same position as the specified HtmlNavigator.\r
+        /// </summary>\r
+        /// <param name="other">The HtmlNavigator that you want to compare against.</param>\r
+        /// <returns>true if the two navigators have the same position, otherwise, false.</returns>\r
+        public override bool IsSamePosition(XPathNavigator other)\r
+        {\r
+            HtmlNodeNavigator nav = other as HtmlNodeNavigator;\r
+            if (nav == null)\r
+            {\r
+                InternalTrace(">false");\r
+                return false;\r
+            }\r
+            InternalTrace(">" + (nav._currentnode == _currentnode));\r
+            return (nav._currentnode == _currentnode);\r
+        }\r
+\r
+        /// <summary>\r
+        /// Moves to the same position as the specified HtmlNavigator.\r
+        /// </summary>\r
+        /// <param name="other">The HtmlNavigator positioned on the node that you want to move to.</param>\r
+        /// <returns>true if successful, otherwise false. If false, the position of the navigator is unchanged.</returns>\r
+        public override bool MoveTo(XPathNavigator other)\r
+        {\r
+            HtmlNodeNavigator nav = other as HtmlNodeNavigator;\r
+            if (nav == null)\r
+            {\r
+                InternalTrace(">false (nav is not an HtmlNodeNavigator)");\r
+                return false;\r
+            }\r
+            InternalTrace("moveto oid=" + nav.GetHashCode()\r
+                          + ", n:" + nav._currentnode.Name\r
+                          + ", a:" + nav._attindex);\r
+\r
+            if (nav._doc == _doc)\r
+            {\r
+                _currentnode = nav._currentnode;\r
+                _attindex = nav._attindex;\r
+                InternalTrace(">true");\r
+                return true;\r
+            }\r
+            // we don't know how to handle that\r
+            InternalTrace(">false (???)");\r
+            return false;\r
+        }\r
+\r
+        /// <summary>\r
+        /// Moves to the HTML attribute with matching LocalName and NamespaceURI.\r
+        /// </summary>\r
+        /// <param name="localName">The local name of the HTML attribute.</param>\r
+        /// <param name="namespaceURI">The namespace URI of the attribute. Unsupported with the HtmlNavigator implementation.</param>\r
+        /// <returns>true if the HTML attribute is found, otherwise, false. If false, the position of the navigator does not change.</returns>\r
+        public override bool MoveToAttribute(string localName, string namespaceURI)\r
+        {\r
+            InternalTrace("localName=" + localName + ", namespaceURI=" + namespaceURI);\r
+            int index = _currentnode.Attributes.GetAttributeIndex(localName);\r
+            if (index == -1)\r
+            {\r
+                InternalTrace(">false");\r
+                return false;\r
+            }\r
+            _attindex = index;\r
+            InternalTrace(">true");\r
+            return true;\r
+        }\r
+\r
+        /// <summary>\r
+        /// Moves to the first sibling of the current node.\r
+        /// </summary>\r
+        /// <returns>true if the navigator is successful moving to the first sibling node, false if there is no first sibling or if the navigator is currently positioned on an attribute node.</returns>\r
+        public override bool MoveToFirst()\r
+        {\r
+            if (_currentnode.ParentNode == null)\r
+            {\r
+                InternalTrace(">false");\r
+                return false;\r
+            }\r
+            if (_currentnode.ParentNode.FirstChild == null)\r
+            {\r
+                InternalTrace(">false");\r
+                return false;\r
+            }\r
+            _currentnode = _currentnode.ParentNode.FirstChild;\r
+            InternalTrace(">true");\r
+            return true;\r
+        }\r
+\r
+        /// <summary>\r
+        /// Moves to the first HTML attribute.\r
+        /// </summary>\r
+        /// <returns>true if the navigator is successful moving to the first HTML attribute, otherwise, false.</returns>\r
+        public override bool MoveToFirstAttribute()\r
+        {\r
+            if (!HasAttributes)\r
+            {\r
+                InternalTrace(">false");\r
+                return false;\r
+            }\r
+            _attindex = 0;\r
+            InternalTrace(">true");\r
+            return true;\r
+        }\r
+\r
+        /// <summary>\r
+        /// Moves to the first child of the current node.\r
+        /// </summary>\r
+        /// <returns>true if there is a first child node, otherwise false.</returns>\r
+        public override bool MoveToFirstChild()\r
+        {\r
+            if (!_currentnode.HasChildNodes)\r
+            {\r
+                InternalTrace(">false");\r
+                return false;\r
+            }\r
+            _currentnode = _currentnode.ChildNodes[0];\r
+            InternalTrace(">true");\r
+            return true;\r
+        }\r
+\r
+        /// <summary>\r
+        /// Moves the XPathNavigator to the first namespace node of the current element.\r
+        /// Always returns false for the HtmlNavigator implementation.\r
+        /// </summary>\r
+        /// <param name="scope">An XPathNamespaceScope value describing the namespace scope.</param>\r
+        /// <returns>Always returns false for the HtmlNavigator implementation.</returns>\r
+        public override bool MoveToFirstNamespace(XPathNamespaceScope scope)\r
+        {\r
+            InternalTrace(null);\r
+            return false;\r
+        }\r
+\r
+        /// <summary>\r
+        /// Moves to the node that has an attribute of type ID whose value matches the specified string.\r
+        /// </summary>\r
+        /// <param name="id">A string representing the ID value of the node to which you want to move. This argument does not need to be atomized.</param>\r
+        /// <returns>true if the move was successful, otherwise false. If false, the position of the navigator is unchanged.</returns>\r
+        public override bool MoveToId(string id)\r
+        {\r
+            InternalTrace("id=" + id);\r
+            HtmlNode node = _doc.GetElementbyId(id);\r
+            if (node == null)\r
+            {\r
+                InternalTrace(">false");\r
+                return false;\r
+            }\r
+            _currentnode = node;\r
+            InternalTrace(">true");\r
+            return true;\r
+        }\r
+\r
+        /// <summary>\r
+        /// Moves the XPathNavigator to the namespace node with the specified local name. \r
+        /// Always returns false for the HtmlNavigator implementation.\r
+        /// </summary>\r
+        /// <param name="name">The local name of the namespace node.</param>\r
+        /// <returns>Always returns false for the HtmlNavigator implementation.</returns>\r
+        public override bool MoveToNamespace(string name)\r
+        {\r
+            InternalTrace("name=" + name);\r
+            return false;\r
+        }\r
+\r
+        /// <summary>\r
+        /// Moves to the next sibling of the current node.\r
+        /// </summary>\r
+        /// <returns>true if the navigator is successful moving to the next sibling node, false if there are no more siblings or if the navigator is currently positioned on an attribute node. If false, the position of the navigator is unchanged.</returns>\r
+        public override bool MoveToNext()\r
+        {\r
+            if (_currentnode.NextSibling == null)\r
+            {\r
+                InternalTrace(">false");\r
+                return false;\r
+            }\r
+            InternalTrace("_c=" + _currentnode.CloneNode(false).OuterHtml);\r
+            InternalTrace("_n=" + _currentnode.NextSibling.CloneNode(false).OuterHtml);\r
+            _currentnode = _currentnode.NextSibling;\r
+            InternalTrace(">true");\r
+            return true;\r
+        }\r
+\r
+        /// <summary>\r
+        /// Moves to the next HTML attribute.\r
+        /// </summary>\r
+        /// <returns></returns>\r
+        public override bool MoveToNextAttribute()\r
+        {\r
+            InternalTrace(null);\r
+            if (_attindex >= (_currentnode.Attributes.Count - 1))\r
+            {\r
+                InternalTrace(">false");\r
+                return false;\r
+            }\r
+            _attindex++;\r
+            InternalTrace(">true");\r
+            return true;\r
+        }\r
+\r
+        /// <summary>\r
+        /// Moves the XPathNavigator to the next namespace node.\r
+        /// Always returns falsefor the HtmlNavigator implementation.\r
+        /// </summary>\r
+        /// <param name="scope">An XPathNamespaceScope value describing the namespace scope.</param>\r
+        /// <returns>Always returns false for the HtmlNavigator implementation.</returns>\r
+        public override bool MoveToNextNamespace(XPathNamespaceScope scope)\r
+        {\r
+            InternalTrace(null);\r
+            return false;\r
+        }\r
+\r
+        /// <summary>\r
+        /// Moves to the parent of the current node.\r
+        /// </summary>\r
+        /// <returns>true if there is a parent node, otherwise false.</returns>\r
+        public override bool MoveToParent()\r
+        {\r
+            if (_currentnode.ParentNode == null)\r
+            {\r
+                InternalTrace(">false");\r
+                return false;\r
+            }\r
+            _currentnode = _currentnode.ParentNode;\r
+            InternalTrace(">true");\r
+            return true;\r
+        }\r
+\r
+        /// <summary>\r
+        /// Moves to the previous sibling of the current node.\r
+        /// </summary>\r
+        /// <returns>true if the navigator is successful moving to the previous sibling node, false if there is no previous sibling or if the navigator is currently positioned on an attribute node.</returns>\r
+        public override bool MoveToPrevious()\r
+        {\r
+            if (_currentnode.PreviousSibling == null)\r
+            {\r
+                InternalTrace(">false");\r
+                return false;\r
+            }\r
+            _currentnode = _currentnode.PreviousSibling;\r
+            InternalTrace(">true");\r
+            return true;\r
+        }\r
+\r
+        /// <summary>\r
+        /// Moves to the root node to which the current node belongs.\r
+        /// </summary>\r
+        public override void MoveToRoot()\r
+        {\r
+            _currentnode = _doc.DocumentNode;\r
+            InternalTrace(null);\r
+        }\r
+\r
+        #endregion\r
+\r
+        #region Internal Methods\r
+\r
+        [Conditional("TRACE")]\r
+        internal void InternalTrace(object traceValue)\r
+        {\r
+            if (!Trace)\r
+            {\r
+                return;\r
+            }\r
+            StackFrame sf = new StackFrame(1, true);\r
+            string name = sf.GetMethod().Name;\r
+            string nodename = _currentnode == null ? "(null)" : _currentnode.Name;\r
+            string nodevalue;\r
+            if (_currentnode == null)\r
+            {\r
+                nodevalue = "(null)";\r
+            }\r
+            else\r
+            {\r
+                switch (_currentnode.NodeType)\r
+                {\r
+                    case HtmlNodeType.Comment:\r
+                        nodevalue = ((HtmlCommentNode) _currentnode).Comment;\r
+                        break;\r
+\r
+                    case HtmlNodeType.Document:\r
+                        nodevalue = "";\r
+                        break;\r
+\r
+                    case HtmlNodeType.Text:\r
+                        nodevalue = ((HtmlTextNode) _currentnode).Text;\r
+                        break;\r
+\r
+                    default:\r
+                        nodevalue = _currentnode.CloneNode(false).OuterHtml;\r
+                        break;\r
+                }\r
+            }\r
+            System.Diagnostics.Trace.WriteLine(string.Format("oid={0},n={1},a={2},v={3},{4}", GetHashCode(), nodename, _attindex, nodevalue, traceValue), "N!" + name);\r
+        }\r
+\r
+        #endregion\r
+\r
+        #region Private Methods\r
+\r
+        private void Reset()\r
+        {\r
+            InternalTrace(null);\r
+            _currentnode = _doc.DocumentNode;\r
+            _attindex = -1;\r
+        }\r
+\r
+        #endregion\r
+    }\r
+}
\ No newline at end of file
diff --git a/docs/HtmlAgilityPack/HtmlNodeType.cs b/docs/HtmlAgilityPack/HtmlNodeType.cs
new file mode 100644 (file)
index 0000000..a84e4af
--- /dev/null
@@ -0,0 +1,29 @@
+// HtmlAgilityPack V1.0 - Simon Mourier <simon underscore mourier at hotmail dot com>\r
+namespace HtmlAgilityPack\r
+{\r
+    /// <summary>\r
+    /// Represents the type of a node.\r
+    /// </summary>\r
+    public enum HtmlNodeType\r
+    {\r
+        /// <summary>\r
+        /// The root of a document.\r
+        /// </summary>\r
+        Document,\r
+\r
+        /// <summary>\r
+        /// An HTML element.\r
+        /// </summary>\r
+        Element,\r
+\r
+        /// <summary>\r
+        /// An HTML comment.\r
+        /// </summary>\r
+        Comment,\r
+\r
+        /// <summary>\r
+        /// A text node is always the child of an element or a document node.\r
+        /// </summary>\r
+        Text,\r
+    }\r
+}
\ No newline at end of file
diff --git a/docs/HtmlAgilityPack/HtmlParseError.cs b/docs/HtmlAgilityPack/HtmlParseError.cs
new file mode 100644 (file)
index 0000000..d3d5e78
--- /dev/null
@@ -0,0 +1,92 @@
+// HtmlAgilityPack V1.0 - Simon Mourier <simon underscore mourier at hotmail dot com>\r
+namespace HtmlAgilityPack\r
+{\r
+    /// <summary>\r
+    /// Represents a parsing error found during document parsing.\r
+    /// </summary>\r
+    public class HtmlParseError\r
+    {\r
+        #region Fields\r
+\r
+        private HtmlParseErrorCode _code;\r
+        private int _line;\r
+        private int _linePosition;\r
+        private string _reason;\r
+        private string _sourceText;\r
+        private int _streamPosition;\r
+\r
+        #endregion\r
+\r
+        #region Constructors\r
+\r
+        internal HtmlParseError(\r
+            HtmlParseErrorCode code,\r
+            int line,\r
+            int linePosition,\r
+            int streamPosition,\r
+            string sourceText,\r
+            string reason)\r
+        {\r
+            _code = code;\r
+            _line = line;\r
+            _linePosition = linePosition;\r
+            _streamPosition = streamPosition;\r
+            _sourceText = sourceText;\r
+            _reason = reason;\r
+        }\r
+\r
+        #endregion\r
+\r
+        #region Properties\r
+\r
+        /// <summary>\r
+        /// Gets the type of error.\r
+        /// </summary>\r
+        public HtmlParseErrorCode Code\r
+        {\r
+            get { return _code; }\r
+        }\r
+\r
+        /// <summary>\r
+        /// Gets the line number of this error in the document.\r
+        /// </summary>\r
+        public int Line\r
+        {\r
+            get { return _line; }\r
+        }\r
+\r
+        /// <summary>\r
+        /// Gets the column number of this error in the document.\r
+        /// </summary>\r
+        public int LinePosition\r
+        {\r
+            get { return _linePosition; }\r
+        }\r
+\r
+        /// <summary>\r
+        /// Gets a description for the error.\r
+        /// </summary>\r
+        public string Reason\r
+        {\r
+            get { return _reason; }\r
+        }\r
+\r
+        /// <summary>\r
+        /// Gets the the full text of the line containing the error.\r
+        /// </summary>\r
+        public string SourceText\r
+        {\r
+            get { return _sourceText; }\r
+        }\r
+\r
+        /// <summary>\r
+        /// Gets the absolute stream position of this error in the document, relative to the start of the document.\r
+        /// </summary>\r
+        public int StreamPosition\r
+        {\r
+            get { return _streamPosition; }\r
+        }\r
+\r
+        #endregion\r
+    }\r
+}
\ No newline at end of file
diff --git a/docs/HtmlAgilityPack/HtmlParseErrorCode.cs b/docs/HtmlAgilityPack/HtmlParseErrorCode.cs
new file mode 100644 (file)
index 0000000..f92128d
--- /dev/null
@@ -0,0 +1,34 @@
+// HtmlAgilityPack V1.0 - Simon Mourier <simon underscore mourier at hotmail dot com>\r
+namespace HtmlAgilityPack\r
+{\r
+    /// <summary>\r
+    /// Represents the type of parsing error.\r
+    /// </summary>\r
+    public enum HtmlParseErrorCode\r
+    {\r
+        /// <summary>\r
+        /// A tag was not closed.\r
+        /// </summary>\r
+        TagNotClosed,\r
+\r
+        /// <summary>\r
+        /// A tag was not opened.\r
+        /// </summary>\r
+        TagNotOpened,\r
+\r
+        /// <summary>\r
+        /// There is a charset mismatch between stream and declared (META) encoding.\r
+        /// </summary>\r
+        CharsetMismatch,\r
+\r
+        /// <summary>\r
+        /// An end tag was not required.\r
+        /// </summary>\r
+        EndTagNotRequired,\r
+\r
+        /// <summary>\r
+        /// An end tag is invalid at this position.\r
+        /// </summary>\r
+        EndTagInvalidHere\r
+    }\r
+}
\ No newline at end of file
diff --git a/docs/HtmlAgilityPack/HtmlTextNode.cs b/docs/HtmlAgilityPack/HtmlTextNode.cs
new file mode 100644 (file)
index 0000000..cdf8bce
--- /dev/null
@@ -0,0 +1,69 @@
+// HtmlAgilityPack V1.0 - Simon Mourier <simon underscore mourier at hotmail dot com>\r
+namespace HtmlAgilityPack\r
+{\r
+    /// <summary>\r
+    /// Represents an HTML text node.\r
+    /// </summary>\r
+    public class HtmlTextNode : HtmlNode\r
+    {\r
+        #region Fields\r
+\r
+        private string _text;\r
+\r
+        #endregion\r
+\r
+        #region Constructors\r
+\r
+        internal HtmlTextNode(HtmlDocument ownerdocument, int index)\r
+            :\r
+                base(HtmlNodeType.Text, ownerdocument, index)\r
+        {\r
+        }\r
+\r
+        #endregion\r
+\r
+        #region Properties\r
+\r
+        /// <summary>\r
+        /// Gets or Sets the HTML between the start and end tags of the object. In the case of a text node, it is equals to OuterHtml.\r
+        /// </summary>\r
+        public override string InnerHtml\r
+        {\r
+            get { return OuterHtml; }\r
+            set { _text = value; }\r
+        }\r
+\r
+        /// <summary>\r
+        /// Gets or Sets the object and its content in HTML.\r
+        /// </summary>\r
+        public override string OuterHtml\r
+        {\r
+            get\r
+            {\r
+                if (_text == null)\r
+                {\r
+                    return base.OuterHtml;\r
+                }\r
+                return _text;\r
+            }\r
+        }\r
+\r
+        /// <summary>\r
+        /// Gets or Sets the text of the node.\r
+        /// </summary>\r
+        public string Text\r
+        {\r
+            get\r
+            {\r
+                if (_text == null)\r
+                {\r
+                    return base.OuterHtml;\r
+                }\r
+                return _text;\r
+            }\r
+            set { _text = value; }\r
+        }\r
+\r
+        #endregion\r
+    }\r
+}
\ No newline at end of file
diff --git a/docs/HtmlAgilityPack/HtmlWeb.cs b/docs/HtmlAgilityPack/HtmlWeb.cs
new file mode 100644 (file)
index 0000000..39dd426
--- /dev/null
@@ -0,0 +1,907 @@
+// HtmlAgilityPack V1.0 - Simon Mourier <simon underscore mourier at hotmail dot com>\r
+using System;\r
+using System.IO;\r
+using System.Net;\r
+using System.Text;\r
+using System.Xml;\r
+using System.Xml.Serialization;\r
+using System.Xml.Xsl;\r
+using Microsoft.Win32;\r
+\r
+namespace HtmlAgilityPack\r
+{\r
+    /// <summary>\r
+    /// A utility class to get HTML document from HTTP.\r
+    /// </summary>\r
+    public class HtmlWeb\r
+    {\r
+        #region Delegates\r
+\r
+        /// <summary>\r
+        /// Represents the method that will handle the PostResponse event.\r
+        /// </summary>\r
+        public delegate void PostResponseHandler(HttpWebRequest request, HttpWebResponse response);\r
+\r
+        /// <summary>\r
+        /// Represents the method that will handle the PreHandleDocument event.\r
+        /// </summary>\r
+        public delegate void PreHandleDocumentHandler(HtmlDocument document);\r
+\r
+        /// <summary>\r
+        /// Represents the method that will handle the PreRequest event.\r
+        /// </summary>\r
+        public delegate bool PreRequestHandler(HttpWebRequest request);\r
+\r
+        #endregion\r
+\r
+        #region Fields\r
+\r
+        private bool _autoDetectEncoding = true;\r
+        private bool _cacheOnly;\r
+\r
+        private string _cachePath;\r
+        private bool _fromCache;\r
+        private int _requestDuration;\r
+        private Uri _responseUri;\r
+        private HttpStatusCode _statusCode = HttpStatusCode.OK;\r
+        private int _streamBufferSize = 1024;\r
+        private bool _useCookies;\r
+        private bool _usingCache;\r
+\r
+        /// <summary>\r
+        /// Occurs after an HTTP request has been executed.\r
+        /// </summary>\r
+        public PostResponseHandler PostResponse;\r
+\r
+        /// <summary>\r
+        /// Occurs before an HTML document is handled.\r
+        /// </summary>\r
+        public PreHandleDocumentHandler PreHandleDocument;\r
+\r
+        /// <summary>\r
+        /// Occurs before an HTTP request is executed.\r
+        /// </summary>\r
+        public PreRequestHandler PreRequest;\r
+\r
+        #endregion\r
+\r
+        #region Properties\r
+\r
+        /// <summary>\r
+        /// Gets or Sets a value indicating if document encoding must be automatically detected.\r
+        /// </summary>\r
+        public bool AutoDetectEncoding\r
+        {\r
+            get { return _autoDetectEncoding; }\r
+            set { _autoDetectEncoding = value; }\r
+        }\r
+\r
+        /// <summary>\r
+        /// Gets or Sets a value indicating whether to get document only from the cache.\r
+        /// If this is set to true and document is not found in the cache, nothing will be loaded.\r
+        /// </summary>\r
+        public bool CacheOnly\r
+        {\r
+            get { return _cacheOnly; }\r
+            set\r
+            {\r
+                if ((value) && !UsingCache)\r
+                {\r
+                    throw new HtmlWebException("Cache is not enabled. Set UsingCache to true first.");\r
+                }\r
+                _cacheOnly = value;\r
+            }\r
+        }\r
+\r
+        /// <summary>\r
+        /// Gets or Sets the cache path. If null, no caching mechanism will be used.\r
+        /// </summary>\r
+        public string CachePath\r
+        {\r
+            get { return _cachePath; }\r
+            set { _cachePath = value; }\r
+        }\r
+\r
+        /// <summary>\r
+        /// Gets a value indicating if the last document was retrieved from the cache.\r
+        /// </summary>\r
+        public bool FromCache\r
+        {\r
+            get { return _fromCache; }\r
+        }\r
+\r
+        /// <summary>\r
+        /// Gets the last request duration in milliseconds.\r
+        /// </summary>\r
+        public int RequestDuration\r
+        {\r
+            get { return _requestDuration; }\r
+        }\r
+\r
+        /// <summary>\r
+        /// Gets the URI of the Internet resource that actually responded to the request.\r
+        /// </summary>\r
+        public Uri ResponseUri\r
+        {\r
+            get { return _responseUri; }\r
+        }\r
+\r
+        /// <summary>\r
+        /// Gets the last request status.\r
+        /// </summary>\r
+        public HttpStatusCode StatusCode\r
+        {\r
+            get { return _statusCode; }\r
+        }\r
+\r
+        /// <summary>\r
+        /// Gets or Sets the size of the buffer used for memory operations.\r
+        /// </summary>\r
+        public int StreamBufferSize\r
+        {\r
+            get { return _streamBufferSize; }\r
+            set\r
+            {\r
+                if (_streamBufferSize <= 0)\r
+                {\r
+                    throw new ArgumentException("Size must be greater than zero.");\r
+                }\r
+                _streamBufferSize = value;\r
+            }\r
+        }\r
+\r
+        /// <summary>\r
+        /// Gets or Sets a value indicating if cookies will be stored.\r
+        /// </summary>\r
+        public bool UseCookies\r
+        {\r
+            get { return _useCookies; }\r
+            set { _useCookies = value; }\r
+        }\r
+\r
+        /// <summary>\r
+        /// Gets or Sets a value indicating whether the caching mechanisms should be used or not.\r
+        /// </summary>\r
+        public bool UsingCache\r
+        {\r
+            get\r
+            {\r
+                if (_cachePath == null)\r
+                {\r
+                    return false;\r
+                }\r
+                return _usingCache;\r
+            }\r
+            set\r
+            {\r
+                if ((value) && (_cachePath == null))\r
+                {\r
+                    throw new HtmlWebException("You need to define a CachePath first.");\r
+                }\r
+                _usingCache = value;\r
+            }\r
+        }\r
+\r
+        #endregion\r
+\r
+        #region Public Methods\r
+\r
+        /// <summary>\r
+        /// Gets the MIME content type for a given path extension.\r
+        /// </summary>\r
+        /// <param name="extension">The input path extension.</param>\r
+        /// <param name="def">The default content type to return if any error occurs.</param>\r
+        /// <returns>The path extension's MIME content type.</returns>\r
+        public static string GetContentTypeForExtension(string extension, string def)\r
+        {\r
+            if (string.IsNullOrEmpty(extension))\r
+            {\r
+                return def;\r
+            }\r
+            string contentType = "";\r
+            try\r
+            {\r
+                RegistryKey reg = Registry.ClassesRoot;\r
+                reg = reg.OpenSubKey(extension, false);\r
+                if (reg != null) contentType = (string)reg.GetValue("", def);\r
+            }\r
+            catch (Exception)\r
+            {\r
+                contentType = def;\r
+            }\r
+            return contentType;\r
+        }\r
+\r
+        /// <summary>\r
+        /// Gets the path extension for a given MIME content type.\r
+        /// </summary>\r
+        /// <param name="contentType">The input MIME content type.</param>\r
+        /// <param name="def">The default path extension to return if any error occurs.</param>\r
+        /// <returns>The MIME content type's path extension.</returns>\r
+        public static string GetExtensionForContentType(string contentType, string def)\r
+        {\r
+            if (string.IsNullOrEmpty(contentType))\r
+            {\r
+                return def;\r
+            }\r
+            string ext = "";\r
+            try\r
+            {\r
+                RegistryKey reg = Registry.ClassesRoot;\r
+                reg = reg.OpenSubKey(@"MIME\Database\Content Type\" + contentType, false);\r
+                if (reg != null) ext = (string)reg.GetValue("Extension", def);\r
+            }\r
+            catch (Exception)\r
+            {\r
+                ext = def;\r
+            }\r
+            return ext;\r
+        }\r
+\r
+        /// <summary>\r
+        /// Creates an instance of the given type from the specified Internet resource.\r
+        /// </summary>\r
+        /// <param name="url">The requested URL, such as "http://Myserver/Mypath/Myfile.asp".</param>\r
+        /// <param name="type">The requested type.</param>\r
+        /// <returns>An newly created instance.</returns>\r
+        public object CreateInstance(string url, Type type)\r
+        {\r
+            return CreateInstance(url, null, null, type);\r
+        }\r
+\r
+        /// <summary>\r
+        /// Creates an instance of the given type from the specified Internet resource.\r
+        /// </summary>\r
+        /// <param name="htmlUrl">The requested URL, such as "http://Myserver/Mypath/Myfile.asp".</param>\r
+        /// <param name="xsltUrl">The URL that specifies the XSLT stylesheet to load.</param>\r
+        /// <param name="xsltArgs">An <see cref="XsltArgumentList"/> containing the namespace-qualified arguments used as input to the transform.</param>\r
+        /// <param name="type">The requested type.</param>\r
+        /// <returns>An newly created instance.</returns>\r
+        public object CreateInstance(string htmlUrl, string xsltUrl, XsltArgumentList xsltArgs, Type type)\r
+        {\r
+            return CreateInstance(htmlUrl, xsltUrl, xsltArgs, type, null);\r
+        }\r
+\r
+        /// <summary>\r
+        /// Creates an instance of the given type from the specified Internet resource.\r
+        /// </summary>\r
+        /// <param name="htmlUrl">The requested URL, such as "http://Myserver/Mypath/Myfile.asp".</param>\r
+        /// <param name="xsltUrl">The URL that specifies the XSLT stylesheet to load.</param>\r
+        /// <param name="xsltArgs">An <see cref="XsltArgumentList"/> containing the namespace-qualified arguments used as input to the transform.</param>\r
+        /// <param name="type">The requested type.</param>\r
+        /// <param name="xmlPath">A file path where the temporary XML before transformation will be saved. Mostly used for debugging purposes.</param>\r
+        /// <returns>An newly created instance.</returns>\r
+        public object CreateInstance(string htmlUrl, string xsltUrl, XsltArgumentList xsltArgs, Type type,\r
+                                     string xmlPath)\r
+        {\r
+            StringWriter sw = new StringWriter();\r
+            XmlTextWriter writer = new XmlTextWriter(sw);\r
+            if (xsltUrl == null)\r
+            {\r
+                LoadHtmlAsXml(htmlUrl, writer);\r
+            }\r
+            else\r
+            {\r
+                if (xmlPath == null)\r
+                {\r
+                    LoadHtmlAsXml(htmlUrl, xsltUrl, xsltArgs, writer);\r
+                }\r
+                else\r
+                {\r
+                    LoadHtmlAsXml(htmlUrl, xsltUrl, xsltArgs, writer, xmlPath);\r
+                }\r
+            }\r
+            writer.Flush();\r
+            StringReader sr = new StringReader(sw.ToString());\r
+            XmlTextReader reader = new XmlTextReader(sr);\r
+            XmlSerializer serializer = new XmlSerializer(type);\r
+            object o;\r
+            try\r
+            {\r
+                o = serializer.Deserialize(reader);\r
+            }\r
+            catch (InvalidOperationException ex)\r
+            {\r
+                throw new Exception(ex + ", --- xml:" + sw);\r
+            }\r
+            return o;\r
+        }\r
+\r
+        /// <summary>\r
+        /// Gets an HTML document from an Internet resource and saves it to the specified file.\r
+        /// </summary>\r
+        /// <param name="url">The requested URL, such as "http://Myserver/Mypath/Myfile.asp".</param>\r
+        /// <param name="path">The location of the file where you want to save the document.</param>\r
+        public void Get(string url, string path)\r
+        {\r
+            Get(url, path, "GET");\r
+        }\r
+\r
+        /// <summary>\r
+        /// Gets an HTML document from an Internet resource and saves it to the specified file. - Proxy aware\r
+        /// </summary>\r
+        /// <param name="url">The requested URL, such as "http://Myserver/Mypath/Myfile.asp".</param>\r
+        /// <param name="path">The location of the file where you want to save the document.</param>\r
+        /// <param name="proxy"></param>\r
+        /// <param name="credentials"></param>\r
+        public void Get(string url, string path, WebProxy proxy, NetworkCredential credentials)\r
+        {\r
+            Get(url, path, proxy, credentials, "GET");\r
+        }\r
+\r
+        /// <summary>\r
+        /// Gets an HTML document from an Internet resource and saves it to the specified file.\r
+        /// </summary>\r
+        /// <param name="url">The requested URL, such as "http://Myserver/Mypath/Myfile.asp".</param>\r
+        /// <param name="path">The location of the file where you want to save the document.</param>\r
+        /// <param name="method">The HTTP method used to open the connection, such as GET, POST, PUT, or PROPFIND.</param>\r
+        public void Get(string url, string path, string method)\r
+        {\r
+            Uri uri = new Uri(url);\r
+            if ((uri.Scheme == Uri.UriSchemeHttps) ||\r
+                (uri.Scheme == Uri.UriSchemeHttp))\r
+            {\r
+                Get(uri, method, path, null, null, null);\r
+            }\r
+            else\r
+            {\r
+                throw new HtmlWebException("Unsupported uri scheme: '" + uri.Scheme + "'.");\r
+            }\r
+        }\r
+\r
+        /// <summary>\r
+        /// Gets an HTML document from an Internet resource and saves it to the specified file.  Understands Proxies\r
+        /// </summary>\r
+        /// <param name="url">The requested URL, such as "http://Myserver/Mypath/Myfile.asp".</param>\r
+        /// <param name="path">The location of the file where you want to save the document.</param>\r
+        /// <param name="credentials"></param>\r
+        /// <param name="method">The HTTP method used to open the connection, such as GET, POST, PUT, or PROPFIND.</param>\r
+        /// <param name="proxy"></param>\r
+        public void Get(string url, string path, WebProxy proxy, NetworkCredential credentials, string method)\r
+        {\r
+            Uri uri = new Uri(url);\r
+            if ((uri.Scheme == Uri.UriSchemeHttps) ||\r
+                (uri.Scheme == Uri.UriSchemeHttp))\r
+            {\r
+                Get(uri, method, path, null, proxy, credentials);\r
+            }\r
+            else\r
+            {\r
+                throw new HtmlWebException("Unsupported uri scheme: '" + uri.Scheme + "'.");\r
+            }\r
+        }\r
+\r
+        /// <summary>\r
+        /// Gets the cache file path for a specified url.\r
+        /// </summary>\r
+        /// <param name="uri">The url fo which to retrieve the cache path. May not be null.</param>\r
+        /// <returns>The cache file path.</returns>\r
+        public string GetCachePath(Uri uri)\r
+        {\r
+            if (uri == null)\r
+            {\r
+                throw new ArgumentNullException("uri");\r
+            }\r
+            if (!UsingCache)\r
+            {\r
+                throw new HtmlWebException("Cache is not enabled. Set UsingCache to true first.");\r
+            }\r
+            string cachePath;\r
+            if (uri.AbsolutePath == "/")\r
+            {\r
+                cachePath = Path.Combine(_cachePath, ".htm");\r
+            }\r
+            else\r
+            {\r
+                cachePath = Path.Combine(_cachePath, (uri.Host + uri.AbsolutePath).Replace('/', '\\'));\r
+            }\r
+            return cachePath;\r
+        }\r
+\r
+        /// <summary>\r
+        /// Gets an HTML document from an Internet resource.\r
+        /// </summary>\r
+        /// <param name="url">The requested URL, such as "http://Myserver/Mypath/Myfile.asp".</param>\r
+        /// <returns>A new HTML document.</returns>\r
+        public HtmlDocument Load(string url)\r
+        {\r
+            return Load(url, "GET");\r
+        }\r
+\r
+        /// <summary>\r
+        /// Gets an HTML document from an Internet resource.\r
+        /// </summary>\r
+        /// <param name="url">The requested URL, such as "http://Myserver/Mypath/Myfile.asp".</param>\r
+        /// <param name="proxyHost">Host to use for Proxy</param>\r
+        /// <param name="proxyPort">Port the Proxy is on</param>\r
+        /// <param name="userId">User Id for Authentication</param>\r
+        /// <param name="password">Password for Authentication</param>\r
+        /// <returns>A new HTML document.</returns>\r
+        public HtmlDocument Load(string url, string proxyHost, int proxyPort, string userId, string password)\r
+        {\r
+            //Create my proxy\r
+            WebProxy myProxy = new WebProxy(proxyHost, proxyPort);\r
+            myProxy.BypassProxyOnLocal = true;\r
+\r
+            //Create my credentials\r
+            NetworkCredential myCreds = null;\r
+            if ((userId != null) && (password != null))\r
+            {\r
+                myCreds = new NetworkCredential(userId, password);\r
+                CredentialCache credCache = new CredentialCache();\r
+                //Add the creds\r
+                credCache.Add(myProxy.Address, "Basic", myCreds);\r
+                credCache.Add(myProxy.Address, "Digest", myCreds);\r
+            }\r
+\r
+            return Load(url, "GET", myProxy, myCreds);\r
+        }\r
+\r
+        /// <summary>\r
+        /// Loads an HTML document from an Internet resource.\r
+        /// </summary>\r
+        /// <param name="url">The requested URL, such as "http://Myserver/Mypath/Myfile.asp".</param>\r
+        /// <param name="method">The HTTP method used to open the connection, such as GET, POST, PUT, or PROPFIND.</param>\r
+        /// <returns>A new HTML document.</returns>\r
+        public HtmlDocument Load(string url, string method)\r
+        {\r
+            Uri uri = new Uri(url);\r
+            HtmlDocument doc;\r
+            if ((uri.Scheme == Uri.UriSchemeHttps) ||\r
+                (uri.Scheme == Uri.UriSchemeHttp))\r
+            {\r
+                doc = LoadUrl(uri, method, null, null);\r
+            }\r
+            else\r
+            {\r
+                if (uri.Scheme == Uri.UriSchemeFile)\r
+                {\r
+                    doc = new HtmlDocument();\r
+                    doc.OptionAutoCloseOnEnd = false;\r
+                    doc.OptionAutoCloseOnEnd = true;\r
+                    doc.DetectEncodingAndLoad(url, _autoDetectEncoding);\r
+                }\r
+                else\r
+                {\r
+                    throw new HtmlWebException("Unsupported uri scheme: '" + uri.Scheme + "'.");\r
+                }\r
+            }\r
+            if (PreHandleDocument != null)\r
+            {\r
+                PreHandleDocument(doc);\r
+            }\r
+            return doc;\r
+        }\r
+\r
+        /// <summary>\r
+        /// Loads an HTML document from an Internet resource.\r
+        /// </summary>\r
+        /// <param name="url">The requested URL, such as "http://Myserver/Mypath/Myfile.asp".</param>\r
+        /// <param name="method">The HTTP method used to open the connection, such as GET, POST, PUT, or PROPFIND.</param>\r
+        /// <param name="proxy">Proxy to use with this request</param>\r
+        /// <param name="credentials">Credentials to use when authenticating</param>\r
+        /// <returns>A new HTML document.</returns>\r
+        public HtmlDocument Load(string url, string method, WebProxy proxy, NetworkCredential credentials)\r
+        {\r
+            Uri uri = new Uri(url);\r
+            HtmlDocument doc;\r
+            if ((uri.Scheme == Uri.UriSchemeHttps) ||\r
+                (uri.Scheme == Uri.UriSchemeHttp))\r
+            {\r
+                doc = LoadUrl(uri, method, proxy, credentials);\r
+            }\r
+            else\r
+            {\r
+                if (uri.Scheme == Uri.UriSchemeFile)\r
+                {\r
+                    doc = new HtmlDocument();\r
+                    doc.OptionAutoCloseOnEnd = false;\r
+                    doc.OptionAutoCloseOnEnd = true;\r
+                    doc.DetectEncodingAndLoad(url, _autoDetectEncoding);\r
+                }\r
+                else\r
+                {\r
+                    throw new HtmlWebException("Unsupported uri scheme: '" + uri.Scheme + "'.");\r
+                }\r
+            }\r
+            if (PreHandleDocument != null)\r
+            {\r
+                PreHandleDocument(doc);\r
+            }\r
+            return doc;\r
+        }\r
+\r
+        /// <summary>\r
+        /// Loads an HTML document from an Internet resource and saves it to the specified XmlTextWriter.\r
+        /// </summary>\r
+        /// <param name="htmlUrl">The requested URL, such as "http://Myserver/Mypath/Myfile.asp".</param>\r
+        /// <param name="writer">The XmlTextWriter to which you want to save.</param>\r
+        public void LoadHtmlAsXml(string htmlUrl, XmlTextWriter writer)\r
+        {\r
+            HtmlDocument doc = Load(htmlUrl);\r
+            doc.Save(writer);\r
+        }\r
+\r
+        /// <summary>\r
+        /// Loads an HTML document from an Internet resource and saves it to the specified XmlTextWriter, after an XSLT transformation.\r
+        /// </summary>\r
+        /// <param name="htmlUrl">The requested URL, such as "http://Myserver/Mypath/Myfile.asp".</param>\r
+        /// <param name="xsltUrl">The URL that specifies the XSLT stylesheet to load.</param>\r
+        /// <param name="xsltArgs">An XsltArgumentList containing the namespace-qualified arguments used as input to the transform.</param>\r
+        /// <param name="writer">The XmlTextWriter to which you want to save.</param>\r
+        public void LoadHtmlAsXml(string htmlUrl, string xsltUrl, XsltArgumentList xsltArgs, XmlTextWriter writer)\r
+        {\r
+            LoadHtmlAsXml(htmlUrl, xsltUrl, xsltArgs, writer, null);\r
+        }\r
+\r
+        /// <summary>\r
+        /// Loads an HTML document from an Internet resource and saves it to the specified XmlTextWriter, after an XSLT transformation.\r
+        /// </summary>\r
+        /// <param name="htmlUrl">The requested URL, such as "http://Myserver/Mypath/Myfile.asp". May not be null.</param>\r
+        /// <param name="xsltUrl">The URL that specifies the XSLT stylesheet to load.</param>\r
+        /// <param name="xsltArgs">An XsltArgumentList containing the namespace-qualified arguments used as input to the transform.</param>\r
+        /// <param name="writer">The XmlTextWriter to which you want to save.</param>\r
+        /// <param name="xmlPath">A file path where the temporary XML before transformation will be saved. Mostly used for debugging purposes.</param>\r
+        public void LoadHtmlAsXml(string htmlUrl, string xsltUrl, XsltArgumentList xsltArgs, XmlTextWriter writer,\r
+                                  string xmlPath)\r
+        {\r
+            if (htmlUrl == null)\r
+            {\r
+                throw new ArgumentNullException("htmlUrl");\r
+            }\r
+\r
+            HtmlDocument doc = Load(htmlUrl);\r
+\r
+            if (xmlPath != null)\r
+            {\r
+                XmlTextWriter w = new XmlTextWriter(xmlPath, doc.Encoding);\r
+                doc.Save(w);\r
+                w.Close();\r
+            }\r
+            if (xsltArgs == null)\r
+            {\r
+                xsltArgs = new XsltArgumentList();\r
+            }\r
+\r
+            // add some useful variables to the xslt doc\r
+            xsltArgs.AddParam("url", "", htmlUrl);\r
+            xsltArgs.AddParam("requestDuration", "", RequestDuration);\r
+            xsltArgs.AddParam("fromCache", "", FromCache);\r
+\r
+            XslCompiledTransform xslt = new XslCompiledTransform();\r
+            xslt.Load(xsltUrl);\r
+            xslt.Transform(doc, xsltArgs, writer);\r
+        }\r
+\r
+        #endregion\r
+\r
+        #region Private Methods\r
+\r
+        private static void FilePreparePath(string target)\r
+        {\r
+            if (File.Exists(target))\r
+            {\r
+                FileAttributes atts = File.GetAttributes(target);\r
+                File.SetAttributes(target, atts & ~FileAttributes.ReadOnly);\r
+            }\r
+            else\r
+            {\r
+                string dir = Path.GetDirectoryName(target);\r
+                if (!Directory.Exists(dir))\r
+                {\r
+                    Directory.CreateDirectory(dir);\r
+                }\r
+            }\r
+        }\r
+\r
+        private static DateTime RemoveMilliseconds(DateTime t)\r
+        {\r
+            return new DateTime(t.Year, t.Month, t.Day, t.Hour, t.Minute, t.Second, 0);\r
+        }\r
+\r
+        // ReSharper disable UnusedMethodReturnValue.Local\r
+        private static long SaveStream(Stream stream, string path, DateTime touchDate, int streamBufferSize)\r
+        // ReSharper restore UnusedMethodReturnValue.Local\r
+        {\r
+            FilePreparePath(path);\r
+            FileStream fs = new FileStream(path, FileMode.Create, FileAccess.Write);\r
+            BinaryReader br = null;\r
+            BinaryWriter bw = null;\r
+            long len = 0;\r
+            try\r
+            {\r
+                br = new BinaryReader(stream);\r
+                bw = new BinaryWriter(fs);\r
+\r
+                byte[] buffer;\r
+                do\r
+                {\r
+                    buffer = br.ReadBytes(streamBufferSize);\r
+                    len += buffer.Length;\r
+                    if (buffer.Length > 0)\r
+                    {\r
+                        bw.Write(buffer);\r
+                    }\r
+                } while (buffer.Length > 0);\r
+            }\r
+            finally\r
+            {\r
+                if (br != null)\r
+                {\r
+                    br.Close();\r
+                }\r
+                if (bw != null)\r
+                {\r
+                    bw.Flush();\r
+                    bw.Close();\r
+                }\r
+                if (fs != null)\r
+                {\r
+                    fs.Close();\r
+                }\r
+            }\r
+            File.SetLastWriteTime(path, touchDate);\r
+            return len;\r
+        }\r
+\r
+        private HttpStatusCode Get(Uri uri, string method, string path, HtmlDocument doc, IWebProxy proxy,\r
+                                   ICredentials creds)\r
+        {\r
+            string cachePath = null;\r
+            HttpWebRequest req;\r
+            bool oldFile = false;\r
+\r
+            req = WebRequest.Create(uri) as HttpWebRequest;\r
+            req.Method = method;\r
+\r
+            if (proxy != null)\r
+            {\r
+                if (creds != null)\r
+                {\r
+                    proxy.Credentials = creds;\r
+                    req.Credentials = creds;\r
+                }\r
+                else\r
+                {\r
+                    proxy.Credentials = CredentialCache.DefaultCredentials;\r
+                    req.Credentials = CredentialCache.DefaultCredentials;\r
+                }\r
+                req.Proxy = proxy;\r
+            }\r
+\r
+            _fromCache = false;\r
+            _requestDuration = 0;\r
+            int tc = Environment.TickCount;\r
+            if (UsingCache)\r
+            {\r
+                cachePath = GetCachePath(req.RequestUri);\r
+                if (File.Exists(cachePath))\r
+                {\r
+                    req.IfModifiedSince = File.GetLastAccessTime(cachePath);\r
+                    oldFile = true;\r
+                }\r
+            }\r
+\r
+            if (_cacheOnly)\r
+            {\r
+                if (!File.Exists(cachePath))\r
+                {\r
+                    throw new HtmlWebException("File was not found at cache path: '" + cachePath + "'");\r
+                }\r
+\r
+                if (path != null)\r
+                {\r
+                    IOLibrary.CopyAlways(cachePath, path);\r
+                    // touch the file\r
+                    File.SetLastWriteTime(path, File.GetLastWriteTime(cachePath));\r
+                }\r
+                _fromCache = true;\r
+                return HttpStatusCode.NotModified;\r
+            }\r
+\r
+            if (_useCookies)\r
+            {\r
+                req.CookieContainer = new CookieContainer();\r
+            }\r
+\r
+            if (PreRequest != null)\r
+            {\r
+                // allow our user to change the request at will\r
+                if (!PreRequest(req))\r
+                {\r
+                    return HttpStatusCode.ResetContent;\r
+                }\r
+\r
+                // dump cookie\r
+                //                             if (_useCookies)\r
+                //                             {\r
+                //                                     foreach(Cookie cookie in req.CookieContainer.GetCookies(req.RequestUri))\r
+                //                                     {\r
+                //                                             HtmlLibrary.Trace("Cookie " + cookie.Name + "=" + cookie.Value + " path=" + cookie.Path + " domain=" + cookie.Domain);\r
+                //                                     }\r
+                //                             }\r
+            }\r
+\r
+            HttpWebResponse resp;\r
+\r
+            try\r
+            {\r
+                resp = req.GetResponse() as HttpWebResponse;\r
+            }\r
+            catch (WebException we)\r
+            {\r
+                _requestDuration = Environment.TickCount - tc;\r
+                resp = (HttpWebResponse)we.Response;\r
+                if (resp == null)\r
+                {\r
+                    if (oldFile)\r
+                    {\r
+                        if (path != null)\r
+                        {\r
+                            IOLibrary.CopyAlways(cachePath, path);\r
+                            // touch the file\r
+                            File.SetLastWriteTime(path, File.GetLastWriteTime(cachePath));\r
+                        }\r
+                        return HttpStatusCode.NotModified;\r
+                    }\r
+                    throw;\r
+                }\r
+            }\r
+            catch (Exception)\r
+            {\r
+                _requestDuration = Environment.TickCount - tc;\r
+                throw;\r
+            }\r
+\r
+            // allow our user to get some info from the response\r
+            if (PostResponse != null)\r
+            {\r
+                PostResponse(req, resp);\r
+            }\r
+\r
+            _requestDuration = Environment.TickCount - tc;\r
+            _responseUri = resp.ResponseUri;\r
+\r
+            bool html = IsHtmlContent(resp.ContentType);\r
+            Encoding respenc;\r
+\r
+            if ((resp.ContentEncoding != null) && (resp.ContentEncoding.Length > 0))\r
+            {\r
+                respenc = Encoding.GetEncoding(resp.ContentEncoding);\r
+            }\r
+            else\r
+            {\r
+                respenc = null;\r
+            }\r
+\r
+            if (resp.StatusCode == HttpStatusCode.NotModified)\r
+            {\r
+                if (UsingCache)\r
+                {\r
+                    _fromCache = true;\r
+                    if (path != null)\r
+                    {\r
+                        IOLibrary.CopyAlways(cachePath, path);\r
+                        // touch the file\r
+                        File.SetLastWriteTime(path, File.GetLastWriteTime(cachePath));\r
+                    }\r
+                    return resp.StatusCode;\r
+                }\r
+                else\r
+                {\r
+                    // this should *never* happen...\r
+                    throw new HtmlWebException("Server has send a NotModifed code, without cache enabled.");\r
+                }\r
+            }\r
+            Stream s = resp.GetResponseStream();\r
+            if (s != null)\r
+            {\r
+                if (UsingCache)\r
+                {\r
+                    // NOTE: LastModified does not contain milliseconds, so we remove them to the file\r
+                    SaveStream(s, cachePath, RemoveMilliseconds(resp.LastModified), _streamBufferSize);\r
+\r
+                    // save headers\r
+                    SaveCacheHeaders(req.RequestUri, resp);\r
+\r
+                    if (path != null)\r
+                    {\r
+                        // copy and touch the file\r
+                        IOLibrary.CopyAlways(cachePath, path);\r
+                        File.SetLastWriteTime(path, File.GetLastWriteTime(cachePath));\r
+                    }\r
+                }\r
+                else\r
+                {\r
+                    // try to work in-memory\r
+                    if ((doc != null) && (html))\r
+                    {\r
+                        if (respenc != null)\r
+                        {\r
+                            doc.Load(s, respenc);\r
+                        }\r
+                        else\r
+                        {\r
+                            doc.Load(s, true);\r
+                        }\r
+                    }\r
+                }\r
+                resp.Close();\r
+            }\r
+            return resp.StatusCode;\r
+        }\r
+\r
+        private string GetCacheHeader(Uri requestUri, string name, string def)\r
+        {\r
+            // note: some headers are collection (ex: www-authenticate)\r
+            // we don't handle that here\r
+            XmlDocument doc = new XmlDocument();\r
+            doc.Load(GetCacheHeadersPath(requestUri));\r
+            XmlNode node =\r
+                doc.SelectSingleNode("//h[translate(@n, 'abcdefghijklmnopqrstuvwxyz','ABCDEFGHIJKLMNOPQRSTUVWXYZ')='" +\r
+                                     name.ToUpper() + "']");\r
+            if (node == null)\r
+            {\r
+                return def;\r
+            }\r
+            // attribute should exist\r
+            return node.Attributes[name].Value;\r
+        }\r
+\r
+        private string GetCacheHeadersPath(Uri uri)\r
+        {\r
+            //return Path.Combine(GetCachePath(uri), ".h.xml");\r
+            return GetCachePath(uri) + ".h.xml";\r
+        }\r
+\r
+        private bool IsCacheHtmlContent(string path)\r
+        {\r
+            string ct = GetContentTypeForExtension(Path.GetExtension(path), null);\r
+            return IsHtmlContent(ct);\r
+        }\r
+\r
+        private bool IsHtmlContent(string contentType)\r
+        {\r
+            return contentType.ToLower().StartsWith("text/html");\r
+        }\r
+\r
+        private HtmlDocument LoadUrl(Uri uri, string method, WebProxy proxy, NetworkCredential creds)\r
+        {\r
+            HtmlDocument doc = new HtmlDocument();\r
+            doc.OptionAutoCloseOnEnd = false;\r
+            doc.OptionFixNestedTags = true;\r
+            _statusCode = Get(uri, method, null, doc, proxy, creds);\r
+            if (_statusCode == HttpStatusCode.NotModified)\r
+            {\r
+                // read cached encoding\r
+                doc.DetectEncodingAndLoad(GetCachePath(uri));\r
+            }\r
+            return doc;\r
+        }\r
+\r
+        private void SaveCacheHeaders(Uri requestUri, HttpWebResponse resp)\r
+        {\r
+            // we cache the original headers aside the cached document.\r
+            string file = GetCacheHeadersPath(requestUri);\r
+            XmlDocument doc = new XmlDocument();\r
+            doc.LoadXml("<c></c>");\r
+            XmlNode cache = doc.FirstChild;\r
+            foreach (string header in resp.Headers)\r
+            {\r
+                XmlNode entry = doc.CreateElement("h");\r
+                XmlAttribute att = doc.CreateAttribute("n");\r
+                att.Value = header;\r
+                entry.Attributes.Append(att);\r
+\r
+                att = doc.CreateAttribute("v");\r
+                att.Value = resp.Headers[header];\r
+                entry.Attributes.Append(att);\r
+\r
+                cache.AppendChild(entry);\r
+            }\r
+            doc.Save(file);\r
+        }\r
+\r
+        #endregion\r
+    }\r
+}
\ No newline at end of file
diff --git a/docs/HtmlAgilityPack/HtmlWebException.cs b/docs/HtmlAgilityPack/HtmlWebException.cs
new file mode 100644 (file)
index 0000000..6896257
--- /dev/null
@@ -0,0 +1,24 @@
+// HtmlAgilityPack V1.0 - Simon Mourier <simon underscore mourier at hotmail dot com>\r
+using System;\r
+\r
+namespace HtmlAgilityPack\r
+{\r
+    /// <summary>\r
+    /// Represents an exception thrown by the HtmlWeb utility class.\r
+    /// </summary>\r
+    public class HtmlWebException : Exception\r
+    {\r
+        #region Constructors\r
+\r
+        /// <summary>\r
+        /// Creates an instance of the HtmlWebException.\r
+        /// </summary>\r
+        /// <param name="message">The exception's message.</param>\r
+        public HtmlWebException(string message)\r
+            : base(message)\r
+        {\r
+        }\r
+\r
+        #endregion\r
+    }\r
+}
\ No newline at end of file
diff --git a/docs/HtmlAgilityPack/IOLibrary.cs b/docs/HtmlAgilityPack/IOLibrary.cs
new file mode 100644 (file)
index 0000000..031040d
--- /dev/null
@@ -0,0 +1,28 @@
+// HtmlAgilityPack V1.0 - Simon Mourier <simon underscore mourier at hotmail dot com>\r
+using System.IO;\r
+\r
+namespace HtmlAgilityPack\r
+{\r
+    internal struct IOLibrary\r
+    {\r
+        #region Internal Methods\r
+\r
+        internal static void CopyAlways(string source, string target)\r
+        {\r
+            if (!File.Exists(source))\r
+                return;\r
+            Directory.CreateDirectory(Path.GetDirectoryName(target));\r
+            MakeWritable(target);\r
+            File.Copy(source, target, true);\r
+        }\r
+\r
+        internal static void MakeWritable(string path)\r
+        {\r
+            if (!File.Exists(path))\r
+                return;\r
+            File.SetAttributes(path, File.GetAttributes(path) & ~FileAttributes.ReadOnly);\r
+        }\r
+\r
+        #endregion\r
+    }\r
+}
\ No newline at end of file
diff --git a/docs/HtmlAgilityPack/MixedCodeDocument.cs b/docs/HtmlAgilityPack/MixedCodeDocument.cs
new file mode 100644 (file)
index 0000000..f12ac45
--- /dev/null
@@ -0,0 +1,453 @@
+// HtmlAgilityPack V1.0 - Simon Mourier <simon underscore mourier at hotmail dot com>\r
+using System;\r
+using System.IO;\r
+using System.Text;\r
+\r
+namespace HtmlAgilityPack\r
+{\r
+    /// <summary>\r
+    /// Represents a document with mixed code and text. ASP, ASPX, JSP, are good example of such documents.\r
+    /// </summary>\r
+    public class MixedCodeDocument\r
+    {\r
+        #region Fields\r
+\r
+        private int _c;\r
+        internal MixedCodeDocumentFragmentList _codefragments;\r
+        private MixedCodeDocumentFragment _currentfragment;\r
+        internal MixedCodeDocumentFragmentList _fragments;\r
+        private int _index;\r
+        private int _line;\r
+        private int _lineposition;\r
+        private ParseState _state;\r
+        private Encoding _streamencoding;\r
+        internal string _text;\r
+        internal MixedCodeDocumentFragmentList _textfragments;\r
+\r
+        /// <summary>\r
+        /// Gets or sets the token representing code end.\r
+        /// </summary>\r
+        public string TokenCodeEnd = "%>";\r
+\r
+        /// <summary>\r
+        /// Gets or sets the token representing code start.\r
+        /// </summary>\r
+        public string TokenCodeStart = "<%";\r
+\r
+        /// <summary>\r
+        /// Gets or sets the token representing code directive.\r
+        /// </summary>\r
+        public string TokenDirective = "@";\r
+\r
+        /// <summary>\r
+        /// Gets or sets the token representing response write directive.\r
+        /// </summary>\r
+        public string TokenResponseWrite = "Response.Write ";\r
+\r
+\r
+        private string TokenTextBlock = "TextBlock({0})";\r
+\r
+        #endregion\r
+\r
+        #region Constructors\r
+\r
+        /// <summary>\r
+        /// Creates a mixed code document instance.\r
+        /// </summary>\r
+        public MixedCodeDocument()\r
+        {\r
+            _codefragments = new MixedCodeDocumentFragmentList(this);\r
+            _textfragments = new MixedCodeDocumentFragmentList(this);\r
+            _fragments = new MixedCodeDocumentFragmentList(this);\r
+        }\r
+\r
+        #endregion\r
+\r
+        #region Properties\r
+\r
+        /// <summary>\r
+        /// Gets the code represented by the mixed code document seen as a template.\r
+        /// </summary>\r
+        public string Code\r
+        {\r
+            get\r
+            {\r
+                string s = "";\r
+                int i = 0;\r
+                foreach (MixedCodeDocumentFragment frag in _fragments)\r
+                {\r
+                    switch (frag._type)\r
+                    {\r
+                        case MixedCodeDocumentFragmentType.Text:\r
+                            s += TokenResponseWrite + string.Format(TokenTextBlock, i) + "\n";\r
+                            i++;\r
+                            break;\r
+\r
+                        case MixedCodeDocumentFragmentType.Code:\r
+                            s += ((MixedCodeDocumentCodeFragment) frag).Code + "\n";\r
+                            break;\r
+                    }\r
+                }\r
+                return s;\r
+            }\r
+        }\r
+\r
+        /// <summary>\r
+        /// Gets the list of code fragments in the document.\r
+        /// </summary>\r
+        public MixedCodeDocumentFragmentList CodeFragments\r
+        {\r
+            get { return _codefragments; }\r
+        }\r
+\r
+        /// <summary>\r
+        /// Gets the list of all fragments in the document.\r
+        /// </summary>\r
+        public MixedCodeDocumentFragmentList Fragments\r
+        {\r
+            get { return _fragments; }\r
+        }\r
+\r
+        /// <summary>\r
+        /// Gets the encoding of the stream used to read the document.\r
+        /// </summary>\r
+        public Encoding StreamEncoding\r
+        {\r
+            get { return _streamencoding; }\r
+        }\r
+\r
+        /// <summary>\r
+        /// Gets the list of text fragments in the document.\r
+        /// </summary>\r
+        public MixedCodeDocumentFragmentList TextFragments\r
+        {\r
+            get { return _textfragments; }\r
+        }\r
+\r
+        #endregion\r
+\r
+        #region Public Methods\r
+\r
+        /// <summary>\r
+        /// Create a code fragment instances.\r
+        /// </summary>\r
+        /// <returns>The newly created code fragment instance.</returns>\r
+        public MixedCodeDocumentCodeFragment CreateCodeFragment()\r
+        {\r
+            return (MixedCodeDocumentCodeFragment) CreateFragment(MixedCodeDocumentFragmentType.Code);\r
+        }\r
+\r
+        /// <summary>\r
+        /// Create a text fragment instances.\r
+        /// </summary>\r
+        /// <returns>The newly created text fragment instance.</returns>\r
+        public MixedCodeDocumentTextFragment CreateTextFragment()\r
+        {\r
+            return (MixedCodeDocumentTextFragment) CreateFragment(MixedCodeDocumentFragmentType.Text);\r
+        }\r
+\r
+        /// <summary>\r
+        /// Loads a mixed code document from a stream.\r
+        /// </summary>\r
+        /// <param name="stream">The input stream.</param>\r
+        public void Load(Stream stream)\r
+        {\r
+            Load(new StreamReader(stream));\r
+        }\r
+\r
+        /// <summary>\r
+        /// Loads a mixed code document from a stream.\r
+        /// </summary>\r
+        /// <param name="stream">The input stream.</param>\r
+        /// <param name="detectEncodingFromByteOrderMarks">Indicates whether to look for byte order marks at the beginning of the file.</param>\r
+        public void Load(Stream stream, bool detectEncodingFromByteOrderMarks)\r
+        {\r
+            Load(new StreamReader(stream, detectEncodingFromByteOrderMarks));\r
+        }\r
+\r
+        /// <summary>\r
+        /// Loads a mixed code document from a stream.\r
+        /// </summary>\r
+        /// <param name="stream">The input stream.</param>\r
+        /// <param name="encoding">The character encoding to use.</param>\r
+        public void Load(Stream stream, Encoding encoding)\r
+        {\r
+            Load(new StreamReader(stream, encoding));\r
+        }\r
+\r
+        /// <summary>\r
+        /// Loads a mixed code document from a stream.\r
+        /// </summary>\r
+        /// <param name="stream">The input stream.</param>\r
+        /// <param name="encoding">The character encoding to use.</param>\r
+        /// <param name="detectEncodingFromByteOrderMarks">Indicates whether to look for byte order marks at the beginning of the file.</param>\r
+        public void Load(Stream stream, Encoding encoding, bool detectEncodingFromByteOrderMarks)\r
+        {\r
+            Load(new StreamReader(stream, encoding, detectEncodingFromByteOrderMarks));\r
+        }\r
+\r
+        /// <summary>\r
+        /// Loads a mixed code document from a stream.\r
+        /// </summary>\r
+        /// <param name="stream">The input stream.</param>\r
+        /// <param name="encoding">The character encoding to use.</param>\r
+        /// <param name="detectEncodingFromByteOrderMarks">Indicates whether to look for byte order marks at the beginning of the file.</param>\r
+        /// <param name="buffersize">The minimum buffer size.</param>\r
+        public void Load(Stream stream, Encoding encoding, bool detectEncodingFromByteOrderMarks, int buffersize)\r
+        {\r
+            Load(new StreamReader(stream, encoding, detectEncodingFromByteOrderMarks, buffersize));\r
+        }\r
+\r
+        /// <summary>\r
+        /// Loads a mixed code document from a file.\r
+        /// </summary>\r
+        /// <param name="path">The complete file path to be read.</param>\r
+        public void Load(string path)\r
+        {\r
+            Load(new StreamReader(path));\r
+        }\r
+\r
+        /// <summary>\r
+        /// Loads a mixed code document from a file.\r
+        /// </summary>\r
+        /// <param name="path">The complete file path to be read.</param>\r
+        /// <param name="detectEncodingFromByteOrderMarks">Indicates whether to look for byte order marks at the beginning of the file.</param>\r
+        public void Load(string path, bool detectEncodingFromByteOrderMarks)\r
+        {\r
+            Load(new StreamReader(path, detectEncodingFromByteOrderMarks));\r
+        }\r
+\r
+        /// <summary>\r
+        /// Loads a mixed code document from a file.\r
+        /// </summary>\r
+        /// <param name="path">The complete file path to be read.</param>\r
+        /// <param name="encoding">The character encoding to use.</param>\r
+        public void Load(string path, Encoding encoding)\r
+        {\r
+            Load(new StreamReader(path, encoding));\r
+        }\r
+\r
+        /// <summary>\r
+        /// Loads a mixed code document from a file.\r
+        /// </summary>\r
+        /// <param name="path">The complete file path to be read.</param>\r
+        /// <param name="encoding">The character encoding to use.</param>\r
+        /// <param name="detectEncodingFromByteOrderMarks">Indicates whether to look for byte order marks at the beginning of the file.</param>\r
+        public void Load(string path, Encoding encoding, bool detectEncodingFromByteOrderMarks)\r
+        {\r
+            Load(new StreamReader(path, encoding, detectEncodingFromByteOrderMarks));\r
+        }\r
+\r
+        /// <summary>\r
+        /// Loads a mixed code document from a file.\r
+        /// </summary>\r
+        /// <param name="path">The complete file path to be read.</param>\r
+        /// <param name="encoding">The character encoding to use.</param>\r
+        /// <param name="detectEncodingFromByteOrderMarks">Indicates whether to look for byte order marks at the beginning of the file.</param>\r
+        /// <param name="buffersize">The minimum buffer size.</param>\r
+        public void Load(string path, Encoding encoding, bool detectEncodingFromByteOrderMarks, int buffersize)\r
+        {\r
+            Load(new StreamReader(path, encoding, detectEncodingFromByteOrderMarks, buffersize));\r
+        }\r
+\r
+        /// <summary>\r
+        /// Loads the mixed code document from the specified TextReader.\r
+        /// </summary>\r
+        /// <param name="reader">The TextReader used to feed the HTML data into the document.</param>\r
+        public void Load(TextReader reader)\r
+        {\r
+            _codefragments.Clear();\r
+            _textfragments.Clear();\r
+\r
+            // all pseudo constructors get down to this one\r
+            StreamReader sr = reader as StreamReader;\r
+            if (sr != null)\r
+            {\r
+                _streamencoding = sr.CurrentEncoding;\r
+            }\r
+\r
+            _text = reader.ReadToEnd();\r
+            reader.Close();\r
+            Parse();\r
+        }\r
+\r
+        /// <summary>\r
+        /// Loads a mixed document from a text\r
+        /// </summary>\r
+        /// <param name="html">The text to load.</param>\r
+        public void LoadHtml(string html)\r
+        {\r
+            Load(new StringReader(html));\r
+        }\r
+\r
+        /// <summary>\r
+        /// Saves the mixed document to the specified stream.\r
+        /// </summary>\r
+        /// <param name="outStream">The stream to which you want to save.</param>\r
+        public void Save(Stream outStream)\r
+        {\r
+            StreamWriter sw = new StreamWriter(outStream, GetOutEncoding());\r
+            Save(sw);\r
+        }\r
+\r
+        /// <summary>\r
+        /// Saves the mixed document to the specified stream.\r
+        /// </summary>\r
+        /// <param name="outStream">The stream to which you want to save.</param>\r
+        /// <param name="encoding">The character encoding to use.</param>\r
+        public void Save(Stream outStream, Encoding encoding)\r
+        {\r
+            StreamWriter sw = new StreamWriter(outStream, encoding);\r
+            Save(sw);\r
+        }\r
+\r
+        /// <summary>\r
+        /// Saves the mixed document to the specified file.\r
+        /// </summary>\r
+        /// <param name="filename">The location of the file where you want to save the document.</param>\r
+        public void Save(string filename)\r
+        {\r
+            StreamWriter sw = new StreamWriter(filename, false, GetOutEncoding());\r
+            Save(sw);\r
+        }\r
+\r
+        /// <summary>\r
+        /// Saves the mixed document to the specified file.\r
+        /// </summary>\r
+        /// <param name="filename">The location of the file where you want to save the document.</param>\r
+        /// <param name="encoding">The character encoding to use.</param>\r
+        public void Save(string filename, Encoding encoding)\r
+        {\r
+            StreamWriter sw = new StreamWriter(filename, false, encoding);\r
+            Save(sw);\r
+        }\r
+\r
+        /// <summary>\r
+        /// Saves the mixed document to the specified StreamWriter.\r
+        /// </summary>\r
+        /// <param name="writer">The StreamWriter to which you want to save.</param>\r
+        public void Save(StreamWriter writer)\r
+        {\r
+            Save((TextWriter) writer);\r
+        }\r
+\r
+        /// <summary>\r
+        /// Saves the mixed document to the specified TextWriter.\r
+        /// </summary>\r
+        /// <param name="writer">The TextWriter to which you want to save.</param>\r
+        public void Save(TextWriter writer)\r
+        {\r
+            writer.Flush();\r
+        }\r
+\r
+        #endregion\r
+\r
+        #region Internal Methods\r
+\r
+        internal MixedCodeDocumentFragment CreateFragment(MixedCodeDocumentFragmentType type)\r
+        {\r
+            switch (type)\r
+            {\r
+                case MixedCodeDocumentFragmentType.Text:\r
+                    return new MixedCodeDocumentTextFragment(this);\r
+\r
+                case MixedCodeDocumentFragmentType.Code:\r
+                    return new MixedCodeDocumentCodeFragment(this);\r
+\r
+                default:\r
+                    throw new NotSupportedException();\r
+            }\r
+        }\r
+\r
+        internal Encoding GetOutEncoding()\r
+        {\r
+            if (_streamencoding != null)\r
+                return _streamencoding;\r
+            return Encoding.Default;\r
+        }\r
+\r
+        #endregion\r
+\r
+        #region Private Methods\r
+\r
+        private void IncrementPosition()\r
+        {\r
+            _index++;\r
+            if (_c == 10)\r
+            {\r
+                _lineposition = 1;\r
+                _line++;\r
+            }\r
+            else\r
+                _lineposition++;\r
+        }\r
+\r
+        private void Parse()\r
+        {\r
+            _state = ParseState.Text;\r
+            _index = 0;\r
+            _currentfragment = CreateFragment(MixedCodeDocumentFragmentType.Text);\r
+\r
+            while (_index < _text.Length)\r
+            {\r
+                _c = _text[_index];\r
+                IncrementPosition();\r
+\r
+                switch (_state)\r
+                {\r
+                    case ParseState.Text:\r
+                        if (_index + TokenCodeStart.Length < _text.Length)\r
+                        {\r
+                            if (_text.Substring(_index - 1, TokenCodeStart.Length) == TokenCodeStart)\r
+                            {\r
+                                _state = ParseState.Code;\r
+                                _currentfragment.Length = _index - 1 - _currentfragment.Index;\r
+                                _currentfragment = CreateFragment(MixedCodeDocumentFragmentType.Code);\r
+                                SetPosition();\r
+                                continue;\r
+                            }\r
+                        }\r
+                        break;\r
+\r
+                    case ParseState.Code:\r
+                        if (_index + TokenCodeEnd.Length < _text.Length)\r
+                        {\r
+                            if (_text.Substring(_index - 1, TokenCodeEnd.Length) == TokenCodeEnd)\r
+                            {\r
+                                _state = ParseState.Text;\r
+                                _currentfragment.Length = _index + TokenCodeEnd.Length - _currentfragment.Index;\r
+                                _index += TokenCodeEnd.Length;\r
+                                _lineposition += TokenCodeEnd.Length;\r
+                                _currentfragment = CreateFragment(MixedCodeDocumentFragmentType.Text);\r
+                                SetPosition();\r
+                                continue;\r
+                            }\r
+                        }\r
+                        break;\r
+                }\r
+            }\r
+\r
+            _currentfragment.Length = _index - _currentfragment.Index;\r
+        }\r
+\r
+        private void SetPosition()\r
+        {\r
+            _currentfragment.Line = _line;\r
+            _currentfragment._lineposition = _lineposition;\r
+            _currentfragment.Index = _index - 1;\r
+            _currentfragment.Length = 0;\r
+        }\r
+\r
+        #endregion\r
+\r
+        #region Nested type: ParseState\r
+\r
+        private enum ParseState\r
+        {\r
+            Text,\r
+            Code\r
+        }\r
+\r
+        #endregion\r
+    }\r
+}
\ No newline at end of file
diff --git a/docs/HtmlAgilityPack/MixedCodeDocumentCodeFragment.cs b/docs/HtmlAgilityPack/MixedCodeDocumentCodeFragment.cs
new file mode 100644 (file)
index 0000000..f74b2f3
--- /dev/null
@@ -0,0 +1,51 @@
+// HtmlAgilityPack V1.0 - Simon Mourier <simon underscore mourier at hotmail dot com>\r
+namespace HtmlAgilityPack\r
+{\r
+    /// <summary>\r
+    /// Represents a fragment of code in a mixed code document.\r
+    /// </summary>\r
+    public class MixedCodeDocumentCodeFragment : MixedCodeDocumentFragment\r
+    {\r
+        #region Fields\r
+\r
+        private string _code;\r
+\r
+        #endregion\r
+\r
+        #region Constructors\r
+\r
+        internal MixedCodeDocumentCodeFragment(MixedCodeDocument doc)\r
+            :\r
+                base(doc, MixedCodeDocumentFragmentType.Code)\r
+        {\r
+        }\r
+\r
+        #endregion\r
+\r
+        #region Properties\r
+\r
+        /// <summary>\r
+        /// Gets the fragment code text.\r
+        /// </summary>\r
+        public string Code\r
+        {\r
+            get\r
+            {\r
+                if (_code == null)\r
+                {\r
+                    _code = FragmentText.Substring(Doc.TokenCodeStart.Length,\r
+                                                   FragmentText.Length - Doc.TokenCodeEnd.Length -\r
+                                                   Doc.TokenCodeStart.Length - 1).Trim();\r
+                    if (_code.StartsWith("="))\r
+                    {\r
+                        _code = Doc.TokenResponseWrite + _code.Substring(1, _code.Length - 1);\r
+                    }\r
+                }\r
+                return _code;\r
+            }\r
+            set { _code = value; }\r
+        }\r
+\r
+        #endregion\r
+    }\r
+}
\ No newline at end of file
diff --git a/docs/HtmlAgilityPack/MixedCodeDocumentFragment.cs b/docs/HtmlAgilityPack/MixedCodeDocumentFragment.cs
new file mode 100644 (file)
index 0000000..cfd268e
--- /dev/null
@@ -0,0 +1,95 @@
+// HtmlAgilityPack V1.0 - Simon Mourier <simon underscore mourier at hotmail dot com>\r
+namespace HtmlAgilityPack\r
+{\r
+    /// <summary>\r
+    /// Represents a base class for fragments in a mixed code document.\r
+    /// </summary>\r
+    public abstract class MixedCodeDocumentFragment\r
+    {\r
+        #region Fields\r
+\r
+        internal MixedCodeDocument Doc;\r
+        private string _fragmentText;\r
+        internal int Index;\r
+        internal int Length;\r
+        private int _line;\r
+        internal int _lineposition;\r
+        internal MixedCodeDocumentFragmentType _type;\r
+\r
+        #endregion\r
+\r
+        #region Constructors\r
+\r
+        internal MixedCodeDocumentFragment(MixedCodeDocument doc, MixedCodeDocumentFragmentType type)\r
+        {\r
+            Doc = doc;\r
+            _type = type;\r
+            switch (type)\r
+            {\r
+                case MixedCodeDocumentFragmentType.Text:\r
+                    Doc._textfragments.Append(this);\r
+                    break;\r
+\r
+                case MixedCodeDocumentFragmentType.Code:\r
+                    Doc._codefragments.Append(this);\r
+                    break;\r
+            }\r
+            Doc._fragments.Append(this);\r
+        }\r
+\r
+        #endregion\r
+\r
+        #region Properties\r
+\r
+        /// <summary>\r
+        /// Gets the fragement text.\r
+        /// </summary>\r
+        public string FragmentText\r
+        {\r
+            get\r
+            {\r
+                if (_fragmentText == null)\r
+                {\r
+                    _fragmentText = Doc._text.Substring(Index, Length);\r
+                }\r
+                return FragmentText;\r
+            }\r
+            internal set { _fragmentText = value; }\r
+        }\r
+\r
+        /// <summary>\r
+        /// Gets the type of fragment.\r
+        /// </summary>\r
+        public MixedCodeDocumentFragmentType FragmentType\r
+        {\r
+            get { return _type; }\r
+        }\r
+\r
+        /// <summary>\r
+        /// Gets the line number of the fragment.\r
+        /// </summary>\r
+        public int Line\r
+        {\r
+            get { return _line; }\r
+            internal set { _line = value; }\r
+        }\r
+\r
+        /// <summary>\r
+        /// Gets the line position (column) of the fragment.\r
+        /// </summary>\r
+        public int LinePosition\r
+        {\r
+            get { return _lineposition; }\r
+        }\r
+\r
+        /// <summary>\r
+        /// Gets the fragment position in the document's stream.\r
+        /// </summary>\r
+        public int StreamPosition\r
+        {\r
+            get { return Index; }\r
+        }\r
+\r
+        #endregion\r
+    }\r
+}
\ No newline at end of file
diff --git a/docs/HtmlAgilityPack/MixedCodeDocumentFragmentList.cs b/docs/HtmlAgilityPack/MixedCodeDocumentFragmentList.cs
new file mode 100644 (file)
index 0000000..4a4a41a
--- /dev/null
@@ -0,0 +1,236 @@
+// HtmlAgilityPack V1.0 - Simon Mourier <simon underscore mourier at hotmail dot com>\r
+using System;\r
+using System.Collections;\r
+\r
+namespace HtmlAgilityPack\r
+{\r
+    /// <summary>\r
+    /// Represents a list of mixed code fragments.\r
+    /// </summary>\r
+    public class MixedCodeDocumentFragmentList : IEnumerable\r
+    {\r
+        #region Fields\r
+\r
+        private MixedCodeDocument _doc;\r
+        private ArrayList _items = new ArrayList();\r
+\r
+        #endregion\r
+\r
+        #region Constructors\r
+\r
+        internal MixedCodeDocumentFragmentList(MixedCodeDocument doc)\r
+        {\r
+            _doc = doc;\r
+        }\r
+\r
+        #endregion\r
+\r
+        #region Properties\r
+\r
+        ///<summary>\r
+        /// Gets the Document\r
+        ///</summary>\r
+        public MixedCodeDocument Doc\r
+        {\r
+            get { return _doc; }\r
+        }\r
+\r
+        /// <summary>\r
+        /// Gets the number of fragments contained in the list.\r
+        /// </summary>\r
+        public int Count\r
+        {\r
+            get { return _items.Count; }\r
+        }\r
+\r
+        /// <summary>\r
+        /// Gets a fragment from the list using its index.\r
+        /// </summary>\r
+        public MixedCodeDocumentFragment this[int index]\r
+        {\r
+            get { return _items[index] as MixedCodeDocumentFragment; }\r
+        }\r
+\r
+        #endregion\r
+\r
+        #region IEnumerable Members\r
+\r
+        /// <summary>\r
+        /// Gets an enumerator that can iterate through the fragment list.\r
+        /// </summary>\r
+        IEnumerator IEnumerable.GetEnumerator()\r
+        {\r
+            return GetEnumerator();\r
+        }\r
+\r
+        #endregion\r
+\r
+        #region Public Methods\r
+\r
+        /// <summary>\r
+        /// Appends a fragment to the list of fragments.\r
+        /// </summary>\r
+        /// <param name="newFragment">The fragment to append. May not be null.</param>\r
+        public void Append(MixedCodeDocumentFragment newFragment)\r
+        {\r
+            if (newFragment == null)\r
+            {\r
+                throw new ArgumentNullException("newFragment");\r
+            }\r
+            _items.Add(newFragment);\r
+        }\r
+\r
+        /// <summary>\r
+        /// Gets an enumerator that can iterate through the fragment list.\r
+        /// </summary>\r
+        public MixedCodeDocumentFragmentEnumerator GetEnumerator()\r
+        {\r
+            return new MixedCodeDocumentFragmentEnumerator(_items);\r
+        }\r
+\r
+        /// <summary>\r
+        /// Prepends a fragment to the list of fragments.\r
+        /// </summary>\r
+        /// <param name="newFragment">The fragment to append. May not be null.</param>\r
+        public void Prepend(MixedCodeDocumentFragment newFragment)\r
+        {\r
+            if (newFragment == null)\r
+            {\r
+                throw new ArgumentNullException("newFragment");\r
+            }\r
+            _items.Insert(0, newFragment);\r
+        }\r
+\r
+        /// <summary>\r
+        /// Remove a fragment from the list of fragments. If this fragment was not in the list, an exception will be raised.\r
+        /// </summary>\r
+        /// <param name="fragment">The fragment to remove. May not be null.</param>\r
+        public void Remove(MixedCodeDocumentFragment fragment)\r
+        {\r
+            if (fragment == null)\r
+            {\r
+                throw new ArgumentNullException("fragment");\r
+            }\r
+            int index = GetFragmentIndex(fragment);\r
+            if (index == -1)\r
+            {\r
+                throw new IndexOutOfRangeException();\r
+            }\r
+            RemoveAt(index);\r
+        }\r
+\r
+        /// <summary>\r
+        /// Remove all fragments from the list.\r
+        /// </summary>\r
+        public void RemoveAll()\r
+        {\r
+            _items.Clear();\r
+        }\r
+\r
+        /// <summary>\r
+        /// Remove a fragment from the list of fragments, using its index in the list.\r
+        /// </summary>\r
+        /// <param name="index">The index of the fragment to remove.</param>\r
+        public void RemoveAt(int index)\r
+        {\r
+            //MixedCodeDocumentFragment frag = (MixedCodeDocumentFragment) _items[index];\r
+            _items.RemoveAt(index);\r
+        }\r
+\r
+        #endregion\r
+\r
+        #region Internal Methods\r
+\r
+        internal void Clear()\r
+        {\r
+            _items.Clear();\r
+        }\r
+\r
+        internal int GetFragmentIndex(MixedCodeDocumentFragment fragment)\r
+        {\r
+            if (fragment == null)\r
+            {\r
+                throw new ArgumentNullException("fragment");\r
+            }\r
+            for (int i = 0; i < _items.Count; i++)\r
+            {\r
+                if ((_items[i]) == fragment)\r
+                {\r
+                    return i;\r
+                }\r
+            }\r
+            return -1;\r
+        }\r
+\r
+        #endregion\r
+\r
+        #region Nested type: MixedCodeDocumentFragmentEnumerator\r
+\r
+        /// <summary>\r
+        /// Represents a fragment enumerator.\r
+        /// </summary>\r
+        public class MixedCodeDocumentFragmentEnumerator : IEnumerator\r
+        {\r
+            #region Fields\r
+\r
+            private int _index;\r
+            private ArrayList _items;\r
+\r
+            #endregion\r
+\r
+            #region Constructors\r
+\r
+            internal MixedCodeDocumentFragmentEnumerator(ArrayList items)\r
+            {\r
+                _items = items;\r
+                _index = -1;\r
+            }\r
+\r
+            #endregion\r
+\r
+            #region Properties\r
+\r
+            /// <summary>\r
+            /// Gets the current element in the collection.\r
+            /// </summary>\r
+            public MixedCodeDocumentFragment Current\r
+            {\r
+                get { return (MixedCodeDocumentFragment) (_items[_index]); }\r
+            }\r
+\r
+            #endregion\r
+\r
+            #region IEnumerator Members\r
+\r
+            /// <summary>\r
+            /// Gets the current element in the collection.\r
+            /// </summary>\r
+            object IEnumerator.Current\r
+            {\r
+                get { return (Current); }\r
+            }\r
+\r
+            /// <summary>\r
+            /// Advances the enumerator to the next element of the collection.\r
+            /// </summary>\r
+            /// <returns>true if the enumerator was successfully advanced to the next element; false if the enumerator has passed the end of the collection.</returns>\r
+            public bool MoveNext()\r
+            {\r
+                _index++;\r
+                return (_index < _items.Count);\r
+            }\r
+\r
+            /// <summary>\r
+            /// Sets the enumerator to its initial position, which is before the first element in the collection.\r
+            /// </summary>\r
+            public void Reset()\r
+            {\r
+                _index = -1;\r
+            }\r
+\r
+            #endregion\r
+        }\r
+\r
+        #endregion\r
+    }\r
+}
\ No newline at end of file
diff --git a/docs/HtmlAgilityPack/MixedCodeDocumentFragmentType.cs b/docs/HtmlAgilityPack/MixedCodeDocumentFragmentType.cs
new file mode 100644 (file)
index 0000000..28ca542
--- /dev/null
@@ -0,0 +1,19 @@
+// HtmlAgilityPack V1.0 - Simon Mourier <simon underscore mourier at hotmail dot com>\r
+namespace HtmlAgilityPack\r
+{\r
+    /// <summary>\r
+    /// Represents the type of fragment in a mixed code document.\r
+    /// </summary>\r
+    public enum MixedCodeDocumentFragmentType\r
+    {\r
+        /// <summary>\r
+        /// The fragment contains code.\r
+        /// </summary>\r
+        Code,\r
+\r
+        /// <summary>\r
+        /// The fragment contains text.\r
+        /// </summary>\r
+        Text,\r
+    }\r
+}
\ No newline at end of file
diff --git a/docs/HtmlAgilityPack/MixedCodeDocumentTextFragment.cs b/docs/HtmlAgilityPack/MixedCodeDocumentTextFragment.cs
new file mode 100644 (file)
index 0000000..8aa3cdd
--- /dev/null
@@ -0,0 +1,32 @@
+// HtmlAgilityPack V1.0 - Simon Mourier <simon underscore mourier at hotmail dot com>\r
+namespace HtmlAgilityPack\r
+{\r
+    /// <summary>\r
+    /// Represents a fragment of text in a mixed code document.\r
+    /// </summary>\r
+    public class MixedCodeDocumentTextFragment : MixedCodeDocumentFragment\r
+    {\r
+        #region Constructors\r
+\r
+        internal MixedCodeDocumentTextFragment(MixedCodeDocument doc)\r
+            :\r
+                base(doc, MixedCodeDocumentFragmentType.Text)\r
+        {\r
+        }\r
+\r
+        #endregion\r
+\r
+        #region Properties\r
+\r
+        /// <summary>\r
+        /// Gets the fragment text.\r
+        /// </summary>\r
+        public string Text\r
+        {\r
+            get { return FragmentText; }\r
+            set { FragmentText = value; }\r
+        }\r
+\r
+        #endregion\r
+    }\r
+}
\ No newline at end of file
diff --git a/docs/HtmlAgilityPack/NameValuePair.cs b/docs/HtmlAgilityPack/NameValuePair.cs
new file mode 100644 (file)
index 0000000..8b70363
--- /dev/null
@@ -0,0 +1,35 @@
+// HtmlAgilityPack V1.0 - Simon Mourier <simon underscore mourier at hotmail dot com>\r
+namespace HtmlAgilityPack\r
+{\r
+    internal class NameValuePair\r
+    {\r
+        #region Fields\r
+\r
+        internal readonly string Name;\r
+        internal string Value;\r
+\r
+        #endregion\r
+\r
+        #region Constructors\r
+\r
+        internal NameValuePair()\r
+        {\r
+        }\r
+\r
+        internal NameValuePair(string name)\r
+            :\r
+                this()\r
+        {\r
+            Name = name;\r
+        }\r
+\r
+        internal NameValuePair(string name, string value)\r
+            :\r
+                this(name)\r
+        {\r
+            Value = value;\r
+        }\r
+\r
+        #endregion\r
+    }\r
+}
\ No newline at end of file
diff --git a/docs/HtmlAgilityPack/NameValuePairList.cs b/docs/HtmlAgilityPack/NameValuePairList.cs
new file mode 100644 (file)
index 0000000..f4776e9
--- /dev/null
@@ -0,0 +1,101 @@
+// HtmlAgilityPack V1.0 - Simon Mourier <simon underscore mourier at hotmail dot com>\r
+using System;\r
+using System.Collections;\r
+\r
+namespace HtmlAgilityPack\r
+{\r
+    internal class NameValuePairList\r
+    {\r
+        #region Fields\r
+\r
+        internal readonly string Text;\r
+        private ArrayList _allPairs;\r
+        private Hashtable _pairsWithName;\r
+\r
+        #endregion\r
+\r
+        #region Constructors\r
+\r
+        internal NameValuePairList() :\r
+            this(null)\r
+        {\r
+        }\r
+\r
+        internal NameValuePairList(string text)\r
+        {\r
+            Text = text;\r
+            _allPairs = new ArrayList();\r
+            _pairsWithName = new Hashtable();\r
+\r
+            Parse(text);\r
+        }\r
+\r
+        #endregion\r
+\r
+        #region Internal Methods\r
+\r
+        internal static string GetNameValuePairsValue(string text, string name)\r
+        {\r
+            NameValuePairList l = new NameValuePairList(text);\r
+            return l.GetNameValuePairValue(name);\r
+        }\r
+\r
+        internal ArrayList GetNameValuePairs(string name)\r
+        {\r
+            if (name == null)\r
+                return _allPairs;\r
+            return _pairsWithName[name] as ArrayList;\r
+        }\r
+\r
+        internal string GetNameValuePairValue(string name)\r
+        {\r
+            if (name == null)\r
+                throw new ArgumentNullException();\r
+            ArrayList al = GetNameValuePairs(name);\r
+            if (al == null)\r
+                return null;\r
+\r
+            // return first item\r
+            NameValuePair nvp = al[0] as NameValuePair;\r
+            return nvp != null ? nvp.Value : string.Empty;\r
+        }\r
+\r
+        #endregion\r
+\r
+        #region Private Methods\r
+\r
+        private void Parse(string text)\r
+        {\r
+            _allPairs.Clear();\r
+            _pairsWithName.Clear();\r
+            if (text == null)\r
+                return;\r
+\r
+            string[] p = text.Split(';');\r
+            foreach (string pv in p)\r
+            {\r
+                if (pv.Length == 0)\r
+                    continue;\r
+                string[] onep = pv.Split(new char[] {'='}, 2);\r
+                if (onep.Length==0)\r
+                    continue;\r
+                NameValuePair nvp = new NameValuePair(onep[0].Trim().ToLower());\r
+\r
+                nvp.Value = onep.Length < 2 ? "" : onep[1];\r
+\r
+                _allPairs.Add(nvp);\r
+\r
+                // index by name\r
+                ArrayList al = _pairsWithName[nvp.Name] as ArrayList;\r
+                if (al == null)\r
+                {\r
+                    al = new ArrayList();\r
+                    _pairsWithName[nvp.Name] = al;\r
+                }\r
+                al.Add(nvp);\r
+            }\r
+        }\r
+\r
+        #endregion\r
+    }\r
+}
\ No newline at end of file
diff --git a/docs/HtmlAgilityPack/crc32.cs b/docs/HtmlAgilityPack/crc32.cs
new file mode 100644 (file)
index 0000000..4cc627b
--- /dev/null
@@ -0,0 +1,156 @@
+// HtmlAgilityPack V1.0 - Simon Mourier <simon underscore mourier at hotmail dot com>\r
+namespace HtmlAgilityPack\r
+{\r
+    /// <summary>\r
+    /// A utility class to compute CRC32.\r
+    /// </summary>\r
+    public class Crc32\r
+    {\r
+        #region Fields\r
+\r
+        private uint _crc32;\r
+\r
+        #endregion\r
+\r
+        #region Static Members\r
+\r
+        private static uint[] crc_32_tab = // CRC polynomial 0xedb88320 \r
+            {\r
+                0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f,\r
+                0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,\r
+                0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2,\r
+                0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,\r
+                0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9,\r
+                0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,\r
+                0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c,\r
+                0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,\r
+                0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423,\r
+                0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,\r
+                0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106,\r
+                0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,\r
+                0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d,\r
+                0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,\r
+                0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950,\r
+                0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,\r
+                0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7,\r
+                0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,\r
+                0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa,\r
+                0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,\r
+                0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81,\r
+                0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,\r
+                0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84,\r
+                0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,\r
+                0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb,\r
+                0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,\r
+                0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e,\r
+                0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,\r
+                0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55,\r
+                0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,\r
+                0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28,\r
+                0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,\r
+                0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f,\r
+                0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,\r
+                0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242,\r
+                0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,\r
+                0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69,\r
+                0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,\r
+                0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc,\r
+                0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,\r
+                0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693,\r
+                0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,\r
+                0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d\r
+            };\r
+\r
+        #endregion\r
+\r
+        #region Properties\r
+\r
+        internal uint CheckSum\r
+        {\r
+            get { return _crc32; }\r
+            set { _crc32 = value; }\r
+        }\r
+\r
+        #endregion\r
+\r
+        #region Public Methods\r
+\r
+        /// <summary>\r
+        /// Compute a checksum for a given array of bytes.\r
+        /// </summary>\r
+        /// <param name="bytes">The array of bytes to compute the checksum for.</param>\r
+        /// <returns>The computed checksum.</returns>\r
+        public static uint CRC32Bytes(byte[] bytes)\r
+        {\r
+            uint oldcrc32;\r
+            oldcrc32 = 0xFFFFFFFF;\r
+            int len = bytes.Length;\r
+\r
+            for (int i = 0; len > 0; i++)\r
+            {\r
+                --len;\r
+                oldcrc32 = UPDC32(bytes[len], oldcrc32);\r
+            }\r
+            return ~oldcrc32;\r
+        }\r
+\r
+        /// <summary>\r
+        /// Compute a checksum for a given string.\r
+        /// </summary>\r
+        /// <param name="text">The string to compute the checksum for.</param>\r
+        /// <returns>The computed checksum.</returns>\r
+        public static uint CRC32String(string text)\r
+        {\r
+            uint oldcrc32;\r
+            oldcrc32 = 0xFFFFFFFF;\r
+            int len = text.Length;\r
+            ushort uCharVal;\r
+            byte lowByte, hiByte;\r
+\r
+            for (int i = 0; len > 0; i++)\r
+            {\r
+                --len;\r
+                uCharVal = text[len];\r
+                unchecked\r
+                {\r
+                    lowByte = (byte) (uCharVal & 0x00ff);\r
+                    hiByte = (byte) (uCharVal >> 8);\r
+                }\r
+                oldcrc32 = UPDC32(hiByte, oldcrc32);\r
+                oldcrc32 = UPDC32(lowByte, oldcrc32);\r
+            }\r
+\r
+            return ~oldcrc32;\r
+        }\r
+\r
+        #endregion\r
+\r
+        #region Internal Methods\r
+\r
+        internal uint AddToCRC32(int c)\r
+        {\r
+            return AddToCRC32((ushort) c);\r
+        }\r
+\r
+        internal uint AddToCRC32(ushort c)\r
+        {\r
+            byte lowByte, hiByte;\r
+            lowByte = (byte) (c & 0x00ff);\r
+            hiByte = (byte) (c >> 8);\r
+            _crc32 = UPDC32(hiByte, _crc32);\r
+            _crc32 = UPDC32(lowByte, _crc32);\r
+            return ~_crc32;\r
+        }\r
+\r
+        #endregion\r
+\r
+        #region Private Methods\r
+\r
+        private static uint UPDC32(byte octet, uint crc)\r
+        {\r
+            return (crc_32_tab[((crc) ^ (octet)) & 0xff] ^ ((crc) >> 8));\r
+        }\r
+\r
+        #endregion\r
+    }\r
+}
\ No newline at end of file
index db1e65aabebce9e73eee0a051c974745c57b7e1b..639b7537d26de211d12c295fbbdfc96af5a39398 100644 (file)
@@ -13,7 +13,6 @@ ASSEMBLED_DOCS = \
 
 EXTRA_DIST = \
        abc-removal.txt         \
-       AgilityPack.dll         \
        api-style.css           \
        assembly-bundle         \
        check-exports           \
@@ -68,12 +67,14 @@ EXTRA_DIST = \
 dist-hook:
        $(mkdir_p)  $(distdir)/sources
        $(mkdir_p)  $(distdir)/svgs
+       $(mkdir_p)  $(distdir)/HtmlAgilityPack
        cp sources/*  $(distdir)/sources
        cp svgs/*     $(distdir)/svgs
+       cp HtmlAgilityPack/*     $(distdir)/HtmlAgilityPack
 
 clean-local:
        -rm -Rf $(srcdir)/html
-       -rm -f $(srcdir)/deploy/* $(srcdir)/convert.exe*
+       -rm -f $(srcdir)/deploy/* $(srcdir)/convert.exe* $(srcdir)/AgilityPack.dll*
        -cd $(srcdir) && rm -f $(ASSEMBLED_DOCS)
 
 monoapi.zip: monoapi.tree
@@ -103,3 +104,5 @@ extract: $(srcdir)/deploy/.stamp
 convert.exe: convert.cs AgilityPack.dll
        cd $(srcdir) && $(MAKE) PROFILE=net_2_0 -f docs.make topdir=$(mcs_topdir_from_srcdir) convert.exe
 
+AgilityPack.dll:
+       cd $(srcdir) && $(MAKE) PROFILE=net_2_0 -f docs.make topdir=$(mcs_topdir_from_srcdir) AgilityPack.dll
index 956c1550bf81a7fe92122845cfc364e258756958..862cd45ae0aeca528d829b040abbc93988e42d37 100644 (file)
@@ -64,10 +64,8 @@ PROGRAMS
 * convert.cs
 
        Converts an HTML file into a valid XML document, uses the
-       AgilityPack.dll.  The sources to this DLL live in GNOME CVS
-       module beagle/Filters/AgilityPack.
-
-       A binary is shipped for our convenience.
+       AgilityPack.dll.  The sources to this DLL live in the 
+        HtmlAgilityPack folder, and are a prerequisite for convert.exe.
 
 DATAFILES:
 ---------
index 50a001f5f29addfbd64ab8b9ffdb023a1bd56e66..7129bcadfc47a43ddae2a8a8209bf3bf9c8d2d9e 100644 (file)
@@ -10,6 +10,9 @@ ASSEMBLED_DOCS = \
 convert.exe: convert.cs AgilityPack.dll
        $(CSCOMPILE) -out:$@ $< -r:AgilityPack.dll
 
+AgilityPack.dll:
+       $(CSCOMPILE) -target:library -out:$@ HtmlAgilityPack/*.cs
+
 monoapi.zip: monoapi.tree
        @test -f $@ || { rm -f $< && $(MAKE) $<; }
 monoapi.tree: toc.xml docs.make