#include "Json.h" namespace wfrest { namespace { json_value_t* json_value_copy(const json_value_t* val); json_value_t* json_value_copy_object(const json_value_t* val) { json_value_t* dest_val = json_value_create(JSON_VALUE_OBJECT); json_object_t* dest_obj = json_value_object(dest_val); json_object_t* obj = json_value_object(val); const char* name; json_object_for_each(name, val, obj) json_object_append(dest_obj, name, 0, json_value_copy(val)); return dest_val; } json_value_t* json_value_copy_array(const json_value_t* val) { json_value_t* dest_val = json_value_create(JSON_VALUE_ARRAY); json_array_t* dest_arr = json_value_array(dest_val); json_array_t* arr = json_value_array(val); json_array_for_each(val, arr) json_array_append(dest_arr, 0, json_value_copy(val)); return dest_val; } json_value_t* json_value_copy(const json_value_t* val) { switch (json_value_type(val)) { case JSON_VALUE_STRING: return json_value_create(JSON_VALUE_STRING, json_value_string(val)); case JSON_VALUE_NUMBER: return json_value_create(JSON_VALUE_NUMBER, json_value_number(val)); case JSON_VALUE_OBJECT: return json_value_copy_object(val); case JSON_VALUE_ARRAY: return json_value_copy_array(val); default: return json_value_create(json_value_type(val)); } } } // namespace // ------------------------ Constructor ------------------------- Json::Json() : node_(json_value_create(JSON_VALUE_NULL)), parent_(nullptr), allocated_(true) { } Json::Json(const std::string& str) : node_(json_value_create(JSON_VALUE_STRING, str.c_str())), parent_(nullptr), allocated_(true) { } Json::Json(const char* str) : node_(json_value_create(JSON_VALUE_STRING, str)), parent_(nullptr), allocated_(true) { } Json::Json(std::nullptr_t null) : node_(json_value_create(JSON_VALUE_NULL)), parent_(nullptr), allocated_(true) { } Json::Json(bool val) : node_(val ? json_value_create(JSON_VALUE_TRUE) : json_value_create(JSON_VALUE_FALSE)), parent_(nullptr), allocated_(true) { } Json::Json(const std::vector& val) : node_(json_value_create(JSON_VALUE_ARRAY)), parent_(nullptr), allocated_(true) { json_array_t* arr = json_value_array(node_); for (const auto& str : val) { json_array_append(arr, JSON_VALUE_STRING, str.c_str()); } } // for parse Json::Json(const std::string& str, bool parse_flag) : parent_(nullptr) { node_ = json_value_parse(str.c_str()); allocated_ = node_ == nullptr ? false : true; } Json::~Json() { destroy_node(&node_); } // watcher constructor Json::Json(const json_value_t* node, const json_value_t* parent, std::string&& key) : node_(const_cast(node)), parent_(parent), allocated_(false), parent_key_(std::move(key)) { } Json::Json(const json_value_t* node, const json_value_t* parent, const std::string& key) : node_(const_cast(node)), parent_(parent), allocated_(false), parent_key_(key) { } Json::Json(JsonType type) : allocated_(true) { if (type == JsonType::Object) { node_ = json_value_create(JSON_VALUE_OBJECT); } else { node_ = json_value_create(JSON_VALUE_ARRAY); } } Json::Json(const Json& other) { node_ = json_value_copy(other.node_); allocated_ = true; } Json& Json::operator=(const Json& other) { if (this == &other) { return *this; } destroy_node(&node_); node_ = json_value_copy(other.node_); parent_ = nullptr; allocated_ = true; parent_key_.clear(); return *this; } Json::Json(Json&& other) : node_(other.node_), parent_(other.parent_), allocated_(other.allocated_), parent_key_(std::move(other.parent_key_)) { other.node_ = nullptr; other.parent_ = nullptr; other.allocated_ = false; } Json& Json::operator=(Json&& other) { if (this == &other) { return *this; } destroy_node(&node_); node_ = other.node_; other.node_ = nullptr; parent_ = other.parent_; other.parent_ = nullptr; allocated_ = other.allocated_; other.allocated_ = false; parent_key_ = std::move(other.parent_key_); return *this; } Json Json::parse(const std::string& str) { return Json(str, true); } Json Json::parse(const std::ifstream& stream) { std::stringstream buffer; buffer << stream.rdbuf(); return Json(buffer.str(), true); } Json Json::parse(FILE* fp) { if (fp == nullptr) { return Json(); } fseek(fp, 0, SEEK_END); long length = ftell(fp); fseek(fp, 0, SEEK_SET); char* buffer = (char*)malloc(length + 1); buffer[length] = '\0'; long ret = fread(buffer, 1, length, fp); Json js; if (ret != length) { js = Json(); } else { js = Json(buffer, true); } free(buffer); return js; } std::string Json::dump() const { return dump(0); } std::string Json::dump(int spaces) const { std::string str; str.reserve(64); value_convert(node_, spaces, 0, &str); return str; } Json Json::operator[](const char* key) { if (is_null() && is_root()) { // todo : need is_root here? to_object(); } else if (is_object()) { // if exists json_object_t* obj = json_value_object(node_); const json_value_t* res = json_object_find(key, obj); if (res != nullptr) { return Json(res, node_, std::string(key)); } } if (is_placeholder()) { destroy_node(&node_); json_object_t* parent_obj = json_value_object(parent_); node_ = const_cast(json_object_append( parent_obj, parent_key_.c_str(), JSON_VALUE_OBJECT)); } if (!is_object()) { return Json(); } // (null, parent(node_), key) Json js = Json(); js.set_parent(node_, std::string(key)); return js; } Json Json::operator[](const char* key) const { if (!is_object()) { return Json(); } const json_value_t* val = node_; json_object_t* obj = json_value_object(val); const json_value_t* res = json_object_find(key, obj); if (res != nullptr) { return Json(res, node_, ""); } return Json(); } Json Json::operator[](const std::string& key) { return this->operator[](key.c_str()); } Json Json::operator[](const std::string& key) const { return this->operator[](key.c_str()); } bool Json::has(const std::string& key) const { json_object_t* obj = json_value_object(node_); const json_value_t* find = json_object_find(key.c_str(), obj); return find != nullptr; } void Json::erase(const std::string& key) { if (!is_object()) return; json_object_t* obj = json_value_object(node_); const json_value_t* find = json_object_find(key.c_str(), obj); if (find == nullptr) return; json_value_t* remove_val = json_object_remove(find, obj); json_value_destroy(remove_val); } Json Json::operator[](int index) { if (!is_array() || index < 0 || index > this->size()) { return Json(); } const json_value_t* val; json_array_t* arr = json_value_array(node_); json_array_for_each(val, arr) { if (index == 0) { return Json(val, node_, ""); } index--; } return Json(); } void Json::erase(int index) { if (!is_array()) return; int cnt = 0; json_array_t* arr = json_value_array(node_); const json_value_t* arr_cursor = nullptr; json_array_for_each(arr_cursor, arr) { if (cnt++ == index) break; } json_value_t* remove_val = json_array_remove(arr_cursor, arr); json_value_destroy(remove_val); } Json Json::operator[](int index) const { if (!is_array() || index < 0 || index > this->size()) { return Json(); } const json_value_t* val; json_array_t* arr = json_value_array(node_); json_array_for_each(val, arr) { if (index == 0) { return Json(val, node_, ""); } index--; } return Json(); } bool Json::can_obj_push_back() { if (is_placeholder() || (parent_ != nullptr && json_value_type(parent_) == JSON_VALUE_OBJECT)) { return true; } if (is_root() && is_null()) { to_object(); } return is_object(); } void Json::push_back(const std::string& key, bool val) { if (is_placeholder()) { *this = Json::Object{{key, val}}; return; } if (!can_obj_push_back()) { return; } json_object_t* obj = json_value_object(node_); int type = val ? JSON_VALUE_TRUE : JSON_VALUE_FALSE; json_object_append(obj, key.c_str(), type); } void Json::push_back(const std::string& key, std::nullptr_t val) { if (is_placeholder()) { *this = Json::Object{{key, val}}; return; } if (!can_obj_push_back()) { return; } json_object_t* obj = json_value_object(node_); json_object_append(obj, key.c_str(), JSON_VALUE_NULL); } void Json::push_back(const std::string& key, const std::string& val) { push_back(key, val.c_str()); } void Json::push_back(const std::string& key, const char* val) { if (is_placeholder()) { *this = Json::Object{{key, val}}; return; } if (!can_obj_push_back()) { return; } json_object_t* obj = json_value_object(node_); json_object_append(obj, key.c_str(), JSON_VALUE_STRING, val); } void Json::push_back(const std::string& key, const std::vector& val) { if (is_placeholder()) { *this = Json::Object{{key, val}}; return; } if (!can_obj_push_back()) { return; } json_object_t* obj = json_value_object(node_); const json_value_t* v = json_object_append(obj, key.c_str(), JSON_VALUE_ARRAY); json_array_t* arr = json_value_array(v); for (const auto& str : val) { json_array_append(arr, JSON_VALUE_STRING, str.c_str()); } } void Json::push_back(const std::string& key, const Json& val) { if (is_placeholder()) { *this = Json::Object{{key, val}}; return; } if (!can_obj_push_back()) { return; } json_object_t* obj = json_value_object(node_); Json copy_json = val; json_object_append(obj, key.c_str(), 0, copy_json.node_); copy_json.reset(); } void Json::placeholder_push_back(const std::string& key, bool val) { json_object_t* obj = json_value_object(parent_); destroy_node(&node_); if (val) { node_ = const_cast( json_object_append(obj, key.c_str(), JSON_VALUE_TRUE)); } else { node_ = const_cast( json_object_append(obj, key.c_str(), JSON_VALUE_FALSE)); } } void Json::placeholder_push_back(const std::string& key, std::nullptr_t val) { json_object_t* obj = json_value_object(parent_); destroy_node(&node_); node_ = const_cast( json_object_append(obj, key.c_str(), JSON_VALUE_NULL)); } void Json::placeholder_push_back(const std::string& key, const std::string& val) { placeholder_push_back(key, val.c_str()); } void Json::placeholder_push_back(const std::string& key, const char* val) { json_object_t* obj = json_value_object(parent_); destroy_node(&node_); node_ = const_cast( json_object_append(obj, key.c_str(), JSON_VALUE_STRING, val)); } void Json::placeholder_push_back(const std::string& key, const std::vector& val) { json_object_t* obj = json_value_object(parent_); destroy_node(&node_); node_ = const_cast( json_object_append(obj, key.c_str(), JSON_VALUE_ARRAY)); json_array_t* arr = json_value_array(node_); for (const auto& str : val) json_array_append(arr, JSON_VALUE_STRING, str.c_str()); } void Json::placeholder_push_back(const std::string& key, const Json& val) { json_object_t* obj = json_value_object(parent_); destroy_node(&node_); Json copy_json = val; node_ = const_cast( json_object_append(obj, key.c_str(), 0, copy_json.node_)); copy_json.reset(); } void Json::normal_push_back(const std::string& key, bool val) { json_object_t* obj = json_value_object(parent_); const json_value_t* find = json_object_find(key.c_str(), obj); int type = val ? JSON_VALUE_TRUE : JSON_VALUE_FALSE; if (find == nullptr) { json_object_append(obj, key.c_str(), type); return; } json_object_insert_before(find, obj, key.c_str(), type); json_value_t* remove_val = json_object_remove(find, obj); json_value_destroy(remove_val); } void Json::normal_push_back(const std::string& key, std::nullptr_t val) { json_object_t* obj = json_value_object(parent_); const json_value_t* find = json_object_find(key.c_str(), obj); if (find == nullptr) { json_object_append(obj, key.c_str(), JSON_VALUE_NULL); return; } json_object_insert_before(find, obj, key.c_str(), JSON_VALUE_NULL); json_value_t* remove_val = json_object_remove(find, obj); json_value_destroy(remove_val); } void Json::normal_push_back(const std::string& key, const std::string& val) { normal_push_back(key, val.c_str()); } void Json::normal_push_back(const std::string& key, const char* val) { json_object_t* obj = json_value_object(parent_); const json_value_t* find = json_object_find(key.c_str(), obj); if (find == nullptr) { json_object_append(obj, key.c_str(), JSON_VALUE_STRING, val); return; } json_object_insert_before(find, obj, key.c_str(), JSON_VALUE_STRING, val); json_value_t* remove_val = json_object_remove(find, obj); json_value_destroy(remove_val); } void Json::normal_push_back(const std::string& key, const std::vector& val) { json_object_t* obj = json_value_object(parent_); const json_value_t* find = json_object_find(key.c_str(), obj); const json_value_t* v; if (find == nullptr) { v = json_object_append(obj, key.c_str(), JSON_VALUE_ARRAY); } else { v = json_object_insert_before(find, obj, key.c_str(), JSON_VALUE_ARRAY); json_value_t* remove_val = json_object_remove(find, obj); json_value_destroy(remove_val); } json_array_t* arr = json_value_array(v); for (const auto& str : val) json_array_append(arr, JSON_VALUE_STRING, str.c_str()); } void Json::normal_push_back(const std::string& key, const Json& val) { json_object_t* obj = json_value_object(parent_); const json_value_t* find = json_object_find(key.c_str(), obj); Json copy_json = val; if (find == nullptr) { json_object_append(obj, key.c_str(), 0, copy_json.node_); copy_json.node_ = nullptr; return; } json_object_insert_before(find, obj, key.c_str(), 0, copy_json.node_); copy_json.reset(); json_value_t* remove_val = json_object_remove(find, obj); json_value_destroy(remove_val); } bool Json::can_arr_push_back() { if (is_root() && is_null()) { to_array(); } return is_array(); } Json Json::copy() const { return *this; } void Json::push_back(bool val) { if (is_placeholder()) { *this = Json::Array{{val}}; return; } if (!can_arr_push_back()) { return; } json_array_t* arr = json_value_array(node_); int type = val ? JSON_VALUE_TRUE : JSON_VALUE_FALSE; json_array_append(arr, type); } void Json::push_back(std::nullptr_t val) { if (is_placeholder()) { *this = Json::Array{{val}}; return; } if (!can_arr_push_back()) { return; } json_array_t* arr = json_value_array(node_); json_array_append(arr, JSON_VALUE_NULL); } void Json::push_back(const std::string& val) { push_back(val.c_str()); } void Json::push_back(const std::vector& val) { for (const auto& str : val) { push_back(str.c_str()); } } void Json::push_back(const char* val) { if (is_placeholder()) { *this = Json::Array{{val}}; return; } if (!can_arr_push_back()) { return; } json_array_t* arr = json_value_array(node_); json_array_append(arr, JSON_VALUE_STRING, val); } void Json::push_back(const Json& val) { if (is_placeholder()) { *this = Json::Array{{val}}; return; } if (!can_arr_push_back()) { return; } json_array_t* arr = json_value_array(node_); Json copy_json = val; json_array_append(arr, 0, copy_json.node_); copy_json.reset(); } void Json::update_arr(bool val) { json_array_t* arr = json_value_array(parent_); int type = val ? JSON_VALUE_TRUE : JSON_VALUE_FALSE; json_array_insert_before(node_, arr, type); json_value_t* remove_val = json_array_remove(node_, arr); json_value_destroy(remove_val); } void Json::update_arr(std::nullptr_t val) { json_array_t* arr = json_value_array(parent_); json_array_insert_before(node_, arr, JSON_VALUE_NULL); json_value_t* remove_val = json_array_remove(node_, arr); json_value_destroy(remove_val); } void Json::update_arr(const std::string& val) { update_arr(val.c_str()); } void Json::update_arr(const char* val) { json_array_t* arr = json_value_array(parent_); json_array_insert_before(node_, arr, JSON_VALUE_STRING, val); json_value_t* remove_val = json_array_remove(node_, arr); json_value_destroy(remove_val); } void Json::update_arr(const std::vector& val) { json_array_t* arr = json_value_array(parent_); const json_value_t* v = json_array_insert_before(node_, arr, JSON_VALUE_ARRAY); json_value_t* remove_val = json_array_remove(node_, arr); json_value_destroy(remove_val); arr = json_value_array(v); for (const auto& str : val) { json_array_append(arr, JSON_VALUE_STRING, str.c_str()); } } void Json::update_arr(const Json& val) { json_array_t* arr = json_value_array(parent_); Json copy_json = val; json_array_insert_before(node_, arr, 0, copy_json.node_); copy_json.reset(); json_value_t* remove_val = json_array_remove(node_, arr); json_value_destroy(remove_val); } std::string Json::type_str() const { switch (type()) { case JSON_VALUE_STRING: return "string"; case JSON_VALUE_NUMBER: return "number"; case JSON_VALUE_OBJECT: return "object"; case JSON_VALUE_ARRAY: return "array"; case JSON_VALUE_TRUE: return "true"; case JSON_VALUE_FALSE: return "false"; case JSON_VALUE_NULL: return "null"; } return "unknown"; } int Json::size() const { if (type() == JSON_VALUE_ARRAY) { json_array_t* array = json_value_array(node_); return json_array_size(array); } else if (type() == JSON_VALUE_OBJECT) { json_object_t* obj = json_value_object(node_); return json_object_size(obj); } return 1; } bool Json::empty() const { switch (type()) { case JSON_VALUE_NULL: { // null values are empty return true; } case JSON_VALUE_ARRAY: case JSON_VALUE_OBJECT: { return size() == 0; } default: // all other types are nonempty return false; } } void Json::clear() { int type = json_value_type(node_); destroy_node(&node_); parent_ = nullptr; allocated_ = true; parent_key_.clear(); if (type == JSON_VALUE_STRING) { node_ = json_value_create(JSON_VALUE_STRING, ""); } else if (type == JSON_VALUE_NUMBER) { node_ = json_value_create(JSON_VALUE_NUMBER, 0.0); } else { node_ = json_value_create(type); } } bool Json::to_object() { if (!allocated_ || !is_null()) { // watcher and non-null type can't change type return false; } destroy_node(&node_); node_ = json_value_create(JSON_VALUE_OBJECT); allocated_ = true; return true; } bool Json::to_array() { if (!allocated_ || !is_null()) { // watcher and non-null type can't change type return false; } destroy_node(&node_); node_ = json_value_create(JSON_VALUE_ARRAY); allocated_ = true; return true; } void Json::value_convert(const json_value_t* val, int spaces, int depth, std::string* out_str) { if (val == nullptr || out_str == nullptr) return; switch (json_value_type(val)) { case JSON_VALUE_STRING: string_convert(json_value_string(val), out_str); break; case JSON_VALUE_NUMBER: number_convert(json_value_number(val), out_str); break; case JSON_VALUE_OBJECT: object_convert(json_value_object(val), spaces, depth, out_str); break; case JSON_VALUE_ARRAY: array_convert(json_value_array(val), spaces, depth, out_str); break; case JSON_VALUE_TRUE: out_str->append("true"); break; case JSON_VALUE_FALSE: out_str->append("false"); break; case JSON_VALUE_NULL: out_str->append("null"); break; } } void Json::string_convert(const char* str, std::string* out_str) { out_str->append("\""); while (*str) { switch (*str) { case '\r': out_str->append("\\r"); break; case '\n': out_str->append("\\n"); break; case '\f': out_str->append("\\f"); break; case '\b': out_str->append("\\b"); break; case '\"': out_str->append("\\\""); break; case '\t': out_str->append("\\t"); break; case '\\': out_str->append("\\\\"); break; default: out_str->push_back(*str); break; } str++; } out_str->append("\""); } void Json::number_convert(double number, std::string* out_str) { std::ostringstream oss; long long integer = number; if (integer == number) oss << integer; else oss << number; out_str->append(oss.str()); } void Json::array_convert_not_format(const json_array_t* arr, std::string* out_str) { const json_value_t* val; int n = 0; out_str->append("["); json_array_for_each(val, arr) { if (n != 0) { out_str->append(","); } n++; value_convert(val, 0, 0, out_str); } out_str->append("]"); } void Json::array_convert(const json_array_t* arr, int spaces, int depth, std::string* out_str) { if (spaces == 0) { return array_convert_not_format(arr, out_str); } const json_value_t* val; int n = 0; int i; std::string padding(spaces, ' '); out_str->append("[\n"); json_array_for_each(val, arr) { if (n != 0) { out_str->append(",\n"); } n++; for (i = 0; i < depth + 1; i++) { out_str->append(padding); } value_convert(val, spaces, depth + 1, out_str); } out_str->append("\n"); for (i = 0; i < depth; i++) { out_str->append(padding); } out_str->append("]"); } void Json::object_convert_not_format(const json_object_t* obj, std::string* out_str) { const char* name; const json_value_t* val; int n = 0; out_str->append("{"); json_object_for_each(name, val, obj) { if (n != 0) { out_str->append(","); } n++; out_str->append("\""); out_str->append(name); out_str->append("\":"); value_convert(val, 0, 0, out_str); } out_str->append("}"); } void Json::object_convert(const json_object_t* obj, int spaces, int depth, std::string* out_str) { if (spaces == 0) { return object_convert_not_format(obj, out_str); } const char* name; const json_value_t* val; int n = 0; int i; std::string padding(spaces, ' '); out_str->append("{\n"); json_object_for_each(name, val, obj) { if (n != 0) { out_str->append(",\n"); } n++; for (i = 0; i < depth + 1; i++) { out_str->append(padding); } out_str->append("\""); out_str->append(name); out_str->append("\": "); value_convert(val, spaces, depth + 1, out_str); } out_str->append("\n"); for (i = 0; i < depth; i++) { out_str->append(padding); } out_str->append("}"); } } // namespace wfrest