public XmlReader(IoMemory mem) : this() { if (mem == null) { throw new ArgumentNullException("mem"); } stream = new KernelIoMemoryStream(mem); }
public XmlReader(byte[] buffer) : this() { if (buffer == null) { throw new ArgumentNullException("buffer"); } stream = new KernelByteMemoryStream(buffer); }
////////////////////////////////////////////////////////////////////// // public XmlNode Parse() { if (stream == null) { return(doc); } TokenType type; string token = null; XmlNode curNode = null; string curAttributeName = null; // Check for a UTF-8 preamble. isUtf8 = false; if (PeekCharacter() == 0xef) { if (ReadCharacter() == 0xef && ReadCharacter() == 0xbb && ReadCharacter() == 0xbf) { isUtf8 = true; } } while (ReadToken(out token, out type)) { switch (state) { case States.START: if (type == TokenType.OPERATOR && token.Equals("<")) { state = States.NEED_ELEMENT_NAME; } else { // All other text is interpreted as freestanding text. // It had better occur within a tag! if (stackTop == 0) { throw new XmlException(lineNumber, "Line " + lineNumber + ": Text must be inside a tag"); } XmlNode lastNode = Peek(); lastNode.AddText(token); // Next state depends on whether we're at the end of // the text-within-a-tag already or not. if (PeekCharacter() == '<') { // Looks like we're already at the end state = States.START; } else { state = States.GET_STRINGS; } } break; case States.NEED_ELEMENT_NAME: if (type == TokenType.NAME) { state = States.NEED_ATTRIBUTE_NAME; curNode = new XmlNode(token); } else if (type == TokenType.OPERATOR && token.Equals("/")) { state = States.NEED_CLOSURE_NAME; } else if (type == TokenType.OPERATOR && (token.Equals("?") || token.Equals("!") || token.Equals('-'))) { // then go to the question mark state and ignore this element state = States.QUESTION_MARK_ELEMENT; } else { throw new XmlException(lineNumber, "Line " + lineNumber + ": Can only begin a tag with / or a name"); } break; case States.NEED_ATTRIBUTE_NAME: if (type == TokenType.NAME) { state = States.NEED_EQUALS_SIGN; curAttributeName = token; } else if (type == TokenType.OPERATOR && token.Equals(">")) { // hold onto this node so we can check it later state = States.START; if (stackTop != 0) { XmlNode parent = Peek(); parent.AddChild(curNode); } else { doc.AddChild(curNode); } Push(curNode); curNode = null; } else if (type == TokenType.OPERATOR && token.Equals("/")) { // this node is almost complete state = States.NEED_CLOSURE_BRACKET; } else { throw new XmlException(lineNumber, "Line " + lineNumber + ": Must have either attributes, '/>', or '>' after the name of an element"); } break; case States.NEED_EQUALS_SIGN: if (type == TokenType.OPERATOR && token.Equals("=")) { state = States.NEED_ATTRIBUTE_VALUE; } else { throw new XmlException(lineNumber, "Line " + lineNumber + ": Need an '=' after an attribute name"); } break; case States.NEED_ATTRIBUTE_VALUE: if (type == TokenType.STRING_LITERAL) { state = States.NEED_ATTRIBUTE_NAME; string unescaped_attribute_value = ExpandEntityReferences(token); curNode.AddAttribute(curAttributeName, unescaped_attribute_value); curAttributeName = null; } else { throw new XmlException(lineNumber, "Line " + lineNumber + ": Must have an attribute value after the '=' in an XML node"); } break; case States.NEED_CLOSURE_BRACKET: if (type == TokenType.OPERATOR && token.Equals(">")) { // this node is done, and we don't have to check it state = States.START; if (stackTop != 0) { XmlNode parent = Peek(); parent.AddChild(curNode); } else { doc.AddChild(curNode); } } else { throw new XmlException(lineNumber, "Line " + lineNumber + ": Must have a '>' after a closing '/' in an XML node"); } break; case States.NEED_CLOSURE_NAME: if (type == TokenType.NAME) { // pop the last XmlNode and make sure that this name matches. // Otherwise we don't have balanced open and close tags state = States.NEED_FINAL_BRACKET; XmlNode xmln = Pop(); if (!token.Equals(xmln.Name)) { throw new XmlException(lineNumber, "Line " + lineNumber + ": " + token + " does not match " + xmln.Name); } } else { throw new XmlException(lineNumber, "Line " + lineNumber + ": Must have a name after an opening />"); } break; case States.NEED_FINAL_BRACKET: if (type == TokenType.OPERATOR && token.Equals(">")) { state = States.START; } else { throw new XmlException(lineNumber, "Line " + lineNumber + ": Must have a > after a closure tag's name"); } break; case States.QUESTION_MARK_ELEMENT: // just stay in this state until you see a '>' while ('>' != ReadCharacter()) { ; } state = States.START; break; case States.GET_STRINGS: { // stay in this state until you see a '<' StringBuilder sb = new StringBuilder(); XmlNode prevNode = Peek(); if (type == TokenType.OPERATOR && token.Equals("<")) { throw new XmlException(lineNumber, "Unexpected tag beginning while in text state"); } sb.Append(token); while (PeekCharacter() != -1 && PeekCharacter() != '<') { sb.Append((char)ReadCharacter()); } prevNode.AddText(sb.ToString()); state = States.START; } break; } } stream.Close(); stream = null; return(doc); }