150 lines
4.6 KiB
C++
150 lines
4.6 KiB
C++
#include <Nazara/Core/JsonSerialization.hpp>
|
|
#include <Nazara/Core/FilesystemAppComponent.hpp>
|
|
#include <Nazara/Core/ApplicationBase.hpp>
|
|
|
|
#include <nlohmann/json.hpp>
|
|
|
|
#include <stack>
|
|
|
|
namespace Nz
|
|
{
|
|
struct JsonImpl
|
|
{
|
|
|
|
nlohmann::json& Top() { return *stack.top(); }
|
|
|
|
bool Pop()
|
|
{
|
|
if (stack.empty())
|
|
{
|
|
NazaraAssert(stack.empty(), "Stack is empty");
|
|
return false;
|
|
}
|
|
stack.pop();
|
|
return true;
|
|
}
|
|
|
|
nlohmann::json json;
|
|
std::stack<nlohmann::json*> stack;
|
|
};
|
|
|
|
JsonSerializationContext::JsonSerializationContext()
|
|
: m_impl(std::make_unique<JsonImpl>())
|
|
{}
|
|
|
|
JsonSerializationContext::~JsonSerializationContext() {}
|
|
|
|
bool JsonSerializationContext::Load(const std::filesystem::path& path)
|
|
{
|
|
Nz::File file(path, Nz::OpenMode::Read);
|
|
return Load(file);
|
|
}
|
|
|
|
bool JsonSerializationContext::Load(Stream& stream)
|
|
{
|
|
if (!stream.IsReadable())
|
|
return false;
|
|
|
|
auto size = stream.GetSize();
|
|
std::vector<char> content(size);
|
|
stream.Read(content.data(), content.size());
|
|
|
|
m_impl->json = nlohmann::json::parse(content.begin(), content.end());
|
|
m_impl->stack.push(&m_impl->json);
|
|
return true;
|
|
}
|
|
|
|
bool JsonSerializationContext::PushObject(std::string_view name)
|
|
{
|
|
if (name.empty()) // special case if name is empty, don't push
|
|
return true;
|
|
|
|
if (!m_impl->Top().contains(name))
|
|
return false;
|
|
|
|
if (!m_impl->Top()[name].is_object())
|
|
{
|
|
NazaraAssert(m_impl->Top()[name].is_object(), "Value is not an object");
|
|
return false;
|
|
}
|
|
m_impl->stack.push(&m_impl->Top()[name]);
|
|
return true;
|
|
}
|
|
|
|
bool JsonSerializationContext::PopObject()
|
|
{
|
|
return m_impl->Pop();
|
|
}
|
|
|
|
bool JsonSerializationContext::PushArray(std::string_view name)
|
|
{
|
|
if (!m_impl->Top()[name].is_array())
|
|
{
|
|
NazaraAssert(m_impl->Top()[name].is_array(), "Value is not an array");
|
|
return false;
|
|
}
|
|
m_impl->stack.push(&m_impl->Top()[name]);
|
|
return true;
|
|
}
|
|
|
|
bool JsonSerializationContext::PopArray()
|
|
{
|
|
return m_impl->Pop();
|
|
}
|
|
|
|
#define DEF_SERIALIZE(Type, cond) \
|
|
bool JsonSerializationContext::Write(std::string_view name, Type value) \
|
|
{ \
|
|
m_impl->Top()[name] = value; \
|
|
return true; \
|
|
} \
|
|
bool JsonSerializationContext::Read(std::string_view name, Type* value) \
|
|
{ \
|
|
if (!m_impl->Top()[name].cond()) \
|
|
{ \
|
|
/*NazaraAssert(m_impl->Top()[name].cond(), "Value failed check: " #cond "()");*/\
|
|
return false; \
|
|
} \
|
|
*value = m_impl->Top()[name].get<Type>(); \
|
|
return true; \
|
|
} \
|
|
|
|
DEF_SERIALIZE(bool, is_boolean);
|
|
DEF_SERIALIZE(Nz::Int8, is_number);
|
|
DEF_SERIALIZE(Nz::Int16, is_number);
|
|
DEF_SERIALIZE(Nz::Int32, is_number);
|
|
DEF_SERIALIZE(Nz::Int64, is_number);
|
|
DEF_SERIALIZE(Nz::UInt8, is_number);
|
|
DEF_SERIALIZE(Nz::UInt16, is_number);
|
|
DEF_SERIALIZE(Nz::UInt32, is_number);
|
|
DEF_SERIALIZE(Nz::UInt64, is_number);
|
|
DEF_SERIALIZE(float, is_number);
|
|
DEF_SERIALIZE(double, is_number);
|
|
#undef DEF_SERIALIZE
|
|
|
|
bool JsonSerializationContext::Write(std::string_view name, const std::string& value)
|
|
{
|
|
m_impl->Top()[name] = value;
|
|
return true;
|
|
}
|
|
|
|
bool JsonSerializationContext::Read(std::string_view name, std::string* value)
|
|
{
|
|
if (!m_impl->Top()[name].is_string())
|
|
{
|
|
NazaraAssert(m_impl->Top()[name].is_string(), "Value failed check: is_string()");
|
|
return false;
|
|
}
|
|
*value = m_impl->Top()[name].get<std::string>();
|
|
return true;
|
|
}
|
|
|
|
std::shared_ptr<JsonSerializationContext> JsonSerializationContext::LoadFromStream(Stream& stream, const JsonSerializationContext::Params&)
|
|
{
|
|
std::shared_ptr<JsonSerializationContext> context = std::make_shared<JsonSerializationContext>();
|
|
if (context->Load(stream))
|
|
return context;
|
|
return {};
|
|
}
|
|
}
|