/* ** sandbox-serial-util.h ** ** This file is part of mkxp. ** ** Copyright (C) 2013 - 2021 Amaryllis Kulla ** ** mkxp is free software: you can redistribute it and/or modify ** it under the terms of the GNU General Public License as published by ** the Free Software Foundation, either version 2 of the License, or ** (at your option) any later version. ** ** mkxp 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 General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with mkxp. If not, see . */ #ifndef MKXPZ_SANDBOX_SERIAL_UTIL_H #define MKXPZ_SANDBOX_SERIAL_UTIL_H #include #include #include #include #include #include "binding-util.h" #include "quadarray.h" namespace mkxp_sandbox { extern std::vector> extra_objects; extern std::unordered_map objects_deser; extern std::unordered_map extra_objects_deser; template using sandbox_serialize_member_declaration = decltype(std::declval().sandbox_serialize(std::declval(), std::declval())); template using sandbox_deserialize_member_declaration = decltype(std::declval().sandbox_deserialize(std::declval(), std::declval())); template typename std::enable_if::value, bool>::type sandbox_serialize(T value, void *&data, wasm_size_t &max_size); template typename std::enable_if::value, bool>::type sandbox_serialize(T value, void *&data, wasm_size_t &max_size); template typename std::enable_if::value && !std::is_enum::value && std::is_arithmetic::value, bool>::type sandbox_serialize(T value, void *&data, wasm_size_t &max_size); template bool sandbox_serialize(const std::vector &value, void *&data, wasm_size_t &max_size); template bool sandbox_serialize(const QuadArray &value, void *&data, wasm_size_t &max_size); template typename std::enable_if::value, bool>::type sandbox_serialize(const T *value, void *&data, wasm_size_t &max_size); template typename std::enable_if::value, bool>::type sandbox_serialize(const T *value, void *&data, wasm_size_t &max_size); template typename std::enable_if::value && boost::is_detected::value, bool>::type sandbox_serialize(const T &value, void *&data, wasm_size_t &max_size); template typename std::enable_if::value && !boost::is_detected::value, bool>::type sandbox_serialize(const T &value, void *&data, wasm_size_t &max_size); template typename std::enable_if::value && std::is_same::value, bool>::type sandbox_deserialize(T &value, void *&data, wasm_size_t &max_size); template typename std::enable_if::value && std::is_enum::value, bool>::type sandbox_deserialize(T &value, void *&data, wasm_size_t &max_size); template typename std::enable_if::value && !std::is_same::value && !std::is_enum::value && std::is_arithmetic::value, bool>::type sandbox_deserialize(T &value, void *&data, wasm_size_t &max_size); template typename std::enable_if::value, bool>::type sandbox_deserialize(std::vector &value, void *&data, wasm_size_t &max_size); template typename std::enable_if::value, bool>::type sandbox_deserialize(QuadArray &value, void *&data, wasm_size_t &max_size); template typename std::enable_if::value && std::is_class::value, bool>::type sandbox_deserialize(T *&value, void *&data, wasm_size_t &max_size); template typename std::enable_if::value && std::is_class::value && boost::is_detected::value, bool>::type sandbox_deserialize(T &value, void *&data, wasm_size_t &max_size); template typename std::enable_if::value && std::is_class::value && !boost::is_detected::value, bool>::type sandbox_deserialize(T &value, void *&data, wasm_size_t &max_size); template struct sandbox_ptr_map { private: struct info { mkxp_sandbox::wasm_objkey_t key; bool is_extra; }; static std::unordered_map map; static bool is_serializing; static bool is_deserializing; public: static void sandbox_serialize_begin() { using namespace mkxp_sandbox; if (is_deserializing) { std::abort(); } if (is_serializing) { return; } is_serializing = true; map.clear(); extra_objects.clear(); wasm_objkey_t key = 0; for (const auto &object : sb()->get_objects()) { ++key; if (object.typenum == get_typenum::value) { map.emplace((T *)object.inner.ptr, (struct info){.key = key, .is_extra = false}); } } } static bool sandbox_serialize(const T *ptr, void *&data, wasm_size_t &max_size) { using namespace mkxp_sandbox; if (is_deserializing) { std::abort(); } if (ptr == nullptr) { if (!mkxp_sandbox::sandbox_serialize((uint8_t)2, data, max_size)) return false; } else { const auto &it = map.find(ptr); if (it != map.end()) { if (!mkxp_sandbox::sandbox_serialize((uint8_t)(it->second.is_extra ? 1 : 0), data, max_size)) return false; if (!mkxp_sandbox::sandbox_serialize(it->second.key, data, max_size)) return false; } else { if (!mkxp_sandbox::sandbox_serialize((uint8_t)1, data, max_size)) return false; constexpr wasm_size_t typenum = get_typenum::value; extra_objects.emplace_back((const void *)ptr, typenum); map.emplace(ptr, (struct info){.key = (wasm_objkey_t)extra_objects.size(), .is_extra = true}); if (!mkxp_sandbox::sandbox_serialize((wasm_objkey_t)extra_objects.size(), data, max_size)) return false; } } return true; } static void sandbox_serialize_end() { if (is_deserializing) { std::abort(); } is_serializing = false; map.clear(); extra_objects.clear(); } static void sandbox_deserialize_begin() { using namespace mkxp_sandbox; if (is_serializing) { std::abort(); } if (is_deserializing) { return; } is_deserializing = true; objects_deser.clear(); extra_objects_deser.clear(); } static bool sandbox_deserialize(T *&ptr, void *&data, wasm_size_t &max_size) { using namespace mkxp_sandbox; if (is_serializing) { std::abort(); } uint8_t type; if (!mkxp_sandbox::sandbox_deserialize(type, data, max_size)) return false; if (type > 2) return false; if (type == 2) { ptr = nullptr; } else { wasm_objkey_t key; if (!mkxp_sandbox::sandbox_deserialize(key, data, max_size)) return false; (type != 0 ? extra_objects_deser : objects_deser).emplace(key, ptr); } return true; } static void sandbox_deserialize_end() { if (is_serializing) { std::abort(); } is_deserializing = false; objects_deser.clear(); extra_objects_deser.clear(); } }; template std::unordered_map::info> sandbox_ptr_map::map; template bool sandbox_ptr_map::is_serializing = false; template bool sandbox_ptr_map::is_deserializing = false; template typename std::enable_if::value, bool>::type sandbox_serialize(const T *value, void *&data, wasm_size_t &max_size) { return sandbox_ptr_map::sandbox_serialize(value, data, max_size); } template typename std::enable_if::value && std::is_class::value, bool>::type sandbox_deserialize(T *&value, void *&data, wasm_size_t &max_size) { return sandbox_ptr_map::sandbox_deserialize(value, data, max_size); } template bool sandbox_serialize(const std::vector &value, void *&data, wasm_size_t &max_size) { if (!sandbox_serialize((wasm_size_t)value.size(), data, max_size)) return false; for (const T &item : value) { if (!sandbox_serialize(item, data, max_size)) return false; } return true; } template typename std::enable_if::value, bool>::type sandbox_deserialize(std::vector &value, void *&data, wasm_size_t &max_size) { wasm_size_t size; if (!sandbox_deserialize(size, data, max_size)) return false; value.clear(); value.reserve(size); while (size > 0) { value.emplace_back(); if (!sandbox_deserialize(value.back(), data, max_size)) return false; --size; } for (const T &item : value) { if (!sandbox_serialize(item, data, max_size)) return false; } return true; } template bool sandbox_serialize(const QuadArray &value, void *&data, wasm_size_t &max_size) { return sandbox_serialize(value.vertices, data, max_size); } template typename std::enable_if::value, bool>::type sandbox_deserialize(QuadArray &value, void *&data, wasm_size_t &max_size) { if (!sandbox_deserialize(value.vertices, data, max_size)) return false; value.quadCount = value.vertices.size() / 4; return true; } template typename std::enable_if::value, bool>::type sandbox_serialize(T value, void *&data, wasm_size_t &max_size) { return sandbox_serialize((int32_t)value, data, max_size); } template typename std::enable_if::value && std::is_enum::value, bool>::type sandbox_deserialize(T &value, void *&data, wasm_size_t &max_size) { return sandbox_deserialize((int32_t &)value, data, max_size); } template typename std::enable_if::value && boost::is_detected::value, bool>::type sandbox_serialize(const T &value, void *&data, wasm_size_t &max_size) { return value.sandbox_serialize(data, max_size); } template typename std::enable_if::value && std::is_class::value && boost::is_detected::value, bool>::type sandbox_deserialize(T &value, void *&data, wasm_size_t &max_size) { return value.sandbox_deserialize(data, max_size); } } #endif // MKXPZ_SANDBOX_SERIAL_UTIL_H