0
0
mirror of https://github.com/OpenVPN/openvpn3.git synced 2024-09-20 12:12:15 +02:00
openvpn3/openvpn/common/jsonhelper.hpp
Charlie Vigue ae663c573a
Using new numeric conversion tools
Using is_safe_conversion in places where it is a better fit than
numeric_cast.

Signed-off-by: Charlie Vigue <charlie.vigue@openvpn.com>
2023-08-23 18:44:29 +02:00

960 lines
31 KiB
C++

// OpenVPN -- An application to securely tunnel IP networks
// over a single port, with support for SSL/TLS-based
// session authentication and key exchange,
// packet encryption, packet authentication, and
// packet compression.
//
// Copyright (C) 2012-2022 OpenVPN Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License Version 3
// as published by the Free Software Foundation.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program in the COPYING file.
// If not, see <http://www.gnu.org/licenses/>.
#pragma once
#include <string>
#include <cstring>
#include <cstdint>
#include <utility>
#include <openvpn/common/exception.hpp>
#include <openvpn/common/string.hpp>
#include <openvpn/common/number.hpp>
#include <openvpn/common/file.hpp>
#include <openvpn/common/jsonlib.hpp>
#include <openvpn/common/jsonhelperfmt.hpp>
#include <openvpn/buffer/bufstr.hpp>
#include <openvpn/buffer/bufstream.hpp>
#ifndef HAVE_JSON
#error no JSON library available
#endif
namespace openvpn {
namespace json {
OPENVPN_EXCEPTION(json_parse);
/* Workaround warnings in gcc 12/13, see https://gcc.gnu.org/bugzilla/show_bug.cgi?id=109642 */
#if !defined(__clang__) && defined(__GNUC__) && __GNUC__ == 13
#define DISABLE_DANGLING_WARNINGS() \
_Pragma("GCC diagnostic push") \
_Pragma("GCC diagnostic ignored \"-Wdangling-reference\"")
#define REENABLE_DANGLING_WARNINGS() \
_Pragma("GCC diagnostic pop")
#else
#define DISABLE_DANGLING_WARNINGS()
#define REENABLE_DANGLING_WARNINGS()
#endif
template <typename TITLE>
inline Json::Value parse(const std::string &str, const TITLE &title)
{
#ifdef OPENVPN_JSON
return Json::Value::parse(str, StringTempl::to_string(title));
#else
Json::CharReaderBuilder builder;
builder["collectComments"] = false;
Json::Value root;
std::string errors;
std::istringstream instr(str);
if (!Json::parseFromStream(builder, instr, &root, &errors))
throw json_parse(StringTempl::to_string(title) + " : " + errors);
return root;
#endif
}
inline Json::Value parse(const std::string &str)
{
return parse(str, "json");
}
inline Json::Value parse_from_file(const std::string &fn)
{
return parse(read_text_utf8(fn), fn);
}
template <typename BUFFER, typename TITLE>
inline Json::Value parse_from_buffer(const BUFFER &buf, const TITLE &title)
{
#ifdef OPENVPN_JSON
return Json::Value::parse(buf, StringTempl::to_string(title));
#else
Json::CharReaderBuilder builder;
builder["collectComments"] = false;
Json::Value root;
std::string errors;
std::unique_ptr<Json::CharReader> reader(builder.newCharReader());
if (!reader->parse(reinterpret_cast<const char *>(buf.c_data()), reinterpret_cast<const char *>(buf.c_data()) + buf.size(), &root, &errors))
throw json_parse(StringTempl::to_string(title) + " : " + errors);
return root;
#endif
}
#ifdef OPENVPN_JSON_INTERNAL
DISABLE_DANGLING_WARNINGS()
template <typename NAME, typename TITLE>
inline const Json::Value &cast(const Json::ValueType target_type,
const Json::Value &value,
const NAME &name,
const bool optional,
const TITLE &title)
{
if (value.isNull())
{
if (optional)
return value;
throw json_parse(Json::Value::type_string(target_type) + " cast " + fmt_name(name, title) + " is null");
}
if (!value.isConvertibleTo(target_type))
throw json_parse(Json::Value::type_string(target_type) + " cast " + fmt_name(name, title) + " is of incorrect type (" + value.type_string() + ')');
return value;
}
REENABLE_DANGLING_WARNINGS()
template <typename NAME>
inline const Json::Value &cast(const Json::ValueType target_type,
const Json::Value &value,
const NAME &name,
const bool optional)
{
return cast(target_type, value, name, optional, nullptr);
}
template <typename NAME, typename TITLE>
inline Json::Value cast(const Json::ValueType target_type,
Json::Value &&value,
const NAME &name,
const bool optional,
const TITLE &title)
{
Json::Value ret = std::move(value);
cast(target_type, ret, name, optional, title);
return ret;
}
template <typename NAME>
inline Json::Value cast(const Json::ValueType target_type,
Json::Value &&value,
const NAME &name,
const bool optional)
{
return cast(target_type, std::move(value), name, optional, nullptr);
}
#endif
template <typename T, typename NAME>
inline void from_vector(Json::Value &root, const T &vec, const NAME &name)
{
Json::Value array(Json::arrayValue);
for (auto &e : vec)
array.append(e.to_json());
if (array.size())
root[name] = array;
}
template <typename TITLE>
inline void assert_dict(const Json::Value &obj, const TITLE &title)
{
if (!obj.isObject())
throw json_parse(fmt_name_cast(title) + " is not a JSON dictionary");
}
template <typename TITLE>
inline bool is_dict(const Json::Value &obj, const TITLE &title)
{
if (obj.isNull())
return false;
assert_dict(obj, title);
return true;
}
template <typename NAME>
inline bool exists(const Json::Value &root, const NAME &name)
{
if (!root.isObject())
return false;
return !root[name].isNull();
}
template <typename NAME>
inline bool string_exists(const Json::Value &root, const NAME &name)
{
if (!root.isObject())
return false;
return root[name].isString();
}
template <typename T, typename NAME, typename TITLE>
inline void to_vector(const Json::Value &root, T &vec, const NAME &name, const TITLE &title)
{
const Json::Value &array = root[name];
if (array.isNull())
return;
if (!array.isArray())
throw json_parse("array " + fmt_name(name, title) + " is of incorrect type");
for (unsigned int i = 0; i < array.size(); ++i)
{
vec.emplace_back();
vec.back().from_json(array[i], fmt_name(name, title));
}
}
template <typename NAME, typename TITLE>
inline std::string get_string(const Json::Value &root,
const NAME &name,
const TITLE &title)
{
const Json::Value &value = root[name];
if (value.isNull())
throw json_parse("string " + fmt_name(name, title) + " is missing");
if (!value.isString())
throw json_parse("string " + fmt_name(name, title) + " is of incorrect type");
return value.asString();
}
template <typename NAME>
inline std::string get_string(const Json::Value &root, const NAME &name)
{
return get_string(root, name, nullptr);
}
#ifdef OPENVPN_JSON_INTERNAL
template <typename NAME, typename TITLE>
inline const std::string &get_string_ref(const Json::Value &root,
const NAME &name,
const TITLE &title)
{
const Json::Value &value = root[name];
if (value.isNull())
throw json_parse("string " + fmt_name(name, title) + " is missing");
if (!value.isString())
throw json_parse("string " + fmt_name(name, title) + " is of incorrect type");
return value.asStringRef();
}
template <typename NAME>
inline const std::string &get_string_ref(const Json::Value &root, const NAME &name)
{
return get_string_ref(root, name, nullptr);
}
// for safety, define an rvalue ref overload that falls back to get_string()
template <typename NAME, typename TITLE>
inline std::string get_string_ref(Json::Value &&root,
const NAME &name,
const TITLE &title)
{
return get_string(root, name, title);
}
template <typename NAME, typename TITLE>
inline const std::string *get_string_ptr(const Json::Value &root,
const NAME &name,
const TITLE &title)
{
const Json::Value &value = root[name];
if (value.isNull())
return nullptr;
if (!value.isString())
throw json_parse("string " + fmt_name(name, title) + " is of incorrect type");
return value.asStringPtr();
}
template <typename NAME>
inline const std::string *get_string_ptr(const Json::Value &root, const NAME &name)
{
return get_string_ptr(root, name, nullptr);
}
#endif
template <typename NAME, typename TITLE>
inline std::string get_string_optional(const Json::Value &root,
const NAME &name,
const std::string &default_value,
const TITLE &title)
{
const Json::Value &value = root[name];
if (value.isNull())
return default_value;
if (!value.isString())
throw json_parse("string " + fmt_name(name, title) + " is of incorrect type");
return value.asString();
}
template <typename NAME>
inline std::string get_string_optional(const Json::Value &root,
const NAME &name,
const std::string &default_value)
{
return get_string_optional(root, name, default_value, nullptr);
}
template <typename TITLE>
inline std::string get_string_from_array(const Json::Value &root,
const Json::ArrayIndex index,
const TITLE &title)
{
const Json::Value &value = root[index];
if (value.isNull())
throw json_parse("string " + fmt_name(index, title) + " is missing");
if (!value.isString())
throw json_parse("string " + fmt_name(index, title) + " is of incorrect type");
return value.asString();
}
inline std::string get_string_from_array(const Json::Value &root,
const Json::ArrayIndex index)
{
return get_string_from_array(root, index, nullptr);
}
template <typename NAME, typename TITLE>
inline int get_int(const Json::Value &root,
const NAME &name,
const TITLE &title)
{
const Json::Value &value = root[name];
if (value.isNull())
throw json_parse("int " + fmt_name(name, title) + " is missing");
if (!value.isInt())
throw json_parse("int " + fmt_name(name, title) + " is of incorrect type");
return value.asInt();
}
template <typename NAME>
inline int get_int(const Json::Value &root, const NAME &name)
{
return get_int(root, name, nullptr);
}
template <typename NAME, typename TITLE>
inline int get_int_optional(const Json::Value &root,
const NAME &name,
const int default_value,
const TITLE &title)
{
const Json::Value &value = root[name];
if (value.isNull())
return default_value;
if (!value.isInt())
throw json_parse("int " + fmt_name(name, title) + " is of incorrect type");
return value.asInt();
}
template <typename NAME>
inline int get_int_optional(const Json::Value &root,
const NAME &name,
const int default_value)
{
return get_int_optional(root, name, default_value, nullptr);
}
template <typename NAME, typename TITLE>
inline unsigned int get_uint(const Json::Value &root,
const NAME &name,
const TITLE &title)
{
const Json::Value &value = root[name];
if (value.isNull())
throw json_parse("uint " + fmt_name(name, title) + " is missing");
if (!value.isUInt())
throw json_parse("uint " + fmt_name(name, title) + " is of incorrect type");
return value.asUInt();
}
template <typename NAME>
inline unsigned int get_uint(const Json::Value &root, const NAME &name)
{
return get_uint(root, name, nullptr);
}
template <typename NAME, typename TITLE>
inline unsigned int get_uint_optional(const Json::Value &root,
const NAME &name,
const unsigned int default_value,
const TITLE &title)
{
const Json::Value &value = root[name];
if (value.isNull())
return default_value;
if (!value.isUInt())
throw json_parse("uint " + fmt_name(name, title) + " is of incorrect type");
return value.asUInt();
}
template <typename NAME>
inline unsigned int get_uint_optional(const Json::Value &root,
const NAME &name,
const unsigned int default_value)
{
return get_uint_optional(root, name, default_value, nullptr);
}
template <typename NAME, typename TITLE>
inline unsigned int get_uint_via_string(const Json::Value &root,
const NAME &name,
const TITLE &title)
{
const Json::Value &value = root[name];
if (value.isNull())
throw json_parse("uint-via-string " + fmt_name(name, title) + " is missing");
if (!value.isString())
throw json_parse("uint-via-string " + fmt_name(name, title) + " is of incorrect type");
unsigned int ret;
if (!parse_number(value.asString(), ret))
throw json_parse("uint-via-string " + fmt_name(name, title) + " failed to parse");
return ret;
}
template <typename NAME>
inline unsigned int get_uint_via_string(const Json::Value &root,
const NAME &name)
{
return get_uint_via_string(root, name, nullptr);
}
template <typename NAME, typename TITLE>
inline unsigned int get_uint_optional_via_string(const Json::Value &root,
const NAME &name,
const unsigned int default_value,
const TITLE &title)
{
const Json::Value &value = root[name];
if (value.isNull())
return default_value;
if (!value.isString())
throw json_parse("uint-via-string " + fmt_name(name, title) + " is of incorrect type");
unsigned int ret;
if (!parse_number(value.asString(), ret))
throw json_parse("uint-via-string " + fmt_name(name, title) + " failed to parse");
return ret;
}
template <typename NAME>
inline unsigned int get_uint_optional_via_string(const Json::Value &root,
const NAME &name,
const unsigned int default_value)
{
return get_uint_optional_via_string(root, name, default_value, nullptr);
}
template <typename NAME, typename TITLE>
inline std::uint64_t get_uint64(const Json::Value &root,
const NAME &name,
const TITLE &title)
{
const Json::Value &value = root[name];
if (value.isNull())
throw json_parse("uint64 " + fmt_name(name, title) + " is missing");
if (!value.isUInt64())
throw json_parse("uint64 " + fmt_name(name, title) + " is of incorrect type");
return value.asUInt64();
}
template <typename NAME>
inline std::uint64_t get_uint64(const Json::Value &root, const NAME &name)
{
return get_uint64(root, name, nullptr);
}
template <typename NAME, typename TITLE>
inline std::uint64_t get_uint64_optional(const Json::Value &root,
const NAME &name,
const std::uint64_t default_value,
const TITLE &title)
{
const Json::Value &value = root[name];
if (value.isNull())
return default_value;
if (!value.isUInt64())
throw json_parse("uint64 " + fmt_name(name, title) + " is of incorrect type");
return value.asUInt64();
}
template <typename NAME, typename TITLE>
inline std::int64_t get_int64_optional(const Json::Value &root,
const NAME &name,
const std::uint64_t default_value,
const TITLE &title)
{
const Json::Value &value = root[name];
if (value.isNull())
return default_value;
if (!value.isInt64())
throw json_parse("int64 " + fmt_name(name, title) + " is of incorrect type");
return value.asInt64();
}
template <typename NAME>
inline std::uint64_t get_uint64_optional(const Json::Value &root,
const NAME &name,
const std::uint64_t default_value)
{
return get_uint64_optional(root, name, default_value, nullptr);
}
/*
* The get_integer_optional function are used to select the right
* method based on the default_value parameter
*/
template <typename NAME, typename TITLE>
std::uint64_t get_integer_optional(const Json::Value &root,
const NAME &name,
const std::uint64_t default_value,
const TITLE &title)
{
return get_uint64_optional(root, name, default_value, title);
}
template <typename NAME, typename TITLE>
std::int64_t get_integer_optional(const Json::Value &root,
const NAME &name,
const std::int64_t default_value,
const TITLE &title)
{
return get_int64_optional(root, name, default_value, title);
}
template <typename NAME, typename TITLE>
inline unsigned int get_integer_optional(const Json::Value &root,
const NAME &name,
const unsigned int default_value,
const TITLE &title)
{
return get_uint_optional(root, name, default_value, title);
}
template <typename NAME, typename TITLE>
inline int get_integer_optional(const Json::Value &root,
const NAME &name,
const int default_value,
const TITLE &title)
{
return get_int_optional(root, name, default_value, title);
}
template <typename NAME, typename TITLE>
inline std::uint64_t get_uint64_via_string(const Json::Value &root,
const NAME &name,
const TITLE &title)
{
const Json::Value &value = root[name];
if (value.isNull())
throw json_parse("uint64-via-string " + fmt_name(name, title) + " is missing");
if (!value.isString())
throw json_parse("uint64-via-string " + fmt_name(name, title) + " is of incorrect type");
std::uint64_t ret;
if (!parse_number(value.asString(), ret))
throw json_parse("uint64-via-string " + fmt_name(name, title) + " failed to parse");
return ret;
}
template <typename NAME>
inline std::uint64_t get_uint64_via_string(const Json::Value &root,
const NAME &name)
{
return get_uint64_via_string(root, name, nullptr);
}
template <typename NAME, typename TITLE>
inline std::uint64_t get_uint64_optional_via_string(const Json::Value &root,
const NAME &name,
const std::uint64_t default_value,
const TITLE &title)
{
const Json::Value &value = root[name];
if (value.isNull())
return default_value;
if (!value.isString())
throw json_parse("uint64-via-string " + fmt_name(name, title) + " is of incorrect type");
std::uint64_t ret;
if (!parse_number(value.asString(), ret))
throw json_parse("uint64-via-string " + fmt_name(name, title) + " failed to parse");
return ret;
}
template <typename NAME>
inline std::uint64_t get_uint64_optional_via_string(const Json::Value &root,
const NAME &name,
const std::uint64_t default_value)
{
return get_uint64_optional_via_string(root, name, default_value, nullptr);
}
template <typename NAME, typename TITLE>
inline bool get_bool(const Json::Value &root,
const NAME &name,
const TITLE &title)
{
const Json::Value &value = root[name];
if (value.isNull())
throw json_parse("bool " + fmt_name(name, title) + " is missing");
if (!value.isBool())
throw json_parse("bool " + fmt_name(name, title) + " is of incorrect type");
return value.asBool();
}
template <typename NAME>
inline bool get_bool(const Json::Value &root, const NAME &name)
{
return get_bool(root, name, nullptr);
}
template <typename NAME>
inline bool get_bool_optional(const Json::Value &root,
const NAME &name,
const bool default_value = false)
{
const Json::Value &jv = root[name];
if (jv.isConvertibleTo(Json::booleanValue))
return jv.asBool();
else
return default_value;
}
template <typename NAME>
inline int get_bool_tristate(const Json::Value &root,
const NAME &name)
{
const Json::Value &jv = root[name];
if (jv.isConvertibleTo(Json::booleanValue))
return jv.asBool() ? 1 : 0;
else
return -1;
}
DISABLE_DANGLING_WARNINGS()
template <typename NAME, typename TITLE>
inline const Json::Value &get_dict(const Json::Value &root,
const NAME &name,
const bool optional,
const TITLE &title)
{
const Json::Value &value = root[name];
if (value.isNull())
{
if (optional)
return value;
throw json_parse("dictionary " + fmt_name(name, title) + " is missing");
}
if (!value.isObject())
throw json_parse("dictionary " + fmt_name(name, title) + " is of incorrect type");
return value;
}
REENABLE_DANGLING_WARNINGS()
template <typename NAME>
inline const Json::Value &get_dict(const Json::Value &root,
const NAME &name,
const bool optional)
{
return get_dict(root, name, optional, nullptr);
}
template <typename NAME, typename TITLE>
inline Json::Value get_dict(Json::Value &&root,
const NAME &name,
const bool optional,
const TITLE &title)
{
Json::Value r = std::move(root);
return get_dict(r, name, optional, title);
}
template <typename NAME>
inline Json::Value get_dict(Json::Value &&root,
const NAME &name,
const bool optional)
{
return get_dict(std::move(root), name, optional, nullptr);
}
DISABLE_DANGLING_WARNINGS()
template <typename TITLE>
inline const Json::Value &cast_dict(const Json::Value &value,
const bool optional,
const TITLE &title)
{
if (value.isNull())
{
if (optional)
return value;
throw json_parse("dictionary cast " + fmt_name_cast(title) + " is null");
}
if (!value.isObject())
throw json_parse("dictionary cast " + fmt_name_cast(title) + " is of incorrect type");
return value;
}
REENABLE_DANGLING_WARNINGS()
inline const Json::Value &cast_dict(const Json::Value &value,
const bool optional)
{
return cast_dict(value, optional, nullptr);
}
template <typename TITLE>
inline Json::Value cast_dict(Json::Value &&value,
const bool optional,
const TITLE &title)
{
Json::Value ret = std::move(value);
cast_dict(ret, optional, title);
return ret;
}
inline Json::Value cast_dict(Json::Value &&value,
const bool optional)
{
return cast_dict(std::move(value), optional, nullptr);
}
DISABLE_DANGLING_WARNINGS()
template <typename NAME, typename TITLE>
inline const Json::Value &get_array(const Json::Value &root,
const NAME &name,
const bool optional,
const TITLE &title)
{
const Json::Value &value = root[name];
if (value.isNull())
{
if (optional)
return value;
throw json_parse("array " + fmt_name(name, title) + " is missing");
}
if (!value.isArray())
throw json_parse("array " + fmt_name(name, title) + " is of incorrect type");
return value;
}
REENABLE_DANGLING_WARNINGS()
template <typename NAME>
inline const Json::Value &get_array(const Json::Value &root,
const NAME &name,
const bool optional)
{
return get_array(root, name, optional, nullptr);
}
template <typename NAME, typename TITLE>
inline Json::Value get_array(Json::Value &&root,
const NAME &name,
const bool optional,
const TITLE &title)
{
Json::Value r = std::move(root);
return get_array(r, name, optional, title);
}
template <typename NAME>
inline Json::Value get_array(Json::Value &&root,
const NAME &name,
const bool optional)
{
return get_array(std::move(root), name, optional, nullptr);
}
DISABLE_DANGLING_WARNINGS()
template <typename TITLE>
inline const Json::Value &cast_array(const Json::Value &value,
const bool optional,
const TITLE &title)
{
if (value.isNull())
{
if (optional)
return value;
throw json_parse("array cast " + fmt_name_cast(title) + " is null");
}
if (!value.isArray())
throw json_parse("array cast " + fmt_name_cast(title) + " is of incorrect type");
return value;
}
REENABLE_DANGLING_WARNINGS()
inline const Json::Value &cast_array(const Json::Value &value,
const bool optional)
{
return cast_array(value, optional, nullptr);
}
template <typename TITLE>
inline Json::Value cast_array(Json::Value &&value,
const bool optional,
const TITLE &title)
{
Json::Value ret = std::move(value);
cast_array(ret, optional, title);
return ret;
}
inline Json::Value cast_array(Json::Value &&value,
const bool optional)
{
return cast_array(std::move(value), optional, nullptr);
}
template <typename NAME, typename TITLE>
inline void to_string(const Json::Value &root,
std::string &dest,
const NAME &name,
const TITLE &title)
{
dest = get_string(root, name, title);
}
template <typename NAME, typename TITLE>
inline void to_string_optional(const Json::Value &root,
std::string &dest,
const NAME &name,
const std::string &default_value,
const TITLE &title)
{
dest = get_string_optional(root, name, default_value, title);
}
template <typename NAME, typename TITLE>
inline void to_int(const Json::Value &root,
int &dest,
const NAME &name,
const TITLE &title)
{
dest = get_int(root, name, title);
}
template <typename NAME, typename TITLE>
inline void to_uchar(const Json::Value &root,
unsigned char &dest,
const NAME &name,
const TITLE &title)
{
auto temp = get_int(root, name, title);
dest = clamp_notify<unsigned char>(temp,
[](decltype(temp) temp) -> unsigned char
{
auto why = std::string("Conversion error [" + std::to_string(temp) + "] to unsigned char");
throw json_parse(std::move(why)); });
}
template <typename NAME, typename TITLE>
inline void to_uint(const Json::Value &root,
unsigned int &dest,
const NAME &name,
const TITLE &title)
{
dest = get_uint(root, name, title);
}
template <typename NAME, typename TITLE>
inline void to_uint_optional(const Json::Value &root,
unsigned int &dest,
const NAME &name,
const unsigned int default_value,
const TITLE &title)
{
dest = get_uint_optional(root, name, default_value, title);
}
template <typename NAME, typename TITLE>
inline void to_uint64(const Json::Value &root,
std::uint64_t &dest,
const NAME &name,
const TITLE &title)
{
dest = get_uint64(root, name, title);
}
template <typename NAME, typename TITLE>
inline void to_bool(const Json::Value &root,
bool &dest,
const NAME &name,
const TITLE &title)
{
dest = get_bool(root, name, title);
}
inline void format_compact(const Json::Value &root, Buffer &buf)
{
#ifdef OPENVPN_JSON
root.toCompactString(buf);
#else
Json::StreamWriterBuilder json_builder;
json_builder.settings_["indentation"] = "";
BufferStreamOut os(buf);
std::unique_ptr<Json::StreamWriter> sw(json_builder.newStreamWriter());
sw->write(root, &os);
#endif
}
inline std::string format_compact(const Json::Value &root,
const size_t size_hint = 256)
{
BufferPtr bp = new BufferAllocated(size_hint, BufferAllocated::GROW);
format_compact(root, *bp);
return buf_to_string(*bp);
}
inline void format(const Json::Value &root, Buffer &buf)
{
#ifdef OPENVPN_JSON
root.toStyledString(buf);
#else
Json::StreamWriterBuilder json_builder;
json_builder.settings_["indentation"] = " ";
BufferStreamOut os(buf);
std::unique_ptr<Json::StreamWriter> sw(json_builder.newStreamWriter());
sw->write(root, &os);
#endif
}
inline std::string format(const Json::Value &root)
{
return root.toStyledString();
}
inline std::string error(const Json::Value &root)
{
const Json::Value &je = root["error"];
if (je.isString())
return je.asString();
else
return std::string();
}
// Guarantee that json object jr is a dictionary.
// Do this by encapsulating jr in a dictionary
// { "result": jr } if it is not already one.
inline Json::Value dict_result(Json::Value jr)
{
if (jr.isObject())
return jr;
else
{
Json::Value jret(Json::objectValue);
jret["result"] = std::move(jr);
return jret;
}
}
} // namespace json
} // namespace openvpn