#include "nlohmann/json.hpp" #include "json.hpp" #include #include #include #include #include std::string JSON::escape_string(std::string string) { for(size_t c = 0; c < string.size(); ++c) { if(string[c] == '\b') { string.replace(c, 1, "\\b"); ++c; } else if(string[c] == '\f') { string.replace(c, 1, "\\f"); ++c; } else if(string[c] == '\n') { string.replace(c, 1, "\\n"); ++c; } else if(string[c] == '\r') { string.replace(c, 1, "\\r"); ++c; } else if(string[c] == '\t') { string.replace(c, 1, "\\t"); ++c; } else if(string[c] == '"') { string.replace(c, 1, "\\\""); ++c; } else if(string[c] == '\\') { string.replace(c, 1, "\\\\"); ++c; } } return string; } JSON::JSON(StructureType type) noexcept : ptr(type == StructureType::object ? new nlohmann::ordered_json() : new nlohmann::ordered_json(nlohmann::ordered_json::array())), owner(true) {} JSON::JSON(const std::string &string) : ptr(new nlohmann::ordered_json(nlohmann::ordered_json::parse(string))), owner(true) {} JSON::JSON(const char *c_str) : ptr(new nlohmann::ordered_json(nlohmann::ordered_json::parse(c_str))), owner(true) {} JSON::JSON(std::istream &istream) : ptr(new nlohmann::ordered_json(nlohmann::ordered_json::parse(istream))), owner(true) {} JSON::JSON(const boost::filesystem::path &path) { std::ifstream input(path.string(), std::ios::binary); if(!input) throw std::runtime_error("could not open file " + path.string()); ptr = new nlohmann::ordered_json(nlohmann::ordered_json::parse(input)); owner = true; } JSON::JSON(JSON &&other) noexcept : ptr(other.ptr), owner(other.owner) { other.owner = false; } JSON &JSON::operator=(JSON &&other) noexcept { if(owner) delete ptr; ptr = other.ptr; owner = other.owner; other.owner = false; return *this; } JSON::~JSON() { if(owner) delete ptr; } JSON JSON::make_owner(JSON &&other) noexcept { auto owner = JSON(new nlohmann::ordered_json(std::move(*other.ptr))); owner.owner = true; other.owner = false; return owner; } std::ostream &operator<<(std::ostream &os, const JSON &json) { return os << *json.ptr; } std::string JSON::to_string(int indent) const { return ptr->dump(indent); } void JSON::to_file(const boost::filesystem::path &path, int indent) const { std::ofstream file(path.string(), std::ios::binary); if(!file) throw std::runtime_error("could not open file " + path.string()); if(indent != -1) file << std::setw(indent); file << *ptr << '\n'; } void JSON::set(const std::string &key, std::string value) noexcept { (*ptr)[key] = std::move(value); } void JSON::set(const std::string &key, const char *value) noexcept { (*ptr)[key] = value; } void JSON::set(const std::string &key, long long value) noexcept { (*ptr)[key] = value; } void JSON::set(const std::string &key, double value) noexcept { (*ptr)[key] = value; } void JSON::set(const std::string &key, bool value) noexcept { (*ptr)[key] = value; } void JSON::set(const std::string &key, JSON &&value) noexcept { (*ptr)[key] = std::move(*value.ptr); value.owner = false; } void JSON::set(const std::string &key, const JSON &value) noexcept { (*ptr)[key] = *value.ptr; } void JSON::remove(const std::string &key) noexcept { ptr->erase(key); } void JSON::emplace_back(JSON &&value) { ptr->emplace_back(std::move(*value.ptr)); value.owner = false; } boost::optional JSON::child_optional(const std::string &key) const noexcept { try { return child(key); } catch(...) { return {}; } } JSON JSON::child(const std::string &key) const { return JSON(&ptr->at(key)); } boost::optional>> JSON::children_optional(const std::string &key) const noexcept { try { return children(key); } catch(...) { return {}; } } std::vector> JSON::children_or_empty(const std::string &key) const noexcept { try { return children(key); } catch(...) { return {}; } } std::vector> JSON::children(const std::string &key) const { return JSON(&ptr->at(key)).children(); } boost::optional>> JSON::children_optional() const noexcept { try { return children(); } catch(...) { return {}; } } std::vector> JSON::children_or_empty() const noexcept { try { return children(); } catch(...) { return {}; } } std::vector> JSON::children() const { if(!ptr->is_object()) throw std::runtime_error("value '" + to_string() + "' is not an object"); std::vector> result; for(auto it = ptr->begin(); it != ptr->end(); ++it) result.emplace_back(it.key(), JSON(&*it)); return result; } boost::optional JSON::object_optional(const std::string &key) const noexcept { try { return object(key); } catch(...) { return {}; } } JSON JSON::object(const std::string &key) const { return JSON(&ptr->at(key)).object(); } boost::optional JSON::object_optional() const noexcept { try { return object(); } catch(...) { return {}; } } JSON JSON::object() const { if(!ptr->is_object()) throw std::runtime_error("value '" + to_string() + "' is not an object"); return JSON(ptr); } boost::optional> JSON::array_optional(const std::string &key) const noexcept { try { return array(key); } catch(...) { return {}; } } std::vector JSON::array_or_empty(const std::string &key) const noexcept { try { return array(key); } catch(...) { return {}; } } std::vector JSON::array(const std::string &key) const { return JSON(&ptr->at(key)).array(); } boost::optional> JSON::array_optional() const noexcept { try { return array(); } catch(...) { return {}; } } std::vector JSON::array_or_empty() const noexcept { try { return array(); } catch(...) { return {}; } } std::vector JSON::array() const { if(!ptr->is_array()) throw std::runtime_error("value '" + to_string() + "' is not an array"); std::vector result; result.reserve(ptr->size()); for(auto &e : *ptr) result.emplace_back(&e); return result; } boost::optional JSON::string_optional(const std::string &key) const noexcept { try { return string(key); } catch(...) { return {}; } } std::string JSON::string_or(const std::string &key, const std::string &default_value) const noexcept { try { return string(key); } catch(...) { return default_value; } } std::string JSON::string(const std::string &key) const { return ptr->at(key).get(); } boost::optional JSON::string_optional() const noexcept { try { return string(); } catch(...) { return {}; } } std::string JSON::string_or(const std::string &default_value) const noexcept { try { return string(); } catch(...) { return default_value; } } std::string JSON::string() const { return ptr->get(); } boost::optional JSON::integer_optional(const std::string &key, ParseOptions parse_options) const noexcept { try { return integer(key, parse_options); } catch(...) { return {}; } } long long JSON::integer_or(const std::string &key, long long default_value, ParseOptions parse_options) const noexcept { try { return integer(key, parse_options); } catch(...) { return default_value; } } long long JSON::integer(const std::string &key, ParseOptions parse_options) const { return JSON(&ptr->at(key)).integer(parse_options); } boost::optional JSON::integer_optional(ParseOptions parse_options) const noexcept { try { return integer(parse_options); } catch(...) { return {}; } } long long JSON::integer_or(long long default_value, ParseOptions parse_options) const noexcept { try { return integer(parse_options); } catch(...) { return default_value; } } long long JSON::integer(ParseOptions parse_options) const { if(auto integer = ptr->get()) return *integer; if(auto floating_point = ptr->get()) return *floating_point; if(parse_options == ParseOptions::accept_string) { if(auto string = ptr->get()) { try { return std::stoll(*string); } catch(...) { } } } throw std::runtime_error("value '" + to_string() + "' could not be converted to integer"); } boost::optional JSON::floating_point_optional(const std::string &key, ParseOptions parse_options) const noexcept { try { return floating_point(key, parse_options); } catch(...) { return {}; } } double JSON::floating_point_or(const std::string &key, double default_value, ParseOptions parse_options) const noexcept { try { return floating_point(key, parse_options); } catch(...) { return default_value; } } double JSON::floating_point(const std::string &key, ParseOptions parse_options) const { return JSON(&ptr->at(key)).floating_point(parse_options); } boost::optional JSON::floating_point_optional(ParseOptions parse_options) const noexcept { try { return floating_point(parse_options); } catch(...) { return {}; } } double JSON::floating_point_or(double default_value, ParseOptions parse_options) const noexcept { try { return floating_point(parse_options); } catch(...) { return default_value; } } double JSON::floating_point(ParseOptions parse_options) const { if(auto floating_point = ptr->get()) return *floating_point; if(auto integer = ptr->get()) return *integer; if(parse_options == ParseOptions::accept_string) { if(auto string = ptr->get()) { try { return std::stof(*string); } catch(...) { } } } throw std::runtime_error("value '" + to_string() + "' could not be converted to floating point"); } boost::optional JSON::boolean_optional(const std::string &key, ParseOptions parse_options) const noexcept { try { return boolean(key, parse_options); } catch(...) { return {}; } } bool JSON::boolean_or(const std::string &key, bool default_value, ParseOptions parse_options) const noexcept { try { return boolean(key, parse_options); } catch(...) { return default_value; } } bool JSON::boolean(const std::string &key, ParseOptions parse_options) const { return JSON(&ptr->at(key)).boolean(parse_options); } boost::optional JSON::boolean_optional(ParseOptions parse_options) const noexcept { try { return boolean(parse_options); } catch(...) { return {}; } } bool JSON::boolean_or(bool default_value, ParseOptions parse_options) const noexcept { try { return boolean(parse_options); } catch(...) { return default_value; } } bool JSON::boolean(ParseOptions parse_options) const { if(auto boolean = ptr->get()) return *boolean; if(auto integer = ptr->get()) { if(*integer == 1) return true; if(*integer == 0) return false; } if(parse_options == ParseOptions::accept_string) { if(auto string = ptr->get()) { if(*string == "true" || *string == "1") return true; if(*string == "false" || *string == "0") return false; } } throw std::runtime_error("value '" + to_string() + "' could not be converted to bool"); }