1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101
|
#include "LuaValueSerializer.h"
#include "scripting/lua/LuaTable.h"
namespace scripting {
namespace util {
LuaValueSerializer::LuaValueSerializer(luacpp::LuaValue value) : m_value(std::move(value)) {}
SCP_vector<uint8_t> LuaValueSerializer::serialize() const
{
std::unique_ptr<json_t> serializedJson(toJson());
const auto json = json_dump_string(serializedJson.get(), JSON_ENCODE_ANY | JSON_COMPACT);
SCP_vector<uint8_t> data;
data.reserve(json.size() + 1);
// Add a tiny header describing the following data for future proofing.
data.push_back(static_cast<uint8_t>(SerializationType::PlainJson));
std::transform(json.cbegin(), json.cend(), std::back_inserter(data), [](char c) {
return static_cast<uint8_t>(c);
});
return data;
}
json_t* LuaValueSerializer::toJson() const
{
switch (m_value.getValueType()) {
case luacpp::ValueType::NIL:
return json_null();
case luacpp::ValueType::BOOLEAN:
return json_boolean(m_value.getValue<bool>());
case luacpp::ValueType::STRING: {
const auto string = m_value.getValue<SCP_string>();
return json_stringn(string.c_str(), string.size());
}
case luacpp::ValueType::NUMBER:
return json_real(m_value.getValue<double>());
case luacpp::ValueType::TABLE:
return tableToJson();
case luacpp::ValueType::NONE:
case luacpp::ValueType::USERDATA:
case luacpp::ValueType::FUNCTION:
case luacpp::ValueType::LIGHTUSERDATA:
case luacpp::ValueType::THREAD:
default:
throw std::runtime_error("Unsupported value type!");
}
}
json_t* LuaValueSerializer::tableToJson() const
{
luacpp::LuaTable tableVal;
tableVal.setReference(m_value.getReference());
auto testVal = tableVal.getValue<luacpp::LuaValue>(1);
if (testVal.getValueType() == luacpp::ValueType::NIL) {
// If there is no first array element then we assume it is an object
return tableToJsonObject(tableVal);
} else {
// Assume this is an object
return tableToJsonArray(tableVal);
}
}
json_t* LuaValueSerializer::tableToJsonArray(const luacpp::LuaTable& table)
{
auto size = table.getLength();
auto jsonArray = json_array();
for (size_t i = 1; i <= size; ++i) {
luacpp::LuaValue arrayVal;
if (!table.getValue(i, arrayVal)) {
json_array_append_new(jsonArray, json_null());
} else {
LuaValueSerializer valueSerializer(arrayVal);
json_array_append_new(jsonArray, valueSerializer.toJson());
}
}
return jsonArray;
}
json_t* LuaValueSerializer::tableToJsonObject(const luacpp::LuaTable& table)
{
auto jsonObj = json_object();
for (const auto& entry : table) {
if (entry.first.getValueType() != luacpp::ValueType::STRING) {
// Ignore non-string indices
continue;
}
const auto index = entry.first.getValue<SCP_string>();
LuaValueSerializer valueSerializer(entry.second);
json_object_set_new(jsonObj, index.c_str(), valueSerializer.toJson());
}
return jsonObj;
}
} // namespace util
} // namespace scripting
|