// // Created by jun on 2023/12/29. // #include "json.h" #include "exception.h" #include 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(_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(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(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 JsonNode::as_vector() { std::vector 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(value.int_value); case JSON_TYPE_DOUBLE: return static_cast(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(_unicode); } else if (_unicode >= 0x80 && _unicode <= 0x7FF) { _out += static_cast((_unicode >> 6) | 0xC0); _out += static_cast((_unicode & 0x3F) | 0x80); } else if (_unicode >= 0x800 && _unicode <= 0xFFFF) { _out += static_cast((_unicode >> 12) | 0xE0); _out += static_cast(((_unicode >> 6) & 0x3F) | 0x80); _out += static_cast((_unicode & 0x3F) | 0x80); } else if (_unicode >= 0x10000 && _unicode <= 0x10FFFF) { _out += static_cast((_unicode >> 18) | 0xF0); _out += static_cast(((_unicode >> 12) & 0x3F) | 0x80); _out += static_cast(((_unicode >> 6) & 0x3F) | 0x80); _out += static_cast((_unicode & 0x3F) | 0x80); } } }