private void Pop()
		{
			if (this.m_stack.Count > 1)
			{
				this.m_node = (Node)this.m_stack.Pop();
			}
		}
		private Node Push(string name, XmlNodeType nt, string value)
		{
			Node result = (Node)this.m_stack.Push();
			if (result == null)
			{
				result = new Node();
				this.m_stack[this.m_stack.Count - 1] = result;
			}

			result.Reset(name, nt, value);
			this.m_node = result;
			return result;
		}
		private Node Push(Node n)
		{
			// we have to do a deep clone of the Node object because
			// it is reused in the stack.
			Node n2 = Push(n.Name, n.NodeType, n.Value);
			n2.DtdType = n.DtdType;
			n2.IsEmpty = n.IsEmpty;
			n2.Space = n.Space;
			n2.XmlLang = n.XmlLang;
			n2.CurrentState = n.CurrentState;
			n2.CopyAttributes(n);
			this.m_node = n2;
			return n2;
		}
		public void CopyAttributes(Node n)
		{
			for (int i = 0, len = n.attributes.Count; i < len; i++)
			{
				Attribute a = (Attribute)n.attributes[i];
				Attribute na = this.AddAttribute(a.Name, a.Value, a.QuoteChar, false);
				na.DtdType = a.DtdType;
			}
		}
		private void Init()
		{
			this.m_state = State.Initial;
			this.m_stack = new HWStack(10);
			this.m_node = Push(null, XmlNodeType.Document, null);
			this.m_node.IsEmpty = false;
			this.m_sb = new StringBuilder();
			this.m_name = new StringBuilder();
			this.m_poptodepth = 0;
			this.m_current = null;
			this.m_partial = '\0';
			this.m_endTag = null;
			this.m_a = null;
			this.m_apos = 0;
			this.m_newnode = null;
			this.m_rootCount = 0;
			this.m_foundRoot = false;
			this.unknownNamespaces.Clear();
		}
		private void ValidateContent(Node node)
		{
			if (node.NodeType == XmlNodeType.Element)
			{
				if (!VerifyName(node.Name))
				{
					Pop();
					Push(null, XmlNodeType.Text, "<" + node.Name + ">");
					return;
				}
			}

			if (this.m_dtd != null)
			{
				// See if this element is allowed inside the current element.
				// If it isn't, then auto-close elements until we find one
				// that it is allowed to be in.                                  
				string name = node.Name.ToUpperInvariant(); // DTD is in upper case
				int i = 0;
				int top = this.m_stack.Count - 2;
				if (node.DtdType != null)
				{
					// it is a known element, let's see if it's allowed in the
					// current context.
					for (i = top; i > 0; i--)
					{
						Node n = (Node)this.m_stack[i];
						if (n.IsEmpty)
							continue; // we'll have to pop this one
						ElementDecl f = n.DtdType;
						if (f != null)
						{
							if ((i == 2) && string.Equals(f.Name, "BODY", StringComparison.OrdinalIgnoreCase)) // NOTE (steveb): never close the BODY tag too early
								break;
							else if (string.Equals(f.Name, this.m_dtd.Name, StringComparison.OrdinalIgnoreCase))
								break; // can't pop the root element.
							else if (f.CanContain(name, this.m_dtd))
							{
								break;
							}
							else if (!f.EndTagOptional)
							{
								// If the end tag is not optional then we can't
								// auto-close it.  We'll just have to live with the
								// junk we've found and move on.
								break;
							}
						}
						else
						{
							// Since we don't understand this tag anyway,
							// we might as well allow this content!
							break;
						}
					}
				}

				if (i == 0)
				{
					// Tag was not found or is not allowed anywhere, ignore it and 
					// continue on.
					return;
				}
				else if (i < top)
				{
					Node n = (Node)this.m_stack[top];
					if (i == top - 1 && string.Equals(name, n.Name, StringComparison.OrdinalIgnoreCase))
					{
						// e.g. p not allowed inside p, not an interesting error.
					}
					else
					{
#if DEBUG
						string closing = "";
						for (int k = top; k >= i + 1; k--)
						{
							if (closing != "") closing += ",";
							Node n2 = (Node)this.m_stack[k];
							closing += "<" + n2.Name + ">";
						}
						Log("Element '{0}' not allowed inside '{1}', closing {2}.", name, n.Name, closing);
#endif
					}

					this.m_state = State.AutoClose;
					this.m_newnode = node;
					Pop(); // save this new node until we pop the others
					this.m_poptodepth = i + 1;
				}
			}
		}
		private static void ValidateAttribute(Node node, Attribute a)
		{
			ElementDecl e = node.DtdType;
			if (e != null)
			{
				AttDef ad = e.FindAttribute(a.Name);
				if (ad != null)
				{
					a.DtdType = ad;
				}
			}
		}
		private void Validate(Node node)
		{
			if (this.m_dtd != null)
			{
				ElementDecl e = this.m_dtd.FindElement(node.Name);
				if (e != null)
				{
					node.DtdType = e;
					if (e.ContentModel.DeclaredContent == DeclaredContent.EMPTY)
						node.IsEmpty = true;
				}
			}
		}
		private bool ParseEndTag()
		{
			this.m_state = State.EndTag;
			this.m_current.ReadChar(); // consume '/' char.
			string name = this.ScanName(SgmlReader.tagterm);
			char ch = this.m_current.SkipWhitespace();
			if (ch != '>')
			{
				Log("Expected empty start tag '/>' sequence instead of '{0}'", ch);
				this.m_current.ScanToEnd(null, "Recovering", ">");
			}

			this.m_current.ReadChar(); // consume '>'

			this.m_endTag = name;

			// Make sure there's a matching start tag for it.                        
			bool caseInsensitive = (this.m_folding == CaseFolding.None);
			this.m_node = (Node)this.m_stack[this.m_stack.Count - 1];
			for (int i = this.m_stack.Count - 1; i > 0; i--)
			{
				Node n = (Node)this.m_stack[i];
				if (string.Equals(n.Name, name, caseInsensitive ? StringComparison.OrdinalIgnoreCase : StringComparison.Ordinal))
				{
					this.m_endTag = n.Name;
					return true;
				}
			}

			Log("No matching start tag for '</{0}>'", name);
			this.m_state = State.Markup;
			return false;
		}
		/// <summary>
		/// Reads the next node from the stream.
		/// </summary>
		/// <returns>true if the next node was read successfully; false if there are no more nodes to read.</returns>
		public override bool Read()
		{
			if (m_current == null)
			{
				OpenInput();
			}

			if (m_node.Simulated)
			{
				// return the next node
				m_node.Simulated = false;
				this.m_node = Top();
				this.m_state = this.m_node.CurrentState;
				return true;
			}

			bool foundnode = false;
			while (!foundnode)
			{
				switch (this.m_state)
				{
					case State.Initial:
						this.m_state = State.Markup;
						this.m_current.ReadChar();
						goto case State.Markup;
					case State.Eof:
						if (this.m_current.Parent != null)
						{
							this.m_current.Close();
							this.m_current = this.m_current.Parent;
						}
						else
						{
							return false;
						}
						break;
					case State.EndTag:
						if (string.Equals(this.m_endTag, this.m_node.Name, StringComparison.OrdinalIgnoreCase))
						{
							Pop(); // we're done!
							this.m_state = State.Markup;
							goto case State.Markup;
						}
						Pop(); // close one element
						foundnode = true;// return another end element.
						break;
					case State.Markup:
						if (this.m_node.IsEmpty)
						{
							Pop();
						}
						foundnode = ParseMarkup();
						break;
					case State.PartialTag:
						Pop(); // remove text node.
						this.m_state = State.Markup;
						foundnode = ParseTag(this.m_partial);
						break;
					case State.PseudoStartTag:
						foundnode = ParseStartTag('<');
						break;
					case State.AutoClose:
						Pop(); // close next node.
						if (this.m_stack.Count <= this.m_poptodepth)
						{
							this.m_state = State.Markup;
							if (this.m_newnode != null)
							{
								Push(this.m_newnode); // now we're ready to start the new node.
								this.m_newnode = null;
								this.m_state = State.Markup;
							}
							else if (this.m_node.NodeType == XmlNodeType.Document)
							{
								this.m_state = State.Eof;
								goto case State.Eof;
							}
						}
						foundnode = true;
						break;
					case State.CData:
						foundnode = ParseCData();
						break;
					case State.Attr:
						goto case State.AttrValue;
					case State.AttrValue:
						this.m_state = State.Markup;
						goto case State.Markup;
					case State.Text:
						Pop();
						goto case State.Markup;
					case State.PartialText:
						if (ParseText(this.m_current.Lastchar, false))
						{
							this.m_node.NodeType = XmlNodeType.Whitespace;
						}

						foundnode = true;
						break;
				}

				if (foundnode && this.m_node.NodeType == XmlNodeType.Whitespace && this.m_whitespaceHandling == false)
				{
					// strip out whitespace (caller is probably pretty printing the XML).
					foundnode = false;
				}
				if (!foundnode && this.m_state == State.Eof && this.m_stack.Count > 1)
				{
					this.m_poptodepth = 1;
					this.m_state = State.AutoClose;
					this.m_node = Top();
					return true;
				}
			}
			if (!m_foundRoot && (this.NodeType == XmlNodeType.Element ||
					this.NodeType == XmlNodeType.Text ||
					this.NodeType == XmlNodeType.CDATA))
			{
				m_foundRoot = true;
				if (this.IsHtml && (this.NodeType != XmlNodeType.Element ||
					!string.Equals(this.LocalName, "html", StringComparison.OrdinalIgnoreCase)))
				{
					// Simulate an HTML root element!
					this.m_node.CurrentState = this.m_state;
					Node root = Push("html", XmlNodeType.Element, null);
					SwapTopNodes(); // make html the outer element.
					this.m_node = root;
					root.Simulated = true;
					root.IsEmpty = false;
					this.m_state = State.Markup;
					//this.state = State.PseudoStartTag;
					//this.startTag = name;
				}

				return true;
			}

			return true;
		}