diff --git a/binding-sandbox/binding-base.cpp b/binding-sandbox/binding-base.cpp index ca2ac6ff..fa5bdcb6 100644 --- a/binding-sandbox/binding-base.cpp +++ b/binding-sandbox/binding-base.cpp @@ -220,6 +220,8 @@ void binding_base::strncpy(wasm_ptr_t dst_address, const char *src, wasm_size_t sandbox_strncpy(instance(), dst_address, src, max_size); } +binding_base::object::object() : inner {.next = 0}, typenum(0) {} + binding_base::object::object(wasm_size_t typenum, void *ptr) : inner {.ptr = ptr}, typenum(typenum) {} binding_base::object::object(struct object &&object) noexcept : inner(std::exchange(object.inner, (union binding_base::object::inner){.next = 0})), typenum(std::exchange(object.typenum, 0)) {} @@ -239,10 +241,6 @@ binding_base::object::~object() { } } -const std::vector &binding_base::get_objects() const noexcept { - return objects; -} - wasm_objkey_t binding_base::create_object(wasm_size_t typenum, void *ptr) { if (ptr == nullptr || typenum == 0 || typenum > typenum_table_size) { std::abort(); diff --git a/binding-sandbox/binding-base.h b/binding-sandbox/binding-base.h index 3b90f218..074441cb 100644 --- a/binding-sandbox/binding-base.h +++ b/binding-sandbox/binding-base.h @@ -199,8 +199,10 @@ namespace mkxp_sandbox { } struct typenum_table_entry { + void *(*constructor)(); void (*destructor)(void *self); bool (*serialize)(const void *self, void *&data, wasm_size_t &max_size); + bool (*deserialize)(void *self, const void *&data, wasm_size_t &max_size); }; extern const struct typenum_table_entry typenum_table[]; @@ -270,6 +272,7 @@ namespace mkxp_sandbox { // Otherwise, this is a number corresponding to the type of the object. wasm_size_t typenum; + object(); object(wasm_size_t typenum, void *ptr); object(const struct object &object) = delete; object(struct object &&object) noexcept; @@ -278,12 +281,14 @@ namespace mkxp_sandbox { ~object(); }; - std::shared_ptr _instance; + public: std::vector objects; - wasm_objkey_t next_free_objkey; + private: + std::shared_ptr _instance; wasm_ptr_t stack_ptr; public: + wasm_objkey_t next_free_objkey; std::unordered_map> fibers; binding_base(std::shared_ptr m); @@ -335,9 +340,6 @@ namespace mkxp_sandbox { return sandbox_arycpy(instance(), dst_address, src, num_elements); } - // Returns a reference to all currently existing objects. - const std::vector &get_objects() const noexcept; - // Creates a new object and returns its key. wasm_objkey_t create_object(wasm_size_t typenum, void *ptr); diff --git a/binding-sandbox/binding-util.cpp b/binding-sandbox/binding-util.cpp index 39717d68..a8806c15 100644 --- a/binding-sandbox/binding-util.cpp +++ b/binding-sandbox/binding-util.cpp @@ -24,9 +24,33 @@ using namespace mkxp_sandbox; +template static typename std::enable_if::value, void *>::type constructor() { + static_assert(!(std::is_same::value || std::is_same::value), "this type should not have a public constructor"); + return new T; +} + +template static typename std::enable_if::value && std::is_constructible::value, void *>::type constructor() { + static_assert(!(std::is_same::value || std::is_same::value), "this type should not have a public constructor"); + Exception e; + T *obj = new T(e); + if (e.is_ok()) { + return obj; + } else { + delete obj; + return nullptr; + } +} + +template static typename std::enable_if::value && !std::is_constructible::value, void *>::type constructor() { + static_assert((std::is_same::value || std::is_same::value), "this type should have a public constructor"); + return nullptr; +} + template static typename std::enable_if::value>::type destructor(void *self) { static_assert(!(std::is_same::value || std::is_same::value), "this type should not have a public destructor"); - delete (T *)self; + if (self != nullptr) { + delete (T *)self; + } } template static typename std::enable_if::value>::type destructor(void *self) { @@ -37,7 +61,11 @@ template static bool serialize(const void *self, void *&data, wasm_ return ((const T *)self)->sandbox_serialize(data, max_size); } -#define _SANDBOX_DEF_TYPENUM_TABLE_ENTRY(_r, _data, T) {.destructor = destructor, .serialize = serialize}, +template static bool deserialize(void *self, const void *&data, wasm_size_t &max_size) { + return ((T *)self)->sandbox_deserialize(data, max_size); +} + +#define _SANDBOX_DEF_TYPENUM_TABLE_ENTRY(_r, _data, T) {.constructor = constructor, .destructor = destructor, .serialize = serialize, .deserialize = deserialize}, extern const struct typenum_table_entry mkxp_sandbox::typenum_table[SANDBOX_NUM_TYPENUMS] = {BOOST_PP_SEQ_FOR_EACH(_SANDBOX_DEF_TYPENUM_TABLE_ENTRY, _, SANDBOX_TYPENUM_TYPES)}; extern const wasm_size_t mkxp_sandbox::typenum_table_size = SANDBOX_NUM_TYPENUMS; diff --git a/binding-sandbox/sandbox-serial-util.cpp b/binding-sandbox/sandbox-serial-util.cpp index e185256f..91494354 100644 --- a/binding-sandbox/sandbox-serial-util.cpp +++ b/binding-sandbox/sandbox-serial-util.cpp @@ -44,7 +44,7 @@ std::vector> mkxp_sandbox::extra_objects; std::unordered_map mkxp_sandbox::objects_deser; std::unordered_map mkxp_sandbox::extra_objects_deser; -sandbox_object_deser_info::sandbox_object_deser_info() : ptr(new std::vector), typenum(0), ref_count(0), exists(false) {} +sandbox_object_deser_info::sandbox_object_deser_info(void *ptr, wasm_size_t typenum) : ptr(ptr), typenum(typenum), ref_count(0), exists(true) {} sandbox_object_deser_info::sandbox_object_deser_info(struct sandbox_object_deser_info &&info) noexcept : ptr(std::exchange(info.ptr, nullptr)), typenum(info.typenum), ref_count(std::exchange(info.ref_count, 1)), exists(std::exchange(info.exists, true)) {} @@ -66,6 +66,32 @@ wasm_size_t sandbox_object_deser_info::get_ref_count() const noexcept { return ref_count; } +bool sandbox_object_deser_info::set_ptr(void *ptr, wasm_size_t typenum) { + if (this->typenum != typenum) { + return false; + } + if (exists && ptr != this->ptr) { + return false; + } + if (!exists) { + for (void **ref : *(std::vector *)this->ptr) { + *ref = ptr; + } + delete (std::vector *)this->ptr; + exists = true; + this->ptr = ptr; + } + return true; +} + +void *sandbox_object_deser_info::get_ptr() { + return exists ? ptr : nullptr; +} + +wasm_size_t sandbox_object_deser_info::get_typenum() { + return typenum; +} + template <> bool mkxp_sandbox::sandbox_serialize(bool value, void *&data, wasm_size_t &max_size) { RESERVE(sizeof(uint8_t)); *(uint8_t *)data = value; @@ -221,7 +247,8 @@ template <> bool mkxp_sandbox::sandbox_deserialize(double &value, const void *&d } template <> bool mkxp_sandbox::sandbox_serialize(const char *value, void *&data, wasm_size_t &max_size) { - wasm_size_t size = std::strlen(value) + 1; + wasm_size_t size = std::strlen(value); + if (!sandbox_serialize(size, data, max_size)) return false; RESERVE(size); std::memcpy(data, value, size); ADVANCE(size); @@ -229,7 +256,8 @@ template <> bool mkxp_sandbox::sandbox_serialize(const char *value, void *&data, } template <> bool mkxp_sandbox::sandbox_serialize(const std::string &value, void *&data, wasm_size_t &max_size) { - wasm_size_t size = value.length() + 1; + wasm_size_t size = value.length(); + if (!sandbox_serialize(size, data, max_size)) return false; RESERVE(size); std::memcpy(data, value.c_str(), size); ADVANCE(size); @@ -239,12 +267,12 @@ template <> bool mkxp_sandbox::sandbox_serialize(const std::string &value, void template <> bool mkxp_sandbox::sandbox_deserialize(std::string &value, const void *&data, wasm_size_t &max_size) { wasm_size_t size; if (!sandbox_deserialize(size, data, max_size)) return false; - if (size == 0 || ((const char *)data)[size - 1] != 0) return false; RESERVE(size); - value.resize(size - 1); + value.clear(); + value.resize(size); char *str = &value[0]; - std::memcpy(str, data, size - 1); - if (std::strlen(str) != size - 1) { + std::memcpy(str, data, size); + if (std::strlen(str) != size) { value.clear(); return false; } diff --git a/binding-sandbox/sandbox-serial-util.h b/binding-sandbox/sandbox-serial-util.h index a6c16016..4857e19c 100644 --- a/binding-sandbox/sandbox-serial-util.h +++ b/binding-sandbox/sandbox-serial-util.h @@ -32,8 +32,8 @@ namespace mkxp_sandbox { struct sandbox_object_deser_info { - sandbox_object_deser_info(); - template sandbox_object_deser_info(T *ptr) : ptr(ptr), typenum(get_typenum::value), ref_count(0), exists(true) {} + template sandbox_object_deser_info(T *&ref) : ptr(new std::vector({(void **)&ref})), typenum(mkxp_sandbox::get_typenum::value), ref_count(1), exists(false) {} + sandbox_object_deser_info(void *ptr, wasm_size_t typenum); sandbox_object_deser_info(const struct sandbox_object_deser_info &) = delete; sandbox_object_deser_info(struct sandbox_object_deser_info &&) noexcept; struct sandbox_object_deser_info &operator=(const struct sandbox_object_deser_info &) = delete; @@ -41,37 +41,25 @@ namespace mkxp_sandbox { ~sandbox_object_deser_info(); wasm_size_t get_ref_count() const noexcept; template bool add_ref(T *&ref) { - if (typenum == 0) { - typenum = get_typenum::value; - } else if (typenum != get_typenum::value) { + if (typenum != mkxp_sandbox::get_typenum::value) { + return false; + } + if (ref_count > 0 && (std::is_same::value || std::is_same::value || std::is_same::value || std::is_same::value || std::is_same::value)) { + // Don't allow types that are copied by value (Color, Tone and Rect) or autotiles/bitmap arrays to be referenced more than once return false; } if (exists) { ref = (T *)ptr; } else { + ref = nullptr; ((std::vector *)ptr)->push_back((void **)&ref); } ++ref_count; return true; } - template bool set_ptr(T *ptr) { - if (typenum == 0) { - typenum = get_typenum::value; - } else if (typenum != get_typenum::value) { - return false; - } - if (exists && ptr != this->ptr) { - return false; - } - if (!exists) { - for (void **ref : *(std::vector *)this->ptr) { - *(T **)ref = ptr; - } - delete (std::vector *)this->ptr; - exists = true; - this->ptr = ptr; - } - } + bool set_ptr(void *ptr, wasm_size_t typenum); + void *get_ptr(); + wasm_size_t get_typenum(); private: // If `exists` is true, this is a pointer to the object. Otherwise, this is a `std::vector` of pointers that are waiting to point to the object. @@ -138,7 +126,7 @@ namespace mkxp_sandbox { extra_objects.clear(); wasm_objkey_t key = 0; - for (const auto &object : sb()->get_objects()) { + for (const auto &object : sb()->objects) { ++key; if (object.typenum == get_typenum::value) { map.emplace((T *)object.inner.ptr, (struct info){.key = key, .is_extra = false}); @@ -221,7 +209,8 @@ namespace mkxp_sandbox { auto &deser_map = type != 0 ? extra_objects_deser : objects_deser; const auto it = deser_map.find(key); if (it == deser_map.end()) { - return deser_map.emplace(key, sandbox_object_deser_info()).first->second.add_ref(ref); + deser_map.emplace(key, sandbox_object_deser_info(ref)); + return true; } else { return it->second.add_ref(ref); } @@ -234,6 +223,15 @@ namespace mkxp_sandbox { is_deserializing = false; objects_deser.clear(); + + // Delete extra objects with no references so we don't leak them + for (auto &pair : extra_objects_deser) { + struct sandbox_object_deser_info &info = pair.second; + if (info.get_ref_count() == 0 && info.get_ptr() != nullptr) { + typenum_table[info.get_typenum() - 1].destructor(info.get_ptr()); + } + } + extra_objects_deser.clear(); } }; @@ -268,9 +266,6 @@ namespace mkxp_sandbox { if (!sandbox_deserialize(value.back(), data, max_size)) return false; --size; } - for (T &item : value) { - if (!sandbox_deserialize(item, data, max_size)) return false; - } return true; } diff --git a/binding-sandbox/sandbox.cpp b/binding-sandbox/sandbox.cpp index 608884a5..3efa0433 100644 --- a/binding-sandbox/sandbox.cpp +++ b/binding-sandbox/sandbox.cpp @@ -129,6 +129,10 @@ bool sandbox::sandbox_serialize_fdtable(void *&data, wasm_size_t &max_size) cons return wasi->sandbox_serialize(data, max_size); } +bool sandbox::sandbox_deserialize_fdtable(const void *&data, wasm_size_t &max_size) { + return wasi->sandbox_deserialize(data, max_size); +} + Movie *sandbox::get_movie_from_main_thread() { return movie.load(std::memory_order_relaxed); // No need for synchronization because we always set the movie from the main thread } diff --git a/binding-sandbox/sandbox.h b/binding-sandbox/sandbox.h index 9ddcd6c8..21e4e63c 100644 --- a/binding-sandbox/sandbox.h +++ b/binding-sandbox/sandbox.h @@ -64,6 +64,7 @@ namespace mkxp_sandbox { sandbox(); ~sandbox(); bool sandbox_serialize_fdtable(void *&data, wasm_size_t &max_size) const; + bool sandbox_deserialize_fdtable(const void *&data, wasm_size_t &max_size); Movie *get_movie_from_main_thread(); Movie *get_movie_from_audio_thread(); void set_movie(Movie *new_movie); diff --git a/binding-sandbox/wasi.cpp b/binding-sandbox/wasi.cpp index 1ee3015c..ca9372ca 100644 --- a/binding-sandbox/wasi.cpp +++ b/binding-sandbox/wasi.cpp @@ -20,6 +20,7 @@ */ #include +#include #include #include #include @@ -41,8 +42,8 @@ struct fs_dir *wasi_file_entry::dir_handle() const noexcept { return (struct fs_dir *)handle; } -struct FileSystem::File *wasi_file_entry::file_handle() const noexcept { - return (struct FileSystem::File *)handle; +struct fs_file *wasi_file_entry::file_handle() const noexcept { + return (struct fs_file *)handle; } wasi_t::w2c_wasi__snapshot__preview1(std::shared_ptr ruby) : ruby(ruby) { @@ -50,15 +51,15 @@ wasi_t::w2c_wasi__snapshot__preview1(std::shared_ptr ruby) : ru fdtable.push_back({.type = wasi_fd_type::STDIN}); fdtable.push_back({.type = wasi_fd_type::STDOUT}); fdtable.push_back({.type = wasi_fd_type::STDERR}); - fdtable.push_back({.type = wasi_fd_type::FS, .handle = new fs_dir {.root = nullptr, .path = std::string("/Game"), .writable = true}}); - fdtable.push_back({.type = wasi_fd_type::FS, .handle = new fs_dir {.root = nullptr, .path = std::string("/Save"), .writable = true}}); - fdtable.push_back({.type = wasi_fd_type::FS, .handle = new fs_dir {.root = nullptr, .path = std::string("/System"), .writable = false}}); - fdtable.push_back({.type = wasi_fd_type::FS, .handle = new fs_dir {.root = nullptr, .path = std::string("/Dist"), .writable = false}}); + fdtable.push_back({.type = wasi_fd_type::FS, .handle = new fs_dir {.path = std::string("/Game"), .writable = true}}); + fdtable.push_back({.type = wasi_fd_type::FS, .handle = new fs_dir {.path = std::string("/Save"), .writable = true}}); + fdtable.push_back({.type = wasi_fd_type::FS, .handle = new fs_dir {.path = std::string("/System"), .writable = false}}); + fdtable.push_back({.type = wasi_fd_type::FS, .handle = new fs_dir {.path = std::string("/Dist"), .writable = false}}); } wasi_t::~w2c_wasi__snapshot__preview1() { // Close all of the open WASI file descriptors - for (size_t i = fdtable.size(); i > 0;) { + for (uint32_t i = fdtable.size(); i > 0;) { deallocate_file_descriptor(--i); } } @@ -76,12 +77,17 @@ struct fs_enumerate_data { uint32_t wasi_t::allocate_file_descriptor(enum wasi_fd_type type, void *handle) { if (vacant_fds.empty()) { + if (fdtable.size() >= UINT32_MAX) { + MKXPZ_THROW(std::bad_alloc()); + } uint32_t fd = fdtable.size(); fdtable.push_back({.type = type, .handle = handle}); return fd; } else { uint32_t fd = vacant_fds.back(); vacant_fds.pop_back(); + fdtable[fd].type = type; + fdtable[fd].handle = handle; return fd; } } @@ -97,16 +103,12 @@ void wasi_t::deallocate_file_descriptor(uint32_t fd) { delete fdtable[fd].file_handle(); break; default: - break; + return; } } - if (!fdtable.empty() && fd == fdtable.size() - 1) { - fdtable.pop_back(); - } else { - fdtable[fd] = {.type = wasi_fd_type::VACANT, .handle = nullptr}; - vacant_fds.push_back(fd); - } + fdtable[fd] = {.type = wasi_fd_type::VACANT, .handle = nullptr}; + vacant_fds.push_back(fd); } void *wasi_t::ptr(wasm_ptr_t address) const noexcept { @@ -130,9 +132,9 @@ const char *wasi_t::str(wasm_ptr_t address) const noexcept { } bool wasi_t::sandbox_serialize(void *&data, mkxp_sandbox::wasm_size_t &max_size) const { - if (!::sandbox_serialize((wasm_size_t)fdtable.size(), data, max_size)) return false; + if (!::sandbox_serialize((uint32_t)fdtable.size(), data, max_size)) return false; - wasm_size_t num_free_handles = 0; + uint32_t num_free_handles = 0; for (const struct wasi_file_entry &entry : fdtable) { if (entry.type == wasi_fd_type::FSDIR) { @@ -142,8 +144,8 @@ bool wasi_t::sandbox_serialize(void *&data, mkxp_sandbox::wasm_size_t &max_size) num_free_handles = 0; } if (!::sandbox_serialize((uint8_t)1, data, max_size)) return false; + if (!::sandbox_serialize(entry.dir_handle()->root, data, max_size)) return false; if (!::sandbox_serialize(entry.dir_handle()->path, data, max_size)) return false; - if (!::sandbox_serialize(entry.dir_handle()->root->path, data, max_size)) return false; } else if (entry.type == wasi_fd_type::FSFILE) { if (num_free_handles > 0) { if (!::sandbox_serialize((uint8_t)0, data, max_size)) return false; @@ -151,7 +153,8 @@ bool wasi_t::sandbox_serialize(void *&data, mkxp_sandbox::wasm_size_t &max_size) num_free_handles = 0; } if (!::sandbox_serialize((uint8_t)2, data, max_size)) return false; - if (!::sandbox_serialize(entry.file_handle()->path(), data, max_size)) return false; + if (!::sandbox_serialize(entry.file_handle()->root, data, max_size)) return false; + if (!::sandbox_serialize(entry.file_handle()->file.path(), data, max_size)) return false; } else { ++num_free_handles; } @@ -165,6 +168,79 @@ bool wasi_t::sandbox_serialize(void *&data, mkxp_sandbox::wasm_size_t &max_size) return true; } +bool wasi_t::sandbox_deserialize(const void *&data, mkxp_sandbox::wasm_size_t &max_size) { + uint32_t size; + if (!::sandbox_deserialize(size, data, max_size)) return false; + + for (uint32_t i = fdtable.size(); i > size;) { + deallocate_file_descriptor(--i); + } + vacant_fds.clear(); + fdtable.resize(size, {.type = wasi_fd_type::VACANT}); + + uint32_t i = 0; + while (i < size) { + uint8_t type; + if (!::sandbox_deserialize(type, data, max_size)) return false; + + if (type == 0) { + uint32_t num_free_handles; + if (!::sandbox_deserialize(num_free_handles, data, max_size)) return false; + if (i + num_free_handles > size || i + num_free_handles < i) return false; + for (uint32_t j = i; j < i + num_free_handles; ++j) { + deallocate_file_descriptor(j); + vacant_fds.clear(); + } + i += num_free_handles; + } else { + if (fdtable[i].type != wasi_fd_type::VACANT && fdtable[i].type != wasi_fd_type::FSDIR && fdtable[i].type != wasi_fd_type::FSFILE) { + return false; + } + if (type == 1) { + if (fdtable[i].type != wasi_fd_type::VACANT && fdtable[i].type != wasi_fd_type::FSDIR) { + deallocate_file_descriptor(i); + vacant_fds.clear(); + } + uint32_t root; + if (!::sandbox_deserialize(root, data, max_size)) return false; + if (root >= fdtable.size() || fdtable[root].type != wasi_fd_type::FS) return false; + std::string path; + if (!::sandbox_deserialize(path, data, max_size)) return false; + path = mkxp_retro::fs->normalize(path.c_str(), false, true); + fdtable[i] = {.type = wasi_fd_type::FSDIR, .handle = new fs_dir {.path = path, .root = root, .writable = fdtable[root].dir_handle()->writable}}; + } else if (type == 2) { + if (fdtable[i].type != wasi_fd_type::VACANT && fdtable[i].type != wasi_fd_type::FSFILE) { + deallocate_file_descriptor(i); + vacant_fds.clear(); + } + uint32_t root; + if (!::sandbox_deserialize(root, data, max_size)) return false; + if (root >= fdtable.size() || fdtable[root].type != wasi_fd_type::FS) return false; + std::string path; + if (!::sandbox_deserialize(path, data, max_size)) return false; + path = mkxp_retro::fs->normalize(path.c_str(), false, true); + struct fs_file *handle = new fs_file {.file {*mkxp_retro::fs, path.c_str(), fdtable[root].dir_handle()->writable ? fdtable[root].dir_handle()->path.c_str() : nullptr, false}, .root = root}; + if (!handle->file.is_open() || (fdtable[root].dir_handle()->writable && !handle->file.is_write_open())) { + delete handle; + return false; + } + fdtable[i] = {.type = wasi_fd_type::FSFILE, .handle = handle}; + } else { + return false; + } + ++i; + } + } + + for (uint32_t j = 0; i < fdtable.size(); ++j) { + if (fdtable[j].type == wasi_fd_type::VACANT) { + vacant_fds.push_back(j); + } + } + + return true; +} + extern "C" uint32_t w2c_wasi__snapshot__preview1_args_get(wasi_t *wasi, wasm_ptr_t argv, wasm_ptr_t argv_buf) { return WASI_ESUCCESS; } @@ -212,6 +288,7 @@ extern "C" uint32_t w2c_wasi__snapshot__preview1_fd_close(wasi_t *wasi, uint32_t case wasi_fd_type::STDOUT: case wasi_fd_type::STDERR: case wasi_fd_type::FS: + return WASI_EINVAL; case wasi_fd_type::FSDIR: case wasi_fd_type::FSFILE: @@ -324,7 +401,7 @@ extern "C" uint32_t w2c_wasi__snapshot__preview1_fd_filestat_get(wasi_t *wasi, u case wasi_fd_type::FSFILE: { PHYSFS_Stat stat; - if (!PHYSFS_stat(wasi->fdtable[fd].file_handle()->path(), &stat)) { + if (!PHYSFS_stat(wasi->fdtable[fd].file_handle()->file.path(), &stat)) { return WASI_ENOENT; } if (stat.filetype != PHYSFS_FILETYPE_REGULAR) { @@ -448,7 +525,7 @@ extern "C" uint32_t w2c_wasi__snapshot__preview1_fd_read(wasi_t *wasi, uint32_t #ifdef MKXPZ_BIG_ENDIAN ptr -= length; #endif // MKXPZ_BIG_ENDIAN - PHYSFS_sint64 n = PHYSFS_readBytes(wasi->fdtable[fd].file_handle()->get(), ptr, length); + PHYSFS_sint64 n = PHYSFS_readBytes(wasi->fdtable[fd].file_handle()->file.get(), ptr, length); #ifdef MKXPZ_BIG_ENDIAN std::reverse(ptr, ptr + length); #endif // MKXPZ_BIG_ENDIAN @@ -597,12 +674,8 @@ extern "C" uint32_t w2c_wasi__snapshot__preview1_fd_renumber(wasi_t *wasi, uint3 } else { wasi->fdtable[to] = wasi->fdtable[fd]; } - if (!wasi->fdtable.empty() && fd == wasi->fdtable.size() - 1) { - wasi->fdtable.pop_back(); - } else { - wasi->fdtable[fd] = {.type = wasi_fd_type::VACANT, .handle = nullptr}; - wasi->vacant_fds.push_back(fd); - } + wasi->fdtable[fd] = {.type = wasi_fd_type::VACANT, .handle = nullptr}; + wasi->vacant_fds.push_back(fd); return WASI_ESUCCESS; } @@ -634,7 +707,7 @@ extern "C" uint32_t w2c_wasi__snapshot__preview1_fd_tell(wasi_t *wasi, uint32_t return WASI_EINVAL; case wasi_fd_type::FSFILE: - wasi->ref(result) = PHYSFS_tell(wasi->fdtable[fd].file_handle()->get()); + wasi->ref(result) = PHYSFS_tell(wasi->fdtable[fd].file_handle()->file.get()); return WASI_ESUCCESS; } @@ -681,7 +754,7 @@ extern "C" uint32_t w2c_wasi__snapshot__preview1_fd_write(wasi_t *wasi, uint32_t case wasi_fd_type::FSFILE: { - if (!wasi->fdtable[fd].file_handle()->is_write_open()) { + if (!wasi->fdtable[fd].file_handle()->file.is_write_open()) { return WASI_EROFS; } uint32_t size = 0; @@ -692,7 +765,7 @@ extern "C" uint32_t w2c_wasi__snapshot__preview1_fd_write(wasi_t *wasi, uint32_t ptr -= length; std::reverse(ptr, ptr + length); #endif // MKXPZ_BIG_ENDIAN - PHYSFS_sint64 n = PHYSFS_writeBytes(wasi->fdtable[fd].file_handle()->get_write(), ptr, length); + PHYSFS_sint64 n = PHYSFS_writeBytes(wasi->fdtable[fd].file_handle()->file.get_write(), ptr, length); #ifdef MKXPZ_BIG_ENDIAN std::reverse(ptr, ptr + length); #endif // MKXPZ_BIG_ENDIAN @@ -777,6 +850,10 @@ extern "C" uint32_t w2c_wasi__snapshot__preview1_path_open(wasi_t *wasi, uint32_ return WASI_EBADF; } + if (wasi->fdtable.size() >= UINT32_MAX && wasi->vacant_fds.empty()) { + return WASI_EMFILE; + } + switch (wasi->fdtable[fd].type) { case wasi_fd_type::VACANT: return WASI_EBADF; @@ -833,26 +910,27 @@ extern "C" uint32_t w2c_wasi__snapshot__preview1_path_open(wasi_t *wasi, uint32_ return WASI_EROFS; } + uint32_t root = wasi->fdtable[fd].type == wasi_fd_type::FS ? fd : wasi->fdtable[fd].dir_handle()->root; + if (exists && stat.filetype == PHYSFS_FILETYPE_DIRECTORY) { - struct fs_dir *root = wasi->fdtable[fd].dir_handle()->root != nullptr ? wasi->fdtable[fd].dir_handle()->root : wasi->fdtable[fd].dir_handle(); - struct fs_dir *handle = new fs_dir {.root = root, .path = new_path, .writable = writable}; + struct fs_dir *handle = new fs_dir {.path = new_path, .root = root, .writable = writable}; wasi->ref(result) = wasi->allocate_file_descriptor(wasi_fd_type::FSDIR, handle); } else { const char *write_path_prefix; if (writable) { - struct fs_dir *root = wasi->fdtable[fd].dir_handle()->root != nullptr ? wasi->fdtable[fd].dir_handle()->root : wasi->fdtable[fd].dir_handle(); - write_path_prefix = root->path.c_str(); + uint32_t root = wasi->fdtable[fd].type == wasi_fd_type::FS ? fd : wasi->fdtable[fd].dir_handle()->root; + write_path_prefix = wasi->fdtable[root].dir_handle()->path.c_str(); } else { write_path_prefix = nullptr; } - struct FileSystem::File *handle = new FileSystem::File(*mkxp_retro::fs, new_path.c_str(), write_path_prefix, truncate, exists); + struct fs_file *handle = new fs_file {.file {*mkxp_retro::fs, new_path.c_str(), write_path_prefix, truncate, exists}, .root = root}; // Check for errors opening the read handle and/or write handle - if (!handle->is_open() || (needs_write && writable && !handle->is_write_open())) { - PHYSFS_ErrorCode error = handle->get_read_error(); - if (error == handle->get_read_error()) { - error = handle->get_write_error(); + if (!handle->file.is_open() || (needs_write && writable && !handle->file.is_write_open())) { + PHYSFS_ErrorCode error = handle->file.get_read_error(); + if (error == handle->file.get_read_error()) { + error = handle->file.get_write_error(); } delete handle; switch (error) { @@ -922,8 +1000,8 @@ extern "C" uint32_t w2c_wasi__snapshot__preview1_path_remove_directory(wasi_t *w return WASI_ENOTDIR; } - struct fs_dir *root = wasi->fdtable[fd].dir_handle()->root != nullptr ? wasi->fdtable[fd].dir_handle()->root : wasi->fdtable[fd].dir_handle(); - if (!PHYSFS_delete(new_path.c_str() + root->path.length())) { + uint32_t root = wasi->fdtable[fd].type == wasi_fd_type::FS ? fd : wasi->fdtable[fd].dir_handle()->root; + if (!PHYSFS_delete(new_path.c_str() + wasi->fdtable[root].dir_handle()->path.length())) { switch (PHYSFS_getLastErrorCode()) { case PHYSFS_ERR_DIR_NOT_EMPTY: return WASI_ENOTEMPTY; @@ -996,8 +1074,8 @@ extern "C" uint32_t w2c_wasi__snapshot__preview1_path_unlink_file(wasi_t *wasi, return WASI_EIO; } - struct fs_dir *root = wasi->fdtable[fd].dir_handle()->root != nullptr ? wasi->fdtable[fd].dir_handle()->root : wasi->fdtable[fd].dir_handle(); - if (!PHYSFS_delete(new_path.c_str() + root->path.length())) { + uint32_t root = wasi->fdtable[fd].type == wasi_fd_type::FS ? fd : wasi->fdtable[fd].dir_handle()->root; + if (!PHYSFS_delete(new_path.c_str() + wasi->fdtable[root].dir_handle()->path.length())) { switch (PHYSFS_getLastErrorCode()) { case PHYSFS_ERR_READ_ONLY: case PHYSFS_ERR_NO_WRITE_DIR: diff --git a/binding-sandbox/wasi.h b/binding-sandbox/wasi.h index 89878a0c..6bb12843 100644 --- a/binding-sandbox/wasi.h +++ b/binding-sandbox/wasi.h @@ -160,18 +160,23 @@ typedef std::pair path_cache_entry_t; struct fs_dir { - struct fs_dir *root; // Null if this is a preopened directory handle, otherwise a pointer to the handle of the preopened directory that contains this directory. std::string path; // Path of the directory. + uint32_t root; // Undefined if this is a preopened directory, otherwise the file descriptor of the preopened directory that contains this directory. bool writable; // If true, writes made to this directory handle will be routed into the save directory. Otherwise, writes are disallowed. }; +struct fs_file { + struct FileSystem::File file; + uint32_t root; // The file descriptor of the preopened directory that contains this file. +}; + enum wasi_fd_type { STDIN, // This file descriptor is standard input. The `handle` field is null. STDOUT, // This file descriptor is standard output. The `handle` field is null. STDERR, // This file descriptor is standard error. The `handle` field is null. FS, // This file descriptor is a preopened directory handled by PhysFS. The `handle` field is a `struct fs_dir *`. FSDIR, // This file descriptor is a directory handled by PhysFS. The `handle` field is a `struct fs_dir *`. - FSFILE, // This file descriptor is a file handled by PhysFS. The `handle` field is a `struct FileSystem::File *`. + FSFILE, // This file descriptor is a file handled by PhysFS. The `handle` field is a `struct fs_file *`. VACANT, // Indicates this is a vacant file descriptor that doesn't correspond to a file. The `handle` field is null. }; @@ -182,7 +187,7 @@ struct wasi_file_entry { void *handle; struct fs_dir *dir_handle() const noexcept; - struct FileSystem::File *file_handle() const noexcept; + struct fs_file *file_handle() const noexcept; }; typedef struct w2c_wasi__snapshot__preview1 { @@ -232,6 +237,8 @@ typedef struct w2c_wasi__snapshot__preview1 { } bool sandbox_serialize(void *&data, mkxp_sandbox::wasm_size_t &max_size) const; + + bool sandbox_deserialize(const void *&data, mkxp_sandbox::wasm_size_t &max_size); } wasi_t; #endif /* MKXPZ_SANDBOX_WASI_H */ diff --git a/src/core.cpp b/src/core.cpp index ca29dee3..ef8b39fd 100644 --- a/src/core.cpp +++ b/src/core.cpp @@ -32,6 +32,7 @@ #include #include +#include "binding-util.h" #include "mkxp-polyfill.h" // std::mutex, std::strtoul #include "git-hash.h" @@ -1567,11 +1568,18 @@ extern "C" RETRO_API size_t retro_serialize_size() { max_size -= (bytes); \ } while (0) -#define OBJECTS_BEGIN_DETAIL(_r, _data, T) sandbox_ptr_map::sandbox_serialize_begin(); -#define OBJECTS_BEGIN do { BOOST_PP_SEQ_FOR_EACH(OBJECTS_BEGIN_DETAIL, _, SANDBOX_TYPENUM_TYPES) } while (0) -#define OBJECTS_END_DETAIL(_r, _data, T) sandbox_ptr_map::sandbox_serialize_end(); -#define OBJECTS_END do { BOOST_PP_SEQ_FOR_EACH(OBJECTS_END_DETAIL, _, SANDBOX_TYPENUM_TYPES) } while (0) -#define OBJECTS_END_FAIL do { OBJECTS_END; return false; } while (0) +#define SER_OBJECTS_BEGIN_DETAIL(_r, _data, T) sandbox_ptr_map::sandbox_serialize_begin(); +#define SER_OBJECTS_BEGIN do { BOOST_PP_SEQ_FOR_EACH(SER_OBJECTS_BEGIN_DETAIL, _, SANDBOX_TYPENUM_TYPES) } while (0) +#define SER_OBJECTS_END_DETAIL(_r, _data, T) sandbox_ptr_map::sandbox_serialize_end(); +#define SER_OBJECTS_END do { BOOST_PP_SEQ_FOR_EACH(SER_OBJECTS_END_DETAIL, _, SANDBOX_TYPENUM_TYPES) } while (0) +#define SER_OBJECTS_END_FAIL do { SER_OBJECTS_END; return false; } while (0) + +#define DESER_FAIL do { deinit_sandbox(); return false; } while (0) +#define DESER_OBJECTS_BEGIN_DETAIL(_r, _data, T) sandbox_ptr_map::sandbox_deserialize_begin(); +#define DESER_OBJECTS_BEGIN do { BOOST_PP_SEQ_FOR_EACH(DESER_OBJECTS_BEGIN_DETAIL, _, SANDBOX_TYPENUM_TYPES) } while (0) +#define DESER_OBJECTS_END_DETAIL(_r, _data, T) sandbox_ptr_map::sandbox_deserialize_end(); +#define DESER_OBJECTS_END do { BOOST_PP_SEQ_FOR_EACH(DESER_OBJECTS_END_DETAIL, _, SANDBOX_TYPENUM_TYPES) } while (0) +#define DESER_OBJECTS_END_FAIL do { DESER_OBJECTS_END; sb()->objects.clear(); sb()->next_free_objkey = 0; DESER_FAIL; } while (0) extern "C" RETRO_API bool retro_serialize(void *data, size_t len) { wasm_size_t max_size = len; @@ -1646,49 +1654,48 @@ extern "C" RETRO_API bool retro_serialize(void *data, size_t len) { if (!sb().sandbox_serialize_fdtable(data, max_size)) return false; // Write the number of objects, then each object - OBJECTS_BEGIN; - if (!sandbox_serialize((wasm_size_t)sb()->get_objects().size(), data, max_size)) OBJECTS_END_FAIL; + SER_OBJECTS_BEGIN; + if (!sandbox_serialize((wasm_size_t)sb()->objects.size(), data, max_size)) SER_OBJECTS_END_FAIL; wasm_size_t num_free_objects = 0; - for (const auto &object : sb()->get_objects()) { + for (const auto &object : sb()->objects) { if (object.typenum == 0) { ++num_free_objects; } else if (object.typenum > SANDBOX_NUM_TYPENUMS) { std::abort(); } else { if (num_free_objects > 0) { - if (!sandbox_serialize((wasm_size_t)0, data, max_size)) OBJECTS_END_FAIL; - if (!sandbox_serialize(num_free_objects, data, max_size)) OBJECTS_END_FAIL; + if (!sandbox_serialize((wasm_size_t)0, data, max_size)) SER_OBJECTS_END_FAIL; + if (!sandbox_serialize(num_free_objects, data, max_size)) SER_OBJECTS_END_FAIL; num_free_objects = 0; } - if (!sandbox_serialize(object.typenum, data, max_size)) OBJECTS_END_FAIL; - if (!typenum_table[object.typenum - 1].serialize(object.inner.ptr, data, max_size)) OBJECTS_END_FAIL; + if (!sandbox_serialize(object.typenum, data, max_size)) SER_OBJECTS_END_FAIL; + if (!typenum_table[object.typenum - 1].serialize(object.inner.ptr, data, max_size)) SER_OBJECTS_END_FAIL; } } if (num_free_objects > 0) { - if (!sandbox_serialize((wasm_size_t)0, data, max_size)) OBJECTS_END_FAIL; - if (!sandbox_serialize(num_free_objects, data, max_size)) OBJECTS_END_FAIL; + if (!sandbox_serialize((wasm_size_t)0, data, max_size)) SER_OBJECTS_END_FAIL; + if (!sandbox_serialize(num_free_objects, data, max_size)) SER_OBJECTS_END_FAIL; num_free_objects = 0; } // Write the number of extra objects that were found during serialization of the normal objects, then each such object - if (max_size < sizeof(wasm_size_t)) OBJECTS_END_FAIL; + if (max_size < sizeof(wasm_size_t)) SER_OBJECTS_END_FAIL; wasm_size_t *num_extra_objects_ptr = (wasm_size_t *)data; ADVANCE(sizeof(wasm_size_t)); for (size_t i = 0; i < extra_objects.size(); ++i) { // More items can be added to this vector during iteration const void *ptr = std::get<0>(extra_objects[i]); wasm_size_t typenum = std::get<1>(extra_objects[i]); - if (typenum == 0) { - std::abort(); - } else if (typenum > SANDBOX_NUM_TYPENUMS) { + if (typenum != get_typenum::value && typenum != get_typenum::value && typenum != get_typenum::value) { + std::fprintf(stderr, "extra object other than Color, Tone or Rect found during save state serialization with typenum %llu (there's probably a bug in the sandbox bindings)\n", (unsigned long long)typenum); std::abort(); } else { - if (!sandbox_serialize(typenum, data, max_size)) OBJECTS_END_FAIL; - if (!typenum_table[typenum - 1].serialize(ptr, data, max_size)) OBJECTS_END_FAIL; + if (!sandbox_serialize(typenum, data, max_size)) SER_OBJECTS_END_FAIL; + if (!typenum_table[typenum - 1].serialize(ptr, data, max_size)) SER_OBJECTS_END_FAIL; } } *num_extra_objects_ptr = (wasm_size_t)extra_objects.size(); - OBJECTS_END; + SER_OBJECTS_END; std::memset(data, 0, max_size); return true; } @@ -1727,37 +1734,37 @@ extern "C" RETRO_API bool retro_unserialize(const void *data, size_t len) { // Read the sandbox state { wasm_ptr_t value; - if (!sandbox_deserialize(value, data, max_size)) return false; + if (!sandbox_deserialize(value, data, max_size)) DESER_FAIL; sb()->set_machine_stack_pointer(value); } { uint8_t value; - if (!sandbox_deserialize(value, data, max_size)) return false; + if (!sandbox_deserialize(value, data, max_size)) DESER_FAIL; sb()->set_asyncify_state(value); } { wasm_ptr_t value; - if (!sandbox_deserialize(value, data, max_size)) return false; + if (!sandbox_deserialize(value, data, max_size)) DESER_FAIL; sb()->set_asyncify_data(value); } - if (!sandbox_deserialize(frame_count, data, max_size)) return false; + if (!sandbox_deserialize(frame_count, data, max_size)) DESER_FAIL; { uint64_t value; - if (!sandbox_deserialize(value, data, max_size)) return false; + if (!sandbox_deserialize(value, data, max_size)) DESER_FAIL; frame_time = value; } - if (!sandbox_deserialize(frame_time_remainder, data, max_size)) return false; - if (!sandbox_deserialize(retro_run_count, data, max_size)) return false; - if (!sandbox_deserialize(sb().transitioning, data, max_size)) return false; + if (!sandbox_deserialize(frame_time_remainder, data, max_size)) DESER_FAIL; + if (!sandbox_deserialize(retro_run_count, data, max_size)) DESER_FAIL; + if (!sandbox_deserialize(sb().transitioning, data, max_size)) DESER_FAIL; { bool have_trans_map; - if (!sandbox_deserialize(have_trans_map, data, max_size)) return false; + if (!sandbox_deserialize(have_trans_map, data, max_size)) DESER_FAIL; if (have_trans_map) { if (sb().trans_map == nullptr) { // TODO - return false; + DESER_FAIL; } - if (!sandbox_deserialize(*sb().trans_map, data, max_size)) return false; + if (!sandbox_deserialize(*sb().trans_map, data, max_size)) DESER_FAIL; } else { if (sb().trans_map != nullptr) { delete sb().trans_map; @@ -1768,14 +1775,14 @@ extern "C" RETRO_API bool retro_unserialize(const void *data, size_t len) { { // TODO: movie bool have_movie; - if (!sandbox_deserialize(have_movie, data, max_size)) return false; - if (have_movie) return false; + if (!sandbox_deserialize(have_movie, data, max_size)) DESER_FAIL; + if (have_movie) DESER_FAIL; } { // Read sandbox fibers wasm_size_t num_fibers; - if (!sandbox_deserialize(num_fibers, data, max_size)) return false; + if (!sandbox_deserialize(num_fibers, data, max_size)) DESER_FAIL; sb()->fibers.clear(); sb()->fibers.reserve(num_fibers); @@ -1783,25 +1790,25 @@ extern "C" RETRO_API bool retro_unserialize(const void *data, size_t len) { while (num_fibers > 0) { // Read the key of the fiber std::tuple key; - if (!sandbox_deserialize(std::get<0>(key), data, max_size)) return false; - if (!sandbox_deserialize(std::get<1>(key), data, max_size)) return false; - if (!sandbox_deserialize(std::get<2>(key), data, max_size)) return false; + if (!sandbox_deserialize(std::get<0>(key), data, max_size)) DESER_FAIL; + if (!sandbox_deserialize(std::get<1>(key), data, max_size)) DESER_FAIL; + if (!sandbox_deserialize(std::get<2>(key), data, max_size)) DESER_FAIL; // Construct the fiber auto &fiber = sb()->fibers.emplace(key, key).first->second; // Read the stack index of the fiber - if (!sandbox_deserialize(fiber.stack_index, data, max_size)) return false; + if (!sandbox_deserialize(fiber.stack_index, data, max_size)) DESER_FAIL; // Read sandbox frames wasm_size_t num_frames; - if (!sandbox_deserialize(num_frames, data, max_size)) return false; + if (!sandbox_deserialize(num_frames, data, max_size)) DESER_FAIL; fiber.deser_stack.reserve(num_frames); while (num_frames > 0) { wasm_ptr_t stack_pointer; - if (!sandbox_deserialize(stack_pointer, data, max_size)) return false; + if (!sandbox_deserialize(stack_pointer, data, max_size)) DESER_FAIL; int32_t state; - if (!sandbox_deserialize(state, data, max_size)) return false; + if (!sandbox_deserialize(state, data, max_size)) DESER_FAIL; fiber.deser_stack.emplace_back(stack_pointer, state); --num_frames; } @@ -1810,6 +1817,85 @@ extern "C" RETRO_API bool retro_unserialize(const void *data, size_t len) { } } + // Read the open WASI file descriptors + if (!sb().sandbox_deserialize_fdtable(data, max_size)) DESER_FAIL; + + // Read objects + DESER_OBJECTS_BEGIN; + sb()->next_free_objkey = 0; + wasm_objkey_t object_key = 1; + wasm_size_t num_objects; + if (!sandbox_deserialize(num_objects, data, max_size)) DESER_OBJECTS_END_FAIL; + sb()->objects.resize(num_objects); + while (object_key <= num_objects) { + wasm_size_t typenum; + if (!sandbox_deserialize(typenum, data, max_size)) DESER_OBJECTS_END_FAIL; + if (typenum == 0) { + wasm_size_t num_free_objects; + if (!::sandbox_deserialize(num_free_objects, data, max_size)) DESER_OBJECTS_END_FAIL; + if (object_key - 1 + num_free_objects > num_objects || object_key + num_free_objects < object_key) DESER_OBJECTS_END_FAIL; + for (wasm_size_t i = object_key; i < object_key + num_free_objects; ++i) { + auto &object = sb()->objects[i - 1]; + if (object.typenum > 0) { + if (object.typenum > SANDBOX_NUM_TYPENUMS) { + std::abort(); + } + typenum_table[object.typenum - 1].destructor(object.inner.ptr); + object.typenum = 0; + } + object.inner.next = sb()->next_free_objkey; + sb()->next_free_objkey = i; + } + object_key += num_free_objects; + } else { + if (typenum > SANDBOX_NUM_TYPENUMS) DESER_OBJECTS_END_FAIL; + auto &object = sb()->objects[object_key - 1]; + if (object.typenum > 0 && object.typenum != typenum) { + typenum_table[object.typenum - 1].destructor(object.inner.ptr); + } + if (object.typenum != typenum) { + object.typenum = typenum; + object.inner.ptr = typenum_table[typenum - 1].constructor(); + if (object.inner.ptr == nullptr && typenum != get_typenum::value && typenum != get_typenum::value) DESER_OBJECTS_END_FAIL; + } + if (!typenum_table[typenum - 1].deserialize(object.inner.ptr, data, max_size)) DESER_OBJECTS_END_FAIL; + auto it = objects_deser.find(object_key); + if (it == objects_deser.end()) { + objects_deser.emplace(object_key, sandbox_object_deser_info(object.inner.ptr, typenum)); + } else { + it->second.set_ptr(object.inner.ptr, typenum); + } + ++object_key; + } + } + + // Read extra objects + wasm_objkey_t extra_object_key = 1; + wasm_size_t num_extra_objects; + if (!sandbox_deserialize(num_extra_objects, data, max_size)) DESER_OBJECTS_END_FAIL; + while (extra_object_key <= num_extra_objects) { + wasm_size_t typenum; + if (!sandbox_deserialize(typenum, data, max_size)) DESER_OBJECTS_END_FAIL; + if (typenum != get_typenum::value && typenum != get_typenum::value && typenum != get_typenum::value) DESER_OBJECTS_END_FAIL; + void *ptr = typenum_table[typenum - 1].constructor(); + if (ptr == nullptr && typenum != get_typenum::value && typenum != get_typenum::value) DESER_OBJECTS_END_FAIL; + if (!typenum_table[typenum - 1].deserialize(ptr, data, max_size)) { + typenum_table[typenum - 1].destructor(ptr); + DESER_OBJECTS_END_FAIL; + } + auto it = extra_objects_deser.find(extra_object_key); + if (it == extra_objects_deser.end()) { + extra_objects_deser.emplace(extra_object_key, sandbox_object_deser_info(ptr, typenum)); + } else { + if (!it->second.set_ptr(ptr, typenum)) { + typenum_table[typenum - 1].destructor(ptr); + DESER_OBJECTS_END_FAIL; + } + } + ++extra_object_key; + } + + DESER_OBJECTS_END; return true; } diff --git a/src/display/bitmap.h b/src/display/bitmap.h index 7aab2887..146b4148 100644 --- a/src/display/bitmap.h +++ b/src/display/bitmap.h @@ -56,7 +56,7 @@ class Bitmap : public Disposable public: Bitmap(Exception &exception, const char *filename); - Bitmap(Exception &exception, int width, int height, bool isHires = false); + Bitmap(Exception &exception, int width = 1, int height = 1, bool isHires = false); Bitmap(Exception &exception, void *pixeldata, int width, int height); Bitmap(Exception &exception, TEXFBO &other); Bitmap(Exception &exception, SDL_Surface *imgSurf, SDL_Surface *imgSurfHires, bool forceMega = false); diff --git a/src/display/font.cpp b/src/display/font.cpp index 5e350e0d..6bfbf760 100644 --- a/src/display/font.cpp +++ b/src/display/font.cpp @@ -693,15 +693,42 @@ Font::getSdlFont(Exception &exception) #ifdef MKXPZ_RETRO bool Font::sandbox_serialize(void *&data, mkxp_sandbox::wasm_size_t &max_size) const { - if (!mkxp_sandbox::sandbox_serialize((int32_t)p->size, data, max_size)) return false; if (!mkxp_sandbox::sandbox_serialize(p->bold, data, max_size)) return false; if (!mkxp_sandbox::sandbox_serialize(p->italic, data, max_size)) return false; if (!mkxp_sandbox::sandbox_serialize(p->outline, data, max_size)) return false; if (!mkxp_sandbox::sandbox_serialize(p->shadow, data, max_size)) return false; - if (!mkxp_sandbox::sandbox_serialize(p->name, data, max_size)) return false; if (!mkxp_sandbox::sandbox_serialize(p->color, data, max_size)) return false; if (!mkxp_sandbox::sandbox_serialize(p->outColor, data, max_size)) return false; + if (!mkxp_sandbox::sandbox_serialize((int32_t)p->size, data, max_size)) return false; + if (!mkxp_sandbox::sandbox_serialize(p->name, data, max_size)) return false; + + return true; +} + +bool Font::sandbox_deserialize(const void *&data, mkxp_sandbox::wasm_size_t &max_size) +{ + if (!mkxp_sandbox::sandbox_deserialize(p->bold, data, max_size)) return false; + if (!mkxp_sandbox::sandbox_deserialize(p->italic, data, max_size)) return false; + if (!mkxp_sandbox::sandbox_deserialize(p->outline, data, max_size)) return false; + if (!mkxp_sandbox::sandbox_deserialize(p->shadow, data, max_size)) return false; + if (!mkxp_sandbox::sandbox_deserialize(p->color, data, max_size)) return false; + if (!mkxp_sandbox::sandbox_deserialize(p->outColor, data, max_size)) return false; + + // Invalidate the inner font object if either the name or size of this font is different from before + if (p->sdlFont != nullptr) { + int32_t size = p->size; + if (!mkxp_sandbox::sandbox_deserialize((int32_t &)p->size, data, max_size)) return false; + std::string name(p->name); + if (!mkxp_sandbox::sandbox_deserialize(p->name, data, max_size)) return false; + if (p->size != size || p->name != name) { + p->sdlFont = nullptr; + } + } else { + if (!mkxp_sandbox::sandbox_deserialize((int32_t &)p->size, data, max_size)) return false; + if (!mkxp_sandbox::sandbox_deserialize(p->name, data, max_size)) return false; + } + return true; } #endif // MKXPZ_RETRO diff --git a/src/display/font.h b/src/display/font.h index b71a77b0..e2cf4604 100644 --- a/src/display/font.h +++ b/src/display/font.h @@ -151,6 +151,7 @@ public: #ifdef MKXPZ_RETRO bool sandbox_serialize(void *&data, mkxp_sandbox::wasm_size_t &max_size) const; + bool sandbox_deserialize(const void *&data, mkxp_sandbox::wasm_size_t &max_size); #endif // MKXPZ_RETRO private: diff --git a/src/display/gl/scene.cpp b/src/display/gl/scene.cpp index 92157499..34087467 100644 --- a/src/display/gl/scene.cpp +++ b/src/display/gl/scene.cpp @@ -211,10 +211,19 @@ void SceneElement::unlink() #ifdef MKXPZ_RETRO bool SceneElement::sandbox_serialize_scene_element(void *&data, mkxp_sandbox::wasm_size_t &max_size) const { - if (!mkxp_sandbox::sandbox_serialize((uint64_t)creationStamp, data, max_size)) return false; + if (!mkxp_sandbox::sandbox_serialize(creationStamp, data, max_size)) return false; if (!mkxp_sandbox::sandbox_serialize((int32_t)z, data, max_size)) return false; if (!mkxp_sandbox::sandbox_serialize(visible, data, max_size)) return false; return true; } + +bool SceneElement::sandbox_deserialize_scene_element(const void *&data, mkxp_sandbox::wasm_size_t &max_size) +{ + if (!mkxp_sandbox::sandbox_deserialize(creationStamp, data, max_size)) return false; + if (!mkxp_sandbox::sandbox_deserialize((int32_t &)z, data, max_size)) return false; + if (!mkxp_sandbox::sandbox_deserialize(visible, data, max_size)) return false; + + return true; +} #endif // MKXPZ_REROO diff --git a/src/display/gl/scene.h b/src/display/gl/scene.h index 0663fe13..1c8e0107 100644 --- a/src/display/gl/scene.h +++ b/src/display/gl/scene.h @@ -97,6 +97,7 @@ public: #ifdef MKXPZ_RETRO bool sandbox_serialize_scene_element(void *&data, mkxp_sandbox::wasm_size_t &max_size) const; + bool sandbox_deserialize_scene_element(const void *&data, mkxp_sandbox::wasm_size_t &max_size); #endif // MKXPZ_REROO protected: @@ -131,7 +132,7 @@ protected: void unlink(); IntruListLink link; - const unsigned int creationStamp; + uint64_t creationStamp; int z; bool visible; Scene *scene; diff --git a/src/display/plane.cpp b/src/display/plane.cpp index d36d3cad..12c9ca1e 100644 --- a/src/display/plane.cpp +++ b/src/display/plane.cpp @@ -372,4 +372,33 @@ bool Plane::sandbox_serialize(void *&data, mkxp_sandbox::wasm_size_t &max_size) return true; } + +bool Plane::sandbox_deserialize(const void *&data, mkxp_sandbox::wasm_size_t &max_size) +{ + { + bool active; + if (!mkxp_sandbox::sandbox_deserialize(active, data, max_size)) return false; + if (!active) { + dispose(); + return true; + } + // TODO: undispose + } + + if (!mkxp_sandbox::sandbox_deserialize(p->opacity, data, max_size)) return false; + if (!mkxp_sandbox::sandbox_deserialize(p->blendType, data, max_size)) return false; + if (!mkxp_sandbox::sandbox_deserialize((int32_t &)p->ox, data, max_size)) return false; + if (!mkxp_sandbox::sandbox_deserialize((int32_t &)p->oy, data, max_size)) return false; + if (!mkxp_sandbox::sandbox_deserialize(p->zoomX, data, max_size)) return false; + if (!mkxp_sandbox::sandbox_deserialize(p->zoomY, data, max_size)) return false; + if (!mkxp_sandbox::sandbox_deserialize(p->sceneGeo, data, max_size)) return false; + if (!mkxp_sandbox::sandbox_deserialize(p->quadSourceDirty, data, max_size)) return false; + if (!mkxp_sandbox::sandbox_deserialize(p->qArray, data, max_size)) return false; + if (!sandbox_deserialize_viewport_element(data, max_size)) return false; + if (!mkxp_sandbox::sandbox_deserialize(p->bitmap, data, max_size)) return false; + if (!mkxp_sandbox::sandbox_deserialize(p->color, data, max_size)) return false; + if (!mkxp_sandbox::sandbox_deserialize(p->tone, data, max_size)) return false; + + return true; +} #endif // MKXPZ_RETRO diff --git a/src/display/plane.h b/src/display/plane.h index b80c6d24..89d33db7 100644 --- a/src/display/plane.h +++ b/src/display/plane.h @@ -55,6 +55,7 @@ public: #ifdef MKXPZ_RETRO bool sandbox_serialize(void *&data, mkxp_sandbox::wasm_size_t &max_size) const; + bool sandbox_deserialize(const void *&data, mkxp_sandbox::wasm_size_t &max_size); #endif // MKXPZ_RETRO private: diff --git a/src/display/sprite.cpp b/src/display/sprite.cpp index 5badc5c4..3b1c2f84 100644 --- a/src/display/sprite.cpp +++ b/src/display/sprite.cpp @@ -896,4 +896,51 @@ bool Sprite::sandbox_serialize(void *&data, mkxp_sandbox::wasm_size_t &max_size) return true; } + +bool Sprite::sandbox_deserialize(const void *&data, mkxp_sandbox::wasm_size_t &max_size) +{ + { + bool active; + if (!mkxp_sandbox::sandbox_deserialize(active, data, max_size)) return false; + if (!active) { + dispose(); + return true; + } + // TODO: undispose + } + + if (!mkxp_sandbox::sandbox_deserialize(p->quad, data, max_size)) return false; + if (!mkxp_sandbox::sandbox_deserialize(p->trans, data, max_size)) return false; + if (!mkxp_sandbox::sandbox_deserialize(p->mirrored, data, max_size)) return false; + if (!mkxp_sandbox::sandbox_deserialize((int32_t &)p->bushDepth, data, max_size)) return false; + if (!mkxp_sandbox::sandbox_deserialize(p->efBushDepth, data, max_size)) return false; + if (!mkxp_sandbox::sandbox_deserialize(p->bushOpacity, data, max_size)) return false; + if (!mkxp_sandbox::sandbox_deserialize(p->opacity, data, max_size)) return false; + if (!mkxp_sandbox::sandbox_deserialize(p->blendType, data, max_size)) return false; + if (!mkxp_sandbox::sandbox_deserialize(p->patternBlendType, data, max_size)) return false; + if (!mkxp_sandbox::sandbox_deserialize(p->patternTile, data, max_size)) return false; + if (!mkxp_sandbox::sandbox_deserialize(p->patternOpacity, data, max_size)) return false; + if (!mkxp_sandbox::sandbox_deserialize(p->patternScroll, data, max_size)) return false; + if (!mkxp_sandbox::sandbox_deserialize(p->patternZoom, data, max_size)) return false; + if (!mkxp_sandbox::sandbox_deserialize(p->invert, data, max_size)) return false; + if (!mkxp_sandbox::sandbox_deserialize(p->sceneRect, data, max_size)) return false; + if (!mkxp_sandbox::sandbox_deserialize(p->sceneOrig, data, max_size)) return false; + if (!mkxp_sandbox::sandbox_deserialize(p->isVisible, data, max_size)) return false; + + if (!mkxp_sandbox::sandbox_deserialize((int32_t &)p->wave.amp, data, max_size)) return false; + if (!mkxp_sandbox::sandbox_deserialize((int32_t &)p->wave.length, data, max_size)) return false; + if (!mkxp_sandbox::sandbox_deserialize((int32_t &)p->wave.speed, data, max_size)) return false; + if (!mkxp_sandbox::sandbox_deserialize(p->wave.phase, data, max_size)) return false; + if (!mkxp_sandbox::sandbox_deserialize(p->wave.qArray, data, max_size)) return false; + + if (!sandbox_deserialize_viewport_element(data, max_size)) return false; + + if (!mkxp_sandbox::sandbox_deserialize(p->bitmap, data, max_size)) return false; + if (!mkxp_sandbox::sandbox_deserialize(p->pattern, data, max_size)) return false; + if (!mkxp_sandbox::sandbox_deserialize(p->srcRect, data, max_size)) return false; + if (!mkxp_sandbox::sandbox_deserialize(p->color, data, max_size)) return false; + if (!mkxp_sandbox::sandbox_deserialize(p->tone, data, max_size)) return false; + + return true; +} #endif // MKXPZ_RETRO diff --git a/src/display/sprite.h b/src/display/sprite.h index 847f740d..ca2f931e 100644 --- a/src/display/sprite.h +++ b/src/display/sprite.h @@ -84,6 +84,7 @@ public: #ifdef MKXPZ_RETRO bool sandbox_serialize(void *&data, mkxp_sandbox::wasm_size_t &max_size) const; + bool sandbox_deserialize(const void *&data, mkxp_sandbox::wasm_size_t &max_size); #endif // MKXPZ_RETRO private: diff --git a/src/display/tilemap-common.h b/src/display/tilemap-common.h index 87559326..f4b4890a 100644 --- a/src/display/tilemap-common.h +++ b/src/display/tilemap-common.h @@ -136,6 +136,11 @@ struct FlashMap return data; } + Table *&getData() + { + return data; + } + void setData(Table *value) { if (data == value) diff --git a/src/display/tilemap.cpp b/src/display/tilemap.cpp index 039b6eff..2e7a17f3 100644 --- a/src/display/tilemap.cpp +++ b/src/display/tilemap.cpp @@ -1463,6 +1463,11 @@ bool Tilemap::Autotiles::sandbox_serialize(void *&data, mkxp_sandbox::wasm_size_ return true; } +bool Tilemap::Autotiles::sandbox_deserialize(const void *&data, mkxp_sandbox::wasm_size_t &max_size) +{ + return true; +} + bool Tilemap::sandbox_serialize(void *&data, mkxp_sandbox::wasm_size_t &max_size) const { if (isDisposed()) return mkxp_sandbox::sandbox_serialize(false, data, max_size); @@ -1515,4 +1520,64 @@ bool Tilemap::sandbox_serialize(void *&data, mkxp_sandbox::wasm_size_t &max_size return true; } + +bool Tilemap::sandbox_deserialize(const void *&data, mkxp_sandbox::wasm_size_t &max_size) +{ + { + bool active; + if (!mkxp_sandbox::sandbox_deserialize(active, data, max_size)) return false; + if (!active) { + dispose(); + return true; + } + // TODO: undispose + } + + if (!mkxp_sandbox::sandbox_deserialize(p->visible, data, max_size)) return false; + if (!mkxp_sandbox::sandbox_deserialize(p->origin, data, max_size)) return false; + if (!mkxp_sandbox::sandbox_deserialize(p->dispPos, data, max_size)) return false; + + if (!mkxp_sandbox::sandbox_deserialize(p->atlas.size, data, max_size)) return false; + if (!mkxp_sandbox::sandbox_deserialize((int32_t &)p->atlas.efTilesetH, data, max_size)) return false; + if (!mkxp_sandbox::sandbox_deserialize(p->atlas.usableATs, data, max_size)) return false; + if (!mkxp_sandbox::sandbox_deserialize(p->atlas.animatedATs, data, max_size)) return false; + for (size_t i = 0; i < autotileCount; ++i) + if (!mkxp_sandbox::sandbox_deserialize(p->atlas.smallATs[i], data, max_size)) return false; + for (size_t i = 0; i < autotileCount; ++i) + if (!mkxp_sandbox::sandbox_deserialize((int32_t &)p->atlas.nATFrames[i], data, max_size)) return false; + + if (!mkxp_sandbox::sandbox_deserialize(p->viewpPos, data, max_size)) return false; + if (!mkxp_sandbox::sandbox_deserialize(p->groundVert, data, max_size)) return false; + for (size_t i = 0; i < zlayersMax; ++i) + if (!mkxp_sandbox::sandbox_deserialize(p->zlayerVert[i], data, max_size)) return false; + for (size_t i = 0; i < zlayersMax + 1; ++i) + if (!mkxp_sandbox::sandbox_deserialize((mkxp_sandbox::wasm_size_t &)p->zlayerBases[i], data, max_size)) return false; + + if (!mkxp_sandbox::sandbox_deserialize(p->tiles.animated, data, max_size)) return false; + if (!mkxp_sandbox::sandbox_deserialize(p->tiles.aniIdx, data, max_size)) return false; + + if (!mkxp_sandbox::sandbox_deserialize(p->flashAlphaIdx, data, max_size)) return false; + + if (!p->elem.ground->sandbox_deserialize_viewport_element(data, max_size)) return false; + + for (size_t i = 0; i < zlayersMax; ++i) + if (!p->elem.zlayers[i]->sandbox_deserialize_viewport_element(data, max_size)) return false; + + if (!mkxp_sandbox::sandbox_deserialize((mkxp_sandbox::wasm_size_t &)p->elem.activeLayers, data, max_size)) return false; + if (!mkxp_sandbox::sandbox_deserialize(p->elem.sceneGeo, data, max_size)) return false; + + if (!mkxp_sandbox::sandbox_deserialize(p->opacity, data, max_size)) return false; + if (!mkxp_sandbox::sandbox_deserialize(p->blendType, data, max_size)) return false; + if (!mkxp_sandbox::sandbox_deserialize(p->viewport, data, max_size)) return false; + for (size_t i = 0; i < autotileCount; ++i) + if (!mkxp_sandbox::sandbox_deserialize(p->autotiles[i], data, max_size)) return false; + if (!mkxp_sandbox::sandbox_deserialize(p->tileset, data, max_size)) return false; + if (!mkxp_sandbox::sandbox_deserialize(p->mapData, data, max_size)) return false; + if (!mkxp_sandbox::sandbox_deserialize(p->priorities, data, max_size)) return false; + if (!mkxp_sandbox::sandbox_deserialize(p->flashMap.getData(), data, max_size)) return false; + if (!mkxp_sandbox::sandbox_deserialize(p->color, data, max_size)) return false; + if (!mkxp_sandbox::sandbox_deserialize(p->tone, data, max_size)) return false; + + return true; +} #endif // MKXPZ_RETRO diff --git a/src/display/tilemap.h b/src/display/tilemap.h index 39a1bdc6..28040d1a 100644 --- a/src/display/tilemap.h +++ b/src/display/tilemap.h @@ -50,6 +50,7 @@ public: #ifdef MKXPZ_RETRO bool sandbox_serialize(void *&data, mkxp_sandbox::wasm_size_t &max_size) const; + bool sandbox_deserialize(const void *&data, mkxp_sandbox::wasm_size_t &max_size); #endif // MKXPZ_RETRO private: @@ -86,6 +87,7 @@ public: #ifdef MKXPZ_RETRO bool sandbox_serialize(void *&data, mkxp_sandbox::wasm_size_t &max_size) const; + bool sandbox_deserialize(const void *&data, mkxp_sandbox::wasm_size_t &max_size); #endif // MKXPZ_RETRO private: diff --git a/src/display/tilemapvx.cpp b/src/display/tilemapvx.cpp index 9844ceed..4bde75bf 100644 --- a/src/display/tilemapvx.cpp +++ b/src/display/tilemapvx.cpp @@ -621,6 +621,11 @@ bool TilemapVX::BitmapArray::sandbox_serialize(void *&data, mkxp_sandbox::wasm_s return true; } +bool TilemapVX::BitmapArray::sandbox_deserialize(const void *&data, mkxp_sandbox::wasm_size_t &max_size) +{ + return true; +} + bool TilemapVX::sandbox_serialize(void *&data, mkxp_sandbox::wasm_size_t &max_size) const { if (isDisposed()) return mkxp_sandbox::sandbox_serialize(false, data, max_size); @@ -645,4 +650,36 @@ bool TilemapVX::sandbox_serialize(void *&data, mkxp_sandbox::wasm_size_t &max_si return true; } + +bool TilemapVX::sandbox_deserialize(const void *&data, mkxp_sandbox::wasm_size_t &max_size) +{ + { + bool active; + if (!mkxp_sandbox::sandbox_deserialize(active, data, max_size)) return false; + if (!active) { + dispose(); + return true; + } + // TODO: undispose + } + + if (!mkxp_sandbox::sandbox_deserialize(p->origin, data, max_size)) return false; + if (!mkxp_sandbox::sandbox_deserialize(p->dispPos, data, max_size)) return false; + if (!mkxp_sandbox::sandbox_deserialize(p->groundVert, data, max_size)) return false; + if (!mkxp_sandbox::sandbox_deserialize(p->aboveVert, data, max_size)) return false; + if (!mkxp_sandbox::sandbox_deserialize((mkxp_sandbox::wasm_size_t &)p->allocQuads, data, max_size)) return false; + if (!mkxp_sandbox::sandbox_deserialize((mkxp_sandbox::wasm_size_t &)p->groundQuads, data, max_size)) return false; + if (!mkxp_sandbox::sandbox_deserialize((mkxp_sandbox::wasm_size_t &)p->aboveQuads, data, max_size)) return false; + if (!mkxp_sandbox::sandbox_deserialize(p->frameIdx, data, max_size)) return false; + if (!mkxp_sandbox::sandbox_deserialize(p->aniOffset, data, max_size)) return false; + if (!mkxp_sandbox::sandbox_deserialize(p->flashAlphaIdx, data, max_size)) return false; + if (!p->above.sandbox_deserialize_viewport_element(data, max_size)) return false; + if (!p->sandbox_deserialize_viewport_element(data, max_size)) return false; + for (size_t i = 0; i < BM_COUNT; ++i) + if (!mkxp_sandbox::sandbox_deserialize(p->bitmaps[i], data, max_size)) return false; + if (!mkxp_sandbox::sandbox_deserialize(p->mapData, data, max_size)) return false; + if (!mkxp_sandbox::sandbox_deserialize(p->flashMap.getData(), data, max_size)) return false; + + return true; +} #endif // MKXPZ_RETRO diff --git a/src/display/tilemapvx.h b/src/display/tilemapvx.h index 46d8e03f..7a808ad9 100644 --- a/src/display/tilemapvx.h +++ b/src/display/tilemapvx.h @@ -46,6 +46,7 @@ public: #ifdef MKXPZ_RETRO bool sandbox_serialize(void *&data, mkxp_sandbox::wasm_size_t &max_size) const; + bool sandbox_deserialize(const void *&data, mkxp_sandbox::wasm_size_t &max_size); #endif // MKXPZ_RETRO private: @@ -74,6 +75,7 @@ public: #ifdef MKXPZ_RETRO bool sandbox_serialize(void *&data, mkxp_sandbox::wasm_size_t &max_size) const; + bool sandbox_deserialize(const void *&data, mkxp_sandbox::wasm_size_t &max_size); #endif // MKXPZ_RETRO private: diff --git a/src/display/viewport.cpp b/src/display/viewport.cpp index 181d1194..dd9d7a56 100644 --- a/src/display/viewport.cpp +++ b/src/display/viewport.cpp @@ -244,6 +244,28 @@ bool Viewport::sandbox_serialize(void *&data, mkxp_sandbox::wasm_size_t &max_siz return true; } + +bool Viewport::sandbox_deserialize(const void *&data, mkxp_sandbox::wasm_size_t &max_size) +{ + { + bool active; + if (!mkxp_sandbox::sandbox_deserialize(active, data, max_size)) return false; + if (!active) { + dispose(); + return true; + } + // TODO: undispose + } + + if (!mkxp_sandbox::sandbox_deserialize(p->screenRect, data, max_size)) return false; + if (!mkxp_sandbox::sandbox_deserialize(p->isOnScreen, data, max_size)) return false; + if (!sandbox_deserialize_scene_element(data, max_size)) return false; + if (!mkxp_sandbox::sandbox_deserialize(p->rect, data, max_size)) return false; + if (!mkxp_sandbox::sandbox_deserialize(p->color, data, max_size)) return false; + if (!mkxp_sandbox::sandbox_deserialize(p->tone, data, max_size)) return false; + + return true; +} #endif // MXKPZ_RETRO @@ -293,4 +315,12 @@ bool ViewportElement::sandbox_serialize_viewport_element(void *&data, mkxp_sandb return true; } + +bool ViewportElement::sandbox_deserialize_viewport_element(const void *&data, mkxp_sandbox::wasm_size_t &max_size) +{ + if (!sandbox_deserialize_scene_element(data, max_size)) return false; + if (!mkxp_sandbox::sandbox_deserialize(m_viewport, data, max_size)) return false; + + return true; +} #endif // MXKPZ_RETRO diff --git a/src/display/viewport.h b/src/display/viewport.h index 586c8b05..3320a831 100644 --- a/src/display/viewport.h +++ b/src/display/viewport.h @@ -53,6 +53,7 @@ public: #ifdef MKXPZ_RETRO bool sandbox_serialize(void *&data, mkxp_sandbox::wasm_size_t &max_size) const; + bool sandbox_deserialize(const void *&data, mkxp_sandbox::wasm_size_t &max_size); #endif // MXKPZ_RETRO private: @@ -85,6 +86,7 @@ public: #ifdef MKXPZ_RETRO bool sandbox_serialize_viewport_element(void *&data, mkxp_sandbox::wasm_size_t &max_size) const; + bool sandbox_deserialize_viewport_element(const void *&data, mkxp_sandbox::wasm_size_t &max_size); #endif // MXKPZ_RETRO protected: diff --git a/src/display/window.cpp b/src/display/window.cpp index 58709670..ccf883d8 100644 --- a/src/display/window.cpp +++ b/src/display/window.cpp @@ -982,4 +982,43 @@ bool Window::sandbox_serialize(void *&data, mkxp_sandbox::wasm_size_t &max_size) return true; } + +bool Window::sandbox_deserialize(const void *&data, mkxp_sandbox::wasm_size_t &max_size) +{ + { + bool active; + if (!mkxp_sandbox::sandbox_deserialize(active, data, max_size)) return false; + if (!active) { + dispose(); + return true; + } + // TODO: undispose + } + + if (!mkxp_sandbox::sandbox_deserialize(p->bgStretch, data, max_size)) return false; + if (!mkxp_sandbox::sandbox_deserialize(p->active, data, max_size)) return false; + if (!mkxp_sandbox::sandbox_deserialize(p->pause, data, max_size)) return false; + if (!mkxp_sandbox::sandbox_deserialize(p->sceneOffset, data, max_size)) return false; + if (!mkxp_sandbox::sandbox_deserialize(p->position, data, max_size)) return false; + if (!mkxp_sandbox::sandbox_deserialize(p->size, data, max_size)) return false; + if (!mkxp_sandbox::sandbox_deserialize(p->contentsOffset, data, max_size)) return false; + if (!mkxp_sandbox::sandbox_deserialize(p->opacity, data, max_size)) return false; + if (!mkxp_sandbox::sandbox_deserialize(p->backOpacity, data, max_size)) return false; + if (!mkxp_sandbox::sandbox_deserialize(p->contentsOpacity, data, max_size)) return false; + if (!mkxp_sandbox::sandbox_deserialize(p->baseQuadArray, data, max_size)) return false; + if (!mkxp_sandbox::sandbox_deserialize(p->useBaseTex, data, max_size)) return false; + if (!mkxp_sandbox::sandbox_deserialize(p->baseTexQuad, data, max_size)) return false; + if (!p->controlsElement.sandbox_deserialize_viewport_element(data, max_size)) return false; + if (!mkxp_sandbox::sandbox_deserialize(p->controlsQuadArray, data, max_size)) return false; + if (!mkxp_sandbox::sandbox_deserialize(p->contentsQuad, data, max_size)) return false; + if (!mkxp_sandbox::sandbox_deserialize(p->cursorAniAlphaIdx, data, max_size)) return false; + if (!mkxp_sandbox::sandbox_deserialize(p->pauseAniAlphaIdx, data, max_size)) return false; + if (!mkxp_sandbox::sandbox_deserialize(p->pauseAniQuadIdx, data, max_size)) return false; + if (!sandbox_deserialize_viewport_element(data, max_size)) return false; + if (!mkxp_sandbox::sandbox_deserialize(p->windowskin, data, max_size)) return false; + if (!mkxp_sandbox::sandbox_deserialize(p->contents, data, max_size)) return false; + if (!mkxp_sandbox::sandbox_deserialize(p->cursorRect, data, max_size)) return false; + + return true; +} #endif // MKXPZ_RETRO diff --git a/src/display/window.h b/src/display/window.h index fd98930b..9f71d634 100644 --- a/src/display/window.h +++ b/src/display/window.h @@ -67,6 +67,7 @@ public: #ifdef MKXPZ_RETRO bool sandbox_serialize(void *&data, mkxp_sandbox::wasm_size_t &max_size) const; + bool sandbox_deserialize(const void *&data, mkxp_sandbox::wasm_size_t &max_size); #endif // MKXPZ_RETRO private: diff --git a/src/display/windowvx.cpp b/src/display/windowvx.cpp index ff177b01..f9e9886b 100644 --- a/src/display/windowvx.cpp +++ b/src/display/windowvx.cpp @@ -1183,11 +1183,6 @@ bool WindowVX::sandbox_serialize(void *&data, mkxp_sandbox::wasm_size_t &max_siz if (!mkxp_sandbox::sandbox_serialize(p->contentsOpacity, data, max_size)) return false; if (!mkxp_sandbox::sandbox_serialize(p->openness, data, max_size)) return false; if (!mkxp_sandbox::sandbox_serialize(p->ctrlVert, data, max_size)) return false; - - if (!mkxp_sandbox::sandbox_serialize(p->pauseVert != nullptr, data, max_size)) return false; - if (p->pauseVert != nullptr) - if (!mkxp_sandbox::sandbox_serialize(*p->pauseVert, data, max_size)) return false; - if (!mkxp_sandbox::sandbox_serialize(p->contentsQuad, data, max_size)) return false; if (!mkxp_sandbox::sandbox_serialize(p->padRect, data, max_size)) return false; if (!mkxp_sandbox::sandbox_serialize(p->clipRect, data, max_size)) return false; @@ -1204,4 +1199,47 @@ bool WindowVX::sandbox_serialize(void *&data, mkxp_sandbox::wasm_size_t &max_siz return true; } + +bool WindowVX::sandbox_deserialize(const void *&data, mkxp_sandbox::wasm_size_t &max_size) +{ + { + bool active; + if (!mkxp_sandbox::sandbox_deserialize(active, data, max_size)) return false; + if (!active) { + dispose(); + return true; + } + // TODO: undispose + } + + if (!mkxp_sandbox::sandbox_deserialize(p->active, data, max_size)) return false; + if (!mkxp_sandbox::sandbox_deserialize(p->arrowsVisible, data, max_size)) return false; + if (!mkxp_sandbox::sandbox_deserialize(p->pause, data, max_size)) return false; + if (!mkxp_sandbox::sandbox_deserialize((int32_t &)p->width, data, max_size)) return false; + if (!mkxp_sandbox::sandbox_deserialize((int32_t &)p->height, data, max_size)) return false; + if (!mkxp_sandbox::sandbox_deserialize(p->geo, data, max_size)) return false; + if (!mkxp_sandbox::sandbox_deserialize(p->contentsOff, data, max_size)) return false; + if (!mkxp_sandbox::sandbox_deserialize((int32_t &)p->padding, data, max_size)) return false; + if (!mkxp_sandbox::sandbox_deserialize((int32_t &)p->paddingBottom, data, max_size)) return false; + if (!mkxp_sandbox::sandbox_deserialize(p->opacity, data, max_size)) return false; + if (!mkxp_sandbox::sandbox_deserialize(p->backOpacity, data, max_size)) return false; + if (!mkxp_sandbox::sandbox_deserialize(p->contentsOpacity, data, max_size)) return false; + if (!mkxp_sandbox::sandbox_deserialize(p->openness, data, max_size)) return false; + if (!mkxp_sandbox::sandbox_deserialize(p->ctrlVert, data, max_size)) return false; + if (!mkxp_sandbox::sandbox_deserialize(p->contentsQuad, data, max_size)) return false; + if (!mkxp_sandbox::sandbox_deserialize(p->padRect, data, max_size)) return false; + if (!mkxp_sandbox::sandbox_deserialize(p->clipRect, data, max_size)) return false; + if (!mkxp_sandbox::sandbox_deserialize(p->cursorVert, data, max_size)) return false; + if (!mkxp_sandbox::sandbox_deserialize(p->pauseAlphaIdx, data, max_size)) return false; + if (!mkxp_sandbox::sandbox_deserialize(p->pauseQuadIdx, data, max_size)) return false; + if (!mkxp_sandbox::sandbox_deserialize(p->cursorAlphaIdx, data, max_size)) return false; + if (!mkxp_sandbox::sandbox_deserialize(p->sceneOffset, data, max_size)) return false; + if (!sandbox_deserialize_viewport_element(data, max_size)) return false; + if (!mkxp_sandbox::sandbox_deserialize(p->windowskin, data, max_size)) return false; + if (!mkxp_sandbox::sandbox_deserialize(p->contents, data, max_size)) return false; + if (!mkxp_sandbox::sandbox_deserialize(p->cursorRect, data, max_size)) return false; + if (!mkxp_sandbox::sandbox_deserialize(p->tone, data, max_size)) return false; + + return true; +} #endif // MKXPZ_RETRO diff --git a/src/display/windowvx.h b/src/display/windowvx.h index 4579ad8f..d83f97b9 100644 --- a/src/display/windowvx.h +++ b/src/display/windowvx.h @@ -74,6 +74,7 @@ public: #ifdef MKXPZ_RETRO bool sandbox_serialize(void *&data, mkxp_sandbox::wasm_size_t &max_size) const; + bool sandbox_deserialize(const void *&data, mkxp_sandbox::wasm_size_t &max_size); #endif // MKXPZ_RETRO private: diff --git a/src/etc/etc.cpp b/src/etc/etc.cpp index 6f49764c..e2701f7e 100644 --- a/src/etc/etc.cpp +++ b/src/etc/etc.cpp @@ -191,6 +191,15 @@ bool Color::sandbox_serialize(void *&data, mkxp_sandbox::wasm_size_t &max_size) return true; } + +bool Color::sandbox_deserialize(const void *&data, mkxp_sandbox::wasm_size_t &max_size) { + if (!mkxp_sandbox::sandbox_deserialize(red, data, max_size)) return false; + if (!mkxp_sandbox::sandbox_deserialize(green, data, max_size)) return false; + if (!mkxp_sandbox::sandbox_deserialize(blue, data, max_size)) return false; + if (!mkxp_sandbox::sandbox_deserialize(alpha, data, max_size)) return false; + + return true; +} #endif // MKXPZ_RETRO @@ -320,6 +329,15 @@ bool Tone::sandbox_serialize(void *&data, mkxp_sandbox::wasm_size_t &max_size) c return true; } + +bool Tone::sandbox_deserialize(const void *&data, mkxp_sandbox::wasm_size_t &max_size) { + if (!mkxp_sandbox::sandbox_deserialize(red, data, max_size)) return false; + if (!mkxp_sandbox::sandbox_deserialize(green, data, max_size)) return false; + if (!mkxp_sandbox::sandbox_deserialize(blue, data, max_size)) return false; + if (!mkxp_sandbox::sandbox_deserialize(gray, data, max_size)) return false; + + return true; +} #endif // MKXPZ_RETRO @@ -472,4 +490,13 @@ bool Rect::sandbox_serialize(void *&data, mkxp_sandbox::wasm_size_t &max_size) c return true; } + +bool Rect::sandbox_deserialize(const void *&data, mkxp_sandbox::wasm_size_t &max_size) { + if (!mkxp_sandbox::sandbox_deserialize((int32_t &)x, data, max_size)) return false; + if (!mkxp_sandbox::sandbox_deserialize((int32_t &)y, data, max_size)) return false; + if (!mkxp_sandbox::sandbox_deserialize((int32_t &)width, data, max_size)) return false; + if (!mkxp_sandbox::sandbox_deserialize((int32_t &)height, data, max_size)) return false; + + return true; +} #endif // MKXPZ_RETRO diff --git a/src/etc/etc.h b/src/etc/etc.h index ae4c7d59..4e08c29a 100644 --- a/src/etc/etc.h +++ b/src/etc/etc.h @@ -94,6 +94,7 @@ struct Color : public Serializable #ifdef MKXPZ_RETRO bool sandbox_serialize(void *&data, mkxp_sandbox::wasm_size_t &max_size) const; + bool sandbox_deserialize(const void *&data, mkxp_sandbox::wasm_size_t &max_size); #endif // MKXPZ_RETRO /* Range (0.0 ~ 255.0) */ @@ -150,6 +151,7 @@ struct Tone : public Serializable #ifdef MKXPZ_RETRO bool sandbox_serialize(void *&data, mkxp_sandbox::wasm_size_t &max_size) const; + bool sandbox_deserialize(const void *&data, mkxp_sandbox::wasm_size_t &max_size); #endif // MKXPZ_RETRO /* Range (-255.0 ~ 255.0) */ @@ -213,6 +215,7 @@ struct Rect : public Serializable #ifdef MKXPZ_RETRO bool sandbox_serialize(void *&data, mkxp_sandbox::wasm_size_t &max_size) const; + bool sandbox_deserialize(const void *&data, mkxp_sandbox::wasm_size_t &max_size); #endif // MKXPZ_RETRO int x; diff --git a/src/etc/table.cpp b/src/etc/table.cpp index c457276c..c9eeb40f 100644 --- a/src/etc/table.cpp +++ b/src/etc/table.cpp @@ -172,11 +172,25 @@ bool Table::sandbox_serialize(void *&data, mkxp_sandbox::wasm_size_t &max_size) if (!mkxp_sandbox::sandbox_serialize((int32_t)xs, data, max_size)) return false; if (!mkxp_sandbox::sandbox_serialize((int32_t)ys, data, max_size)) return false; if (!mkxp_sandbox::sandbox_serialize((int32_t)zs, data, max_size)) return false; - if (xs * ys * zs != this->data.size()) std::abort(); + if ((uint32_t)xs * (uint32_t)ys * (uint32_t)zs != this->data.size()) std::abort(); if (max_size < this->data.size() * sizeof(int16_t)) return false; memcpy(data, this->data.data(), this->data.size() * sizeof(int16_t)); data = (uint8_t *)data + this->data.size() * sizeof(int16_t); max_size -= this->data.size() * sizeof(int16_t); return true; } + +bool Table::sandbox_deserialize(const void *&data, mkxp_sandbox::wasm_size_t &max_size) +{ + if (!mkxp_sandbox::sandbox_deserialize((int32_t &)xs, data, max_size)) return false; + if (!mkxp_sandbox::sandbox_deserialize((int32_t &)ys, data, max_size)) return false; + if (!mkxp_sandbox::sandbox_deserialize((int32_t &)zs, data, max_size)) return false; + this->data.clear(); + this->data.resize((uint32_t)xs * (uint32_t)ys * (uint32_t)zs); + if (max_size < this->data.size() * sizeof(int16_t)) return false; + memcpy(this->data.data(), data, this->data.size() * sizeof(int16_t)); + data = (uint8_t *)data + this->data.size() * sizeof(int16_t); + max_size -= this->data.size() * sizeof(int16_t); + return true; +} #endif // MKXPZ_RETRO diff --git a/src/etc/table.h b/src/etc/table.h index a4020af7..89a7c640 100644 --- a/src/etc/table.h +++ b/src/etc/table.h @@ -35,7 +35,7 @@ class Table : public Serializable { public: - Table(int x, int y = 1, int z = 1); + Table(int x = 1, int y = 1, int z = 1); /* Clone constructor */ Table(const Table &other); virtual ~Table() {} @@ -70,6 +70,7 @@ public: #ifdef MKXPZ_RETRO bool sandbox_serialize(void *&data, mkxp_sandbox::wasm_size_t &max_size) const; + bool sandbox_deserialize(const void *&data, mkxp_sandbox::wasm_size_t &max_size); #endif // MKXPZ_RETRO private: diff --git a/src/sharedstate.cpp b/src/sharedstate.cpp index 4a179b6a..cc5438da 100644 --- a/src/sharedstate.cpp +++ b/src/sharedstate.cpp @@ -107,7 +107,7 @@ struct SharedStatePrivate Quad gpQuad; - unsigned int stampCounter; + uint64_t stampCounter; std::chrono::time_point startupTime; @@ -435,7 +435,7 @@ double SharedState::runTime() { #endif // MKXPZ_RETRO } -unsigned int SharedState::genTimeStamp() +uint64_t SharedState::genTimeStamp() { return p->stampCounter++; } diff --git a/src/sharedstate.h b/src/sharedstate.h index f203b58d..1004c83f 100644 --- a/src/sharedstate.h +++ b/src/sharedstate.h @@ -84,7 +84,7 @@ struct SharedState sigslot::signal<> prepareDraw; - unsigned int genTimeStamp(); + uint64_t genTimeStamp(); // Returns time since SharedState was constructed in microseconds double runTime();