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.

498 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");
}