Continue implementing save state deserialization in libretro builds

This commit is contained in:
刘皓 2025-05-27 16:59:41 -04:00
parent 290ce15875
commit 8ca753d85d
No known key found for this signature in database
GPG key ID: 7901753DB465B711
36 changed files with 758 additions and 148 deletions

View file

@ -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); 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(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)) {} 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<struct binding_base::object> &binding_base::get_objects() const noexcept {
return objects;
}
wasm_objkey_t binding_base::create_object(wasm_size_t typenum, void *ptr) { wasm_objkey_t binding_base::create_object(wasm_size_t typenum, void *ptr) {
if (ptr == nullptr || typenum == 0 || typenum > typenum_table_size) { if (ptr == nullptr || typenum == 0 || typenum > typenum_table_size) {
std::abort(); std::abort();

View file

@ -199,8 +199,10 @@ namespace mkxp_sandbox {
} }
struct typenum_table_entry { struct typenum_table_entry {
void *(*constructor)();
void (*destructor)(void *self); void (*destructor)(void *self);
bool (*serialize)(const void *self, void *&data, wasm_size_t &max_size); 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[]; 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. // Otherwise, this is a number corresponding to the type of the object.
wasm_size_t typenum; wasm_size_t typenum;
object();
object(wasm_size_t typenum, void *ptr); object(wasm_size_t typenum, void *ptr);
object(const struct object &object) = delete; object(const struct object &object) = delete;
object(struct object &&object) noexcept; object(struct object &&object) noexcept;
@ -278,12 +281,14 @@ namespace mkxp_sandbox {
~object(); ~object();
}; };
std::shared_ptr<struct w2c_ruby> _instance; public:
std::vector<struct object> objects; std::vector<struct object> objects;
wasm_objkey_t next_free_objkey; private:
std::shared_ptr<struct w2c_ruby> _instance;
wasm_ptr_t stack_ptr; wasm_ptr_t stack_ptr;
public: public:
wasm_objkey_t next_free_objkey;
std::unordered_map<key_t, struct fiber, boost::hash<key_t>> fibers; std::unordered_map<key_t, struct fiber, boost::hash<key_t>> fibers;
binding_base(std::shared_ptr<struct w2c_ruby> m); binding_base(std::shared_ptr<struct w2c_ruby> m);
@ -335,9 +340,6 @@ namespace mkxp_sandbox {
return sandbox_arycpy(instance(), dst_address, src, num_elements); return sandbox_arycpy(instance(), dst_address, src, num_elements);
} }
// Returns a reference to all currently existing objects.
const std::vector<struct object> &get_objects() const noexcept;
// Creates a new object and returns its key. // Creates a new object and returns its key.
wasm_objkey_t create_object(wasm_size_t typenum, void *ptr); wasm_objkey_t create_object(wasm_size_t typenum, void *ptr);

View file

@ -24,9 +24,33 @@
using namespace mkxp_sandbox; using namespace mkxp_sandbox;
template <typename T> static typename std::enable_if<std::is_constructible<T>::value, void *>::type constructor() {
static_assert(!(std::is_same<T, Tilemap::Autotiles>::value || std::is_same<T, TilemapVX::BitmapArray>::value), "this type should not have a public constructor");
return new T;
}
template <typename T> static typename std::enable_if<!std::is_constructible<T>::value && std::is_constructible<T, Exception &>::value, void *>::type constructor() {
static_assert(!(std::is_same<T, Tilemap::Autotiles>::value || std::is_same<T, TilemapVX::BitmapArray>::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 <typename T> static typename std::enable_if<!std::is_constructible<T>::value && !std::is_constructible<T, Exception &>::value, void *>::type constructor() {
static_assert((std::is_same<T, Tilemap::Autotiles>::value || std::is_same<T, TilemapVX::BitmapArray>::value), "this type should have a public constructor");
return nullptr;
}
template <typename T> static typename std::enable_if<std::is_destructible<T>::value>::type destructor(void *self) { template <typename T> static typename std::enable_if<std::is_destructible<T>::value>::type destructor(void *self) {
static_assert(!(std::is_same<T, Tilemap::Autotiles>::value || std::is_same<T, TilemapVX::BitmapArray>::value), "this type should not have a public destructor"); static_assert(!(std::is_same<T, Tilemap::Autotiles>::value || std::is_same<T, TilemapVX::BitmapArray>::value), "this type should not have a public destructor");
delete (T *)self; if (self != nullptr) {
delete (T *)self;
}
} }
template <typename T> static typename std::enable_if<!std::is_destructible<T>::value>::type destructor(void *self) { template <typename T> static typename std::enable_if<!std::is_destructible<T>::value>::type destructor(void *self) {
@ -37,7 +61,11 @@ template <typename T> static bool serialize(const void *self, void *&data, wasm_
return ((const T *)self)->sandbox_serialize(data, max_size); return ((const T *)self)->sandbox_serialize(data, max_size);
} }
#define _SANDBOX_DEF_TYPENUM_TABLE_ENTRY(_r, _data, T) {.destructor = destructor<T>, .serialize = serialize<T>}, template <typename T> 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<T>, .destructor = destructor<T>, .serialize = serialize<T>, .deserialize = deserialize<T>},
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 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; extern const wasm_size_t mkxp_sandbox::typenum_table_size = SANDBOX_NUM_TYPENUMS;

View file

@ -44,7 +44,7 @@ std::vector<std::tuple<const void *, wasm_size_t>> mkxp_sandbox::extra_objects;
std::unordered_map<wasm_size_t, struct sandbox_object_deser_info> mkxp_sandbox::objects_deser; std::unordered_map<wasm_size_t, struct sandbox_object_deser_info> mkxp_sandbox::objects_deser;
std::unordered_map<wasm_size_t, struct sandbox_object_deser_info> mkxp_sandbox::extra_objects_deser; std::unordered_map<wasm_size_t, struct sandbox_object_deser_info> mkxp_sandbox::extra_objects_deser;
sandbox_object_deser_info::sandbox_object_deser_info() : ptr(new std::vector<void **>), 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)) {} 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; 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<void **> *)this->ptr) {
*ref = ptr;
}
delete (std::vector<void **> *)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) { template <> bool mkxp_sandbox::sandbox_serialize(bool value, void *&data, wasm_size_t &max_size) {
RESERVE(sizeof(uint8_t)); RESERVE(sizeof(uint8_t));
*(uint8_t *)data = value; *(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) { 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); RESERVE(size);
std::memcpy(data, value, size); std::memcpy(data, value, size);
ADVANCE(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) { 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); RESERVE(size);
std::memcpy(data, value.c_str(), size); std::memcpy(data, value.c_str(), size);
ADVANCE(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) { template <> bool mkxp_sandbox::sandbox_deserialize(std::string &value, const void *&data, wasm_size_t &max_size) {
wasm_size_t size; wasm_size_t size;
if (!sandbox_deserialize(size, data, max_size)) return false; if (!sandbox_deserialize(size, data, max_size)) return false;
if (size == 0 || ((const char *)data)[size - 1] != 0) return false;
RESERVE(size); RESERVE(size);
value.resize(size - 1); value.clear();
value.resize(size);
char *str = &value[0]; char *str = &value[0];
std::memcpy(str, data, size - 1); std::memcpy(str, data, size);
if (std::strlen(str) != size - 1) { if (std::strlen(str) != size) {
value.clear(); value.clear();
return false; return false;
} }

View file

@ -32,8 +32,8 @@
namespace mkxp_sandbox { namespace mkxp_sandbox {
struct sandbox_object_deser_info { struct sandbox_object_deser_info {
sandbox_object_deser_info(); template <typename T> sandbox_object_deser_info(T *&ref) : ptr(new std::vector<void **>({(void **)&ref})), typenum(mkxp_sandbox::get_typenum<T>::value), ref_count(1), exists(false) {}
template <typename T> sandbox_object_deser_info(T *ptr) : ptr(ptr), typenum(get_typenum<T>::value), ref_count(0), exists(true) {} 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(const struct sandbox_object_deser_info &) = delete;
sandbox_object_deser_info(struct sandbox_object_deser_info &&) noexcept; sandbox_object_deser_info(struct sandbox_object_deser_info &&) noexcept;
struct sandbox_object_deser_info &operator=(const struct sandbox_object_deser_info &) = delete; struct sandbox_object_deser_info &operator=(const struct sandbox_object_deser_info &) = delete;
@ -41,37 +41,25 @@ namespace mkxp_sandbox {
~sandbox_object_deser_info(); ~sandbox_object_deser_info();
wasm_size_t get_ref_count() const noexcept; wasm_size_t get_ref_count() const noexcept;
template <typename T> bool add_ref(T *&ref) { template <typename T> bool add_ref(T *&ref) {
if (typenum == 0) { if (typenum != mkxp_sandbox::get_typenum<T>::value) {
typenum = get_typenum<T>::value; return false;
} else if (typenum != get_typenum<T>::value) { }
if (ref_count > 0 && (std::is_same<T, Color>::value || std::is_same<T, Tone>::value || std::is_same<T, Rect>::value || std::is_same<T, Tilemap::Autotiles>::value || std::is_same<T, TilemapVX::BitmapArray>::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; return false;
} }
if (exists) { if (exists) {
ref = (T *)ptr; ref = (T *)ptr;
} else { } else {
ref = nullptr;
((std::vector<void **> *)ptr)->push_back((void **)&ref); ((std::vector<void **> *)ptr)->push_back((void **)&ref);
} }
++ref_count; ++ref_count;
return true; return true;
} }
template <typename T> bool set_ptr(T *ptr) { bool set_ptr(void *ptr, wasm_size_t typenum);
if (typenum == 0) { void *get_ptr();
typenum = get_typenum<T>::value; wasm_size_t get_typenum();
} else if (typenum != get_typenum<T>::value) {
return false;
}
if (exists && ptr != this->ptr) {
return false;
}
if (!exists) {
for (void **ref : *(std::vector<void **> *)this->ptr) {
*(T **)ref = ptr;
}
delete (std::vector<void **> *)this->ptr;
exists = true;
this->ptr = ptr;
}
}
private: private:
// If `exists` is true, this is a pointer to the object. Otherwise, this is a `std::vector<void **>` of pointers that are waiting to point to the object. // If `exists` is true, this is a pointer to the object. Otherwise, this is a `std::vector<void **>` of pointers that are waiting to point to the object.
@ -138,7 +126,7 @@ namespace mkxp_sandbox {
extra_objects.clear(); extra_objects.clear();
wasm_objkey_t key = 0; wasm_objkey_t key = 0;
for (const auto &object : sb()->get_objects()) { for (const auto &object : sb()->objects) {
++key; ++key;
if (object.typenum == get_typenum<T>::value) { if (object.typenum == get_typenum<T>::value) {
map.emplace((T *)object.inner.ptr, (struct info){.key = key, .is_extra = false}); 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; auto &deser_map = type != 0 ? extra_objects_deser : objects_deser;
const auto it = deser_map.find(key); const auto it = deser_map.find(key);
if (it == deser_map.end()) { 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 { } else {
return it->second.add_ref(ref); return it->second.add_ref(ref);
} }
@ -234,6 +223,15 @@ namespace mkxp_sandbox {
is_deserializing = false; is_deserializing = false;
objects_deser.clear(); 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(); extra_objects_deser.clear();
} }
}; };
@ -268,9 +266,6 @@ namespace mkxp_sandbox {
if (!sandbox_deserialize(value.back(), data, max_size)) return false; if (!sandbox_deserialize(value.back(), data, max_size)) return false;
--size; --size;
} }
for (T &item : value) {
if (!sandbox_deserialize(item, data, max_size)) return false;
}
return true; return true;
} }

View file

@ -129,6 +129,10 @@ bool sandbox::sandbox_serialize_fdtable(void *&data, wasm_size_t &max_size) cons
return wasi->sandbox_serialize(data, max_size); 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() { 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 return movie.load(std::memory_order_relaxed); // No need for synchronization because we always set the movie from the main thread
} }

View file

@ -64,6 +64,7 @@ namespace mkxp_sandbox {
sandbox(); sandbox();
~sandbox(); ~sandbox();
bool sandbox_serialize_fdtable(void *&data, wasm_size_t &max_size) const; 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_main_thread();
Movie *get_movie_from_audio_thread(); Movie *get_movie_from_audio_thread();
void set_movie(Movie *new_movie); void set_movie(Movie *new_movie);

View file

@ -20,6 +20,7 @@
*/ */
#include <algorithm> #include <algorithm>
#include <cstdint>
#include <cstring> #include <cstring>
#include <random> #include <random>
#include <sstream> #include <sstream>
@ -41,8 +42,8 @@ struct fs_dir *wasi_file_entry::dir_handle() const noexcept {
return (struct fs_dir *)handle; return (struct fs_dir *)handle;
} }
struct FileSystem::File *wasi_file_entry::file_handle() const noexcept { struct fs_file *wasi_file_entry::file_handle() const noexcept {
return (struct FileSystem::File *)handle; return (struct fs_file *)handle;
} }
wasi_t::w2c_wasi__snapshot__preview1(std::shared_ptr<struct w2c_ruby> ruby) : ruby(ruby) { wasi_t::w2c_wasi__snapshot__preview1(std::shared_ptr<struct w2c_ruby> ruby) : ruby(ruby) {
@ -50,15 +51,15 @@ wasi_t::w2c_wasi__snapshot__preview1(std::shared_ptr<struct w2c_ruby> ruby) : ru
fdtable.push_back({.type = wasi_fd_type::STDIN}); fdtable.push_back({.type = wasi_fd_type::STDIN});
fdtable.push_back({.type = wasi_fd_type::STDOUT}); fdtable.push_back({.type = wasi_fd_type::STDOUT});
fdtable.push_back({.type = wasi_fd_type::STDERR}); 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 {.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 {.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 {.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("/Dist"), .writable = false}});
} }
wasi_t::~w2c_wasi__snapshot__preview1() { wasi_t::~w2c_wasi__snapshot__preview1() {
// Close all of the open WASI file descriptors // 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); 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) { uint32_t wasi_t::allocate_file_descriptor(enum wasi_fd_type type, void *handle) {
if (vacant_fds.empty()) { if (vacant_fds.empty()) {
if (fdtable.size() >= UINT32_MAX) {
MKXPZ_THROW(std::bad_alloc());
}
uint32_t fd = fdtable.size(); uint32_t fd = fdtable.size();
fdtable.push_back({.type = type, .handle = handle}); fdtable.push_back({.type = type, .handle = handle});
return fd; return fd;
} else { } else {
uint32_t fd = vacant_fds.back(); uint32_t fd = vacant_fds.back();
vacant_fds.pop_back(); vacant_fds.pop_back();
fdtable[fd].type = type;
fdtable[fd].handle = handle;
return fd; return fd;
} }
} }
@ -97,16 +103,12 @@ void wasi_t::deallocate_file_descriptor(uint32_t fd) {
delete fdtable[fd].file_handle(); delete fdtable[fd].file_handle();
break; break;
default: default:
break; return;
} }
} }
if (!fdtable.empty() && fd == fdtable.size() - 1) { fdtable[fd] = {.type = wasi_fd_type::VACANT, .handle = nullptr};
fdtable.pop_back(); vacant_fds.push_back(fd);
} else {
fdtable[fd] = {.type = wasi_fd_type::VACANT, .handle = nullptr};
vacant_fds.push_back(fd);
}
} }
void *wasi_t::ptr(wasm_ptr_t address) const noexcept { 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 { 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) { for (const struct wasi_file_entry &entry : fdtable) {
if (entry.type == wasi_fd_type::FSDIR) { 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; num_free_handles = 0;
} }
if (!::sandbox_serialize((uint8_t)1, data, max_size)) return false; 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()->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) { } else if (entry.type == wasi_fd_type::FSFILE) {
if (num_free_handles > 0) { if (num_free_handles > 0) {
if (!::sandbox_serialize((uint8_t)0, data, max_size)) return false; 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; num_free_handles = 0;
} }
if (!::sandbox_serialize((uint8_t)2, data, max_size)) return false; 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 { } else {
++num_free_handles; ++num_free_handles;
} }
@ -165,6 +168,79 @@ bool wasi_t::sandbox_serialize(void *&data, mkxp_sandbox::wasm_size_t &max_size)
return true; 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) { 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; 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::STDOUT:
case wasi_fd_type::STDERR: case wasi_fd_type::STDERR:
case wasi_fd_type::FS: case wasi_fd_type::FS:
return WASI_EINVAL;
case wasi_fd_type::FSDIR: case wasi_fd_type::FSDIR:
case wasi_fd_type::FSFILE: 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: case wasi_fd_type::FSFILE:
{ {
PHYSFS_Stat stat; 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; return WASI_ENOENT;
} }
if (stat.filetype != PHYSFS_FILETYPE_REGULAR) { 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 #ifdef MKXPZ_BIG_ENDIAN
ptr -= length; ptr -= length;
#endif // MKXPZ_BIG_ENDIAN #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 #ifdef MKXPZ_BIG_ENDIAN
std::reverse(ptr, ptr + length); std::reverse(ptr, ptr + length);
#endif // MKXPZ_BIG_ENDIAN #endif // MKXPZ_BIG_ENDIAN
@ -597,12 +674,8 @@ extern "C" uint32_t w2c_wasi__snapshot__preview1_fd_renumber(wasi_t *wasi, uint3
} else { } else {
wasi->fdtable[to] = wasi->fdtable[fd]; wasi->fdtable[to] = wasi->fdtable[fd];
} }
if (!wasi->fdtable.empty() && fd == wasi->fdtable.size() - 1) { wasi->fdtable[fd] = {.type = wasi_fd_type::VACANT, .handle = nullptr};
wasi->fdtable.pop_back(); wasi->vacant_fds.push_back(fd);
} else {
wasi->fdtable[fd] = {.type = wasi_fd_type::VACANT, .handle = nullptr};
wasi->vacant_fds.push_back(fd);
}
return WASI_ESUCCESS; 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; return WASI_EINVAL;
case wasi_fd_type::FSFILE: case wasi_fd_type::FSFILE:
wasi->ref<uint64_t>(result) = PHYSFS_tell(wasi->fdtable[fd].file_handle()->get()); wasi->ref<uint64_t>(result) = PHYSFS_tell(wasi->fdtable[fd].file_handle()->file.get());
return WASI_ESUCCESS; 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: 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; return WASI_EROFS;
} }
uint32_t size = 0; 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; ptr -= length;
std::reverse(ptr, ptr + length); std::reverse(ptr, ptr + length);
#endif // MKXPZ_BIG_ENDIAN #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 #ifdef MKXPZ_BIG_ENDIAN
std::reverse(ptr, ptr + length); std::reverse(ptr, ptr + length);
#endif // MKXPZ_BIG_ENDIAN #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; return WASI_EBADF;
} }
if (wasi->fdtable.size() >= UINT32_MAX && wasi->vacant_fds.empty()) {
return WASI_EMFILE;
}
switch (wasi->fdtable[fd].type) { switch (wasi->fdtable[fd].type) {
case wasi_fd_type::VACANT: case wasi_fd_type::VACANT:
return WASI_EBADF; return WASI_EBADF;
@ -833,26 +910,27 @@ extern "C" uint32_t w2c_wasi__snapshot__preview1_path_open(wasi_t *wasi, uint32_
return WASI_EROFS; 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) { 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 {.path = new_path, .root = root, .writable = writable};
struct fs_dir *handle = new fs_dir {.root = root, .path = new_path, .writable = writable};
wasi->ref<uint32_t>(result) = wasi->allocate_file_descriptor(wasi_fd_type::FSDIR, handle); wasi->ref<uint32_t>(result) = wasi->allocate_file_descriptor(wasi_fd_type::FSDIR, handle);
} else { } else {
const char *write_path_prefix; const char *write_path_prefix;
if (writable) { if (writable) {
struct fs_dir *root = wasi->fdtable[fd].dir_handle()->root != nullptr ? wasi->fdtable[fd].dir_handle()->root : wasi->fdtable[fd].dir_handle(); uint32_t root = wasi->fdtable[fd].type == wasi_fd_type::FS ? fd : wasi->fdtable[fd].dir_handle()->root;
write_path_prefix = root->path.c_str(); write_path_prefix = wasi->fdtable[root].dir_handle()->path.c_str();
} else { } else {
write_path_prefix = nullptr; 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 // Check for errors opening the read handle and/or write handle
if (!handle->is_open() || (needs_write && writable && !handle->is_write_open())) { if (!handle->file.is_open() || (needs_write && writable && !handle->file.is_write_open())) {
PHYSFS_ErrorCode error = handle->get_read_error(); PHYSFS_ErrorCode error = handle->file.get_read_error();
if (error == handle->get_read_error()) { if (error == handle->file.get_read_error()) {
error = handle->get_write_error(); error = handle->file.get_write_error();
} }
delete handle; delete handle;
switch (error) { switch (error) {
@ -922,8 +1000,8 @@ extern "C" uint32_t w2c_wasi__snapshot__preview1_path_remove_directory(wasi_t *w
return WASI_ENOTDIR; 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(); 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() + root->path.length())) { if (!PHYSFS_delete(new_path.c_str() + wasi->fdtable[root].dir_handle()->path.length())) {
switch (PHYSFS_getLastErrorCode()) { switch (PHYSFS_getLastErrorCode()) {
case PHYSFS_ERR_DIR_NOT_EMPTY: case PHYSFS_ERR_DIR_NOT_EMPTY:
return WASI_ENOTEMPTY; return WASI_ENOTEMPTY;
@ -996,8 +1074,8 @@ extern "C" uint32_t w2c_wasi__snapshot__preview1_path_unlink_file(wasi_t *wasi,
return WASI_EIO; 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(); 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() + root->path.length())) { if (!PHYSFS_delete(new_path.c_str() + wasi->fdtable[root].dir_handle()->path.length())) {
switch (PHYSFS_getLastErrorCode()) { switch (PHYSFS_getLastErrorCode()) {
case PHYSFS_ERR_READ_ONLY: case PHYSFS_ERR_READ_ONLY:
case PHYSFS_ERR_NO_WRITE_DIR: case PHYSFS_ERR_NO_WRITE_DIR:

View file

@ -160,18 +160,23 @@
typedef std::pair<u32, std::string> path_cache_entry_t; typedef std::pair<u32, std::string> path_cache_entry_t;
struct fs_dir { 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. 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. 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 { enum wasi_fd_type {
STDIN, // This file descriptor is standard input. The `handle` field is null. STDIN, // This file descriptor is standard input. The `handle` field is null.
STDOUT, // This file descriptor is standard output. 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. 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 *`. 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 *`. 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. 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; void *handle;
struct fs_dir *dir_handle() const noexcept; 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 { 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_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; } wasi_t;
#endif /* MKXPZ_SANDBOX_WASI_H */ #endif /* MKXPZ_SANDBOX_WASI_H */

View file

@ -32,6 +32,7 @@
#include <alext.h> #include <alext.h>
#include <fluidsynth.h> #include <fluidsynth.h>
#include "binding-util.h"
#include "mkxp-polyfill.h" // std::mutex, std::strtoul #include "mkxp-polyfill.h" // std::mutex, std::strtoul
#include "git-hash.h" #include "git-hash.h"
@ -1567,11 +1568,18 @@ extern "C" RETRO_API size_t retro_serialize_size() {
max_size -= (bytes); \ max_size -= (bytes); \
} while (0) } while (0)
#define OBJECTS_BEGIN_DETAIL(_r, _data, T) sandbox_ptr_map<T>::sandbox_serialize_begin(); #define SER_OBJECTS_BEGIN_DETAIL(_r, _data, T) sandbox_ptr_map<T>::sandbox_serialize_begin();
#define OBJECTS_BEGIN do { BOOST_PP_SEQ_FOR_EACH(OBJECTS_BEGIN_DETAIL, _, SANDBOX_TYPENUM_TYPES) } while (0) #define SER_OBJECTS_BEGIN do { BOOST_PP_SEQ_FOR_EACH(SER_OBJECTS_BEGIN_DETAIL, _, SANDBOX_TYPENUM_TYPES) } while (0)
#define OBJECTS_END_DETAIL(_r, _data, T) sandbox_ptr_map<T>::sandbox_serialize_end(); #define SER_OBJECTS_END_DETAIL(_r, _data, T) sandbox_ptr_map<T>::sandbox_serialize_end();
#define OBJECTS_END do { BOOST_PP_SEQ_FOR_EACH(OBJECTS_END_DETAIL, _, SANDBOX_TYPENUM_TYPES) } while (0) #define SER_OBJECTS_END do { BOOST_PP_SEQ_FOR_EACH(SER_OBJECTS_END_DETAIL, _, SANDBOX_TYPENUM_TYPES) } while (0)
#define OBJECTS_END_FAIL do { OBJECTS_END; return false; } 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<T>::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<T>::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) { extern "C" RETRO_API bool retro_serialize(void *data, size_t len) {
wasm_size_t max_size = 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; if (!sb().sandbox_serialize_fdtable(data, max_size)) return false;
// Write the number of objects, then each object // Write the number of objects, then each object
OBJECTS_BEGIN; SER_OBJECTS_BEGIN;
if (!sandbox_serialize((wasm_size_t)sb()->get_objects().size(), data, max_size)) OBJECTS_END_FAIL; if (!sandbox_serialize((wasm_size_t)sb()->objects.size(), data, max_size)) SER_OBJECTS_END_FAIL;
wasm_size_t num_free_objects = 0; wasm_size_t num_free_objects = 0;
for (const auto &object : sb()->get_objects()) { for (const auto &object : sb()->objects) {
if (object.typenum == 0) { if (object.typenum == 0) {
++num_free_objects; ++num_free_objects;
} else if (object.typenum > SANDBOX_NUM_TYPENUMS) { } else if (object.typenum > SANDBOX_NUM_TYPENUMS) {
std::abort(); std::abort();
} else { } else {
if (num_free_objects > 0) { if (num_free_objects > 0) {
if (!sandbox_serialize((wasm_size_t)0, 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)) OBJECTS_END_FAIL; if (!sandbox_serialize(num_free_objects, data, max_size)) SER_OBJECTS_END_FAIL;
num_free_objects = 0; num_free_objects = 0;
} }
if (!sandbox_serialize(object.typenum, 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)) 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 (num_free_objects > 0) {
if (!sandbox_serialize((wasm_size_t)0, 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)) OBJECTS_END_FAIL; if (!sandbox_serialize(num_free_objects, data, max_size)) SER_OBJECTS_END_FAIL;
num_free_objects = 0; num_free_objects = 0;
} }
// Write the number of extra objects that were found during serialization of the normal objects, then each such object // 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; wasm_size_t *num_extra_objects_ptr = (wasm_size_t *)data;
ADVANCE(sizeof(wasm_size_t)); 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 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]); const void *ptr = std::get<0>(extra_objects[i]);
wasm_size_t typenum = std::get<1>(extra_objects[i]); wasm_size_t typenum = std::get<1>(extra_objects[i]);
if (typenum == 0) { if (typenum != get_typenum<Color>::value && typenum != get_typenum<Tone>::value && typenum != get_typenum<Rect>::value) {
std::abort(); 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);
} else if (typenum > SANDBOX_NUM_TYPENUMS) {
std::abort(); std::abort();
} else { } else {
if (!sandbox_serialize(typenum, 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)) 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(); *num_extra_objects_ptr = (wasm_size_t)extra_objects.size();
OBJECTS_END; SER_OBJECTS_END;
std::memset(data, 0, max_size); std::memset(data, 0, max_size);
return true; return true;
} }
@ -1727,37 +1734,37 @@ extern "C" RETRO_API bool retro_unserialize(const void *data, size_t len) {
// Read the sandbox state // Read the sandbox state
{ {
wasm_ptr_t 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_machine_stack_pointer(value); sb()->set_machine_stack_pointer(value);
} }
{ {
uint8_t 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); sb()->set_asyncify_state(value);
} }
{ {
wasm_ptr_t 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); 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; uint64_t value;
if (!sandbox_deserialize(value, data, max_size)) return false; if (!sandbox_deserialize(value, data, max_size)) DESER_FAIL;
frame_time = value; frame_time = value;
} }
if (!sandbox_deserialize(frame_time_remainder, 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)) return false; if (!sandbox_deserialize(retro_run_count, data, max_size)) DESER_FAIL;
if (!sandbox_deserialize(sb().transitioning, data, max_size)) return false; if (!sandbox_deserialize(sb().transitioning, data, max_size)) DESER_FAIL;
{ {
bool have_trans_map; 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 (have_trans_map) {
if (sb().trans_map == nullptr) { if (sb().trans_map == nullptr) {
// TODO // 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 { } else {
if (sb().trans_map != nullptr) { if (sb().trans_map != nullptr) {
delete sb().trans_map; delete sb().trans_map;
@ -1768,14 +1775,14 @@ extern "C" RETRO_API bool retro_unserialize(const void *data, size_t len) {
{ {
// TODO: movie // TODO: movie
bool have_movie; bool have_movie;
if (!sandbox_deserialize(have_movie, data, max_size)) return false; if (!sandbox_deserialize(have_movie, data, max_size)) DESER_FAIL;
if (have_movie) return false; if (have_movie) DESER_FAIL;
} }
{ {
// Read sandbox fibers // Read sandbox fibers
wasm_size_t num_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.clear();
sb()->fibers.reserve(num_fibers); 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) { while (num_fibers > 0) {
// Read the key of the fiber // Read the key of the fiber
std::tuple<wasm_size_t, wasm_size_t, wasm_size_t> key; std::tuple<wasm_size_t, wasm_size_t, wasm_size_t> key;
if (!sandbox_deserialize(std::get<0>(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)) return false; if (!sandbox_deserialize(std::get<1>(key), data, max_size)) DESER_FAIL;
if (!sandbox_deserialize(std::get<2>(key), data, max_size)) return false; if (!sandbox_deserialize(std::get<2>(key), data, max_size)) DESER_FAIL;
// Construct the fiber // Construct the fiber
auto &fiber = sb()->fibers.emplace(key, key).first->second; auto &fiber = sb()->fibers.emplace(key, key).first->second;
// Read the stack index of the fiber // 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 // Read sandbox frames
wasm_size_t num_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); fiber.deser_stack.reserve(num_frames);
while (num_frames > 0) { while (num_frames > 0) {
wasm_ptr_t stack_pointer; 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; 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); fiber.deser_stack.emplace_back(stack_pointer, state);
--num_frames; --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<Tilemap::Autotiles>::value && typenum != get_typenum<TilemapVX::BitmapArray>::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<Color>::value && typenum != get_typenum<Tone>::value && typenum != get_typenum<Rect>::value) DESER_OBJECTS_END_FAIL;
void *ptr = typenum_table[typenum - 1].constructor();
if (ptr == nullptr && typenum != get_typenum<Tilemap::Autotiles>::value && typenum != get_typenum<TilemapVX::BitmapArray>::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; return true;
} }

View file

@ -56,7 +56,7 @@ class Bitmap : public Disposable
public: public:
Bitmap(Exception &exception, const char *filename); 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, void *pixeldata, int width, int height);
Bitmap(Exception &exception, TEXFBO &other); Bitmap(Exception &exception, TEXFBO &other);
Bitmap(Exception &exception, SDL_Surface *imgSurf, SDL_Surface *imgSurfHires, bool forceMega = false); Bitmap(Exception &exception, SDL_Surface *imgSurf, SDL_Surface *imgSurfHires, bool forceMega = false);

View file

@ -693,15 +693,42 @@ Font::getSdlFont(Exception &exception)
#ifdef MKXPZ_RETRO #ifdef MKXPZ_RETRO
bool Font::sandbox_serialize(void *&data, mkxp_sandbox::wasm_size_t &max_size) const 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->bold, data, max_size)) return false;
if (!mkxp_sandbox::sandbox_serialize(p->italic, 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->outline, data, max_size)) return false;
if (!mkxp_sandbox::sandbox_serialize(p->shadow, 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->color, data, max_size)) return false;
if (!mkxp_sandbox::sandbox_serialize(p->outColor, 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; return true;
} }
#endif // MKXPZ_RETRO #endif // MKXPZ_RETRO

View file

@ -151,6 +151,7 @@ public:
#ifdef MKXPZ_RETRO #ifdef MKXPZ_RETRO
bool sandbox_serialize(void *&data, mkxp_sandbox::wasm_size_t &max_size) const; 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 #endif // MKXPZ_RETRO
private: private:

View file

@ -211,10 +211,19 @@ void SceneElement::unlink()
#ifdef MKXPZ_RETRO #ifdef MKXPZ_RETRO
bool SceneElement::sandbox_serialize_scene_element(void *&data, mkxp_sandbox::wasm_size_t &max_size) const 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((int32_t)z, data, max_size)) return false;
if (!mkxp_sandbox::sandbox_serialize(visible, data, max_size)) return false; if (!mkxp_sandbox::sandbox_serialize(visible, data, max_size)) return false;
return true; 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 #endif // MKXPZ_REROO

View file

@ -97,6 +97,7 @@ public:
#ifdef MKXPZ_RETRO #ifdef MKXPZ_RETRO
bool sandbox_serialize_scene_element(void *&data, mkxp_sandbox::wasm_size_t &max_size) const; 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 #endif // MKXPZ_REROO
protected: protected:
@ -131,7 +132,7 @@ protected:
void unlink(); void unlink();
IntruListLink<SceneElement> link; IntruListLink<SceneElement> link;
const unsigned int creationStamp; uint64_t creationStamp;
int z; int z;
bool visible; bool visible;
Scene *scene; Scene *scene;

View file

@ -372,4 +372,33 @@ bool Plane::sandbox_serialize(void *&data, mkxp_sandbox::wasm_size_t &max_size)
return true; 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 #endif // MKXPZ_RETRO

View file

@ -55,6 +55,7 @@ public:
#ifdef MKXPZ_RETRO #ifdef MKXPZ_RETRO
bool sandbox_serialize(void *&data, mkxp_sandbox::wasm_size_t &max_size) const; 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 #endif // MKXPZ_RETRO
private: private:

View file

@ -896,4 +896,51 @@ bool Sprite::sandbox_serialize(void *&data, mkxp_sandbox::wasm_size_t &max_size)
return true; 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 #endif // MKXPZ_RETRO

View file

@ -84,6 +84,7 @@ public:
#ifdef MKXPZ_RETRO #ifdef MKXPZ_RETRO
bool sandbox_serialize(void *&data, mkxp_sandbox::wasm_size_t &max_size) const; 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 #endif // MKXPZ_RETRO
private: private:

View file

@ -136,6 +136,11 @@ struct FlashMap
return data; return data;
} }
Table *&getData()
{
return data;
}
void setData(Table *value) void setData(Table *value)
{ {
if (data == value) if (data == value)

View file

@ -1463,6 +1463,11 @@ bool Tilemap::Autotiles::sandbox_serialize(void *&data, mkxp_sandbox::wasm_size_
return true; 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 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); 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; 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 #endif // MKXPZ_RETRO

View file

@ -50,6 +50,7 @@ public:
#ifdef MKXPZ_RETRO #ifdef MKXPZ_RETRO
bool sandbox_serialize(void *&data, mkxp_sandbox::wasm_size_t &max_size) const; 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 #endif // MKXPZ_RETRO
private: private:
@ -86,6 +87,7 @@ public:
#ifdef MKXPZ_RETRO #ifdef MKXPZ_RETRO
bool sandbox_serialize(void *&data, mkxp_sandbox::wasm_size_t &max_size) const; 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 #endif // MKXPZ_RETRO
private: private:

View file

@ -621,6 +621,11 @@ bool TilemapVX::BitmapArray::sandbox_serialize(void *&data, mkxp_sandbox::wasm_s
return true; 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 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); 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; 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 #endif // MKXPZ_RETRO

View file

@ -46,6 +46,7 @@ public:
#ifdef MKXPZ_RETRO #ifdef MKXPZ_RETRO
bool sandbox_serialize(void *&data, mkxp_sandbox::wasm_size_t &max_size) const; 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 #endif // MKXPZ_RETRO
private: private:
@ -74,6 +75,7 @@ public:
#ifdef MKXPZ_RETRO #ifdef MKXPZ_RETRO
bool sandbox_serialize(void *&data, mkxp_sandbox::wasm_size_t &max_size) const; 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 #endif // MKXPZ_RETRO
private: private:

View file

@ -244,6 +244,28 @@ bool Viewport::sandbox_serialize(void *&data, mkxp_sandbox::wasm_size_t &max_siz
return true; 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 #endif // MXKPZ_RETRO
@ -293,4 +315,12 @@ bool ViewportElement::sandbox_serialize_viewport_element(void *&data, mkxp_sandb
return true; 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 #endif // MXKPZ_RETRO

View file

@ -53,6 +53,7 @@ public:
#ifdef MKXPZ_RETRO #ifdef MKXPZ_RETRO
bool sandbox_serialize(void *&data, mkxp_sandbox::wasm_size_t &max_size) const; 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 #endif // MXKPZ_RETRO
private: private:
@ -85,6 +86,7 @@ public:
#ifdef MKXPZ_RETRO #ifdef MKXPZ_RETRO
bool sandbox_serialize_viewport_element(void *&data, mkxp_sandbox::wasm_size_t &max_size) const; 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 #endif // MXKPZ_RETRO
protected: protected:

View file

@ -982,4 +982,43 @@ bool Window::sandbox_serialize(void *&data, mkxp_sandbox::wasm_size_t &max_size)
return true; 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 #endif // MKXPZ_RETRO

View file

@ -67,6 +67,7 @@ public:
#ifdef MKXPZ_RETRO #ifdef MKXPZ_RETRO
bool sandbox_serialize(void *&data, mkxp_sandbox::wasm_size_t &max_size) const; 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 #endif // MKXPZ_RETRO
private: private:

View file

@ -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->contentsOpacity, data, max_size)) return false;
if (!mkxp_sandbox::sandbox_serialize(p->openness, 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->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->contentsQuad, data, max_size)) return false;
if (!mkxp_sandbox::sandbox_serialize(p->padRect, 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; 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; 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 #endif // MKXPZ_RETRO

View file

@ -74,6 +74,7 @@ public:
#ifdef MKXPZ_RETRO #ifdef MKXPZ_RETRO
bool sandbox_serialize(void *&data, mkxp_sandbox::wasm_size_t &max_size) const; 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 #endif // MKXPZ_RETRO
private: private:

View file

@ -191,6 +191,15 @@ bool Color::sandbox_serialize(void *&data, mkxp_sandbox::wasm_size_t &max_size)
return true; 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 #endif // MKXPZ_RETRO
@ -320,6 +329,15 @@ bool Tone::sandbox_serialize(void *&data, mkxp_sandbox::wasm_size_t &max_size) c
return true; 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 #endif // MKXPZ_RETRO
@ -472,4 +490,13 @@ bool Rect::sandbox_serialize(void *&data, mkxp_sandbox::wasm_size_t &max_size) c
return true; 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 #endif // MKXPZ_RETRO

View file

@ -94,6 +94,7 @@ struct Color : public Serializable
#ifdef MKXPZ_RETRO #ifdef MKXPZ_RETRO
bool sandbox_serialize(void *&data, mkxp_sandbox::wasm_size_t &max_size) const; 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 #endif // MKXPZ_RETRO
/* Range (0.0 ~ 255.0) */ /* Range (0.0 ~ 255.0) */
@ -150,6 +151,7 @@ struct Tone : public Serializable
#ifdef MKXPZ_RETRO #ifdef MKXPZ_RETRO
bool sandbox_serialize(void *&data, mkxp_sandbox::wasm_size_t &max_size) const; 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 #endif // MKXPZ_RETRO
/* Range (-255.0 ~ 255.0) */ /* Range (-255.0 ~ 255.0) */
@ -213,6 +215,7 @@ struct Rect : public Serializable
#ifdef MKXPZ_RETRO #ifdef MKXPZ_RETRO
bool sandbox_serialize(void *&data, mkxp_sandbox::wasm_size_t &max_size) const; 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 #endif // MKXPZ_RETRO
int x; int x;

View file

@ -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)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)ys, data, max_size)) return false;
if (!mkxp_sandbox::sandbox_serialize((int32_t)zs, 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; if (max_size < this->data.size() * sizeof(int16_t)) return false;
memcpy(data, this->data.data(), this->data.size() * sizeof(int16_t)); memcpy(data, this->data.data(), this->data.size() * sizeof(int16_t));
data = (uint8_t *)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); max_size -= this->data.size() * sizeof(int16_t);
return true; 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 #endif // MKXPZ_RETRO

View file

@ -35,7 +35,7 @@
class Table : public Serializable class Table : public Serializable
{ {
public: public:
Table(int x, int y = 1, int z = 1); Table(int x = 1, int y = 1, int z = 1);
/* Clone constructor */ /* Clone constructor */
Table(const Table &other); Table(const Table &other);
virtual ~Table() {} virtual ~Table() {}
@ -70,6 +70,7 @@ public:
#ifdef MKXPZ_RETRO #ifdef MKXPZ_RETRO
bool sandbox_serialize(void *&data, mkxp_sandbox::wasm_size_t &max_size) const; 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 #endif // MKXPZ_RETRO
private: private:

View file

@ -107,7 +107,7 @@ struct SharedStatePrivate
Quad gpQuad; Quad gpQuad;
unsigned int stampCounter; uint64_t stampCounter;
std::chrono::time_point<std::chrono::steady_clock> startupTime; std::chrono::time_point<std::chrono::steady_clock> startupTime;
@ -435,7 +435,7 @@ double SharedState::runTime() {
#endif // MKXPZ_RETRO #endif // MKXPZ_RETRO
} }
unsigned int SharedState::genTimeStamp() uint64_t SharedState::genTimeStamp()
{ {
return p->stampCounter++; return p->stampCounter++;
} }

View file

@ -84,7 +84,7 @@ struct SharedState
sigslot::signal<> prepareDraw; sigslot::signal<> prepareDraw;
unsigned int genTimeStamp(); uint64_t genTimeStamp();
// Returns time since SharedState was constructed in microseconds // Returns time since SharedState was constructed in microseconds
double runTime(); double runTime();