mirror of https://gitlab.com/cppit/jucipp
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.
497 lines
12 KiB
497 lines
12 KiB
#include "nlohmann/json.hpp" |
|
#include "json.hpp" |
|
#include <algorithm> |
|
#include <fstream> |
|
#include <iomanip> |
|
#include <iostream> |
|
#include <sstream> |
|
|
|
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> 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<std::vector<std::pair<std::string, JSON>>> JSON::children_optional(const std::string &key) const noexcept { |
|
try { |
|
return children(key); |
|
} |
|
catch(...) { |
|
return {}; |
|
} |
|
} |
|
|
|
std::vector<std::pair<std::string, JSON>> JSON::children_or_empty(const std::string &key) const noexcept { |
|
try { |
|
return children(key); |
|
} |
|
catch(...) { |
|
return {}; |
|
} |
|
} |
|
|
|
std::vector<std::pair<std::string, JSON>> JSON::children(const std::string &key) const { |
|
return JSON(&ptr->at(key)).children(); |
|
} |
|
|
|
boost::optional<std::vector<std::pair<std::string, JSON>>> JSON::children_optional() const noexcept { |
|
try { |
|
return children(); |
|
} |
|
catch(...) { |
|
return {}; |
|
} |
|
} |
|
|
|
std::vector<std::pair<std::string, JSON>> JSON::children_or_empty() const noexcept { |
|
try { |
|
return children(); |
|
} |
|
catch(...) { |
|
return {}; |
|
} |
|
} |
|
|
|
std::vector<std::pair<std::string, JSON>> JSON::children() const { |
|
if(!ptr->is_object()) |
|
throw std::runtime_error("value '" + to_string() + "' is not an object"); |
|
std::vector<std::pair<std::string, JSON>> result; |
|
for(auto it = ptr->begin(); it != ptr->end(); ++it) |
|
result.emplace_back(it.key(), JSON(&*it)); |
|
return result; |
|
} |
|
|
|
boost::optional<JSON> 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> 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<std::vector<JSON>> JSON::array_optional(const std::string &key) const noexcept { |
|
try { |
|
return array(key); |
|
} |
|
catch(...) { |
|
return {}; |
|
} |
|
} |
|
|
|
std::vector<JSON> JSON::array_or_empty(const std::string &key) const noexcept { |
|
try { |
|
return array(key); |
|
} |
|
catch(...) { |
|
return {}; |
|
} |
|
} |
|
|
|
std::vector<JSON> JSON::array(const std::string &key) const { |
|
return JSON(&ptr->at(key)).array(); |
|
} |
|
|
|
boost::optional<std::vector<JSON>> JSON::array_optional() const noexcept { |
|
try { |
|
return array(); |
|
} |
|
catch(...) { |
|
return {}; |
|
} |
|
} |
|
|
|
std::vector<JSON> JSON::array_or_empty() const noexcept { |
|
try { |
|
return array(); |
|
} |
|
catch(...) { |
|
return {}; |
|
} |
|
} |
|
|
|
std::vector<JSON> JSON::array() const { |
|
if(!ptr->is_array()) |
|
throw std::runtime_error("value '" + to_string() + "' is not an array"); |
|
std::vector<JSON> result; |
|
result.reserve(ptr->size()); |
|
for(auto &e : *ptr) |
|
result.emplace_back(&e); |
|
return result; |
|
} |
|
|
|
boost::optional<std::string> 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<std::string>(); |
|
} |
|
|
|
boost::optional<std::string> 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<std::string>(); |
|
} |
|
|
|
boost::optional<long long> 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<long long> 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<nlohmann::ordered_json::number_integer_t *>()) |
|
return *integer; |
|
if(auto floating_point = ptr->get<nlohmann::ordered_json::number_float_t *>()) |
|
return *floating_point; |
|
if(parse_options == ParseOptions::accept_string) { |
|
if(auto string = ptr->get<nlohmann::ordered_json::string_t *>()) { |
|
try { |
|
return std::stoll(*string); |
|
} |
|
catch(...) { |
|
} |
|
} |
|
} |
|
throw std::runtime_error("value '" + to_string() + "' could not be converted to integer"); |
|
} |
|
|
|
boost::optional<double> 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<double> 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<nlohmann::ordered_json::number_float_t *>()) |
|
return *floating_point; |
|
if(auto integer = ptr->get<nlohmann::ordered_json::number_integer_t *>()) |
|
return *integer; |
|
if(parse_options == ParseOptions::accept_string) { |
|
if(auto string = ptr->get<nlohmann::ordered_json::string_t *>()) { |
|
try { |
|
return std::stof(*string); |
|
} |
|
catch(...) { |
|
} |
|
} |
|
} |
|
throw std::runtime_error("value '" + to_string() + "' could not be converted to floating point"); |
|
} |
|
|
|
boost::optional<bool> 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<bool> 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<nlohmann::ordered_json::boolean_t *>()) |
|
return *boolean; |
|
if(auto integer = ptr->get<nlohmann::ordered_json::number_integer_t *>()) { |
|
if(*integer == 1) |
|
return true; |
|
if(*integer == 0) |
|
return false; |
|
} |
|
if(parse_options == ParseOptions::accept_string) { |
|
if(auto string = ptr->get<nlohmann::ordered_json::string_t *>()) { |
|
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"); |
|
}
|
|
|