diff options
| author | Tatsuhiro Tsujikawa <tatsuhiro.t@gmail.com> | 2012-07-10 01:42:42 +0900 |
|---|---|---|
| committer | Tatsuhiro Tsujikawa <tatsuhiro.t@gmail.com> | 2012-07-10 01:42:42 +0900 |
| commit | 57b46d5123084a42a2936e9014a43115d0dc070f (patch) | |
| tree | 2b20f73adab6854856ccd1c63d5aafc1ef05a913 /src | |
| parent | c7131c14fe0b65975a880956ea3569d873305e64 (diff) | |
Added streaming parser for structured data format.
Added JSON streaming parser. Note that currently JSON parser ignores
frac and exp parts of number construct.
Diffstat (limited to 'src')
| -rw-r--r-- | src/GenericParser.h | 86 | ||||
| -rw-r--r-- | src/JsonParser.cc | 747 | ||||
| -rw-r--r-- | src/JsonParser.h | 119 | ||||
| -rw-r--r-- | src/Makefile.am | 6 | ||||
| -rw-r--r-- | src/StructParserStateMachine.h | 70 | ||||
| -rw-r--r-- | src/ValueBaseJsonParser.h | 53 | ||||
| -rw-r--r-- | src/ValueBaseStructParserState.h | 57 | ||||
| -rw-r--r-- | src/ValueBaseStructParserStateImpl.cc | 139 | ||||
| -rw-r--r-- | src/ValueBaseStructParserStateImpl.h | 158 | ||||
| -rw-r--r-- | src/ValueBaseStructParserStateMachine.cc | 225 | ||||
| -rw-r--r-- | src/ValueBaseStructParserStateMachine.h | 116 | ||||
| -rw-r--r-- | src/XmlRpcRequestParserController.cc | 9 | ||||
| -rw-r--r-- | src/XmlRpcRequestParserController.h | 8 |
13 files changed, 1793 insertions, 0 deletions
diff --git a/src/GenericParser.h b/src/GenericParser.h new file mode 100644 index 00000000..77985f69 --- /dev/null +++ b/src/GenericParser.h @@ -0,0 +1,86 @@ +/* <!-- copyright */ +/* + * aria2 - The high speed download utility + * + * Copyright (C) 2012 Tatsuhiro Tsujikawa + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * In addition, as a special exception, the copyright holders give + * permission to link the code of portions of this program with the + * OpenSSL library under certain conditions as described in each + * individual source file, and distribute linked combinations + * including the two. + * You must obey the GNU General Public License in all respects + * for all of the code used other than OpenSSL. If you modify + * file(s) with this exception, you may extend this exception to your + * version of the file(s), but you are not obligated to do so. If you + * do not wish to do so, delete this exception statement from your + * version. If you delete this exception statement from all source + * files in the program, then also delete it here. + */ +/* copyright --> */ +#ifndef D_GENERIC_PARSER_H +#define D_GENERIC_PARSER_H + +#include "common.h" +#include "SharedHandle.h" + +namespace aria2 { + +template<typename Parser, typename ParserStateMachine> +class GenericParser { +public: + GenericParser() + : parser_(&psm_) + {} + + ~GenericParser() + {} + + // Parses |size| bytes of data |data| and returns the number of + // bytes processed. On error, one of the negative error codes is + // returned. + ssize_t parseUpdate(const char* data, size_t size) + { + return parser_.parseUpdate(data, size); + } + + // Parses |size| bytes of data |data| and returns result. On error, + // null value is returned. On success, the |error| will be the + // number of bytes processed (>= 0). On error, it will be one of the + // negative error code. This function also resets underlying parser + // facility and make it ready to reuse. + typename ParserStateMachine::ResultType + parseFinal(const char* data, size_t size, ssize_t& error) + { + typename ParserStateMachine::ResultType res; + error = parser_.parseFinal(data, size); + if(error < 0) { + res = ParserStateMachine::noResult; + } else { + res = psm_.getResult(); + } + parser_.reset(); + return res; + } +private: + ParserStateMachine psm_; + Parser parser_; +}; + +} // namespace aria2 + +#endif // D_GENERIC_PARSER_H diff --git a/src/JsonParser.cc b/src/JsonParser.cc new file mode 100644 index 00000000..59d98aec --- /dev/null +++ b/src/JsonParser.cc @@ -0,0 +1,747 @@ +/* <!-- copyright */ +/* + * aria2 - The high speed download utility + * + * Copyright (C) 2012 Tatsuhiro Tsujikawa + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * In addition, as a special exception, the copyright holders give + * permission to link the code of portions of this program with the + * OpenSSL library under certain conditions as described in each + * individual source file, and distribute linked combinations + * including the two. + * You must obey the GNU General Public License in all respects + * for all of the code used other than OpenSSL. If you modify + * file(s) with this exception, you may extend this exception to your + * version of the file(s), but you are not obligated to do so. If you + * do not wish to do so, delete this exception statement from your + * version. If you delete this exception statement from all source + * files in the program, then also delete it here. + */ +/* copyright --> */ +#include "JsonParser.h" +#include "StructParserStateMachine.h" + +#include "util.h" + +namespace aria2 { + +namespace json { + +namespace { +enum { + JSON_FINISH, + JSON_ERROR, + JSON_VALUE, + JSON_OBJECT_KEY, + JSON_OBJECT_VAL, + JSON_OBJECT_SEP, + JSON_ARRAY, + JSON_ARRAY_SEP, + JSON_STRING, + JSON_STRING_ESCAPE, + JSON_STRING_UNICODE, + JSON_STRING_LOW_SURROGATE_ESCAPE, + JSON_STRING_LOW_SURROGATE_U, + JSON_STRING_LOW_SURROGATE, + JSON_NUMBER, + JSON_NUMBER_FRAC, + JSON_NUMBER_EXP_SIGN, + JSON_NUMBER_EXP, + JSON_TRUE, + JSON_FALSE, + JSON_NULL +}; +} // namespace + +namespace { +const char JSON_TRUE_STR[] = "true"; +const char JSON_FALSE_STR[] = "false"; +const char JSON_NULL_STR[] = "null"; +} // namespace + +JsonParser::JsonParser(StructParserStateMachine* psm) + : psm_(psm), + currentState_(JSON_VALUE), + codepoint_(0), + codepoint2_(0), + numberSign_(1), + number_(0), + frac_(0), + expSign_(1), + exp_(0), + numConsumed_(0), + lastError_(0) +{ + stateStack_.push(JSON_FINISH); +} + +JsonParser::~JsonParser() +{} + +namespace { +bool isSpace(char c) +{ + return util::isLws(c) || util::isCRLF(c); +} +} // namespace + +ssize_t JsonParser::parseUpdate(const char* data, size_t size) +{ + size_t i; + if(currentState_ == JSON_FINISH) { + return 0; + } else if(currentState_ == JSON_ERROR) { + return lastError_; + } + for(i = 0; i < size; ++i) { + char c = data[i]; + switch(currentState_) { + case JSON_ARRAY: + if(c == ']') { + onArrayEnd(); + break; + } else if(isSpace(c)) { + break; + } else { + pushState(currentState_); + currentState_ = JSON_VALUE; + runBeginCallback(STRUCT_ARRAY_DATA_T); + } + // Fall through + case JSON_VALUE: + switch(c) { + case '{': + currentState_ = JSON_OBJECT_KEY; + runBeginCallback(STRUCT_DICT_T); + break; + case'[': + currentState_ = JSON_ARRAY; + runBeginCallback(STRUCT_ARRAY_T); + break; + case '"': + currentState_ = JSON_STRING; + runBeginCallback(STRUCT_STRING_T); + break; + case '-': + number_ = 0; + numberSign_ = -1; + numConsumed_ = 0; + currentState_ = JSON_NUMBER; + runBeginCallback(STRUCT_NUMBER_T); + break; + case 't': + numConsumed_ = 1; + currentState_ = JSON_TRUE; + runBeginCallback(STRUCT_BOOL_T); + break; + case 'f': + numConsumed_ = 1; + currentState_ = JSON_FALSE; + runBeginCallback(STRUCT_BOOL_T); + break; + case 'n': + numConsumed_ = 1; + currentState_ = JSON_NULL; + runBeginCallback(STRUCT_NULL_T); + break; + default: + if(util::isDigit(c)) { + number_ = c - '0'; + numberSign_ = 1; + numConsumed_ = 1; + currentState_ = JSON_NUMBER; + runBeginCallback(STRUCT_NUMBER_T); + } else if(!isSpace(c)) { + currentState_ = JSON_ERROR; + return lastError_ = ERR_UNEXPECTED_CHAR_BEFORE_VAL; + } + } + break; + case JSON_TRUE: + if(JSON_TRUE_STR[numConsumed_] == c) { + ++numConsumed_; + if(numConsumed_ == sizeof(JSON_TRUE_STR)-1) { + runBoolCallback(true); + onBoolEnd(); + } + } else { + currentState_ = JSON_ERROR; + return lastError_ = ERR_UNEXPECTED_LITERAL; + } + break; + case JSON_FALSE: + if(JSON_FALSE_STR[numConsumed_] == c) { + ++numConsumed_; + if(numConsumed_ == sizeof(JSON_FALSE_STR)-1) { + runBoolCallback(false); + onBoolEnd(); + } + } else { + currentState_ = JSON_ERROR; + return lastError_ = ERR_UNEXPECTED_LITERAL; + } + break; + case JSON_NULL: + if(JSON_NULL_STR[numConsumed_] == c) { + ++numConsumed_; + if(numConsumed_ == sizeof(JSON_NULL_STR)-1) { + onNullEnd(); + } + } else { + currentState_ = JSON_ERROR; + return lastError_ = ERR_UNEXPECTED_LITERAL; + } + break; + case JSON_OBJECT_KEY: + switch(c) { + case '"': + pushState(currentState_); + currentState_ = JSON_STRING; + runBeginCallback(STRUCT_DICT_KEY_T); + break; + case '}': + onObjectEnd(); + break; + default: + if(!isSpace(c)) { + currentState_ = JSON_ERROR; + return lastError_ = ERR_UNEXPECTED_CHAR_BEFORE_OBJ_KEY; + } + } + break; + + case JSON_OBJECT_VAL: + switch(c) { + case ':': + pushState(currentState_); + currentState_ = JSON_VALUE; + runBeginCallback(STRUCT_DICT_DATA_T); + break; + default: + if(!isSpace(c)) { + currentState_ = JSON_ERROR; + return lastError_ = ERR_UNEXPECTED_CHAR_BEFORE_OBJ_VAL; + } + } + break; + case JSON_OBJECT_SEP: + switch(c) { + case ',': + currentState_ = JSON_OBJECT_KEY; + break; + case '}': + onObjectEnd(); + break; + default: + if(!isSpace(c)) { + currentState_ = JSON_ERROR; + return lastError_ = ERR_UNEXPECTED_CHAR_BEFORE_OBJ_SEP; + } + } + break; + case JSON_ARRAY_SEP: + switch(c) { + case ',': + pushState(JSON_ARRAY); + currentState_ = JSON_VALUE; + runBeginCallback(STRUCT_ARRAY_DATA_T); + break; + case ']': + onArrayEnd(); + break; + default: + if(!isSpace(c)) { + currentState_ = JSON_ERROR; + return lastError_ = ERR_UNEXPECTED_CHAR_BEFORE_ARRAY_SEP; + } + } + break; + case JSON_STRING: + switch(c) { + case '"': + onStringEnd(); + break; + case '\\': + currentState_ = JSON_STRING_ESCAPE; + break; + default: { + size_t j; + for(j = i; j < size && data[j] != '\\' && data[j] != '"'; ++j); + if(j - i >= 1) { + runCharactersCallback(&data[i], j - i); + } + i = j - 1; + break; + } + } + break; + case JSON_STRING_ESCAPE: + switch(c) { + case 'u': + codepoint_ = 0; + numConsumed_ = 0; + currentState_ = JSON_STRING_UNICODE; + break; + default: + switch(c) { + case 'b': + runCharactersCallback("\b", 1); + break; + case 'f': + runCharactersCallback("\f", 1); + break; + case 'n': + runCharactersCallback("\n", 1); + break; + case 'r': + runCharactersCallback("\r", 1); + break; + case 't': + runCharactersCallback("\t", 1); + break; + default: { + char temp[1]; + temp[0] = c; + runCharactersCallback(temp, 1); + break; + } + } + currentState_ = JSON_STRING; + } + break; + case JSON_STRING_UNICODE: { + size_t j; + for(j = i; j < size && currentState_ == JSON_STRING_UNICODE; ++j) { + if(util::isHexDigit(data[j])) { + consumeUnicode(data[j]); + } else { + currentState_ = JSON_ERROR; + return lastError_ = ERR_INVALID_UNICODE_POINT; + } + } + i = j - 1; + break; + } + case JSON_STRING_LOW_SURROGATE_ESCAPE: + switch(c) { + case '\\': + currentState_ = JSON_STRING_LOW_SURROGATE_U; + break; + default: + currentState_ = JSON_ERROR; + return lastError_ = ERR_INVALID_UNICODE_POINT; + } + break; + case JSON_STRING_LOW_SURROGATE_U: + switch(c) { + case 'u': + codepoint2_ = 0; + numConsumed_ = 0; + currentState_ = JSON_STRING_LOW_SURROGATE; + break; + default: + currentState_ = JSON_ERROR; + return lastError_ = ERR_INVALID_UNICODE_POINT; + } + break; + case JSON_STRING_LOW_SURROGATE: { + size_t j; + for(j = i; j < size && currentState_ == JSON_STRING_LOW_SURROGATE; ++j) { + if(util::isHexDigit(data[j])) { + int rv = consumeLowSurrogate(data[j]); + if(rv != 0) { + currentState_ = JSON_ERROR; + lastError_ = rv; + return rv; + } + } else { + currentState_ = JSON_ERROR; + return lastError_ = ERR_INVALID_UNICODE_POINT; + } + } + i = j - 1; + break; + } + case JSON_NUMBER: { + size_t j; + for(j = i; j < size && in(data[j], '0', '9'); ++j) { + if((INT64_MAX - (data[j] - '0'))/ 10 < number_) { + currentState_ = JSON_ERROR; + return lastError_ = ERR_NUMBER_OUT_OF_RANGE; + } + number_ *= 10; + number_ += data[j] - '0'; + } + numConsumed_ += j - i; + if(j != size) { + if(numConsumed_ == 0) { + currentState_ = JSON_ERROR; + return lastError_ = ERR_INVALID_NUMBER; + } + switch(data[j]) { + case '.': + frac_ = 0; + numConsumed_ = 0; + currentState_ = JSON_NUMBER_FRAC; + i = j; + break; + case 'e': + case 'E': + expSign_ = 1; + exp_ = 0; + numConsumed_ = 0; + currentState_ = JSON_NUMBER_EXP_SIGN; + i = j; + break; + default: + onNumberEnd(); + i = j - 1; + } + } else { + i = j - 1; + } + break; + } + case JSON_NUMBER_FRAC: { + size_t j; + for(j = i; j < size && in(data[j], '0', '9'); ++j) { + // Take into account at most 8 digits + if(frac_ < 100000000) { + frac_ *= 10; + frac_ += data[j] - '0'; + } + } + numConsumed_ += j - i; + if(j != size) { + if(numConsumed_ == 0) { + currentState_ = JSON_ERROR; + return lastError_ = ERR_INVALID_NUMBER; + } + switch(data[j]) { + case 'e': + case 'E': + exp_ = 0; + numConsumed_ = 0; + currentState_ = JSON_NUMBER_EXP_SIGN; + i = j; + break; + default: + i = j - 1; + onNumberEnd(); + } + } else { + i = j - 1; + } + break; + } + case JSON_NUMBER_EXP_SIGN: + switch(c) { + case '+': + currentState_ = JSON_NUMBER_EXP; + break; + case '-': + expSign_ = -1; + currentState_ = JSON_NUMBER_EXP; + break; + default: + break; + } + if(currentState_ == JSON_NUMBER_EXP) { + break; + } else { + currentState_ = JSON_NUMBER_EXP; + // Fall through + } + case JSON_NUMBER_EXP: { + size_t j; + for(j = i; j < size && in(data[j], '0', '9'); ++j) { + // Take into account at most 8 digits + exp_ *= 10; + exp_ += data[j] - '0'; + if(exp_ > 18) { + currentState_ = JSON_ERROR; + return lastError_ = ERR_NUMBER_OUT_OF_RANGE; + } + } + numConsumed_ += j - i; + if(j != size) { + if(numConsumed_ == 0) { + currentState_ = JSON_ERROR; + return lastError_ = ERR_INVALID_NUMBER; + } + switch(data[j]) { + default: + onNumberEnd(); + } + } + i = j - 1; + break; + } + } + if(currentState_ == JSON_FINISH) { + break; + } + } + return i; +} + +ssize_t JsonParser::parseFinal(const char* data, size_t len) +{ + ssize_t rv; + rv = parseUpdate(data, len); + if(rv >= 0) { + if(currentState_ != JSON_FINISH) { + rv = ERR_PREMATURE_DATA; + } + } + return rv; +} + +void JsonParser::reset() +{ + psm_->reset(); + currentState_ = JSON_VALUE; + lastError_ = 0; + while(!stateStack_.empty()) { + stateStack_.pop(); + } + stateStack_.push(JSON_FINISH); +} + +void JsonParser::onStringEnd() +{ + runEndCallback(stateTop() == JSON_OBJECT_KEY ? + STRUCT_DICT_KEY_T : STRUCT_STRING_T); + onValueEnd(); +} + +void JsonParser::onNumberEnd() +{ + runNumberCallback(numberSign_ * number_, frac_, expSign_ * exp_); + runEndCallback(STRUCT_NUMBER_T); + onValueEnd(); +} + +void JsonParser::onObjectEnd() +{ + runEndCallback(STRUCT_DICT_T); + onValueEnd(); +} + +void JsonParser::onArrayEnd() +{ + runEndCallback(STRUCT_ARRAY_T); + onValueEnd(); +} + +void JsonParser::onBoolEnd() +{ + runEndCallback(STRUCT_BOOL_T); + onValueEnd(); +} + +void JsonParser::onNullEnd() +{ + runEndCallback(STRUCT_NULL_T); + onValueEnd(); +} + +void JsonParser::onValueEnd() +{ + switch(stateTop()) { + case JSON_OBJECT_KEY: + popState(); + currentState_ = JSON_OBJECT_VAL; + break; + case JSON_OBJECT_VAL: + runEndCallback(STRUCT_DICT_DATA_T); + popState(); + currentState_ = JSON_OBJECT_SEP; + break; + case JSON_ARRAY: + runEndCallback(STRUCT_ARRAY_DATA_T); + popState(); + currentState_ = JSON_ARRAY_SEP; + break; + default: + assert(stateTop() == JSON_FINISH); + currentState_ = stateTop(); + break; + } +} + +void JsonParser::pushState(int state) +{ + stateStack_.push(state); +} + +int JsonParser::stateTop() const +{ + return stateStack_.top(); +} + +int JsonParser::popState() +{ + int state = stateStack_.top(); + stateStack_.pop(); + return state; +} + +void JsonParser::consumeUnicode(char c) +{ + codepoint_ *= 16; + codepoint_ += util::hexCharToUInt(c); + ++numConsumed_; + if(numConsumed_ == 4) { + if(in(codepoint_, 0xD800u, 0xDBFFu)) { + // This is high-surrogate codepoint + currentState_ = JSON_STRING_LOW_SURROGATE_ESCAPE; + } else { + char temp[3]; + size_t len; + if(codepoint_ <= 0x007fu) { + temp[0] = static_cast<char>(codepoint_); + len = 1; + } else if(codepoint_ <= 0x07ffu) { + temp[0] = 0xC0u | (codepoint_ >> 6); + temp[1] = 0x80u | (codepoint_ & 0x003fu); + len = 2; + } else { + temp[0] = 0xE0u | (codepoint_ >> 12); + temp[1] = 0x80u | ((codepoint_ >> 6) & 0x003Fu); + temp[2] = 0x80u | (codepoint_ & 0x003Fu); + len = 3; + } + runCharactersCallback(temp, len); + currentState_ = JSON_STRING; + } + } +} + +int JsonParser::consumeLowSurrogate(char c) +{ + codepoint2_ *= 16; + codepoint2_ += util::hexCharToUInt(c); + ++numConsumed_; + if(numConsumed_ == 4) { + if(!in(codepoint2_, 0xDC00u, 0xDFFFu)) { + return ERR_INVALID_UNICODE_POINT; + } + uint32_t fullcodepoint = 0x010000u; + fullcodepoint += (codepoint_ & 0x03FFu) << 10; + fullcodepoint += (codepoint2_ & 0x03FFu); + char temp[4]; + temp[0] = 0xf0u | (fullcodepoint >> 18); + temp[1] = 0x80u | ((fullcodepoint >> 12) & 0x003Fu); + temp[2] = 0x80u | ((fullcodepoint >> 6) & 0x003Fu); + temp[3] = 0x80u | (fullcodepoint & 0x003Fu); + runCharactersCallback(temp, sizeof(temp)); + currentState_ = JSON_STRING; + } + return 0; +} + +void JsonParser::runBeginCallback(int elementType) +{ + // switch(elementType) { + // case STRUCT_DICT_T: + // std::cout << "object start" << std::endl; + // break; + // case STRUCT_DICT_KEY_T: + // std::cout << "object key start" << std::endl; + // break; + // case STRUCT_DICT_DATA_T: + // std::cout << "object data start" << std::endl; + // break; + // case STRUCT_ARRAY_T: + // std::cout << "array start" << std::endl; + // break; + // case STRUCT_ARRAY_DATA_T: + // std::cout << "array data start" << std::endl; + // break; + // case STRUCT_STRING_T: + // std::cout << "string start" << std::endl; + // break; + // case STRUCT_NUMBER_T: + // std::cout << "number start" << std::endl; + // break; + // case STRUCT_BOOL_T: + // std::cout << "bool start" << std::endl; + // break; + // case STRUCT_NULL_T: + // std::cout << "null start" << std::endl; + // break; + // default: + // break; + // }; + psm_->beginElement(elementType); +} + +void JsonParser::runEndCallback(int elementType) +{ + // switch(elementType) { + // case STRUCT_DICT_T: + // std::cout << "object end" << std::endl; + // break; + // case STRUCT_DICT_KEY_T: + // std::cout << "object key end" << std::endl; + // break; + // case STRUCT_DICT_DATA_T: + // std::cout << "object data end" << std::endl; + // break; + // case STRUCT_ARRAY_T: + // std::cout << "array end" << std::endl; + // break; + // case STRUCT_ARRAY_DATA_T: + // std::cout << "array data end" << std::endl; + // break; + // case STRUCT_STRING_T: + // std::cout << "string end" << std::endl; + // break; + // case STRUCT_NUMBER_T: + // std::cout << "number end" << std::endl; + // break; + // case STRUCT_BOOL_T: + // std::cout << "bool end" << std::endl; + // break; + // case STRUCT_NULL_T: + // std::cout << "null end" << std::endl; + // break; + // default: + // break; + // }; + psm_->endElement(elementType); +} + +void JsonParser::runCharactersCallback(const char* data, size_t len) +{ + psm_->charactersCallback(data, len); +} + +void JsonParser::runNumberCallback(int64_t number, int frac, int exp) +{ + psm_->numberCallback(number, frac, exp); +} + +void JsonParser::runBoolCallback(bool bval) +{ + psm_->boolCallback(bval); +} + +} // namespace json + +} // namespace aria2 diff --git a/src/JsonParser.h b/src/JsonParser.h new file mode 100644 index 00000000..f08546ee --- /dev/null +++ b/src/JsonParser.h @@ -0,0 +1,119 @@ +/* <!-- copyright */ +/* + * aria2 - The high speed download utility + * + * Copyright (C) 2012 Tatsuhiro Tsujikawa + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * In addition, as a special exception, the copyright holders give + * permission to link the code of portions of this program with the + * OpenSSL library under certain conditions as described in each + * individual source file, and distribute linked combinations + * including the two. + * You must obey the GNU General Public License in all respects + * for all of the code used other than OpenSSL. If you modify + * file(s) with this exception, you may extend this exception to your + * version of the file(s), but you are not obligated to do so. If you + * do not wish to do so, delete this exception statement from your + * version. If you delete this exception statement from all source + * files in the program, then also delete it here. + */ +/* copyright --> */ +#ifndef D_JSON_PARSER_H +#define D_JSON_PARSER_H + +#include "common.h" + +#include <stack> + +namespace aria2 { + +class StructParserStateMachine; + +namespace json { + +enum JsonError { + ERR_UNEXPECTED_CHAR_BEFORE_VAL = -1, + ERR_UNEXPECTED_CHAR_BEFORE_OBJ_KEY = -2, + ERR_UNEXPECTED_CHAR_BEFORE_OBJ_VAL = -3, + ERR_UNEXPECTED_CHAR_BEFORE_OBJ_SEP = -4, + ERR_INVALID_UNICODE_POINT = -5, + ERR_INVALID_NUMBER = -6, + ERR_NUMBER_OUT_OF_RANGE = -7, + ERR_UNEXPECTED_CHAR_BEFORE_ARRAY_SEP = -8, + ERR_UNEXPECTED_LITERAL = -9, + ERR_PREMATURE_DATA = -10 +}; + +class JsonParser { +public: + JsonParser(StructParserStateMachine* psm); + ~JsonParser(); + // Parses |size| bytes of data |data| and returns the number of + // bytes processed. On error, one of the negative error codes is + // returned. + ssize_t parseUpdate(const char* data, size_t size); + // Parses |size| bytes of data |data| and returns the number of + // bytes processed. On error, one of the negative error codes is + // returned. Call this function to signal the parser that this is + // the last piece of data. This function does NOT reset the internal + // state. + ssize_t parseFinal(const char* data, size_t size); + // Resets the internal state of the parser and makes it ready for + // reuse. + void reset(); +private: + void pushState(int state); + int stateTop() const; + int popState(); + void runBeginCallback(int elementType); + void runEndCallback(int elementType); + void runCharactersCallback(const char* data, size_t len); + void runNumberCallback(int64_t number, int frac, int exp); + void runBoolCallback(bool bval); + + void onStringEnd(); + void onNumberEnd(); + void onObjectEnd(); + void onArrayEnd(); + void onValueEnd(); + void onBoolEnd(); + void onNullEnd(); + + void consumeUnicode(char c); + int consumeLowSurrogate(char c); + + StructParserStateMachine* psm_; + std::stack<int> stateStack_; + int currentState_; + // Unicode codepoint + uint16_t codepoint_; + // For low-surrogate codepoint + uint16_t codepoint2_; + int numberSign_; + int64_t number_; + int frac_; + int expSign_; + int exp_; + size_t numConsumed_; + int lastError_; +}; + +} // namespace json + +} // namespace aria2 + +#endif // D_JSON_PARSER_H diff --git a/src/Makefile.am b/src/Makefile.am index 04112fe1..ec063a36 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -199,6 +199,12 @@ SRCS = Socket.h\ Triplet.h\ cookie_helper.cc cookie_helper.h\ json.cc json.h\ + JsonParser.cc JsonParser.h\ + StructParserStateMachine.h\ + ValueBaseJsonParser.h\ + ValueBaseStructParserState.h\ + ValueBaseStructParserStateImpl.cc ValueBaseStructParserStateImpl.h\ + ValueBaseStructParserStateMachine.cc ValueBaseStructParserStateMachine.h\ HttpServerBodyCommand.cc HttpServerBodyCommand.h\ RpcRequest.cc RpcRequest.h\ RpcMethod.cc RpcMethod.h\ diff --git a/src/StructParserStateMachine.h b/src/StructParserStateMachine.h new file mode 100644 index 00000000..a30cc4d7 --- /dev/null +++ b/src/StructParserStateMachine.h @@ -0,0 +1,70 @@ +/* <!-- copyright */ +/* + * aria2 - The high speed download utility + * + * Copyright (C) 2012 Tatsuhiro Tsujikawa + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * In addition, as a special exception, the copyright holders give + * permission to link the code of portions of this program with the + * OpenSSL library under certain conditions as described in each + * individual source file, and distribute linked combinations + * including the two. + * You must obey the GNU General Public License in all respects + * for all of the code used other than OpenSSL. If you modify + * file(s) with this exception, you may extend this exception to your + * version of the file(s), but you are not obligated to do so. If you + * do not wish to do so, delete this exception statement from your + * version. If you delete this exception statement from all source + * files in the program, then also delete it here. + */ +/* copyright --> */ +#ifndef D_STRUCT_PARSER_STATE_MACHINE_H +#define D_STRUCT_PARSER_STATE_MACHINE_H + +#include "common.h" + +namespace aria2 { + +enum StructElementType { + STRUCT_DICT_T, + STRUCT_DICT_KEY_T, + STRUCT_DICT_DATA_T, + STRUCT_ARRAY_T, + STRUCT_ARRAY_DATA_T, + STRUCT_STRING_T, + STRUCT_NUMBER_T, + STRUCT_BOOL_T, + STRUCT_NULL_T +}; + +// Interface for streaming parser of structured data format (e.g., +// JSON, Bencode). +class StructParserStateMachine { +public: + virtual ~StructParserStateMachine() {} + + virtual void beginElement(int elementType) = 0; + virtual void endElement(int elementType) = 0; + virtual void reset() = 0; + virtual void charactersCallback(const char* data, size_t len) = 0; + virtual void numberCallback(int64_t number, int frac, int exp) = 0; + virtual void boolCallback(bool bval) = 0; +}; + +} // namespace aria2 + +#endif // D_STRUCT_PARSER_STATE_MACHINE_H diff --git a/src/ValueBaseJsonParser.h b/src/ValueBaseJsonParser.h new file mode 100644 index 00000000..35118211 --- /dev/null +++ b/src/ValueBaseJsonParser.h @@ -0,0 +1,53 @@ +/* <!-- copyright */ +/* + * aria2 - The high speed download utility + * + * Copyright (C) 2012 Tatsuhiro Tsujikawa + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * In addition, as a special exception, the copyright holders give + * permission to link the code of portions of this program with the + * OpenSSL library under certain conditions as described in each + * individual source file, and distribute linked combinations + * including the two. + * You must obey the GNU General Public License in all respects + * for all of the code used other than OpenSSL. If you modify + * file(s) with this exception, you may extend this exception to your + * version of the file(s), but you are not obligated to do so. If you + * do not wish to do so, delete this exception statement from your + * version. If you delete this exception statement from all source + * files in the program, then also delete it here. + */ +/* copyright --> */ +#ifndef D_VALUE_BASE_JSON_PARSER_H +#define D_VALUE_BASE_JSON_PARSER_H + +#include "GenericParser.h" +#include "JsonParser.h" +#include "ValueBaseStructParserStateMachine.h" + +namespace aria2 { + +namespace json { + +typedef GenericParser<JsonParser, ValueBaseStructParserStateMachine> +ValueBaseJsonParser; + +} // namespace json + +} // namespace aria2 + +#endif // D_VALUE_BASE_JSON_PARSER_H diff --git a/src/ValueBaseStructParserState.h b/src/ValueBaseStructParserState.h new file mode 100644 index 00000000..9f00050e --- /dev/null +++ b/src/ValueBaseStructParserState.h @@ -0,0 +1,57 @@ +/* <!-- copyright */ +/* + * aria2 - The high speed download utility + * + * Copyright (C) 2012 Tatsuhiro Tsujikawa + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * In addition, as a special exception, the copyright holders give + * permission to link the code of portions of this program with the + * OpenSSL library under certain conditions as described in each + * individual source file, and distribute linked combinations + * including the two. + * You must obey the GNU General Public License in all respects + * for all of the code used other than OpenSSL. If you modify + * file(s) with this exception, you may extend this exception to your + * version of the file(s), but you are not obligated to do so. If you + * do not wish to do so, delete this exception statement from your + * version. If you delete this exception statement from all source + * files in the program, then also delete it here. + */ +/* copyright --> */ +#ifndef D_VALUE_BASE_STRUCT_PARSER_STATE_H +#define D_VALUE_BASE_STRUCT_PARSER_STATE_H + +#include "common.h" + +namespace aria2 { + +class ValueBaseStructParserStateMachine; + +class ValueBaseStructParserState { +public: + virtual ~ValueBaseStructParserState() {} + + virtual void beginElement(ValueBaseStructParserStateMachine* psm, + int elementType) = 0; + + virtual void endElement(ValueBaseStructParserStateMachine* psm, + int elementType) = 0; +}; + +} // namespace aria2 + +#endif // D_VALUE_BASE_STRUCT_PARSER_STATE_H diff --git a/src/ValueBaseStructParserStateImpl.cc b/src/ValueBaseStructParserStateImpl.cc new file mode 100644 index 00000000..4d62426e --- /dev/null +++ b/src/ValueBaseStructParserStateImpl.cc @@ -0,0 +1,139 @@ +/* <!-- copyright */ +/* + * aria2 - The high speed download utility + * + * Copyright (C) 2012 Tatsuhiro Tsujikawa + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * In addition, as a special exception, the copyright holders give + * permission to link the code of portions of this program with the + * OpenSSL library under certain conditions as described in each + * individual source file, and distribute linked combinations + * including the two. + * You must obey the GNU General Public License in all respects + * for all of the code used other than OpenSSL. If you modify + * file(s) with this exception, you may extend this exception to your + * version of the file(s), but you are not obligated to do so. If you + * do not wish to do so, delete this exception statement from your + * version. If you delete this exception statement from all source + * files in the program, then also delete it here. + */ +/* copyright --> */ +#include "ValueBaseStructParserStateImpl.h" +#include "ValueBaseStructParserStateMachine.h" +#include "ValueBase.h" + +namespace aria2 { + +void ValueValueBaseStructParserState::beginElement +(ValueBaseStructParserStateMachine* psm, int elementType) +{ + switch(elementType) { + case STRUCT_DICT_T: + psm->setCurrentFrameValue(Dict::g()); + psm->pushDictState(); + break; + case STRUCT_ARRAY_T: + psm->setCurrentFrameValue(List::g()); + psm->pushArrayState(); + break; + case STRUCT_STRING_T: + psm->pushStringState(); + break; + case STRUCT_NUMBER_T: + psm->pushNumberState(); + break; + case STRUCT_BOOL_T: + psm->pushBoolState(); + break; + case STRUCT_NULL_T: + psm->pushNullState(); + break; + default: + // Not reachable + assert(0); + } +} + +void DictValueBaseStructParserState::beginElement +(ValueBaseStructParserStateMachine* psm, int elementType) +{ + switch(elementType) { + case STRUCT_DICT_KEY_T: + psm->pushFrame(); + psm->pushDictKeyState(); + break; + case STRUCT_DICT_DATA_T: + psm->pushDictDataState(); + break; + default: + // Not reachable + assert(0); + } +} + +void DictKeyValueBaseStructParserState::endElement +(ValueBaseStructParserStateMachine* psm, int elementType) +{ + psm->setCurrentFrameName(psm->getCharacters()); +} + +void DictDataValueBaseStructParserState::endElement +(ValueBaseStructParserStateMachine* psm, int elementType) +{ + psm->popDictFrame(); +} + +void ArrayValueBaseStructParserState::beginElement +(ValueBaseStructParserStateMachine* psm, int elementType) +{ + assert(elementType == STRUCT_ARRAY_DATA_T); + psm->pushFrame(); + psm->pushArrayDataState(); +} + +void ArrayDataValueBaseStructParserState::endElement +(ValueBaseStructParserStateMachine* psm, int elementType) +{ + psm->popArrayFrame(); +} + +void StringValueBaseStructParserState::endElement +(ValueBaseStructParserStateMachine* psm, int elementType) +{ + psm->setCurrentFrameValue(String::g(psm->getCharacters())); +} + +void NumberValueBaseStructParserState::endElement +(ValueBaseStructParserStateMachine* psm, int elementType) +{ + // TODO Ignore frac and exp + psm->setCurrentFrameValue(Integer::g(psm->getNumber().number)); +} + +void BoolValueBaseStructParserState::endElement +(ValueBaseStructParserStateMachine* psm, int elementType) +{ + psm->setCurrentFrameValue(psm->getBool() ? Bool::gTrue() : Bool::gFalse()); +} + +void NullValueBaseStructParserState::endElement +(ValueBaseStructParserStateMachine* psm, int elementType) +{ + psm->setCurrentFrameValue(Null::g()); +} + +} // namespace aria2 diff --git a/src/ValueBaseStructParserStateImpl.h b/src/ValueBaseStructParserStateImpl.h new file mode 100644 index 00000000..adef7f64 --- /dev/null +++ b/src/ValueBaseStructParserStateImpl.h @@ -0,0 +1,158 @@ +/* <!-- copyright */ +/* + * aria2 - The high speed download utility + * + * Copyright (C) 2012 Tatsuhiro Tsujikawa + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * In addition, as a special exception, the copyright holders give + * permission to link the code of portions of this program with the + * OpenSSL library under certain conditions as described in each + * individual source file, and distribute linked combinations + * including the two. + * You must obey the GNU General Public License in all respects + * for all of the code used other than OpenSSL. If you modify + * file(s) with this exception, you may extend this exception to your + * version of the file(s), but you are not obligated to do so. If you + * do not wish to do so, delete this exception statement from your + * version. If you delete this exception statement from all source + * files in the program, then also delete it here. + */ +/* copyright --> */ +#ifndef D_VALUE_BASE_STRUCT_PARSER_STATE_IMPL_H +#define D_VALUE_BASE_STRUCT_PARSER_STATE_IMPL_H + +#include "ValueBaseStructParserState.h" + +namespace aria2 { + +class ValueValueBaseStructParserState : public ValueBaseStructParserState { +public: + virtual ~ValueValueBaseStructParserState() {} + + virtual void beginElement(ValueBaseStructParserStateMachine* psm, + int elementType); + + virtual void endElement(ValueBaseStructParserStateMachine* psm, + int elementType) + {} +}; + +class DictValueBaseStructParserState : public ValueBaseStructParserState { +public: + virtual ~DictValueBaseStructParserState() {} + + virtual void beginElement(ValueBaseStructParserStateMachine* psm, + int elementType); + + virtual void endElement(ValueBaseStructParserStateMachine* psm, + int elementType) + {} +}; + +class DictKeyValueBaseStructParserState : public ValueBaseStructParserState { +public: + virtual ~DictKeyValueBaseStructParserState() {} + + virtual void beginElement(ValueBaseStructParserStateMachine* psm, + int elementType) + {} + + virtual void endElement(ValueBaseStructParserStateMachine* psm, + int elementType); +}; + +class DictDataValueBaseStructParserState : + public ValueValueBaseStructParserState { +public: + virtual ~DictDataValueBaseStructParserState() {} + + virtual void endElement(ValueBaseStructParserStateMachine* psm, + int elementType); +}; + +class ArrayValueBaseStructParserState : public ValueBaseStructParserState { +public: + virtual ~ArrayValueBaseStructParserState() {} + + virtual void beginElement(ValueBaseStructParserStateMachine* psm, + int elementType); + + virtual void endElement(ValueBaseStructParserStateMachine* psm, + int elementType) + {} +}; + +class ArrayDataValueBaseStructParserState : + public ValueValueBaseStructParserState { +public: + virtual ~ArrayDataValueBaseStructParserState() {} + + virtual void endElement(ValueBaseStructParserStateMachine* psm, + int elementType); +}; + +class StringValueBaseStructParserState : public ValueBaseStructParserState { +public: + virtual ~StringValueBaseStructParserState() {} + + virtual void beginElement(ValueBaseStructParserStateMachine* psm, + int elementType) + {} + + virtual void endElement(ValueBaseStructParserStateMachine* psm, + int elementType); +}; + +class NumberValueBaseStructParserState : public ValueBaseStructParserState { +public: + virtual ~NumberValueBaseStructParserState() {} + + virtual void beginElement(ValueBaseStructParserStateMachine* psm, + int elementType) + {} + + virtual void endElement(ValueBaseStructParserStateMachine* psm, + int elementType); +}; + +class BoolValueBaseStructParserState : public ValueBaseStructParserState { +public: + virtual ~BoolValueBaseStructParserState() {} + + virtual void beginElement(ValueBaseStructParserStateMachine* psm, + int elementType) + {} + + virtual void endElement(ValueBaseStructParserStateMachine* psm, + int elementType); +}; + +class NullValueBaseStructParserState : public ValueBaseStructParserState { +public: + virtual ~NullValueBaseStructParserState() {} + + virtual void beginElement(ValueBaseStructParserStateMachine* psm, + int elementType) + {} + + virtual void endElement(ValueBaseStructParserStateMachine* psm, + int elementType); +}; + +} // namespace aria2 + +#endif // D_VALUE_BASE_STRUCT_PARSER_STATE_IMPL_H diff --git a/src/ValueBaseStructParserStateMachine.cc b/src/ValueBaseStructParserStateMachine.cc new file mode 100644 index 00000000..4a446a15 --- /dev/null +++ b/src/ValueBaseStructParserStateMachine.cc @@ -0,0 +1,225 @@ +/* <!-- copyright */ +/* + * aria2 - The high speed download utility + * + * Copyright (C) 2012 Tatsuhiro Tsujikawa + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * In addition, as a special exception, the copyright holders give + * permission to link the code of portions of this program with the + * OpenSSL library under certain conditions as described in each + * individual source file, and distribute linked combinations + * including the two. + * You must obey the GNU General Public License in all respects + * for all of the code used other than OpenSSL. If you modify + * file(s) with this exception, you may extend this exception to your + * version of the file(s), but you are not obligated to do so. If you + * do not wish to do so, delete this exception statement from your + * version. If you delete this exception statement from all source + * files in the program, then also delete it here. + */ +/* copyright --> */ +#include "ValueBaseStructParserStateMachine.h" + +#include <cstring> + +#include "XmlRpcRequestParserController.h" +#include "ValueBaseStructParserStateImpl.h" +#include "ValueBase.h" + +namespace aria2 { + +namespace { +ValueValueBaseStructParserState* valueState = + new ValueValueBaseStructParserState(); +DictValueBaseStructParserState* dictState = + new DictValueBaseStructParserState(); +DictKeyValueBaseStructParserState* dictKeyState = + new DictKeyValueBaseStructParserState(); +DictDataValueBaseStructParserState* dictDataState = + new DictDataValueBaseStructParserState(); +ArrayValueBaseStructParserState* arrayState = + new ArrayValueBaseStructParserState(); +ArrayDataValueBaseStructParserState* arrayDataState = + new ArrayDataValueBaseStructParserState(); +StringValueBaseStructParserState* stringState = + new StringValueBaseStructParserState(); +NumberValueBaseStructParserState* numberState = + new NumberValueBaseStructParserState(); +BoolValueBaseStructParserState* boolState = + new BoolValueBaseStructParserState(); +NullValueBaseStructParserState* nullState = + new NullValueBaseStructParserState(); +} // namespace + +const SharedHandle<ValueBase> +ValueBaseStructParserStateMachine::noResult = ValueBase::none; + +ValueBaseStructParserStateMachine::ValueBaseStructParserStateMachine() + : ctrl_(new rpc::XmlRpcRequestParserController()) +{ + stateStack_.push(valueState); +} + +ValueBaseStructParserStateMachine::~ValueBaseStructParserStateMachine() +{ + delete ctrl_; +} + +void ValueBaseStructParserStateMachine::reset() +{ + while(!stateStack_.empty()) { + stateStack_.pop(); + } + stateStack_.push(valueState); + ctrl_->reset(); +} + +void ValueBaseStructParserStateMachine::beginElement(int elementType) +{ + stateStack_.top()->beginElement(this, elementType); +} + +void ValueBaseStructParserStateMachine::endElement(int elementType) +{ + stateStack_.top()->endElement(this, elementType); + stateStack_.pop(); +} + +SharedHandle<ValueBase> +ValueBaseStructParserStateMachine::getResult() const +{ + return getCurrentFrameValue(); +} + +void ValueBaseStructParserStateMachine::charactersCallback +(const char* data, size_t len) +{ + sessionData_.str.append(data, len); +} + +void ValueBaseStructParserStateMachine::numberCallback +(int64_t number, int frac, int exp) +{ + sessionData_.number.number = number; + sessionData_.number.frac = frac; + sessionData_.number.exp = exp; +} + +void ValueBaseStructParserStateMachine::boolCallback(bool bval) +{ + sessionData_.bval = bval; +} + +const std::string& ValueBaseStructParserStateMachine::getCharacters() const +{ + return sessionData_.str; +} + +const ValueBaseStructParserStateMachine::NumberData& +ValueBaseStructParserStateMachine::getNumber() const +{ + return sessionData_.number; +} + +bool ValueBaseStructParserStateMachine::getBool() const +{ + return sessionData_.bval; +} + +void ValueBaseStructParserStateMachine::popArrayFrame() +{ + ctrl_->popArrayFrame(); +} + +void ValueBaseStructParserStateMachine::popDictFrame() +{ + ctrl_->popStructFrame(); +} + +void ValueBaseStructParserStateMachine::pushFrame() +{ + ctrl_->pushFrame(); +} + +void ValueBaseStructParserStateMachine::setCurrentFrameValue +(const SharedHandle<ValueBase>& value) +{ + ctrl_->setCurrentFrameValue(value); +} + +const SharedHandle<ValueBase>& +ValueBaseStructParserStateMachine::getCurrentFrameValue() const +{ + return ctrl_->getCurrentFrameValue(); +} + +void ValueBaseStructParserStateMachine::setCurrentFrameName +(const std::string& name) +{ + ctrl_->setCurrentFrameName(name); +} + +void ValueBaseStructParserStateMachine::pushDictState() +{ + stateStack_.push(dictState); +} + +void ValueBaseStructParserStateMachine::pushDictKeyState() +{ + sessionData_.str.clear(); + stateStack_.push(dictKeyState); +} + +void ValueBaseStructParserStateMachine::pushDictDataState() +{ + stateStack_.push(dictDataState); +} + +void ValueBaseStructParserStateMachine::pushArrayState() +{ + stateStack_.push(arrayState); +} + +void ValueBaseStructParserStateMachine::pushArrayDataState() +{ + stateStack_.push(arrayDataState); +} + +void ValueBaseStructParserStateMachine::pushStringState() +{ + sessionData_.str.clear(); + stateStack_.push(stringState); +} + +void ValueBaseStructParserStateMachine::pushNumberState() +{ + memset(&sessionData_.number, 0, sizeof(sessionData_.number)); + stateStack_.push(numberState); +} + +void ValueBaseStructParserStateMachine::pushBoolState() +{ + sessionData_.bval = false; + stateStack_.push(boolState); +} + +void ValueBaseStructParserStateMachine::pushNullState() +{ + stateStack_.push(nullState); +} + +} // namespace aria2 diff --git a/src/ValueBaseStructParserStateMachine.h b/src/ValueBaseStructParserStateMachine.h new file mode 100644 index 00000000..30143181 --- /dev/null +++ b/src/ValueBaseStructParserStateMachine.h @@ -0,0 +1,116 @@ +/* <!-- copyright */ +/* + * aria2 - The high speed download utility + * + * Copyright (C) 2012 Tatsuhiro Tsujikawa + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * In addition, as a special exception, the copyright holders give + * permission to link the code of portions of this program with the + * OpenSSL library under certain conditions as described in each + * individual source file, and distribute linked combinations + * including the two. + * You must obey the GNU General Public License in all respects + * for all of the code used other than OpenSSL. If you modify + * file(s) with this exception, you may extend this exception to your + * version of the file(s), but you are not obligated to do so. If you + * do not wish to do so, delete this exception statement from your + * version. If you delete this exception statement from all source + * files in the program, then also delete it here. + */ +/* copyright --> */ +#ifndef D_VALUE_BASE_STRUCT_PARSER_STATE_MACHINE_H +#define D_VALUE_BASE_STRUCT_PARSER_STATE_MACHINE_H + +#include "StructParserStateMachine.h" + +#include <string> +#include <stack> + +#include "SharedHandle.h" + +namespace aria2 { + +class ValueBase; + +namespace rpc { +class XmlRpcRequestParserController; +} // namespace rpc; + +class ValueBaseStructParserState; + +// Implementation of StructParserStateMachine, using ValueBase as +// value holder. +class ValueBaseStructParserStateMachine : public StructParserStateMachine { +public: + typedef SharedHandle<ValueBase> ResultType; + static const SharedHandle<ValueBase> noResult; + + struct NumberData { + int64_t number; + int frac; + int exp; + }; + + struct SessionData { + std::string str; + NumberData number; + bool bval; + }; + + ValueBaseStructParserStateMachine(); + virtual ~ValueBaseStructParserStateMachine(); + + virtual void beginElement(int elementType); + virtual void endElement(int elementType); + + virtual void charactersCallback(const char* data, size_t len); + virtual void numberCallback(int64_t number, int frac, int exp); + virtual void boolCallback(bool bval); + + SharedHandle<ValueBase> getResult() const; + + virtual void reset(); + + const std::string& getCharacters() const; + const NumberData& getNumber() const; + bool getBool() const; + + void popArrayFrame(); + void popDictFrame(); + void pushFrame(); + void setCurrentFrameValue(const SharedHandle<ValueBase>& value); + const SharedHandle<ValueBase>& getCurrentFrameValue() const; + void setCurrentFrameName(const std::string& name); + + void pushDictState(); + void pushDictKeyState(); + void pushDictDataState(); + void pushArrayState(); + void pushArrayDataState(); + void pushStringState(); + void pushNumberState(); + void pushBoolState(); + void pushNullState(); +private: + rpc::XmlRpcRequestParserController* ctrl_; + std::stack<ValueBaseStructParserState*> stateStack_; + SessionData sessionData_; +}; + +} // namespace aria2 + +#endif // D_VALUE_BASE_STRUCT_PARSER_STATE_MACHINE_H diff --git a/src/XmlRpcRequestParserController.cc b/src/XmlRpcRequestParserController.cc index 6c9a543f..957766aa 100644 --- a/src/XmlRpcRequestParserController.cc +++ b/src/XmlRpcRequestParserController.cc @@ -92,6 +92,15 @@ XmlRpcRequestParserController::getCurrentFrameValue() const return currentFrame_.value_; } +void XmlRpcRequestParserController::reset() +{ + while(!frameStack_.empty()) { + frameStack_.pop(); + } + currentFrame_.reset(); + methodName_.clear(); +} + } // namespace rpc } // namespace aria2 diff --git a/src/XmlRpcRequestParserController.h b/src/XmlRpcRequestParserController.h index c89b596e..099e4c77 100644 --- a/src/XmlRpcRequestParserController.h +++ b/src/XmlRpcRequestParserController.h @@ -57,6 +57,12 @@ private: { return value_ && !name_.empty(); } + + void reset() + { + value_.reset(); + name_.clear(); + } }; std::stack<StateFrame> frameStack_; @@ -87,6 +93,8 @@ public: } const std::string& getMethodName() const { return methodName_; } + + void reset(); }; } // namespace rpc |
