#include "LuaValueSerializer.h" #include "scripting/lua/LuaTable.h" namespace scripting { namespace util { LuaValueSerializer::LuaValueSerializer(luacpp::LuaValue value) : m_value(std::move(value)) {} SCP_vector LuaValueSerializer::serialize() const { std::unique_ptr serializedJson(toJson()); const auto json = json_dump_string(serializedJson.get(), JSON_ENCODE_ANY | JSON_COMPACT); SCP_vector data; data.reserve(json.size() + 1); // Add a tiny header describing the following data for future proofing. data.push_back(static_cast(SerializationType::PlainJson)); std::transform(json.cbegin(), json.cend(), std::back_inserter(data), [](char c) { return static_cast(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()); case luacpp::ValueType::STRING: { const auto string = m_value.getValue(); return json_stringn(string.c_str(), string.size()); } case luacpp::ValueType::NUMBER: return json_real(m_value.getValue()); 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(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(std::move(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(); LuaValueSerializer valueSerializer(entry.second); json_object_set_new(jsonObj, index.c_str(), valueSerializer.toJson()); } return jsonObj; } } // namespace util } // namespace scripting