mirror of
https://github.com/OpenRCT2/OpenRCT2
synced 2026-01-24 15:24:30 +01:00
199 lines
7.4 KiB
C++
199 lines
7.4 KiB
C++
/*****************************************************************************
|
|
* Copyright (c) 2014-2020 OpenRCT2 developers
|
|
*
|
|
* For a complete list of all authors, please refer to contributors.md
|
|
* Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2
|
|
*
|
|
* OpenRCT2 is licensed under the GNU General Public License version 3.
|
|
*****************************************************************************/
|
|
|
|
#pragma once
|
|
|
|
#include "../common.h"
|
|
#include "FileSystem.hpp"
|
|
|
|
#include <nlohmann/json.hpp>
|
|
#include <string>
|
|
#include <string_view>
|
|
|
|
#if NLOHMANN_JSON_VERSION_MAJOR < 3 || (NLOHMANN_JSON_VERSION_MAJOR == 3 && NLOHMANN_JSON_VERSION_MINOR < 6)
|
|
# error "Unsupported version of nlohmann json library, must be >= 3.6"
|
|
#endif // NLOHMANN_JSON_VERSION_MAJOR < 3 || (NLOHMANN_JSON_VERSION_MAJOR == 3 && NLOHMANN_JSON_VERSION_MINOR < 6)
|
|
|
|
using json_t = nlohmann::json;
|
|
|
|
namespace Json
|
|
{
|
|
// Don't try to load JSON files that exceed 64 MiB
|
|
constexpr uint64_t MAX_JSON_SIZE = 64 * 1024 * 1024;
|
|
|
|
/**
|
|
* Read JSON file and parse contents
|
|
* @param path Path to the source file
|
|
* @param maxSize Max file size in bytes allowed
|
|
* @return A JSON representation of the file
|
|
* @note This function will throw an exception if the JSON file cannot be parsed
|
|
*/
|
|
json_t ReadFromFile(const utf8* path, size_t maxSize = MAX_JSON_SIZE);
|
|
json_t ReadFromFile(const fs::path& path, size_t maxSize = MAX_JSON_SIZE);
|
|
|
|
/**
|
|
* Read JSON file and parse the contents
|
|
* @param path Path to the destination file
|
|
* @param jsonData A JSON object
|
|
* @param indentSize The number of spaces in an indent, or removes whitespace on -1
|
|
*/
|
|
void WriteToFile(const utf8* path, const json_t& jsonData, int indentSize = 4);
|
|
void WriteToFile(const fs::path& path, const json_t& jsonData, int indentSize = 4);
|
|
|
|
/**
|
|
* Parse JSON from a string
|
|
* @param raw JSON string
|
|
* @return A JSON representation of the string
|
|
* @note This function will throw an exception if the JSON string cannot be parsed
|
|
*/
|
|
json_t FromString(std::string_view raw);
|
|
|
|
/**
|
|
* Parse JSON from a vector of characters
|
|
* @param vec Vector of characters containing JSON
|
|
* @return A JSON representation of the vector
|
|
* @note This function will throw an exception if the JSON vector cannot be parsed
|
|
*/
|
|
json_t FromVector(const std::vector<uint8_t>& vec);
|
|
|
|
/**
|
|
* Explicit type conversion between a JSON object and a compatible number value
|
|
* @param T Destination numeric type
|
|
* @param jsonObj JSON object holding the value
|
|
* @param defaultValue Default value to return if the JSON object is not a number type
|
|
* @return Copy of the JSON value converted to the given type
|
|
*/
|
|
template<typename T> T GetNumber(const json_t& jsonObj, T defaultValue = 0)
|
|
{
|
|
static_assert(std::is_arithmetic<T>::value, "GetNumber template parameter must be arithmetic");
|
|
|
|
return jsonObj.is_number() ? jsonObj.get<T>() : defaultValue;
|
|
}
|
|
|
|
/**
|
|
* Explicit type conversion between a JSON object and a compatible enum value
|
|
* @param T Destination enum
|
|
* @param jsonObj JSON object holding the value
|
|
* @param defaultValue Default value to return if the JSON object is not an enum type
|
|
* @return Copy of the JSON value converted to the given enum type
|
|
*/
|
|
template<typename T> T GetEnum(const json_t& jsonObj, T defaultValue)
|
|
{
|
|
static_assert(std::is_enum<T>::value, "GetEnum template parameter must be an enum");
|
|
|
|
return jsonObj.is_number_integer() ? jsonObj.get<T>() : defaultValue;
|
|
}
|
|
|
|
/**
|
|
* Explicit type conversion between a JSON object and an std::string
|
|
* @param jsonObj JSON object holding the value
|
|
* @param defaultValue Default value to return if the JSON object is not a string
|
|
* @return Copy of the JSON value converted to std::string
|
|
*/
|
|
std::string GetString(const json_t& jsonObj, const std::string& defaultValue = std::string());
|
|
|
|
/**
|
|
* Explicit type conversion between a JSON object and a boolean
|
|
* @param jsonObj JSON object holding the value
|
|
* @param defaultValue Default value to return if the JSON object is not a boolean
|
|
* @return Copy of the JSON value converted to bool
|
|
*/
|
|
bool GetBoolean(const json_t& jsonObj, bool defaultValue = false);
|
|
|
|
/**
|
|
* Ensures a given JSON object is an object type
|
|
* @param jsonObj JSON object
|
|
* @return The JSON object if it is an object type, or an empty object otherwise
|
|
*/
|
|
json_t AsObject(const json_t& jsonObj);
|
|
|
|
/**
|
|
* Ensures a given JSON object is an array type
|
|
* @param jsonObj JSON object
|
|
* @return The JSON object if it is an array type, or an array containing the JSON object otherwise
|
|
*/
|
|
json_t AsArray(const json_t& jsonObj);
|
|
|
|
/**
|
|
* Helper function to convert a json object and an initializer list to binary flags
|
|
* @param T Type to return
|
|
* @param jsonObj JSON object containing boolean values
|
|
* @param list List of pairs of keys and bits to enable if that key in the object is true
|
|
* @return Value with relevant bits flipped
|
|
*/
|
|
template<typename T> T GetFlags(const json_t& jsonObj, std::initializer_list<std::pair<std::string, T>> list)
|
|
{
|
|
static_assert(std::is_convertible<T, int>::value, "GetFlags template parameter must be integral or a weak enum");
|
|
|
|
T flags{};
|
|
for (const auto& item : list)
|
|
{
|
|
if (jsonObj.contains(item.first) && Json::GetBoolean(jsonObj[item.first]))
|
|
{
|
|
flags = static_cast<T>(flags | item.second);
|
|
}
|
|
}
|
|
return flags;
|
|
}
|
|
|
|
/**
|
|
* Used by the GetFlags function to allow for inverted values
|
|
*/
|
|
enum class FlagType : uint8_t
|
|
{
|
|
// Flag is turned on if the key is true
|
|
Normal,
|
|
// Flag is turned on if the key is false
|
|
Inverted
|
|
};
|
|
|
|
/**
|
|
* Helper function to convert a json object and an initializer list to binary flags
|
|
* @param T Type to return
|
|
* @param jsonObj JSON object containing boolean values
|
|
* @param list List of tuples of keys, bits to change and flag type
|
|
* @return Value with relevant bits flipped
|
|
* @note FLAG_NORMAL behaves like the other GetFlags function, but FLAG_INVERTED will turn the flag on when false
|
|
*/
|
|
template<typename T> T GetFlags(const json_t& jsonObj, std::initializer_list<std::tuple<std::string, T, FlagType>> list)
|
|
{
|
|
static_assert(std::is_convertible<T, int>::value, "GetFlags template parameter must be integral or a weak enum");
|
|
|
|
T flags{};
|
|
for (const auto& item : list)
|
|
{
|
|
if (std::get<2>(item) == FlagType::Normal)
|
|
{
|
|
if (jsonObj.contains(std::get<0>(item)) && Json::GetBoolean(jsonObj[std::get<0>(item)]))
|
|
{
|
|
flags = static_cast<T>(flags | std::get<1>(item));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// if the json flag doesn't exist, assume it's false
|
|
if (!jsonObj.contains(std::get<0>(item)) || !Json::GetBoolean(jsonObj[std::get<0>(item)]))
|
|
{
|
|
flags = static_cast<T>(flags | std::get<1>(item));
|
|
}
|
|
}
|
|
}
|
|
return flags;
|
|
}
|
|
} // namespace Json
|
|
|
|
class JsonException final : public std::runtime_error
|
|
{
|
|
public:
|
|
explicit JsonException(const std::string& message)
|
|
: std::runtime_error(message)
|
|
{
|
|
}
|
|
};
|