mirror of https://github.com/aria2/aria2
Added streaming parser for structured data format.
Added JSON streaming parser. Note that currently JSON parser ignores frac and exp parts of number construct.pull/25/merge
parent
c7131c14fe
commit
57b46d5123
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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\
|
||||
|
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -74,6 +74,7 @@ aria2c_SOURCES = AllTest.cc\
|
|||
TripletTest.cc\
|
||||
CookieHelperTest.cc\
|
||||
JsonTest.cc\
|
||||
ValueBaseJsonParserTest.cc\
|
||||
RpcResponseTest.cc\
|
||||
RpcMethodTest.cc\
|
||||
BufferedFileTest.cc\
|
||||
|
|
|
@ -0,0 +1,293 @@
|
|||
#include "ValueBaseJsonParser.h"
|
||||
|
||||
#include <cppunit/extensions/HelperMacros.h>
|
||||
|
||||
#include "RecoverableException.h"
|
||||
#include "array_fun.h"
|
||||
#include "ValueBase.h"
|
||||
|
||||
namespace aria2 {
|
||||
|
||||
class ValueBaseJsonParserTest:public CppUnit::TestFixture {
|
||||
|
||||
CPPUNIT_TEST_SUITE(ValueBaseJsonParserTest);
|
||||
CPPUNIT_TEST(testParseUpdate);
|
||||
CPPUNIT_TEST(testParseUpdate_error);
|
||||
CPPUNIT_TEST_SUITE_END();
|
||||
private:
|
||||
|
||||
public:
|
||||
void testParseUpdate();
|
||||
void testParseUpdate_error();
|
||||
};
|
||||
|
||||
CPPUNIT_TEST_SUITE_REGISTRATION( ValueBaseJsonParserTest );
|
||||
|
||||
void ValueBaseJsonParserTest::testParseUpdate()
|
||||
{
|
||||
json::ValueBaseJsonParser parser;
|
||||
ssize_t error;
|
||||
{
|
||||
// empty object
|
||||
std::string src = "{}";
|
||||
SharedHandle<ValueBase> r = parser.parseFinal(src.c_str(), src.size(),
|
||||
error);
|
||||
const Dict* dict = downcast<Dict>(r);
|
||||
CPPUNIT_ASSERT(dict);
|
||||
}
|
||||
{
|
||||
// empty object
|
||||
std::string src = "{ }";
|
||||
SharedHandle<ValueBase> r = parser.parseFinal(src.c_str(), src.size(),
|
||||
error);
|
||||
const Dict* dict = downcast<Dict>(r);
|
||||
CPPUNIT_ASSERT(dict);
|
||||
}
|
||||
{
|
||||
// empty array
|
||||
std::string src = "[]";
|
||||
SharedHandle<ValueBase> r = parser.parseFinal(src.c_str(), src.size(),
|
||||
error);
|
||||
const List* list = downcast<List>(r);
|
||||
CPPUNIT_ASSERT(list);
|
||||
}
|
||||
{
|
||||
// empty array
|
||||
std::string src = "[ ]";
|
||||
SharedHandle<ValueBase> r = parser.parseFinal(src.c_str(), src.size(),
|
||||
error);
|
||||
const List* list = downcast<List>(r);
|
||||
CPPUNIT_ASSERT(list);
|
||||
}
|
||||
{
|
||||
// empty string
|
||||
std::string src = "[\"\"]";
|
||||
SharedHandle<ValueBase> r = parser.parseFinal(src.c_str(), src.size(),
|
||||
error);
|
||||
const List* list = downcast<List>(r);
|
||||
CPPUNIT_ASSERT(list);
|
||||
const String* s = downcast<String>(list->get(0));
|
||||
CPPUNIT_ASSERT_EQUAL(std::string(), s->s());
|
||||
}
|
||||
{
|
||||
// string
|
||||
std::string src = "[\"foobar\"]";
|
||||
SharedHandle<ValueBase> r = parser.parseFinal(src.c_str(), src.size(),
|
||||
error);
|
||||
const List* list = downcast<List>(r);
|
||||
CPPUNIT_ASSERT(list);
|
||||
const String* s = downcast<String>(list->get(0));
|
||||
CPPUNIT_ASSERT_EQUAL(std::string("foobar"), s->s());
|
||||
}
|
||||
{
|
||||
// string with escape
|
||||
std::string src = "[\"\\\\foo\\\"\\\"bar\"]";
|
||||
SharedHandle<ValueBase> r = parser.parseFinal(src.c_str(), src.size(),
|
||||
error);
|
||||
const List* list = downcast<List>(r);
|
||||
CPPUNIT_ASSERT(list);
|
||||
const String* s = downcast<String>(list->get(0));
|
||||
CPPUNIT_ASSERT_EQUAL(std::string("\\foo\"\"bar"), s->s());
|
||||
}
|
||||
{
|
||||
// string with escape
|
||||
std::string src = "[\"foo\\\"\"]";
|
||||
SharedHandle<ValueBase> r = parser.parseFinal(src.c_str(), src.size(),
|
||||
error);
|
||||
const List* list = downcast<List>(r);
|
||||
CPPUNIT_ASSERT(list);
|
||||
const String* s = downcast<String>(list->get(0));
|
||||
CPPUNIT_ASSERT_EQUAL(std::string("foo\""), s->s());
|
||||
}
|
||||
{
|
||||
// string: utf-8 1 to 3 bytes.
|
||||
std::string src = "[\"\\u0024\\u00A2\\u20AC\"]";
|
||||
SharedHandle<ValueBase> r = parser.parseFinal(src.c_str(), src.size(),
|
||||
error);
|
||||
const List* list = downcast<List>(r);
|
||||
CPPUNIT_ASSERT(list);
|
||||
const String* s = downcast<String>(list->get(0));
|
||||
CPPUNIT_ASSERT_EQUAL(std::string("$¢€"), s->s());
|
||||
}
|
||||
{
|
||||
// string: utf-8 4 bytes
|
||||
std::string src = "[\"\\uD852\\uDF62\"]";
|
||||
SharedHandle<ValueBase> r = parser.parseFinal(src.c_str(), src.size(),
|
||||
error);
|
||||
const List* list = downcast<List>(r);
|
||||
CPPUNIT_ASSERT(list);
|
||||
const String* s = downcast<String>(list->get(0));
|
||||
const unsigned char arr[] = { 0xF0u, 0xA4u, 0xADu, 0xA2u };
|
||||
CPPUNIT_ASSERT_EQUAL(std::string(vbegin(arr), vend(arr)), s->s());
|
||||
}
|
||||
{
|
||||
// null
|
||||
std::string src = "[null]";
|
||||
SharedHandle<ValueBase> r = parser.parseFinal(src.c_str(), src.size(),
|
||||
error);
|
||||
const List* list = downcast<List>(r);
|
||||
CPPUNIT_ASSERT(list);
|
||||
const Null* s = downcast<Null>(list->get(0));
|
||||
CPPUNIT_ASSERT(s);
|
||||
}
|
||||
{
|
||||
// true, false
|
||||
std::string src = "[true, false]";
|
||||
SharedHandle<ValueBase> r = parser.parseFinal(src.c_str(), src.size(),
|
||||
error);
|
||||
const List* list = downcast<List>(r);
|
||||
CPPUNIT_ASSERT(list);
|
||||
const Bool* trueValue = downcast<Bool>(list->get(0));
|
||||
CPPUNIT_ASSERT(trueValue);
|
||||
CPPUNIT_ASSERT(trueValue->val());
|
||||
const Bool* falseValue = downcast<Bool>(list->get(1));
|
||||
CPPUNIT_ASSERT(falseValue);
|
||||
CPPUNIT_ASSERT(!falseValue->val());
|
||||
}
|
||||
{
|
||||
// object: 1 member
|
||||
std::string src = "{\"foo\":[\"bar\"]}";
|
||||
SharedHandle<ValueBase> r = parser.parseFinal(src.c_str(), src.size(),
|
||||
error);
|
||||
const Dict* dict = downcast<Dict>(r);
|
||||
CPPUNIT_ASSERT(dict);
|
||||
const List* list = downcast<List>(dict->get("foo"));
|
||||
CPPUNIT_ASSERT(list);
|
||||
const String* s = downcast<String>(list->get(0));
|
||||
CPPUNIT_ASSERT_EQUAL(std::string("bar"), s->s());
|
||||
}
|
||||
{
|
||||
// object: 2 members
|
||||
// TODO ValueBaseJsonParser does not allow empty dict key
|
||||
std::string src = "{\"foo\":[\"bar\"], \"alpha\" : \"bravo\"}";
|
||||
SharedHandle<ValueBase> r = parser.parseFinal(src.c_str(), src.size(),
|
||||
error);
|
||||
const Dict* dict = downcast<Dict>(r);
|
||||
CPPUNIT_ASSERT(dict);
|
||||
const List* list = downcast<List>(dict->get("foo"));
|
||||
CPPUNIT_ASSERT(list);
|
||||
const String* s = downcast<String>(list->get(0));
|
||||
CPPUNIT_ASSERT_EQUAL(std::string("bar"), s->s());
|
||||
const String* str = downcast<String>(dict->get("alpha"));
|
||||
CPPUNIT_ASSERT_EQUAL(std::string("bravo"), str->s());
|
||||
}
|
||||
{
|
||||
// array: 2 values
|
||||
std::string src = "[\"foo\", {}]";
|
||||
SharedHandle<ValueBase> r = parser.parseFinal(src.c_str(), src.size(),
|
||||
error);
|
||||
const List* list = downcast<List>(r);
|
||||
CPPUNIT_ASSERT(list);
|
||||
const String* s = downcast<String>(list->get(0));
|
||||
CPPUNIT_ASSERT_EQUAL(std::string("foo"), s->s());
|
||||
const Dict* dict = downcast<Dict>(list->get(1));
|
||||
CPPUNIT_ASSERT(dict);
|
||||
}
|
||||
{
|
||||
// Number: currently we ignore frac and exp
|
||||
std::string src = "[0,-1,1.2,-1.2e-10,-1e10]";
|
||||
SharedHandle<ValueBase> r = parser.parseFinal(src.c_str(), src.size(),
|
||||
error);
|
||||
const List* list = downcast<List>(r);
|
||||
CPPUNIT_ASSERT(list);
|
||||
const Integer* i = downcast<Integer>(list->get(0));
|
||||
CPPUNIT_ASSERT_EQUAL((Integer::ValueType)0, i->i());
|
||||
const Integer* i1 = downcast<Integer>(list->get(1));
|
||||
CPPUNIT_ASSERT_EQUAL((Integer::ValueType)-1, i1->i());
|
||||
const Integer* i2 = downcast<Integer>(list->get(2));
|
||||
CPPUNIT_ASSERT_EQUAL((Integer::ValueType)1, i2->i());
|
||||
const Integer* i3 = downcast<Integer>(list->get(3));
|
||||
CPPUNIT_ASSERT_EQUAL((Integer::ValueType)-1, i3->i());
|
||||
const Integer* i4 = downcast<Integer>(list->get(4));
|
||||
CPPUNIT_ASSERT_EQUAL((Integer::ValueType)-1, i4->i());
|
||||
}
|
||||
{
|
||||
// escape chars: ", \, /, \b, \f, \n, \r, \t
|
||||
std::string src = "[\"\\\"\\\\\\/\\b\\f\\n\\r\\t\"]";
|
||||
SharedHandle<ValueBase> r = parser.parseFinal(src.c_str(), src.size(),
|
||||
error);
|
||||
const List* list = downcast<List>(r);
|
||||
const String* s = downcast<String>(list->get(0));
|
||||
CPPUNIT_ASSERT_EQUAL(std::string("\"\\/\b\f\n\r\t"), s->s());
|
||||
}
|
||||
{
|
||||
// string: literal + escaped chars.
|
||||
std::string src = "[\"foo\\u0024b\\u00A2\\u20ACbaz\"]";
|
||||
SharedHandle<ValueBase> r = parser.parseFinal(src.c_str(), src.size(),
|
||||
error);
|
||||
const List* list = downcast<List>(r);
|
||||
CPPUNIT_ASSERT(list);
|
||||
const String* s = downcast<String>(list->get(0));
|
||||
CPPUNIT_ASSERT_EQUAL(std::string("foo$b¢€baz"), s->s());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
namespace {
|
||||
void checkDecodeError(const std::string& src)
|
||||
{
|
||||
json::ValueBaseJsonParser parser;
|
||||
ssize_t error;
|
||||
SharedHandle<ValueBase> r = parser.parseFinal(src.c_str(), src.size(),
|
||||
error);
|
||||
CPPUNIT_ASSERT(!r);
|
||||
CPPUNIT_ASSERT(error < 0);
|
||||
}
|
||||
} // namespace
|
||||
|
||||
void ValueBaseJsonParserTest::testParseUpdate_error()
|
||||
{
|
||||
// object
|
||||
checkDecodeError("{");
|
||||
// object
|
||||
checkDecodeError("}");
|
||||
// object
|
||||
checkDecodeError("{\"\":");
|
||||
// object
|
||||
checkDecodeError("{\"\":\"\",");
|
||||
// array
|
||||
checkDecodeError("[");
|
||||
// array
|
||||
checkDecodeError("]");
|
||||
// array
|
||||
checkDecodeError("[\"\"");
|
||||
// array
|
||||
checkDecodeError("[\"\",");
|
||||
// string
|
||||
checkDecodeError("[\"foo]");
|
||||
// string
|
||||
checkDecodeError("[\"\\u\"]");
|
||||
// string
|
||||
checkDecodeError("[\"\\u");
|
||||
// string
|
||||
checkDecodeError("[\"\\u000\"]");
|
||||
// string
|
||||
checkDecodeError("[\"\\u000");
|
||||
// string
|
||||
checkDecodeError("[\"\\uD852foo\"]");
|
||||
// string
|
||||
checkDecodeError("[\"\\uD852");
|
||||
// string
|
||||
checkDecodeError("[\"\\uD852\\u\"]");
|
||||
// string
|
||||
checkDecodeError("[\"\\uD852\\u");
|
||||
// string
|
||||
checkDecodeError("[\"\\uD852\\u0000\"]");
|
||||
// string
|
||||
checkDecodeError("[\"\\uD852\\uDF62");
|
||||
// object
|
||||
checkDecodeError("{:\"\"}");
|
||||
// object
|
||||
checkDecodeError("{\"foo\":}");
|
||||
// number
|
||||
// TODO ValueBaseJsonParser allows leading zeros
|
||||
//checkDecodeError("[00]");
|
||||
// number
|
||||
checkDecodeError("[1.]");
|
||||
// number
|
||||
checkDecodeError("[1.1e]");
|
||||
// bool
|
||||
checkDecodeError("[t");
|
||||
}
|
||||
|
||||
} // namespace aria2
|
Loading…
Reference in New Issue