You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
sems/apps/jsonrpc/jsonxx.cpp

284 lines
5.9 KiB

// Author: Hong Jiang <hong@hjiang.net>
#include "jsonxx.h"
#include <cctype>
#include <iostream>
#include <sstream>
namespace jsonxx {
void eat_whitespaces(std::istream& input) {
char ch;
do {
input.get(ch);
} while(isspace(ch));
input.putback(ch);
}
// Try to consume characters from the input stream and match the
// pattern string. Leading whitespaces from the input are ignored if
// ignore_ws is true.
bool match(const std::string& pattern, std::istream& input,
bool ignore_ws) {
if (ignore_ws) {
eat_whitespaces(input);
}
std::string::const_iterator cur(pattern.begin());
char ch(0);
while(input && !input.eof() && cur != pattern.end()) {
input.get(ch);
if (ch != *cur) {
input.putback(ch);
return false;
} else {
cur++;
}
}
return cur == pattern.end();
}
bool parse_string(std::istream& input, std::string* value) {
if (!match("\"", input)) {
return false;
}
char ch;
while(!input.eof() && input.good()) {
input.get(ch);
if (ch == '"') {
break;
}
value->push_back(ch);
}
if (input && ch == '"') {
return true;
} else {
return false;
}
}
bool parse_bool(std::istream& input, bool* value) {
if (match("true", input)) {
*value = true;
return true;
}
if (match("false", input)) {
*value = false;
return true;
}
return false;
}
bool parse_null(std::istream& input) {
if (match("null", input)) {
return true;
}
return false;
}
bool parse_float(std::istream& input, double* value) {
eat_whitespaces(input);
char ch;
bool has_dot = false;
std::string value_str;
int sign = 1;
if (match("-", input)) {
sign = -1;
} else {
match("+", input);
}
while(input && !input.eof()) {
input.get(ch);
if (ch=='.')
has_dot = true;
if (!isdigit(ch) && (!(ch == '.'))) {
input.putback(ch);
break;
}
value_str.push_back(ch);
}
if (!has_dot) {
for (std::string::reverse_iterator r_it=
value_str.rbegin(); r_it != value_str.rend(); r_it++)
input.putback(*r_it);
return false;
}
if (value_str.size() > 0) {
std::istringstream(value_str) >> *value;
*value*=sign;
return true;
} else {
return false;
}
}
bool parse_number(std::istream& input, long* value) {
eat_whitespaces(input);
char ch;
std::string value_str;
int sign = 1;
if (match("-", input)) {
sign = -1;
} else {
match("+", input);
}
while(input && !input.eof()) {
input.get(ch);
if (!isdigit(ch)) {
input.putback(ch);
break;
}
value_str.push_back(ch);
}
if (value_str.size() > 0) {
std::istringstream(value_str) >> *value;
*value*=sign;
return true;
} else {
return false;
}
}
bool parse_number(std::istream& input, int* value) {
eat_whitespaces(input);
char ch;
std::string value_str;
int sign = 1;
if (match("-", input)) {
sign = -1;
} else {
match("+", input);
}
while(input && !input.eof()) {
input.get(ch);
if (!isdigit(ch)) {
input.putback(ch);
break;
}
value_str.push_back(ch);
}
if (value_str.size() > 0) {
std::istringstream(value_str) >> *value;
*value*=sign;
return true;
} else {
return false;
}
}
Object::Object() : value_map_() {}
Object::~Object() {
std::map<std::string, Value*>::iterator i;
for (i = value_map_.begin(); i != value_map_.end(); ++i) {
delete i->second;
}
}
bool Object::parse(std::istream& input) {
if (!match("{", input)) {
return false;
}
do {
std::string key;
if (!parse_string(input, &key)) {
return false;
}
if (!match(":", input)) {
return false;
}
Value* v = new Value();
if (!v->parse(input)) {
delete v;
break;
}
value_map_[key] = v;
} while (match(",", input));
if (!match("}", input)) {
return false;
}
return true;
}
Value::Value() : type_(INVALID_) {}
Value::~Value() {
if (type_ == STRING_) {
delete string_value_;
}
if (type_ == OBJECT_) {
delete object_value_;
}
if (type_ == ARRAY_) {
delete array_value_;
}
}
bool Value::parse(std::istream& input) {
std::string string_value;
if (parse_string(input, &string_value)) {
string_value_ = new std::string();
string_value_->swap(string_value);
type_ = STRING_;
return true;
}
if (parse_number(input, &integer_value_)) {
type_ = INTEGER_;
return true;
}
if (parse_bool(input, &bool_value_)) {
type_ = BOOL_;
return true;
}
if (parse_null(input)) {
type_ = NULL_;
return true;
}
array_value_ = new Array();
if (array_value_->parse(input)) {
type_ = ARRAY_;
return true;
}
delete array_value_;
object_value_ = new Object();
if (object_value_->parse(input)) {
type_ = OBJECT_;
return true;
}
delete object_value_;
return false;
}
Array::Array() : values_() {}
Array::~Array() {
for (unsigned int i = 0; i < values_.size(); ++i) {
delete values_[i];
}
}
bool Array::parse(std::istream& input) {
if (!match("[", input)) {
return false;
}
do {
Value* v = new Value();
if (!v->parse(input)) {
delete v;
break;
}
values_.push_back(v);
} while (match(",", input));
if (!match("]", input)) {
return false;
}
return true;
}
} // namespace jsonxx