/*-------------------------------------------------------------------------* drawElements Quality Program Test Executor* ------------------------------------------** Copyright 2014 The Android Open Source Project** Licensed under the Apache License, Version 2.0 (the "License");* you may not use this file except in compliance with the License.* You may obtain a copy of the License at** http://www.apache.org/licenses/LICENSE-2.0** Unless required by applicable law or agreed to in writing, software* distributed under the License is distributed on an "AS IS" BASIS,* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.* See the License for the specific language governing permissions and* limitations under the License.**//*!* \file* \brief XML Parser.*//*--------------------------------------------------------------------*/#include "xeXMLParser.hpp"#include "deInt32.h"namespace xe{namespace xml{enum{TOKENIZER_INITIAL_BUFFER_SIZE = 1024};static inline bool isIdentifierStartChar (int ch){return de::inRange<int>(ch, 'a', 'z') || de::inRange<int>(ch, 'A', 'Z');}static inline bool isIdentifierChar (int ch){return isIdentifierStartChar(ch) || de::inRange<int>(ch, '0', '9') || (ch == '-') || (ch == '_');}static inline bool isWhitespaceChar (int ch){return ch == ' ' || ch == '\t' || ch == '\r' || ch == '\n';}static int getNextBufferSize (int curSize, int minNewSize){return de::max(curSize*2, 1<<deLog2Ceil32(minNewSize));}Tokenizer::Tokenizer (void): m_curToken (TOKEN_INCOMPLETE), m_curTokenLen (0), m_state (STATE_DATA), m_buf (TOKENIZER_INITIAL_BUFFER_SIZE){}Tokenizer::~Tokenizer (void){}void Tokenizer::clear (void){m_curToken = TOKEN_INCOMPLETE;m_curTokenLen = 0;m_state = STATE_DATA;m_buf.clear();}void Tokenizer::error (const std::string& what){throw ParseError(what);}void Tokenizer::feed (const deUint8* bytes, int numBytes){// Grow buffer if necessary.if (m_buf.getNumFree() < numBytes){m_buf.resize(getNextBufferSize(m_buf.getSize(), m_buf.getNumElements()+numBytes));}// Append to front.m_buf.pushFront(bytes, numBytes);// If we haven't parsed complete token, re-try after data feed.if (m_curToken == TOKEN_INCOMPLETE)advance();}int Tokenizer::getChar (int offset) const{DE_ASSERT(de::inRange(offset, 0, m_buf.getNumElements()));if (offset < m_buf.getNumElements())return m_buf.peekBack(offset);elsereturn END_OF_BUFFER;}void Tokenizer::advance (void){if (m_curToken != TOKEN_INCOMPLETE){// Parser should not try to advance beyond end of string.DE_ASSERT(m_curToken != TOKEN_END_OF_STRING);// If current token is tag end, change state to data.if (m_curToken == TOKEN_TAG_END ||m_curToken == TOKEN_EMPTY_ELEMENT_END ||m_curToken == TOKEN_PROCESSING_INSTRUCTION_END ||m_curToken == TOKEN_COMMENT ||m_curToken == TOKEN_ENTITY)m_state = STATE_DATA;// Advance buffer by length of last token.m_buf.popBack(m_curTokenLen);// Reset state.m_curToken = TOKEN_INCOMPLETE;m_curTokenLen = 0;// If we hit end of string here, report it as end of string.if (getChar(0) == END_OF_STRING){m_curToken = TOKEN_END_OF_STRING;m_curTokenLen = 1;return;}}int curChar = getChar(m_curTokenLen);for (;;){if (m_state == STATE_DATA){// Advance until we hit end of buffer or tag start and treat that as data token.if (curChar == END_OF_STRING || curChar == (int)END_OF_BUFFER || curChar == '<' || curChar == '&'){if (curChar == '<')m_state = STATE_TAG;else if (curChar == '&')m_state = STATE_ENTITY;if (m_curTokenLen > 0){// Report data token.m_curToken = TOKEN_DATA;return;}else if (curChar == END_OF_STRING || curChar == (int)END_OF_BUFFER){// Just return incomplete token, no data parsed.return;}else{DE_ASSERT(m_state == STATE_TAG || m_state == STATE_ENTITY);continue;}}}else{// Eat all whitespace if present.if (m_curTokenLen == 0){while (isWhitespaceChar(curChar)){m_buf.popBack();curChar = getChar(0);}}// Handle end of string / buffer.if (curChar == END_OF_STRING)error("Unexpected end of string");else if (curChar == (int)END_OF_BUFFER){DE_ASSERT(m_curToken == TOKEN_INCOMPLETE);return;}if (m_curTokenLen == 0){// Expect start of identifier, value or special tag token.if (curChar == '\'' || curChar == '"')m_state = STATE_VALUE;else if (isIdentifierStartChar(curChar))m_state = STATE_IDENTIFIER;else if (curChar == '<' || curChar == '?' || curChar == '/')m_state = STATE_TAG;else if (curChar == '&')DE_ASSERT(m_state == STATE_ENTITY);else if (curChar == '='){m_curToken = TOKEN_EQUAL;m_curTokenLen = 1;return;}else if (curChar == '>'){m_curToken = TOKEN_TAG_END;m_curTokenLen = 1;return;}elseerror("Unexpected character");}else if (m_state == STATE_IDENTIFIER){if (!isIdentifierChar(curChar)){m_curToken = TOKEN_IDENTIFIER;return;}}else if (m_state == STATE_VALUE){// \todo [2012年06月07日 pyry] Escapes.if (curChar == '\'' || curChar == '"'){// \todo [2012年10月17日 pyry] Should we actually do the check against getChar(0)?if (curChar != getChar(0))error("Mismatched quote");m_curToken = TOKEN_STRING;m_curTokenLen += 1;return;}}else if (m_state == STATE_COMMENT){DE_ASSERT(m_curTokenLen >= 2); // 2 characters have been parsed if we are in comment state.if (m_curTokenLen <= 3){if (curChar != '-')error("Invalid comment start");}else{int prev2 = m_curTokenLen > 5 ? getChar(m_curTokenLen-2) : 0;int prev1 = m_curTokenLen > 4 ? getChar(m_curTokenLen-1) : 0;if (prev2 == '-' && prev1 == '-'){if (curChar != '>')error("Invalid comment end");m_curToken = TOKEN_COMMENT;m_curTokenLen += 1;return;}}}else if (m_state == STATE_ENTITY){if (m_curTokenLen >= 1){if (curChar == ';'){m_curToken = TOKEN_ENTITY;m_curTokenLen += 1;return;}else if (!de::inRange<int>(curChar, '0', '9') &&!de::inRange<int>(curChar, 'a', 'z') &&!de::inRange<int>(curChar, 'A', 'Z'))error("Invalid entity");}}else{// Special tokens are at most 2 characters.DE_ASSERT(m_state == STATE_TAG && m_curTokenLen == 1);int prevChar = getChar(m_curTokenLen-1);if (prevChar == '<'){// Tag start.if (curChar == '/'){m_curToken = TOKEN_END_TAG_START;m_curTokenLen = 2;return;}else if (curChar == '?'){m_curToken = TOKEN_PROCESSING_INSTRUCTION_START;m_curTokenLen = 2;return;}else if (curChar == '!'){m_state = STATE_COMMENT;}else{m_curToken = TOKEN_TAG_START;m_curTokenLen = 1;return;}}else if (prevChar == '?'){if (curChar != '>')error("Invalid processing instruction end");m_curToken = TOKEN_PROCESSING_INSTRUCTION_END;m_curTokenLen = 2;return;}else if (prevChar == '/'){if (curChar != '>')error("Invalid empty element end");m_curToken = TOKEN_EMPTY_ELEMENT_END;m_curTokenLen = 2;return;}elseerror("Could not parse special token");}}m_curTokenLen += 1;curChar = getChar(m_curTokenLen);}}void Tokenizer::getString (std::string& dst) const{DE_ASSERT(m_curToken == TOKEN_STRING);dst.resize(m_curTokenLen-2);for (int ndx = 0; ndx < m_curTokenLen-2; ndx++)dst[ndx] = m_buf.peekBack(ndx+1);}Parser::Parser (void): m_element (ELEMENT_INCOMPLETE), m_state (STATE_DATA){}Parser::~Parser (void){}void Parser::clear (void){m_tokenizer.clear();m_elementName.clear();m_attributes.clear();m_attribName.clear();m_entityValue.clear();m_element = ELEMENT_INCOMPLETE;m_state = STATE_DATA;}void Parser::error (const std::string& what){throw ParseError(what);}void Parser::feed (const deUint8* bytes, int numBytes){m_tokenizer.feed(bytes, numBytes);if (m_element == ELEMENT_INCOMPLETE)advance();}void Parser::advance (void){if (m_element == ELEMENT_START)m_attributes.clear();// \note No token is advanced when element end is reported.if (m_state == STATE_YIELD_EMPTY_ELEMENT_END){DE_ASSERT(m_element == ELEMENT_START);m_element = ELEMENT_END;m_state = STATE_DATA;return;}if (m_element != ELEMENT_INCOMPLETE){m_tokenizer.advance();m_element = ELEMENT_INCOMPLETE;}for (;;){Token curToken = m_tokenizer.getToken();// Skip comments.while (curToken == TOKEN_COMMENT){m_tokenizer.advance();curToken = m_tokenizer.getToken();}if (curToken == TOKEN_INCOMPLETE){DE_ASSERT(m_element == ELEMENT_INCOMPLETE);return;}switch (m_state){case STATE_ENTITY:m_state = STATE_DATA;// Fall-through to STATE_DATA processing.case STATE_DATA:switch (curToken){case TOKEN_DATA:m_element = ELEMENT_DATA;return;case TOKEN_END_OF_STRING:m_element = ELEMENT_END_OF_STRING;return;case TOKEN_TAG_START:m_state = STATE_START_TAG_OPEN;break;case TOKEN_END_TAG_START:m_state = STATE_END_TAG_OPEN;break;case TOKEN_PROCESSING_INSTRUCTION_START:m_state = STATE_IN_PROCESSING_INSTRUCTION;break;case TOKEN_ENTITY:m_state = STATE_ENTITY;m_element = ELEMENT_DATA;parseEntityValue();return;default:error("Unexpected token");}break;case STATE_IN_PROCESSING_INSTRUCTION:if (curToken == TOKEN_PROCESSING_INSTRUCTION_END)m_state = STATE_DATA;elseif (curToken != TOKEN_IDENTIFIER && curToken != TOKEN_EQUAL && curToken != TOKEN_STRING)error("Unexpected token in processing instruction");break;case STATE_START_TAG_OPEN:if (curToken != TOKEN_IDENTIFIER)error("Expected identifier");m_tokenizer.getTokenStr(m_elementName);m_state = STATE_ATTRIBUTE_LIST;break;case STATE_END_TAG_OPEN:if (curToken != TOKEN_IDENTIFIER)error("Expected identifier");m_tokenizer.getTokenStr(m_elementName);m_state = STATE_EXPECTING_END_TAG_CLOSE;break;case STATE_EXPECTING_END_TAG_CLOSE:if (curToken != TOKEN_TAG_END)error("Expected tag end");m_state = STATE_DATA;m_element = ELEMENT_END;return;case STATE_ATTRIBUTE_LIST:if (curToken == TOKEN_IDENTIFIER){m_tokenizer.getTokenStr(m_attribName);m_state = STATE_EXPECTING_ATTRIBUTE_EQ;}else if (curToken == TOKEN_EMPTY_ELEMENT_END){m_state = STATE_YIELD_EMPTY_ELEMENT_END;m_element = ELEMENT_START;return;}else if (curToken == TOKEN_TAG_END){m_state = STATE_DATA;m_element = ELEMENT_START;return;}elseerror("Unexpected token");break;case STATE_EXPECTING_ATTRIBUTE_EQ:if (curToken != TOKEN_EQUAL)error("Expected '='");m_state = STATE_EXPECTING_ATTRIBUTE_VALUE;break;case STATE_EXPECTING_ATTRIBUTE_VALUE:if (curToken != TOKEN_STRING)error("Expected value");if (hasAttribute(m_attribName.c_str()))error("Duplicate attribute");m_tokenizer.getString(m_attributes[m_attribName]);m_state = STATE_ATTRIBUTE_LIST;break;default:DE_ASSERT(false);}m_tokenizer.advance();}}static char getEntityValue (const std::string& entity){static const struct{const char* name;char value;} s_entities[] ={{ "<", '<' },{ ">", '>' },{ "&", '&' },{ "'", '\''},{ """, '"' },};for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(s_entities); ndx++){if (entity == s_entities[ndx].name)return s_entities[ndx].value;}return 0;}void Parser::parseEntityValue (void){DE_ASSERT(m_state == STATE_ENTITY && m_tokenizer.getToken() == TOKEN_ENTITY);std::string entity;m_tokenizer.getTokenStr(entity);const char value = getEntityValue(entity);if (value == 0)error("Invalid entity '" + entity + "'");m_entityValue.resize(1);m_entityValue[0] = value;}} // xml} // xe
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。