-// -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-\r
-//\r
-// System.Xml.XmlTextReader.cs\r
-//\r
-// Author:\r
-// Jason Diamond (jason@injektilo.org)\r
-//\r
-// (C) 2001 Jason Diamond http://injektilo.org/\r
-//\r
-\r
-// FIXME:\r
-// This can only parse basic XML: elements, attributes, processing\r
-// instructions, and comments are OK but there's no support for\r
-// entity/character references or namespaces yet.\r
-//\r
-// It barfs on DOCTYPE declarations and CDATA sections.\r
-//\r
-// There's also no checking being done for either well-formedness\r
-// or validity.\r
-//\r
-// ParserContext and NameTables aren't being used yet.\r
-//\r
-// The XmlTextReader-specific properties and methods have yet to\r
-// be added or implemented.\r
-//\r
-// Some thought needs to be given to performance. There's too many\r
-// strings and string builders being allocated.\r
-//\r
-// None of the MoveTo methods have been implemented yet.\r
-//\r
-// LineNumber and LinePosition aren't being tracked.\r
-//\r
-// xml:space, xml:lang, and xml:base aren't being tracked.\r
-//\r
-// Depth isn't being tracked.\r
-\r
-using System;\r
-using System.Collections;\r
-using System.IO;\r
-using System.Net;\r
-using System.Text;\r
-\r
-namespace System.Xml\r
-{\r
- public class XmlTextReader : XmlReader\r
- {\r
- // constructors\r
-\r
- protected XmlTextReader()\r
- {\r
- Init();\r
- }\r
-\r
- public XmlTextReader(Stream input)\r
- {\r
- Init();\r
- reader = new StreamReader(\r
- input,\r
- Encoding.UTF8,\r
- true);\r
- }\r
-\r
- public XmlTextReader(string url)\r
- {\r
- Init();\r
- WebClient client = new WebClient();\r
- reader = new StreamReader(\r
- client.OpenRead(url),\r
- Encoding.UTF8,\r
- true);\r
- }\r
-\r
- public XmlTextReader(TextReader input)\r
- {\r
- Init();\r
- reader = input;\r
- }\r
-\r
- public XmlTextReader(Stream input, XmlNameTable nameTable)\r
- {\r
- // TODO: implement me.\r
- throw new NotImplementedException();\r
- }\r
-\r
- public XmlTextReader(string baseURI, Stream input)\r
- {\r
- // TODO: implement me.\r
- throw new NotImplementedException();\r
- }\r
-\r
- public XmlTextReader(string baseURI, TextReader input)\r
- {\r
- // TODO: implement me.\r
- throw new NotImplementedException();\r
- }\r
-\r
- public XmlTextReader(string url, XmlNameTable nameTable)\r
- {\r
- // TODO: implement me.\r
- throw new NotImplementedException();\r
- }\r
-\r
- public XmlTextReader(\r
- TextReader input,\r
- XmlNameTable nameTable)\r
- {\r
- // TODO: implement me.\r
- throw new NotImplementedException();\r
- }\r
-\r
- public XmlTextReader(\r
- Stream inputFragment,\r
- XmlNodeType fragmentType,\r
- XmlParserContext context)\r
- {\r
- // TODO: implement me.\r
- throw new NotImplementedException();\r
- }\r
-\r
- public XmlTextReader(\r
- string baseURI,\r
- Stream input,\r
- XmlNameTable nameTable)\r
- {\r
- // TODO: implement me.\r
- throw new NotImplementedException();\r
- }\r
-\r
- public XmlTextReader(\r
- string baseURI,\r
- TextReader input,\r
- XmlNameTable nameTable)\r
- {\r
- // TODO: implement me.\r
- throw new NotImplementedException();\r
- }\r
-\r
- public XmlTextReader(\r
- string fragment,\r
- XmlNodeType fragmentType,\r
- XmlParserContext context)\r
- {\r
- // TODO: implement me.\r
- throw new NotImplementedException();\r
- }\r
-\r
- // properties\r
-\r
- public override int AttributeCount\r
- {\r
- get\r
- {\r
- return attributes.Count;\r
- }\r
- }\r
-\r
- public override string BaseURI\r
- {\r
- get\r
- {\r
- // TODO: implement me.\r
- return null;\r
- }\r
- }\r
-\r
- public override bool CanResolveEntity\r
- {\r
- get\r
- {\r
- // TODO: implement me.\r
- return false;\r
- }\r
- }\r
-\r
- public override int Depth\r
- {\r
- get\r
- {\r
- // TODO: implement me.\r
- return 0;\r
- }\r
- }\r
-\r
- public override bool EOF\r
- {\r
- get\r
- {\r
- return\r
- readState == ReadState.EndOfFile ||\r
- readState == ReadState.Closed;\r
- }\r
- }\r
-\r
- public override bool HasValue\r
- {\r
- get\r
- {\r
- return value != String.Empty;\r
- }\r
- }\r
-\r
- public override bool IsDefault\r
- {\r
- get\r
- {\r
- // TODO: implement me.\r
- return false;\r
- }\r
- }\r
-\r
- public override bool IsEmptyElement\r
- {\r
- get\r
- {\r
- return isEmptyElement;\r
- }\r
- }\r
-\r
- public override string this[int i]\r
- {\r
- get\r
- {\r
- return GetAttribute(i);\r
- }\r
- }\r
-\r
- public override string this[string name]\r
- {\r
- get\r
- {\r
- return GetAttribute(name);\r
- }\r
- }\r
-\r
- public override string this[\r
- string localName,\r
- string namespaceName]\r
- {\r
- get\r
- {\r
- return GetAttribute(localName, namespaceName);\r
- }\r
- }\r
-\r
- public override string LocalName\r
- {\r
- get\r
- {\r
- // TODO: implement me.\r
- return null;\r
- }\r
- }\r
-\r
- public override string Name\r
- {\r
- get\r
- {\r
- return name;\r
- }\r
- }\r
-\r
- public override string NamespaceURI\r
- {\r
- get\r
- {\r
- // TODO: implement me.\r
- return null;\r
- }\r
- }\r
-\r
- public override XmlNameTable NameTable\r
- {\r
- get\r
- {\r
- // TODO: implement me.\r
- return null;\r
- }\r
- }\r
-\r
- public override XmlNodeType NodeType\r
- {\r
- get\r
- {\r
- return nodeType;\r
- }\r
- }\r
-\r
- public override string Prefix\r
- {\r
- get\r
- {\r
- // TODO: implement me.\r
- return null;\r
- }\r
- }\r
-\r
- public override char QuoteChar\r
- {\r
- get\r
- {\r
- // TODO: implement me.\r
- return '"';\r
- }\r
- }\r
-\r
- public override ReadState ReadState\r
- {\r
- get\r
- {\r
- return readState;\r
- }\r
- }\r
-\r
- public override string Value\r
- {\r
- get\r
- {\r
- return value;\r
- }\r
- }\r
-\r
- public override string XmlLang\r
- {\r
- get\r
- {\r
- // TODO: implement me.\r
- return null;\r
- }\r
- }\r
-\r
- public override XmlSpace XmlSpace\r
- {\r
- get\r
- {\r
- // TODO: implement me.\r
- return XmlSpace.Default;\r
- }\r
- }\r
-\r
- // methods\r
-\r
- public override void Close()\r
- {\r
- readState = ReadState.Closed;\r
- }\r
-\r
- public override string GetAttribute(int i)\r
- {\r
- // TODO: implement me.\r
- return null;\r
- }\r
-\r
- public override string GetAttribute(string name)\r
- {\r
- return (string)attributes[name];\r
- }\r
-\r
- public override string GetAttribute(\r
- string localName,\r
- string namespaceName)\r
- {\r
- // TODO: implement me.\r
- return null;\r
- }\r
-\r
- public override string LookupNamespace(string prefix)\r
- {\r
- // TODO: implement me.\r
- return null;\r
- }\r
-\r
- public override void MoveToAttribute(int i)\r
- {\r
- // TODO: implement me.\r
- }\r
-\r
- public override bool MoveToAttribute(string name)\r
- {\r
- // TODO: implement me.\r
- return false;\r
- }\r
-\r
- public override bool MoveToAttribute(\r
- string localName,\r
- string namespaceName)\r
- {\r
- // TODO: implement me.\r
- return false;\r
- }\r
-\r
- public override bool MoveToElement()\r
- {\r
- // TODO: implement me.\r
- return false;\r
- }\r
-\r
- public override bool MoveToFirstAttribute()\r
- {\r
- // TODO: implement me.\r
- return false;\r
- }\r
-\r
- public override bool MoveToNextAttribute()\r
- {\r
- // TODO: implement me.\r
- return false;\r
- }\r
-\r
- public override bool Read()\r
- {\r
- bool more = false;\r
-\r
- readState = ReadState.Interactive;\r
-\r
- more = ReadContent();\r
-\r
- return more;\r
- }\r
-\r
- public override bool ReadAttributeValue()\r
- {\r
- // TODO: implement me.\r
- return false;\r
- }\r
-\r
- public override string ReadInnerXml()\r
- {\r
- // TODO: implement me.\r
- return null;\r
- }\r
-\r
- public override string ReadOuterXml()\r
- {\r
- // TODO: implement me.\r
- return null;\r
- }\r
-\r
- public override string ReadString()\r
- {\r
- // TODO: implement me.\r
- return null;\r
- }\r
-\r
- public override void ResolveEntity()\r
- {\r
- // TODO: implement me.\r
- }\r
-\r
- // privates\r
-\r
- private TextReader reader;\r
- private ReadState readState;\r
-\r
- private XmlNodeType nodeType;\r
- private string name;\r
- private bool isEmptyElement;\r
- private string value;\r
- private Hashtable attributes;\r
-\r
- private void Init()\r
- {\r
- readState = ReadState.Initial;\r
-\r
- nodeType = XmlNodeType.None;\r
- name = String.Empty;\r
- isEmptyElement = false;\r
- value = String.Empty;\r
- attributes = new Hashtable();\r
- }\r
-\r
- // Use this method rather than setting the properties\r
- // directly so that all the necessary properties can\r
- // be changed in harmony with each other. Maybe the\r
- // fields should be in a seperate class to help enforce\r
- // this.\r
- private void SetProperties(\r
- XmlNodeType nodeType,\r
- string name,\r
- bool isEmptyElement,\r
- string value,\r
- bool clearAttributes)\r
- {\r
- this.nodeType = nodeType;\r
- this.name = name;\r
- this.isEmptyElement = isEmptyElement;\r
- this.value = value;\r
-\r
- if (clearAttributes)\r
- {\r
- ClearAttributes();\r
- }\r
- }\r
-\r
- private void AddAttribute(string name, string value)\r
- {\r
- attributes.Add(name, value);\r
- }\r
-\r
- private void ClearAttributes()\r
- {\r
- attributes.Clear();\r
- }\r
-\r
- // This should really keep track of some state so\r
- // that it's not possible to have more than one document\r
- // element or text outside of the document element.\r
- private bool ReadContent()\r
- {\r
- bool more = false;\r
-\r
- switch (reader.Peek())\r
- {\r
- case '<':\r
- reader.Read();\r
- ReadTag();\r
- more = true;\r
- break;\r
- case -1:\r
- readState = ReadState.EndOfFile;\r
- SetProperties(\r
- XmlNodeType.None, // nodeType\r
- String.Empty, // name\r
- false, // isEmptyElement\r
- String.Empty, // value\r
- true // clearAttributes\r
- );\r
- more = false;\r
- break;\r
- default:\r
- ReadText();\r
- more = true;\r
- break;\r
- }\r
-\r
- return more;\r
- }\r
-\r
- // The leading '<' has already been consumed.\r
- private void ReadTag()\r
- {\r
- switch (reader.Peek())\r
- {\r
- case '/':\r
- reader.Read();\r
- ReadEndTag();\r
- break;\r
- case '?':\r
- reader.Read();\r
- ReadProcessingInstruction();\r
- break;\r
- case '!':\r
- reader.Read();\r
- ReadComment();\r
- break;\r
- default:\r
- ReadStartTag();\r
- break;\r
- }\r
- }\r
-\r
- // The leading '<' has already been consumed.\r
- private void ReadStartTag()\r
- {\r
- string name = ReadName();\r
- SkipWhitespace();\r
-\r
- bool isEmptyElement = false;\r
-\r
- ClearAttributes();\r
-\r
- if (XmlChar.IsFirstNameChar(reader.Peek()))\r
- {\r
- ReadAttributes();\r
- }\r
-\r
- if (reader.Peek() == '/')\r
- {\r
- reader.Read();\r
- isEmptyElement = true;\r
- }\r
-\r
- Expect('>');\r
-\r
- SetProperties(\r
- XmlNodeType.Element, // nodeType\r
- name, // name\r
- isEmptyElement, // isEmptyElement\r
- String.Empty, // value\r
- false // clearAttributes\r
- );\r
- }\r
-\r
- // The reader is positioned on the first character\r
- // of the element's name.\r
- private void ReadEndTag()\r
- {\r
- string name = ReadName();\r
- SkipWhitespace();\r
- Expect('>');\r
-\r
- SetProperties(\r
- XmlNodeType.EndElement, // nodeType\r
- name, // name\r
- false, // isEmptyElement\r
- String.Empty, // value\r
- true // clearAttributes\r
- );\r
- }\r
-\r
- // The reader is positioned on the first character\r
- // of the text.\r
- private void ReadText()\r
- {\r
- StringBuilder text = new StringBuilder();\r
- text.Append((char)reader.Read());\r
-\r
- while (reader.Peek() != '<' && reader.Peek() != -1)\r
- {\r
- text.Append((char)reader.Read());\r
- }\r
-\r
- SetProperties(\r
- XmlNodeType.Text, // nodeType\r
- String.Empty, // name\r
- false, // isEmptyElement\r
- text.ToString(), // value\r
- true // clearAttributes\r
- );\r
- }\r
-\r
- // The reader is positioned on the first character of\r
- // the attribute name.\r
- private void ReadAttributes()\r
- {\r
- do\r
- {\r
- string name = ReadName();\r
- SkipWhitespace();\r
- Expect('=');\r
- SkipWhitespace();\r
- string value = ReadAttribute();\r
- SkipWhitespace();\r
-\r
- AddAttribute(name, value);\r
- }\r
- while (reader.Peek() != '/' && reader.Peek() != '>' && reader.Peek() != -1);\r
- }\r
-\r
- // The reader is positioned on the quote character.\r
- private string ReadAttribute()\r
- {\r
- int quoteChar = reader.Read();\r
-\r
- if (quoteChar != '\'' && quoteChar != '\"')\r
- {\r
- throw new Exception("an attribute value was not quoted");\r
- }\r
-\r
- StringBuilder valueBuilder = new StringBuilder();\r
-\r
- while (reader.Peek() != quoteChar)\r
- {\r
- int ch = reader.Read();\r
-\r
- switch (ch)\r
- {\r
- case '<':\r
- throw new Exception("attribute values cannot contain '<'");\r
- case -1:\r
- throw new Exception("unexpected end of file in an attribute value");\r
- }\r
-\r
- valueBuilder.Append((char)ch);\r
- }\r
-\r
- reader.Read();\r
-\r
- return valueBuilder.ToString();\r
- }\r
-\r
- // The reader is positioned on the first character\r
- // of the target.\r
- private void ReadProcessingInstruction()\r
- {\r
- string target = ReadName();\r
- SkipWhitespace();\r
-\r
- StringBuilder valueBuilder = new StringBuilder();\r
-\r
- while (reader.Peek() != -1)\r
- {\r
- int ch = reader.Read();\r
-\r
- if (ch == '?' && reader.Peek() == '>')\r
- {\r
- reader.Read();\r
- break;\r
- }\r
-\r
- valueBuilder.Append((char)ch);\r
- }\r
-\r
- SetProperties(\r
- XmlNodeType.ProcessingInstruction, // nodeType\r
- target, // name\r
- false, // isEmptyElement\r
- valueBuilder.ToString(), // value\r
- true // clearAttributes\r
- );\r
- }\r
-\r
- // The reader is positioned on the first character after\r
- // the leading '<!'.\r
- private void ReadComment()\r
- {\r
- Expect('-');\r
- Expect('-');\r
-\r
- StringBuilder valueBuilder = new StringBuilder();\r
-\r
- while (reader.Peek() != -1)\r
- {\r
- int ch = reader.Read();\r
-\r
- if (ch == '-' && reader.Peek() == '-')\r
- {\r
- reader.Read();\r
-\r
- if (reader.Peek() != '>')\r
- {\r
- throw new Exception("comments cannot contain '--'");\r
- }\r
-\r
- reader.Read();\r
- break;\r
- }\r
-\r
- valueBuilder.Append((char)ch);\r
- }\r
-\r
- SetProperties(\r
- XmlNodeType.Comment, // nodeType\r
- String.Empty, // name\r
- false, // isEmptyElement\r
- valueBuilder.ToString(), // value\r
- true // clearAttributes\r
- );\r
- }\r
-\r
- // The reader is positioned on the first character\r
- // of the name.\r
- private string ReadName()\r
- {\r
- if (!XmlChar.IsFirstNameChar(reader.Peek()))\r
- {\r
- throw new Exception("a name did not start with a legal character");\r
- }\r
-\r
- StringBuilder nameBuilder = new StringBuilder();\r
-\r
- nameBuilder.Append((char)reader.Read());\r
-\r
- while (XmlChar.IsNameChar(reader.Peek()))\r
- {\r
- nameBuilder.Append((char)reader.Read());\r
- }\r
-\r
- return nameBuilder.ToString();\r
- }\r
-\r
- // Read the next character and compare it against the\r
- // specified character.\r
- private void Expect(int expected)\r
- {\r
- int ch = reader.Read();\r
-\r
- if (ch != expected)\r
- {\r
- throw new Exception(String.Format(\r
- "expected '{0}' ({1:X}) but found '{2}' ({3:X})",\r
- (char)expected,\r
- expected,\r
- (char)ch,\r
- ch));\r
- }\r
- }\r
-\r
- // Does not consume the first non-whitespace character.\r
- private void SkipWhitespace()\r
- {\r
- while (XmlChar.IsWhitespace(reader.Peek()))\r
- {\r
- reader.Read();\r
- }\r
- }\r
- }\r
-}\r
+//
+// System.Xml.XmlTextReader
+//
+// Author:
+// Jason Diamond (jason@injektilo.org)
+//
+// (C) 2001, 2002 Jason Diamond http://injektilo.org/
+//
+
+// FIXME:
+// This can only parse basic XML: elements, attributes, processing
+// instructions, and comments are OK.
+//
+// It barfs on DOCTYPE declarations.
+//
+// There's also no checking being done for either well-formedness
+// or validity.
+//
+// NameTables aren't being used everywhere yet.
+//
+// Some thought needs to be given to performance. There's too many
+// strings being allocated.
+//
+// Some of the MoveTo methods haven't been implemented yet.
+//
+// LineNumber and LinePosition aren't being tracked.
+//
+// xml:space, xml:lang, and xml:base aren't being tracked.
+//
+
+using System;
+using System.Collections;
+using System.IO;
+using System.Text;
+
+namespace System.Xml
+{
+ public class XmlTextReader : XmlReader, IXmlLineInfo
+ {
+ #region Constructors
+
+ [MonoTODO]
+ protected XmlTextReader ()
+ {
+ throw new NotImplementedException ();
+ }
+
+ [MonoTODO]
+ public XmlTextReader (Stream input)
+ {
+ throw new NotImplementedException ();
+ }
+
+ [MonoTODO]
+ public XmlTextReader (string url)
+ {
+ throw new NotImplementedException ();
+ }
+
+ [MonoTODO]
+ public XmlTextReader (TextReader input)
+ {
+ XmlNameTable nt = new NameTable ();
+ XmlNamespaceManager nsMgr = new XmlNamespaceManager (nt);
+ parserContext = new XmlParserContext (null, nsMgr, null, XmlSpace.None);
+ Init ();
+ reader = input;
+ }
+
+ [MonoTODO]
+ protected XmlTextReader (XmlNameTable nt)
+ {
+ throw new NotImplementedException ();
+ }
+
+ [MonoTODO]
+ public XmlTextReader (Stream input, XmlNameTable nt)
+ {
+ throw new NotImplementedException ();
+ }
+
+ [MonoTODO]
+ public XmlTextReader (string url, Stream input)
+ {
+ throw new NotImplementedException ();
+ }
+
+ [MonoTODO]
+ public XmlTextReader (string url, TextReader input)
+ {
+ throw new NotImplementedException ();
+ }
+
+ [MonoTODO]
+ public XmlTextReader (string url, XmlNameTable nt)
+ {
+ throw new NotImplementedException ();
+ }
+
+ [MonoTODO]
+ public XmlTextReader (TextReader input, XmlNameTable nt)
+ {
+ throw new NotImplementedException ();
+ }
+
+ [MonoTODO]
+ public XmlTextReader (Stream xmlFragment, XmlNodeType fragType, XmlParserContext context)
+ {
+ throw new NotImplementedException ();
+ }
+
+ [MonoTODO]
+ public XmlTextReader (string url, Stream input, XmlNameTable nt)
+ {
+ throw new NotImplementedException ();
+ }
+
+ [MonoTODO]
+ public XmlTextReader (string url, TextReader input, XmlNameTable nt)
+ {
+ throw new NotImplementedException ();
+ }
+
+ [MonoTODO]
+ public XmlTextReader (string xmlFragment, XmlNodeType fragType, XmlParserContext context)
+ {
+ throw new NotImplementedException ();
+ }
+
+ #endregion
+
+ #region Properties
+
+ public override int AttributeCount
+ {
+ get { return attributes.Count; }
+ }
+
+ [MonoTODO]
+ public override string BaseURI
+ {
+ get { throw new NotImplementedException (); }
+ }
+
+ public override int Depth
+ {
+ get { return depth > 0 ? depth : 0; }
+ }
+
+ [MonoTODO]
+ public Encoding Encoding
+ {
+ get { throw new NotImplementedException (); }
+ }
+
+ public override bool EOF
+ {
+ get
+ {
+ return
+ readState == ReadState.EndOfFile ||
+ readState == ReadState.Closed;
+ }
+ }
+
+ public override bool HasValue
+ {
+ get { return value != String.Empty; }
+ }
+
+ public override bool IsDefault
+ {
+ get
+ {
+ // XmlTextReader does not expand default attributes.
+ return false;
+ }
+ }
+
+ public override bool IsEmptyElement
+ {
+ get { return isEmptyElement; }
+ }
+
+ public override string this [int i]
+ {
+ get { return GetAttribute (i); }
+ }
+
+ public override string this [string name]
+ {
+ get { return GetAttribute (name); }
+ }
+
+ public override string this [string localName, string namespaceName]
+ {
+ get { return GetAttribute (localName, namespaceName); }
+ }
+
+ [MonoTODO]
+ public int LineNumber
+ {
+ get { throw new NotImplementedException (); }
+ }
+
+ [MonoTODO]
+ public int LinePosition
+ {
+ get { throw new NotImplementedException (); }
+ }
+
+ public override string LocalName
+ {
+ get { return localName; }
+ }
+
+ public override string Name
+ {
+ get { return name; }
+ }
+
+ [MonoTODO]
+ public bool Namespaces
+ {
+ get { throw new NotImplementedException (); }
+ set { throw new NotImplementedException (); }
+ }
+
+ public override string NamespaceURI
+ {
+ get { return namespaceURI; }
+ }
+
+ public override XmlNameTable NameTable
+ {
+ get { return parserContext.NameTable; }
+ }
+
+ public override XmlNodeType NodeType
+ {
+ get { return nodeType; }
+ }
+
+ [MonoTODO]
+ public bool Normalization
+ {
+ get { throw new NotImplementedException (); }
+ set { throw new NotImplementedException (); }
+ }
+
+ public override string Prefix
+ {
+ get { return prefix; }
+ }
+
+ [MonoTODO]
+ public override char QuoteChar
+ {
+ get { throw new NotImplementedException (); }
+ }
+
+ public override ReadState ReadState
+ {
+ get { return readState; }
+ }
+
+ public override string Value
+ {
+ get { return value; }
+ }
+
+ [MonoTODO]
+ public WhitespaceHandling WhitespaceHandling
+ {
+ get { throw new NotImplementedException (); }
+ set { throw new NotImplementedException (); }
+ }
+
+ [MonoTODO]
+ public override string XmlLang
+ {
+ get { throw new NotImplementedException (); }
+ }
+
+ [MonoTODO]
+ public XmlResolver XmlResolver
+ {
+ set { throw new NotImplementedException (); }
+ }
+
+ [MonoTODO]
+ public override XmlSpace XmlSpace
+ {
+ get { throw new NotImplementedException (); }
+ }
+
+ #endregion
+
+ #region Methods
+
+ [MonoTODO]
+ public override void Close ()
+ {
+ readState = ReadState.Closed;
+ }
+
+ [MonoTODO]
+ public override string GetAttribute (int i)
+ {
+ throw new NotImplementedException ();
+ }
+
+ public override string GetAttribute (string name)
+ {
+ return attributes [name] as string;
+ }
+
+ public override string GetAttribute (string localName, string namespaceURI)
+ {
+ foreach (DictionaryEntry entry in attributes)
+ {
+ string thisName = entry.Key as string;
+
+ int indexOfColon = thisName.IndexOf (':');
+
+ if (indexOfColon != -1) {
+ string thisLocalName = thisName.Substring (indexOfColon + 1);
+
+ if (localName == thisLocalName) {
+ string thisPrefix = thisName.Substring (0, indexOfColon);
+ string thisNamespaceURI = LookupNamespace (thisPrefix);
+
+ if (namespaceURI == thisNamespaceURI)
+ return attributes [thisName] as string;
+ }
+ } else if (localName == "xmlns" && namespaceURI == "http://www.w3.org/2000/xmlns/" && thisName == "xmlns")
+ return attributes [thisName] as string;
+ }
+
+ return String.Empty;
+ }
+
+ [MonoTODO]
+ public TextReader GetRemainder ()
+ {
+ throw new NotImplementedException ();
+ }
+
+ [MonoTODO]
+ bool IXmlLineInfo.HasLineInfo ()
+ {
+ throw new NotImplementedException ();
+ }
+
+ public override string LookupNamespace (string prefix)
+ {
+ return parserContext.NamespaceManager.LookupNamespace (prefix);
+ }
+
+ [MonoTODO]
+ public override void MoveToAttribute (int i)
+ {
+ throw new NotImplementedException ();
+ }
+
+ [MonoTODO]
+ public override bool MoveToAttribute (string name)
+ {
+ throw new NotImplementedException ();
+ }
+
+ [MonoTODO]
+ public override bool MoveToAttribute (string localName, string namespaceName)
+ {
+ throw new NotImplementedException ();
+ }
+
+ public override bool MoveToElement ()
+ {
+ if (nodeType == XmlNodeType.Attribute) {
+ RestoreProperties ();
+ return true;
+ }
+
+ return false;
+ }
+
+ public override bool MoveToFirstAttribute ()
+ {
+ MoveToElement ();
+ return MoveToNextAttribute ();
+ }
+
+ public override bool MoveToNextAttribute ()
+ {
+ if (attributes == null)
+ return false;
+
+ if (attributeEnumerator == null) {
+ SaveProperties ();
+ attributeEnumerator = attributes.GetEnumerator ();
+ }
+
+ if (attributeEnumerator.MoveNext ()) {
+ string name = attributeEnumerator.Key as string;
+ string value = attributeEnumerator.Value as string;
+ SetProperties (
+ XmlNodeType.Attribute, // nodeType
+ name, // name
+ false, // isEmptyElement
+ value, // value
+ false // clearAttributes
+ );
+ return true;
+ }
+
+ return false;
+ }
+
+ public override bool Read ()
+ {
+ bool more = false;
+
+ readState = ReadState.Interactive;
+
+ more = ReadContent ();
+
+ return more;
+ }
+
+ [MonoTODO]
+ public override bool ReadAttributeValue ()
+ {
+ throw new NotImplementedException ();
+ }
+
+ [MonoTODO]
+ public int ReadBase64 (byte [] buffer, int offset, int length)
+ {
+ throw new NotImplementedException ();
+ }
+
+ [MonoTODO]
+ public int ReadBinHex (byte [] buffer, int offset, int length)
+ {
+ throw new NotImplementedException ();
+ }
+
+ [MonoTODO]
+ public int ReadChars (char [] buffer, int offset, int length)
+ {
+ throw new NotImplementedException ();
+ }
+
+ [MonoTODO]
+ public override string ReadInnerXml ()
+ {
+ throw new NotImplementedException ();
+ }
+
+ [MonoTODO]
+ public override string ReadOuterXml ()
+ {
+ throw new NotImplementedException ();
+ }
+
+ [MonoTODO]
+ public override string ReadString ()
+ {
+ throw new NotImplementedException ();
+ }
+
+ [MonoTODO]
+ public void ResetState ()
+ {
+ throw new NotImplementedException ();
+ }
+
+ public override void ResolveEntity ()
+ {
+ // XmlTextReaders don't resolve entities.
+ throw new InvalidOperationException ("XmlTextReaders don't resolve entities.");
+ }
+
+ #endregion
+
+ // privates
+
+ private XmlParserContext parserContext;
+
+ private TextReader reader;
+ private ReadState readState;
+
+ private int depth;
+ private bool depthDown;
+
+ private bool popScope;
+
+ private XmlNodeType nodeType;
+ private string name;
+ private string prefix;
+ private string localName;
+ private string namespaceURI;
+ private bool isEmptyElement;
+ private string value;
+
+ private XmlNodeType saveNodeType;
+ private string saveName;
+ private string savePrefix;
+ private string saveLocalName;
+ private string saveNamespaceURI;
+ private bool saveIsEmptyElement;
+
+ private Hashtable attributes;
+ private IDictionaryEnumerator attributeEnumerator;
+
+ private bool returnEntityReference;
+ private string entityReferenceName;
+
+ private char [] nameBuffer;
+ private int nameLength;
+ private int nameCapacity;
+ private const int initialNameCapacity = 256;
+
+ private char [] valueBuffer;
+ private int valueLength;
+ private int valueCapacity;
+ private const int initialValueCapacity = 8192;
+
+ private void Init ()
+ {
+ readState = ReadState.Initial;
+
+ depth = -1;
+ depthDown = false;
+
+ popScope = false;
+
+ nodeType = XmlNodeType.None;
+ name = String.Empty;
+ prefix = String.Empty;
+ localName = string.Empty;
+ isEmptyElement = false;
+ value = String.Empty;
+
+ attributes = new Hashtable ();
+ attributeEnumerator = null;
+
+ returnEntityReference = false;
+ entityReferenceName = String.Empty;
+
+ nameBuffer = new char [initialNameCapacity];
+ nameLength = 0;
+ nameCapacity = initialNameCapacity;
+
+ valueBuffer = new char [initialValueCapacity];
+ valueLength = 0;
+ valueCapacity = initialValueCapacity;
+ }
+
+ // Use this method rather than setting the properties
+ // directly so that all the necessary properties can
+ // be changed in harmony with each other. Maybe the
+ // fields should be in a seperate class to help enforce
+ // this.
+ private void SetProperties (
+ XmlNodeType nodeType,
+ string name,
+ bool isEmptyElement,
+ string value,
+ bool clearAttributes)
+ {
+ this.nodeType = nodeType;
+ this.name = name;
+ this.isEmptyElement = isEmptyElement;
+ this.value = value;
+
+ if (clearAttributes)
+ ClearAttributes ();
+
+ int indexOfColon = name.IndexOf (':');
+
+ if (indexOfColon == -1) {
+ prefix = String.Empty;
+ localName = name;
+ } else {
+ prefix = name.Substring (0, indexOfColon);
+ localName = name.Substring (indexOfColon + 1);
+ }
+
+ namespaceURI = LookupNamespace (prefix);
+ }
+
+ private void SaveProperties ()
+ {
+ saveNodeType = nodeType;
+ saveName = name;
+ savePrefix = prefix;
+ saveLocalName = localName;
+ saveNamespaceURI = namespaceURI;
+ saveIsEmptyElement = isEmptyElement;
+ // An element's value is always String.Empty.
+ }
+
+ private void RestoreProperties ()
+ {
+ nodeType = saveNodeType;
+ name = saveName;
+ prefix = savePrefix;
+ localName = saveLocalName;
+ namespaceURI = saveNamespaceURI;
+ isEmptyElement = saveIsEmptyElement;
+ value = String.Empty;
+ }
+
+ private void AddAttribute (string name, string value)
+ {
+ attributes.Add (name, value);
+ }
+
+ private void ClearAttributes ()
+ {
+ if (attributes.Count > 0)
+ attributes.Clear ();
+
+ attributeEnumerator = null;
+ }
+
+ private int PeekChar ()
+ {
+ return reader.Peek ();
+ }
+
+ private int ReadChar ()
+ {
+ return reader.Read ();
+ }
+
+ // This should really keep track of some state so
+ // that it's not possible to have more than one document
+ // element or text outside of the document element.
+ private bool ReadContent ()
+ {
+ bool more = false;
+
+ if (popScope) {
+ parserContext.NamespaceManager.PopScope ();
+ popScope = false;
+ }
+
+ if (depthDown)
+ --depth;
+
+ if (returnEntityReference) {
+ ++depth;
+ SetEntityReferenceProperties ();
+ more = true;
+ } else {
+ switch (PeekChar ())
+ {
+ case '<':
+ ReadChar ();
+ ReadTag ();
+ more = true;
+ break;
+ case -1:
+ readState = ReadState.EndOfFile;
+ SetProperties (
+ XmlNodeType.None, // nodeType
+ String.Empty, // name
+ false, // isEmptyElement
+ String.Empty, // value
+ true // clearAttributes
+ );
+ more = false;
+ break;
+ default:
+ ReadText ();
+ more = true;
+ break;
+ }
+ }
+
+ return more;
+ }
+
+ private void SetEntityReferenceProperties ()
+ {
+ SetProperties (
+ XmlNodeType.EntityReference, // nodeType
+ entityReferenceName, // name
+ false, // isEmptyElement
+ String.Empty, // value
+ true // clearAttributes
+ );
+
+ returnEntityReference = false;
+ entityReferenceName = String.Empty;
+ }
+
+ // The leading '<' has already been consumed.
+ private void ReadTag ()
+ {
+ switch (PeekChar ())
+ {
+ case '/':
+ ReadChar ();
+ ReadEndTag ();
+ break;
+ case '?':
+ ReadChar ();
+ ReadProcessingInstruction ();
+ break;
+ case '!':
+ ReadChar ();
+ ReadDeclaration ();
+ break;
+ default:
+ ReadStartTag ();
+ break;
+ }
+ }
+
+ // The leading '<' has already been consumed.
+ private void ReadStartTag ()
+ {
+ parserContext.NamespaceManager.PushScope ();
+
+ string name = ReadName ();
+ SkipWhitespace ();
+
+ bool isEmptyElement = false;
+
+ ClearAttributes ();
+
+ if (XmlChar.IsFirstNameChar (PeekChar ()))
+ ReadAttributes ();
+
+ if (PeekChar () == '/') {
+ ReadChar ();
+ isEmptyElement = true;
+ depthDown = true;
+ popScope = true;
+ }
+
+ Expect ('>');
+
+ ++depth;
+
+ SetProperties (
+ XmlNodeType.Element, // nodeType
+ name, // name
+ isEmptyElement, // isEmptyElement
+ String.Empty, // value
+ false // clearAttributes
+ );
+ }
+
+ // The reader is positioned on the first character
+ // of the element's name.
+ private void ReadEndTag ()
+ {
+ string name = ReadName ();
+ SkipWhitespace ();
+ Expect ('>');
+
+ --depth;
+
+ SetProperties (
+ XmlNodeType.EndElement, // nodeType
+ name, // name
+ false, // isEmptyElement
+ String.Empty, // value
+ true // clearAttributes
+ );
+
+ popScope = true;
+ }
+
+ private void AppendNameChar (int ch)
+ {
+ CheckNameCapacity ();
+ nameBuffer [nameLength++] = (char)ch;
+ }
+
+ private void CheckNameCapacity ()
+ {
+ if (nameLength == nameCapacity) {
+ nameCapacity = nameCapacity * 2;
+ char [] oldNameBuffer = nameBuffer;
+ nameBuffer = new char [nameCapacity];
+ Array.Copy (oldNameBuffer, nameBuffer, nameLength);
+ }
+ }
+
+ private string CreateNameString ()
+ {
+ return new String (nameBuffer, 0, nameLength);
+ }
+
+ private void AppendValueChar (int ch)
+ {
+ CheckValueCapacity ();
+ valueBuffer [valueLength++] = (char)ch;
+ }
+
+ private void CheckValueCapacity ()
+ {
+ if (valueLength == valueCapacity) {
+ valueCapacity = valueCapacity * 2;
+ char [] oldValueBuffer = valueBuffer;
+ valueBuffer = new char [valueCapacity];
+ Array.Copy (oldValueBuffer, valueBuffer, valueLength);
+ }
+ }
+
+ private string CreateValueString ()
+ {
+ return new String (valueBuffer, 0, valueLength);
+ }
+
+ // The reader is positioned on the first character
+ // of the text.
+ private void ReadText ()
+ {
+ valueLength = 0;
+
+ int ch = PeekChar ();
+
+ while (ch != '<' && ch != -1) {
+ if (ch == '&') {
+ ReadChar ();
+ if (ReadReference (false))
+ break;
+ } else
+ AppendValueChar (ReadChar ());
+
+ ch = PeekChar ();
+ }
+
+ if (returnEntityReference && valueLength == 0) {
+ ++depth;
+ SetEntityReferenceProperties ();
+ } else {
+ if (depth >= 0) {
+ ++depth;
+ depthDown = true;
+ }
+
+ SetProperties (
+ XmlNodeType.Text, // nodeType
+ String.Empty, // name
+ false, // isEmptyElement
+ CreateValueString (), // value
+ true // clearAttributes
+ );
+ }
+ }
+
+ // The leading '&' has already been consumed.
+ // Returns true if the entity reference isn't a simple
+ // character reference or one of the predefined entities.
+ // This allows the ReadText method to break so that the
+ // next call to Read will return the EntityReference node.
+ private bool ReadReference (bool ignoreEntityReferences)
+ {
+ if (PeekChar () == '#') {
+ ReadChar ();
+ ReadCharacterReference ();
+ } else
+ ReadEntityReference (ignoreEntityReferences);
+
+ return returnEntityReference;
+ }
+
+ private void ReadCharacterReference ()
+ {
+ int value = 0;
+
+ if (PeekChar () == 'x') {
+ ReadChar ();
+
+ while (PeekChar () != ';' && PeekChar () != -1) {
+ int ch = ReadChar ();
+
+ if (ch >= '0' && ch <= '9')
+ value = (value << 4) + ch - '0';
+ else if (ch >= 'A' && ch <= 'F')
+ value = (value << 4) + ch - 'A' + 10;
+ else if (ch >= 'a' && ch <= 'f')
+ value = (value << 4) + ch - 'a' + 10;
+ else
+ throw new XmlException (
+ String.Format (
+ "invalid hexadecimal digit: {0} (#x{1:X})",
+ (char)ch,
+ ch));
+ }
+ } else {
+ while (PeekChar () != ';' && PeekChar () != -1) {
+ int ch = ReadChar ();
+
+ if (ch >= '0' && ch <= '9')
+ value = value * 10 + ch - '0';
+ else
+ throw new XmlException (
+ String.Format (
+ "invalid decimal digit: {0} (#x{1:X})",
+ (char)ch,
+ ch));
+ }
+ }
+
+ ReadChar (); // ';'
+
+ AppendValueChar (value);
+ }
+
+ private void ReadEntityReference (bool ignoreEntityReferences)
+ {
+ nameLength = 0;
+
+ int ch = PeekChar ();
+
+ while (ch != ';' && ch != -1) {
+ AppendNameChar (ReadChar ());
+ ch = PeekChar ();
+ }
+
+ Expect (';');
+
+ string name = CreateNameString ();
+
+ switch (name)
+ {
+ case "lt":
+ AppendValueChar ('<');
+ break;
+ case "gt":
+ AppendValueChar ('>');
+ break;
+ case "amp":
+ AppendValueChar ('&');
+ break;
+ case "apos":
+ AppendValueChar ('\'');
+ break;
+ case "quot":
+ AppendValueChar ('"');
+ break;
+ default:
+ if (ignoreEntityReferences) {
+ AppendValueChar ('&');
+
+ foreach (char ch2 in name) {
+ AppendValueChar (ch2);
+ }
+
+ AppendValueChar (';');
+ } else {
+ returnEntityReference = true;
+ entityReferenceName = name;
+ }
+ break;
+ }
+ }
+
+ // The reader is positioned on the first character of
+ // the attribute name.
+ private void ReadAttributes ()
+ {
+ do {
+ string name = ReadName ();
+ SkipWhitespace ();
+ Expect ('=');
+ SkipWhitespace ();
+ string value = ReadAttribute ();
+ SkipWhitespace ();
+
+ if (name == "xmlns")
+ parserContext.NamespaceManager.AddNamespace (String.Empty, value);
+ else if (name.StartsWith ("xmlns:"))
+ parserContext.NamespaceManager.AddNamespace (name.Substring (6), value);
+
+ AddAttribute (name, value);
+ } while (PeekChar () != '/' && PeekChar () != '>' && PeekChar () != -1);
+ }
+
+ // The reader is positioned on the quote character.
+ private string ReadAttribute ()
+ {
+ int quoteChar = ReadChar ();
+
+ if (quoteChar != '\'' && quoteChar != '\"')
+ throw new XmlException ("an attribute value was not quoted");
+
+ valueLength = 0;
+
+ while (PeekChar () != quoteChar) {
+ int ch = ReadChar ();
+
+ switch (ch)
+ {
+ case '<':
+ throw new XmlException ("attribute values cannot contain '<'");
+ case '&':
+ ReadReference (true);
+ break;
+ case -1:
+ throw new XmlException ("unexpected end of file in an attribute value");
+ default:
+ AppendValueChar (ch);
+ break;
+ }
+ }
+
+ ReadChar (); // quoteChar
+
+ return CreateValueString ();
+ }
+
+ // The reader is positioned on the first character
+ // of the target.
+ private void ReadProcessingInstruction ()
+ {
+ string target = ReadName ();
+ SkipWhitespace ();
+
+ valueLength = 0;
+
+ while (PeekChar () != -1) {
+ int ch = ReadChar ();
+
+ if (ch == '?' && PeekChar () == '>') {
+ ReadChar ();
+ break;
+ }
+
+ AppendValueChar ((char)ch);
+ }
+
+ SetProperties (
+ XmlNodeType.ProcessingInstruction, // nodeType
+ target, // name
+ false, // isEmptyElement
+ CreateValueString (), // value
+ true // clearAttributes
+ );
+ }
+
+ // The reader is positioned on the first character after
+ // the leading '<!'.
+ private void ReadDeclaration ()
+ {
+ int ch = PeekChar ();
+
+ switch (ch)
+ {
+ case '-':
+ Expect ('-');
+ Expect ('-');
+ ReadComment ();
+ break;
+ case '[':
+ ReadChar ();
+ Expect ('C');
+ Expect ('D');
+ Expect ('A');
+ Expect ('T');
+ Expect ('A');
+ Expect ('[');
+ ReadCDATA ();
+ break;
+ }
+ }
+
+ // The reader is positioned on the first character after
+ // the leading '<!--'.
+ private void ReadComment ()
+ {
+ valueLength = 0;
+
+ while (PeekChar () != -1) {
+ int ch = ReadChar ();
+
+ if (ch == '-' && PeekChar () == '-') {
+ ReadChar ();
+
+ if (PeekChar () != '>')
+ throw new XmlException ("comments cannot contain '--'");
+
+ ReadChar ();
+ break;
+ }
+
+ AppendValueChar ((char)ch);
+ }
+
+ SetProperties (
+ XmlNodeType.Comment, // nodeType
+ String.Empty, // name
+ false, // isEmptyElement
+ CreateValueString (), // value
+ true // clearAttributes
+ );
+ }
+
+ // The reader is positioned on the first character after
+ // the leading '<![CDATA['.
+ private void ReadCDATA ()
+ {
+ valueLength = 0;
+
+ while (PeekChar () != -1) {
+ int ch = ReadChar ();
+
+ if (ch == ']' && PeekChar () == ']') {
+ ch = ReadChar (); // ']'
+
+ if (PeekChar () == '>') {
+ ReadChar (); // '>'
+ break;
+ } else {
+ AppendValueChar (']');
+ AppendValueChar (']');
+ ch = ReadChar ();
+ }
+ }
+
+ AppendValueChar ((char)ch);
+ }
+
+ ++depth;
+
+ SetProperties (
+ XmlNodeType.CDATA, // nodeType
+ String.Empty, // name
+ false, // isEmptyElement
+ CreateValueString (), // value
+ true // clearAttributes
+ );
+ }
+
+ // The reader is positioned on the first character
+ // of the name.
+ private string ReadName ()
+ {
+ if (!XmlChar.IsFirstNameChar (PeekChar ()))
+ throw new XmlException ("a name did not start with a legal character");
+
+ nameLength = 0;
+
+ AppendNameChar (ReadChar ());
+
+ while (XmlChar.IsNameChar (PeekChar ())) {
+ AppendNameChar (ReadChar ());
+ }
+
+ return CreateNameString ();
+ }
+
+ // Read the next character and compare it against the
+ // specified character.
+ private void Expect (int expected)
+ {
+ int ch = ReadChar ();
+
+ if (ch != expected) {
+ throw new XmlException (
+ String.Format (
+ "expected '{0}' ({1:X}) but found '{2}' ({3:X})",
+ (char)expected,
+ expected,
+ (char)ch,
+ ch));
+ }
+ }
+
+ // Does not consume the first non-whitespace character.
+ private void SkipWhitespace ()
+ {
+ while (XmlChar.IsWhitespace (PeekChar ()))
+ ReadChar ();
+ }
+ }
+}