947 lines
30 KiB
C++
947 lines
30 KiB
C++
//
|
|
// Created by jun on 2023/12/29.
|
|
//
|
|
|
|
#include "json.h"
|
|
#include "exception.h"
|
|
#include <cmath>
|
|
|
|
namespace simpleJson {
|
|
|
|
/*************************************************class JsonNode*************************************************/
|
|
JsonNode::JsonNode() : key(""), type(JSON_TYPE_NULL), string_value("") {
|
|
child_head = nullptr;
|
|
next = nullptr;
|
|
prev = nullptr;
|
|
children_size = 0;
|
|
}
|
|
|
|
JsonNode::JsonNode(JsonValueTypeEnum type, const std::string &key = "") : key(key), type(type), string_value("") {
|
|
child_head = nullptr;
|
|
next = nullptr;
|
|
prev = nullptr;
|
|
children_size = 0;
|
|
}
|
|
|
|
double JsonNode::get_number_value() const {
|
|
if (type != JSON_TYPE_INT && type != JSON_TYPE_DOUBLE) {
|
|
throw std::runtime_error("JsonNode::get_number_value() error: type is not number");
|
|
} else if (type == JSON_TYPE_INT) {
|
|
return (double) (value.int_value);
|
|
} else {
|
|
return value.double_value;
|
|
}
|
|
}
|
|
|
|
bool JsonNode::get_bool_value() const {
|
|
if (type != JSON_TYPE_BOOL) {
|
|
throw std::runtime_error("JsonNode::get_bool_value() error: type is not bool");
|
|
} else {
|
|
return value.bool_value;
|
|
}
|
|
}
|
|
|
|
std::string JsonNode::get_string_value() const {
|
|
if (type != JSON_TYPE_STRING) {
|
|
throw std::runtime_error("JsonNode::get_string_value() error: type is not string");
|
|
} else {
|
|
return string_value;
|
|
}
|
|
}
|
|
|
|
JsonNode &JsonNode::get_object_value() {
|
|
if (type != JSON_TYPE_OBJECT) {
|
|
throw std::runtime_error("JsonNode::get_object_value() error: type is not object");
|
|
} else {
|
|
return *this;
|
|
}
|
|
}
|
|
|
|
int JsonNode::get_children_size() const {
|
|
if (type != JSON_TYPE_LIST && type != JSON_TYPE_OBJECT) {
|
|
throw std::runtime_error("JsonNode::get_children_size() error: type is not list or object");
|
|
} else {
|
|
return children_size;
|
|
}
|
|
}
|
|
|
|
void JsonNode::set_value(double _value) {
|
|
if (type != JSON_TYPE_INT && type != JSON_TYPE_DOUBLE && type != JSON_TYPE_BOOL) {
|
|
throw std::runtime_error("JsonNode::set_value(double) error: type is not number");
|
|
} else {
|
|
value.double_value = 0;
|
|
if (type == JSON_TYPE_INT) {
|
|
value.int_value = (int) _value;
|
|
} else if (type == JSON_TYPE_DOUBLE) {
|
|
value.double_value = _value;
|
|
} else {
|
|
value.bool_value = _value > 0;
|
|
}
|
|
}
|
|
children_size = 0;
|
|
}
|
|
|
|
void JsonNode::set_value(const std::string &_value) {
|
|
if (type != JSON_TYPE_STRING) {
|
|
throw std::runtime_error("JsonNode::set_value(string) error: type is not string");
|
|
} else {
|
|
string_value = _value;
|
|
}
|
|
children_size = 0;
|
|
}
|
|
|
|
void JsonNode::set_key(const std::string &_key) {
|
|
key = _key;
|
|
}
|
|
|
|
std::string JsonNode::get_key() const {
|
|
return key;
|
|
}
|
|
|
|
void JsonNode::push_back(simpleJson::JsonNodePtr node) {
|
|
if (type != JSON_TYPE_LIST && type != JSON_TYPE_OBJECT) {
|
|
throw std::runtime_error("JsonNode::push_back() error: type is not list or object");
|
|
} else {
|
|
if (child_head == nullptr) {
|
|
child_head = node;
|
|
node->prev = nullptr;
|
|
node->next = nullptr;
|
|
} else {
|
|
JsonNodePtr tail = child_head;
|
|
while (tail->next != nullptr) {
|
|
tail = tail->next;
|
|
}
|
|
tail->next = node;
|
|
node->prev = tail;
|
|
node->next = nullptr;
|
|
}
|
|
children_size++;
|
|
}
|
|
}
|
|
|
|
void JsonNode::push_front(simpleJson::JsonNodePtr node) {
|
|
if (type != JSON_TYPE_LIST && type != JSON_TYPE_OBJECT) {
|
|
throw std::runtime_error("JsonNode::push_front() error: type is not list or object");
|
|
} else {
|
|
if (child_head == nullptr) {
|
|
child_head = node;
|
|
node->prev = nullptr;
|
|
node->next = nullptr;
|
|
} else {
|
|
child_head->prev = node;
|
|
node->next = child_head;
|
|
node->prev = nullptr;
|
|
child_head = node;
|
|
}
|
|
children_size++;
|
|
}
|
|
}
|
|
|
|
void JsonNode::clear() {
|
|
if (type != JSON_TYPE_LIST && type != JSON_TYPE_OBJECT) {
|
|
throw std::runtime_error("JsonNode::clear() error: type is not list or object");
|
|
} else {
|
|
child_head = nullptr;
|
|
children_size = 0;
|
|
}
|
|
}
|
|
|
|
bool JsonNode::set_list(int _size) {
|
|
if (type == JSON_TYPE_NULL) {
|
|
setValueType(JSON_TYPE_LIST);
|
|
}
|
|
if (type != JSON_TYPE_LIST) {
|
|
throw JsonTypeError(INVALID_TYPE, __func__, JSON_TYPE_LIST, type);
|
|
|
|
}
|
|
try {
|
|
clear();
|
|
for (int i = 0; i < _size; i++) {
|
|
push_back(JsonNodePtr(new JsonNode(JSON_TYPE_NULL)));
|
|
}
|
|
children_size = _size;
|
|
} catch (std::exception &e) {
|
|
std::cerr << e.what() << std::endl;
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
JsonNode &JsonNode::list_get(int index) {
|
|
if (type != JSON_TYPE_LIST) {
|
|
throw JsonTypeError(INVALID_TYPE, __func__, JSON_TYPE_LIST, type);
|
|
} else if (index < 0 || index >= children_size) {
|
|
throw std::runtime_error("JsonNode::list_get() error: index out of range");
|
|
} else {
|
|
JsonNodePtr node = child_head;
|
|
for (int i = 0; i < index; i++) {
|
|
node = node->next;
|
|
}
|
|
return *node;
|
|
}
|
|
}
|
|
|
|
void JsonNode::list_insert(int index, simpleJson::JsonNodePtr node) {
|
|
if (type != JSON_TYPE_LIST) {
|
|
throw JsonTypeError(INVALID_TYPE, __func__, JSON_TYPE_LIST, type);
|
|
} else if (index < 0 || index > children_size) {
|
|
throw std::runtime_error("JsonNode::list_insert() error: index out of range");
|
|
} else {
|
|
if (index == 0) {
|
|
push_front(node);
|
|
} else if (index == children_size) {
|
|
push_back(node);
|
|
} else {
|
|
JsonNodePtr p = child_head;
|
|
for (int i = 0; i < index; i++) {
|
|
p = p->next;
|
|
}
|
|
node->prev = p->prev;
|
|
node->next = p;
|
|
p->prev->next = node;
|
|
p->prev = node;
|
|
children_size++;
|
|
}
|
|
}
|
|
}
|
|
|
|
void JsonNode::list_erase(int index) {
|
|
if (type != JSON_TYPE_LIST) {
|
|
throw JsonTypeError(INVALID_TYPE, __func__, JSON_TYPE_LIST, type);
|
|
|
|
} else if (index < 0 || index >= children_size) {
|
|
throw std::runtime_error("JsonNode::list_erase() error: index out of range");
|
|
} else {
|
|
if (index == 0) {
|
|
child_head = child_head->next;
|
|
child_head->prev = nullptr;
|
|
} else if (index == children_size - 1) {
|
|
JsonNodePtr p = child_head;
|
|
for (int i = 0; i < index - 1; i++) {
|
|
p = p->next;
|
|
}
|
|
p->next = nullptr;
|
|
} else {
|
|
JsonNodePtr p = child_head;
|
|
for (int i = 0; i < index; i++) {
|
|
p = p->next;
|
|
}
|
|
p->prev->next = p->next;
|
|
p->next->prev = p->prev;
|
|
}
|
|
children_size--;
|
|
}
|
|
}
|
|
|
|
bool JsonNode::obj_has_item(const std::string &key) {
|
|
if (type != JSON_TYPE_OBJECT) {
|
|
throw JsonTypeError(INVALID_TYPE, __func__, JSON_TYPE_OBJECT, type);
|
|
} else {
|
|
JsonNodePtr p = child_head;
|
|
while (p != nullptr) {
|
|
if (p->key == key) {
|
|
return true;
|
|
}
|
|
p = p->next;
|
|
}
|
|
return false;
|
|
}
|
|
}
|
|
|
|
JsonNode &JsonNode::obj_get(const std::string &key) {
|
|
if (type != JSON_TYPE_OBJECT) {
|
|
throw JsonTypeError(INVALID_TYPE, __func__, JSON_TYPE_OBJECT, type);
|
|
} else {
|
|
JsonNodePtr p = child_head;
|
|
while (p != nullptr) {
|
|
if (p->key == key) {
|
|
return *p;
|
|
}
|
|
p = p->next;
|
|
}
|
|
throw std::runtime_error("JsonNode::obj_get() error: key \"" + key + "\" not found");
|
|
}
|
|
}
|
|
|
|
void JsonNode::obj_set(simpleJson::JsonNodePtr node) {
|
|
if (type != JSON_TYPE_OBJECT) {
|
|
throw JsonTypeError(INVALID_TYPE, __func__, JSON_TYPE_OBJECT, type);
|
|
} else {
|
|
if (obj_has_item(node->key)) {
|
|
obj_get(node->key) = *node;
|
|
} else {
|
|
push_back(node);
|
|
}
|
|
}
|
|
}
|
|
|
|
void JsonNode::to_json_string(std::string &_dst_str, bool _print_key, int _tab_dep, bool _one_line) const {
|
|
for (int i = 0; i < _tab_dep; i++) {
|
|
_dst_str += "\t";
|
|
}
|
|
if (key.size() != 0 && _print_key) {
|
|
_dst_str += "\"" + key + "\":";
|
|
}
|
|
int dep = _one_line ? 0 : _tab_dep + 1;
|
|
switch (type) {
|
|
case JSON_TYPE_INT: {
|
|
_dst_str += std::to_string(value.int_value);
|
|
break;
|
|
}
|
|
case JSON_TYPE_DOUBLE: {
|
|
_dst_str += std::to_string(value.double_value);
|
|
break;
|
|
}
|
|
case JSON_TYPE_BOOL: {
|
|
_dst_str += value.bool_value ? "true" : "false";
|
|
break;
|
|
}
|
|
case JSON_TYPE_STRING: {
|
|
_dst_str += "\"" + string_value + "\"";
|
|
break;
|
|
}
|
|
case JSON_TYPE_LIST: {
|
|
_dst_str += "[";
|
|
if (!_one_line) {
|
|
_dst_str += "\n";
|
|
}
|
|
JsonNodePtr p = child_head;
|
|
while (p != nullptr) {
|
|
p->to_json_string(_dst_str, false, dep, _one_line);
|
|
if (p->next != nullptr) {
|
|
_dst_str += ",";
|
|
}
|
|
if (!_one_line) {
|
|
_dst_str += "\n";
|
|
}
|
|
p = p->next;
|
|
}
|
|
for (int i = 0; i < _tab_dep; i++) {
|
|
_dst_str += "\t";
|
|
}
|
|
_dst_str += "]";
|
|
break;
|
|
}
|
|
case JSON_TYPE_OBJECT: {
|
|
_dst_str += "{";
|
|
if (!_one_line) {
|
|
_dst_str += "\n";
|
|
}
|
|
JsonNodePtr p = child_head;
|
|
while (p != nullptr) {
|
|
p->to_json_string(_dst_str, true, dep, _one_line);
|
|
if (p->next != nullptr) {
|
|
_dst_str += ",";
|
|
}
|
|
if (!_one_line) {
|
|
_dst_str += "\n";
|
|
}
|
|
p = p->next;
|
|
}
|
|
for (int i = 0; i < _tab_dep; i++) {
|
|
_dst_str += "\t";
|
|
}
|
|
_dst_str += "}";
|
|
break;
|
|
}
|
|
default:
|
|
break;
|
|
}
|
|
|
|
}
|
|
|
|
JsonNode &JsonNode::operator[](const std::string &key) {
|
|
if (type == JSON_TYPE_NULL) {
|
|
setValueType(JSON_TYPE_OBJECT);
|
|
}
|
|
if (type != JSON_TYPE_OBJECT) {
|
|
throw JsonTypeError(INVALID_TYPE, __func__, JSON_TYPE_OBJECT, type);
|
|
} else {
|
|
if (obj_has_item(key)) {
|
|
return obj_get(key);
|
|
} else {
|
|
JsonNodePtr node = JsonNodePtr(new JsonNode(JSON_TYPE_NULL, key));
|
|
obj_set(node);
|
|
return *node;
|
|
}
|
|
}
|
|
}
|
|
|
|
JsonNode &JsonNode::operator[](int index) {
|
|
if (type == JSON_TYPE_NULL) {
|
|
setValueType(JSON_TYPE_LIST);
|
|
}
|
|
if (type != JSON_TYPE_LIST) {
|
|
throw JsonTypeError(INVALID_TYPE, __func__, JSON_TYPE_LIST, type);
|
|
} else {
|
|
if (index < 0 || index >= children_size) {
|
|
throw std::runtime_error("JsonNode::operator[]() error: index out of range");
|
|
} else {
|
|
return list_get(index);
|
|
}
|
|
}
|
|
}
|
|
|
|
double JsonNode::operator=(double _value) {
|
|
if (type == JSON_TYPE_NULL) {
|
|
setValueType(JSON_TYPE_DOUBLE);
|
|
}
|
|
if (type == JSON_TYPE_DOUBLE) {
|
|
value.double_value = _value;
|
|
return _value;
|
|
} else if (type == JSON_TYPE_INT) {
|
|
value.int_value = static_cast<int>(_value);
|
|
return _value;
|
|
} else if (type == JSON_TYPE_BOOL) {
|
|
value.bool_value = _value > 0;
|
|
return _value;
|
|
} else {
|
|
throw JsonTypeError(INVALID_TYPE, __func__, JSON_TYPE_INT, type);
|
|
}
|
|
}
|
|
|
|
int JsonNode::as_int() const {
|
|
switch (type) {
|
|
case JSON_TYPE_INT: {
|
|
return value.int_value;
|
|
}
|
|
case JSON_TYPE_DOUBLE: {
|
|
return static_cast<int>(value.double_value);
|
|
}
|
|
case JSON_TYPE_BOOL: {
|
|
return value.bool_value ? 1 : 0;
|
|
}
|
|
case JSON_TYPE_NULL: {
|
|
return 0;
|
|
}
|
|
default: {
|
|
throw JsonTypeError(INVALID_TYPE, __func__, JSON_TYPE_INT, type);
|
|
}
|
|
}
|
|
}
|
|
|
|
double JsonNode::as_double() const {
|
|
switch (type) {
|
|
case JSON_TYPE_INT: {
|
|
return static_cast<double>(value.int_value);
|
|
}
|
|
case JSON_TYPE_DOUBLE: {
|
|
return value.double_value;
|
|
}
|
|
case JSON_TYPE_BOOL: {
|
|
return value.bool_value ? 1.0 : 0.0;
|
|
}
|
|
case JSON_TYPE_NULL: {
|
|
return 0.0;
|
|
}
|
|
default: {
|
|
throw JsonTypeError(INVALID_TYPE, __func__, JSON_TYPE_DOUBLE, type);
|
|
}
|
|
}
|
|
}
|
|
|
|
std::string JsonNode::as_string() const {
|
|
switch (type) {
|
|
case JSON_TYPE_STRING: {
|
|
return string_value;
|
|
}
|
|
case JSON_TYPE_INT: {
|
|
return std::to_string(value.int_value);
|
|
}
|
|
case JSON_TYPE_DOUBLE: {
|
|
return std::to_string(value.double_value);
|
|
}
|
|
case JSON_TYPE_BOOL: {
|
|
return value.bool_value ? "true" : "false";
|
|
}
|
|
case JSON_TYPE_NULL: {
|
|
return "NULL";
|
|
}
|
|
default: {
|
|
throw JsonTypeError(INVALID_TYPE, __func__, JSON_TYPE_STRING, type);
|
|
}
|
|
}
|
|
}
|
|
|
|
std::vector<JsonNodePtr> JsonNode::as_vector() {
|
|
std::vector<JsonNodePtr> vec;
|
|
JsonNodePtr p = child_head;
|
|
while (p != nullptr) {
|
|
vec.push_back(p);
|
|
p = p->next;
|
|
}
|
|
return vec;
|
|
}
|
|
|
|
void JsonNode::setValueType(simpleJson::JsonValueTypeEnum _type) {
|
|
type = _type;
|
|
}
|
|
|
|
bool JsonNode::as_bool() const {
|
|
switch (type) {
|
|
case JSON_TYPE_INT:
|
|
return static_cast<bool>(value.int_value);
|
|
case JSON_TYPE_DOUBLE:
|
|
return static_cast<bool>(value.double_value);
|
|
case JSON_TYPE_BOOL:
|
|
return value.bool_value;
|
|
case JSON_TYPE_NULL:
|
|
return false;
|
|
default:
|
|
throw JsonTypeError(INVALID_TYPE, __func__, JSON_TYPE_BOOL, type);
|
|
}
|
|
return false;
|
|
}
|
|
/*****************************************************************************************************************/
|
|
|
|
/***********************************************JsonReader*******************************************************/
|
|
JsonReader::JsonReader() {
|
|
src_str = "";
|
|
src_str_len = 0;
|
|
curr_ptr = -1;
|
|
curr_line = 0;
|
|
curr_col = 0;
|
|
|
|
eof = 1;
|
|
}
|
|
|
|
JsonReader::JsonReader(const std::string &_src_str) {
|
|
src_str = _src_str;
|
|
src_str_len = src_str.size();
|
|
if (src_str_len <= 0) {
|
|
curr_ptr = -1;
|
|
curr_line = 0;
|
|
curr_col = 0;
|
|
eof = 1;
|
|
} else {
|
|
curr_ptr = 0;
|
|
curr_line = 1;
|
|
curr_col = 1;
|
|
eof = 0;
|
|
}
|
|
}
|
|
|
|
JsonReader::JsonReader(std::ifstream &_input_file_stream) {
|
|
if (!_input_file_stream) {
|
|
throw std::runtime_error("JsonReader::JsonReader() error: input file stream is not valid");
|
|
}
|
|
std::string line = "";
|
|
while (std::getline(_input_file_stream, line)) {
|
|
src_str += line + "\n";
|
|
}
|
|
src_str_len = src_str.size();
|
|
if (src_str_len <= 0) {
|
|
curr_ptr = -1;
|
|
curr_line = 0;
|
|
curr_col = 0;
|
|
eof = 1;
|
|
} else {
|
|
curr_ptr = 0;
|
|
curr_line = 1;
|
|
curr_col = 1;
|
|
eof = 0;
|
|
}
|
|
}
|
|
|
|
char JsonReader::curr_char() const {
|
|
if (curr_ptr < 0 || curr_ptr >= src_str_len) {
|
|
throw std::runtime_error("JsonReader::curr_char() error: current pointer out of range");
|
|
} else {
|
|
return src_str[curr_ptr];
|
|
}
|
|
}
|
|
|
|
char JsonReader::get_char() {
|
|
if (eof) {
|
|
throw std::runtime_error("JsonReader::get_char() error: end of file");
|
|
} else {
|
|
if (curr_ptr >= src_str_len) {
|
|
eof = 1;
|
|
return '\0';
|
|
} else {
|
|
auto ch = src_str[curr_ptr++];
|
|
if (src_str[curr_ptr] == '\n') {
|
|
curr_line++;
|
|
curr_col = 1;
|
|
} else if (src_str[curr_ptr] == '\t') {
|
|
curr_col += 4;
|
|
} else if (src_str[curr_ptr] == '\r') {
|
|
curr_col = 0;
|
|
} else {
|
|
curr_col++;
|
|
}
|
|
|
|
if (curr_ptr >= src_str_len) {
|
|
eof = 1;
|
|
}
|
|
return ch;
|
|
}
|
|
}
|
|
}
|
|
|
|
std::string JsonReader::str_ahead(int _len) const {
|
|
return src_str.substr(curr_ptr, std::min(_len, src_str_len - curr_ptr));
|
|
}
|
|
|
|
std::string JsonReader::get_str(int _len) {
|
|
auto str = str_ahead(_len);
|
|
if (curr_ptr >= src_str_len) {
|
|
throw std::runtime_error("JsonReader::get_str() error: end of file");
|
|
}
|
|
curr_ptr += _len;
|
|
return str;
|
|
}
|
|
|
|
int JsonReader::get_curr_line() const {
|
|
return curr_line;
|
|
}
|
|
|
|
int JsonReader::get_curr_col() const {
|
|
return curr_col;
|
|
}
|
|
|
|
void JsonReader::skip_space() {
|
|
while (curr_ptr < src_str_len &&
|
|
(src_str[curr_ptr] == ' ' || src_str[curr_ptr] == '\t' || src_str[curr_ptr] == '\n' ||
|
|
src_str[curr_ptr] == '\r')) {
|
|
get_char();
|
|
}
|
|
if (curr_ptr >= src_str_len) {
|
|
eof = 1;
|
|
}
|
|
}
|
|
|
|
bool JsonReader::is_eof() const {
|
|
return eof;
|
|
}
|
|
/****************************************************************************************************************/
|
|
/**********************************************JsonParser********************************************************/
|
|
|
|
JsonParser::JsonParser() {
|
|
root = JsonNodePtr(new JsonNode(JSON_TYPE_OBJECT));
|
|
}
|
|
|
|
JsonParser::JsonParser(const std::string &_src_str) {
|
|
root = JsonNodePtr(new JsonNode(JSON_TYPE_OBJECT));
|
|
try {
|
|
JsonReader reader(_src_str);
|
|
parseValue(reader, root);
|
|
is_parse_success = true;
|
|
} catch (std::exception &e) {
|
|
std::cerr << e.what() << std::endl;
|
|
is_parse_success = false;
|
|
}
|
|
}
|
|
|
|
JsonParser::JsonParser(std::ifstream &_input_file_stream) {
|
|
root = JsonNodePtr(new JsonNode(JSON_TYPE_OBJECT));
|
|
try {
|
|
JsonReader reader(_input_file_stream);
|
|
parseValue(reader, root);
|
|
is_parse_success = true;
|
|
} catch (std::exception &e) {
|
|
std::cerr << e.what() << std::endl;
|
|
is_parse_success = false;
|
|
}
|
|
}
|
|
|
|
JsonNode &JsonParser::get_root() {
|
|
return *root;
|
|
}
|
|
|
|
bool JsonParser::is_success() const {
|
|
return is_parse_success;
|
|
}
|
|
|
|
bool JsonParser::fail() const {
|
|
return !is_parse_success;
|
|
}
|
|
|
|
void JsonParser::parseValue(simpleJson::JsonReader &reader, simpleJson::JsonNodePtr &node) {
|
|
reader.skip_space();
|
|
|
|
char ch = reader.curr_char();
|
|
if (ch == '{') {
|
|
parseObject(reader, node);
|
|
} else if (ch == '\"') {
|
|
parseString(reader, node);
|
|
} else if (ch == '[') {
|
|
parseList(reader, node);
|
|
} else if (ch == '-' || isdigit(ch)) {
|
|
parseNumber(reader, node);
|
|
} else {
|
|
if (reader.str_ahead(4) == "true") {
|
|
node->setValueType(JSON_TYPE_BOOL);
|
|
node->set_value(1);
|
|
reader.get_str(4);
|
|
} else if (reader.str_ahead(5) == "false") {
|
|
node->setValueType(JSON_TYPE_BOOL);
|
|
node->set_value(0);
|
|
reader.get_str(5);
|
|
} else if (reader.str_ahead(4) == "null" || reader.str_ahead(4) == "NULL") {
|
|
node->setValueType(JSON_TYPE_NULL);
|
|
reader.get_str(4);
|
|
} else {
|
|
throw JsonParseError(reader.get_curr_line(), reader.get_curr_col(), SYNTAX_ERROR);
|
|
}
|
|
}
|
|
}
|
|
|
|
void JsonParser::parseObject(simpleJson::JsonReader &reader, simpleJson::JsonNodePtr &node) {
|
|
node->setValueType(JSON_TYPE_OBJECT);
|
|
auto ch = reader.curr_char();
|
|
if (ch != '{') {
|
|
throw JsonInvalidSym(reader.get_curr_line(), reader.get_curr_col(), ch);
|
|
} else {
|
|
reader.get_char();
|
|
reader.skip_space();
|
|
ch = reader.curr_char();
|
|
}
|
|
|
|
while (ch != '}') {
|
|
if (ch != '\"') {
|
|
throw JsonInvalidSym(reader.get_curr_line(), reader.get_curr_col(), ch);
|
|
} else {
|
|
reader.get_char();
|
|
ch = reader.curr_char();
|
|
std::string key;
|
|
while (ch != '\"') {
|
|
key += reader.get_char();
|
|
ch = reader.curr_char();
|
|
}
|
|
reader.get_char();
|
|
reader.skip_space();
|
|
ch = reader.curr_char();
|
|
|
|
if (ch != ':') {
|
|
throw JsonInvalidSym(reader.get_curr_line(), reader.get_curr_col(), ch);
|
|
} else {
|
|
reader.get_char();
|
|
reader.skip_space();
|
|
ch = reader.curr_char();
|
|
JsonNodePtr child(new JsonNode(JSON_TYPE_NULL, key));
|
|
parseValue(reader, child);
|
|
|
|
node->push_back(child);
|
|
|
|
reader.skip_space();
|
|
ch = reader.curr_char();
|
|
|
|
if (ch == ',') {
|
|
reader.get_char();
|
|
reader.skip_space();
|
|
} else if (ch != '}') {
|
|
throw JsonInvalidSym(reader.get_curr_line(), reader.get_curr_col(), ch);
|
|
} else {
|
|
reader.get_char();
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
ch = reader.curr_char();
|
|
}
|
|
reader.get_char();
|
|
}
|
|
|
|
void JsonParser::parseList(simpleJson::JsonReader &reader, simpleJson::JsonNodePtr &node) {
|
|
node->setValueType(JSON_TYPE_LIST);
|
|
char ch = reader.curr_char();
|
|
if (ch != '[') {
|
|
throw JsonInvalidSym(reader.get_curr_line(), reader.get_curr_col(), ch);
|
|
} else {
|
|
reader.get_char();
|
|
reader.skip_space();
|
|
ch = reader.curr_char();
|
|
}
|
|
while (ch != ']') {
|
|
JsonNodePtr child(new JsonNode(JSON_TYPE_NULL));
|
|
parseValue(reader, child);
|
|
node->push_back(child);
|
|
|
|
reader.skip_space();
|
|
ch = reader.curr_char();
|
|
|
|
if (ch == ',') {
|
|
reader.get_char();
|
|
reader.skip_space();
|
|
} else if (ch != ']') {
|
|
throw JsonInvalidSym(reader.get_curr_line(), reader.get_curr_col(), ch);
|
|
} else {
|
|
reader.get_char();
|
|
return;
|
|
}
|
|
ch = reader.curr_char();
|
|
}
|
|
reader.get_char();
|
|
}
|
|
|
|
void JsonParser::parseString(simpleJson::JsonReader &reader, simpleJson::JsonNodePtr &node) {
|
|
node->setValueType(JSON_TYPE_STRING);
|
|
std::string str;
|
|
char ch = reader.curr_char();
|
|
if (ch != '\"') {
|
|
throw JsonInvalidSym(reader.get_curr_line(), reader.get_curr_col(), ch);
|
|
}
|
|
|
|
reader.get_char();
|
|
ch = reader.curr_char();
|
|
|
|
while (ch != '\"') {
|
|
if (ch == '\\') {
|
|
reader.get_char();
|
|
ch = reader.curr_char();
|
|
if (ch == '\"' || ch == '\\' || ch == '/' || ch == '\b' || ch == '\f' || ch == '\n' || ch == '\r' ||
|
|
ch == '\t') {
|
|
str += ch;
|
|
} else if (ch == 'u') {
|
|
std::string unicode_str;
|
|
for (int i = 0; i < 4; i ++) {
|
|
reader.get_char();
|
|
ch = reader.curr_char();
|
|
if (ch >= '0' && ch <= '9' || ch >= 'a' && ch <= 'f' || ch >= 'A' && ch <= 'F') {
|
|
unicode_str += ch;
|
|
} else {
|
|
throw JsonInvalidUnicodeSym(reader.get_curr_line(), reader.get_curr_col(), ch);
|
|
}
|
|
}
|
|
long unicode = std::stol(unicode_str.data(), nullptr, 16);
|
|
std::string utf8_str;
|
|
encode_utf8(unicode, utf8_str);
|
|
str += utf8_str;
|
|
} else {
|
|
throw JsonInvalidEscapedSym(reader.get_curr_line(), reader.get_curr_col(), ch);
|
|
}
|
|
reader.get_char();
|
|
ch = reader.curr_char();
|
|
} else {
|
|
str += ch;
|
|
reader.get_char();
|
|
ch = reader.curr_char();
|
|
}
|
|
}
|
|
reader.get_char();
|
|
node->set_value(str);
|
|
}
|
|
|
|
void JsonParser::parseNumber(simpleJson::JsonReader &reader, simpleJson::JsonNodePtr &node) {
|
|
node->setValueType(JSON_TYPE_DOUBLE);
|
|
bool sign = 1;
|
|
double value = 0;
|
|
bool exp_sign = 1;
|
|
int exp_val = 0;
|
|
int scale = 0, sub_scale = 0;
|
|
|
|
char ch = reader.curr_char();
|
|
if (ch != '-' && !isdigit(ch)) {
|
|
throw JsonInvalidSym(reader.get_curr_line(), reader.get_curr_col(), ch);
|
|
}
|
|
if (ch == '-') {
|
|
sign = 0;
|
|
reader.get_char();
|
|
ch = reader.curr_char();
|
|
}
|
|
if (isdigit(ch) && ch != '0') {
|
|
while(isdigit(ch)) {
|
|
value = value * 10 + (ch - '0');
|
|
reader.get_char();
|
|
ch = reader.curr_char();
|
|
}
|
|
} else if (ch == '0') {
|
|
reader.get_char();
|
|
ch = reader.curr_char();
|
|
}
|
|
if (ch == '.') {
|
|
reader.get_char();
|
|
ch = reader.curr_char();
|
|
if (!isdigit(ch)) {
|
|
throw JsonInvalidSym(reader.get_curr_line(), reader.get_curr_col(), ch);
|
|
}
|
|
while(isdigit(ch)) {
|
|
sub_scale += 1;
|
|
value = value + double(ch-'0')*std::pow(0.1, double(sub_scale));
|
|
reader.get_char();
|
|
ch = reader.curr_char();
|
|
}
|
|
}
|
|
|
|
if (ch == 'e' || ch == 'E') {
|
|
reader.get_char();
|
|
ch = reader.curr_char();
|
|
|
|
if (ch == '-') {
|
|
exp_sign = 0;
|
|
reader.get_char();
|
|
ch = reader.curr_char();
|
|
} else if (ch == '+') {
|
|
reader.get_char();
|
|
ch = reader.curr_char();
|
|
}
|
|
|
|
if (!isdigit(ch)) {
|
|
throw JsonInvalidSym(reader.get_curr_line(), reader.get_curr_col(), ch);
|
|
}
|
|
while(isdigit(ch)) {
|
|
exp_val = exp_val * 10 + (ch - '0');
|
|
reader.get_char();
|
|
ch = reader.curr_char();
|
|
}
|
|
|
|
exp_val *= exp_sign ? 1 : -1;
|
|
}
|
|
|
|
value = (value * (sign ? 1 : -1)) * std::pow(10, exp_val);
|
|
node->set_value(value);
|
|
}
|
|
|
|
|
|
void JsonParser::to_json_string(std::string &_dst_str, bool _one_line) const {
|
|
_dst_str.clear();
|
|
root->to_json_string(_dst_str, false, 0, _one_line);
|
|
}
|
|
|
|
bool JsonParser::save_to_file(const std::string &_file_path, bool _one_line) const {
|
|
std::ofstream output_file_stream(_file_path);
|
|
if (!output_file_stream) {
|
|
throw FilePathNotValid(_file_path);
|
|
}
|
|
std::string json_str;
|
|
to_json_string(json_str, _one_line);
|
|
output_file_stream << json_str;
|
|
output_file_stream.close();
|
|
return true;
|
|
}
|
|
|
|
|
|
/****************************************************************************************************************/
|
|
|
|
void encode_utf8(long _unicode, std::string& _out)
|
|
{
|
|
if (_unicode < 0 || _unicode > 0x10FFFF)
|
|
return;
|
|
|
|
_out.clear();
|
|
if (_unicode <= 0x7F)
|
|
{
|
|
_out += static_cast<char>(_unicode);
|
|
}
|
|
else if (_unicode >= 0x80 && _unicode <= 0x7FF)
|
|
{
|
|
_out += static_cast<char>((_unicode >> 6) | 0xC0);
|
|
_out += static_cast<char>((_unicode & 0x3F) | 0x80);
|
|
}
|
|
else if (_unicode >= 0x800 && _unicode <= 0xFFFF)
|
|
{
|
|
_out += static_cast<char>((_unicode >> 12) | 0xE0);
|
|
_out += static_cast<char>(((_unicode >> 6) & 0x3F) | 0x80);
|
|
_out += static_cast<char>((_unicode & 0x3F) | 0x80);
|
|
}
|
|
else if (_unicode >= 0x10000 && _unicode <= 0x10FFFF)
|
|
{
|
|
_out += static_cast<char>((_unicode >> 18) | 0xF0);
|
|
_out += static_cast<char>(((_unicode >> 12) & 0x3F) | 0x80);
|
|
_out += static_cast<char>(((_unicode >> 6) & 0x3F) | 0x80);
|
|
_out += static_cast<char>((_unicode & 0x3F) | 0x80);
|
|
}
|
|
|
|
}
|
|
} |