summaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
author feos <vadosnaprimer@users.noreply.github.com>2020-02-24 19:25:32 +0300
committer GitHub <noreply@github.com>2020-02-24 11:25:32 -0500
commit2d1b881c794286f0e090fbc837db1132c6ea042d (patch)
tree0ca6d28a4da247fa680ff78e915c7fe00b6623fa
parent53250a489d13cb5f2bd0f9e09177dba430e805cd (diff)
luaengine: save state to/from binary string buffer (#6354)
* luaengine: save state to/from binary string buffer * account for error * luaL_error makes it exit immediately, but explicit return is required by compiler. actual return is nil if it fails.
-rw-r--r--src/emu/save.cpp103
-rw-r--r--src/emu/save.h3
-rw-r--r--src/frontend/mame/luaengine.cpp27
3 files changed, 133 insertions, 0 deletions
diff --git a/src/emu/save.cpp b/src/emu/save.cpp
index 72a164345f2..c345ef3e6ac 100644
--- a/src/emu/save.cpp
+++ b/src/emu/save.cpp
@@ -341,6 +341,109 @@ save_error save_manager::write_file(emu_file &file)
//-------------------------------------------------
+// save - write the current machine state to the
+// allocated stream
+//-------------------------------------------------
+
+save_error save_manager::write_buffer(u8 *data, size_t size)
+{
+ // if we have illegal registrations, return an error
+ if (m_illegal_regs > 0)
+ return STATERR_ILLEGAL_REGISTRATIONS;
+
+ // verify the buffer length
+ if (size != ram_state::get_size(*this))
+ return STATERR_WRITE_ERROR;
+
+ // generate the header
+ u8 header[HEADER_SIZE];
+ memcpy(&header[0], STATE_MAGIC_NUM, 8);
+ header[8] = SAVE_VERSION;
+ header[9] = NATIVE_ENDIAN_VALUE_LE_BE(0, SS_MSB_FIRST);
+ strncpy((char *)&header[0x0a], machine().system().name, 0x1c - 0x0a);
+ u32 sig = signature();
+ *(u32 *)&header[0x1c] = little_endianize_int32(sig);
+
+ // write the header
+ memcpy(data, header, sizeof(header));
+
+ // advance the pointer
+ u8 *byte_ptr = data + sizeof(header);
+
+ // call the pre-save functions
+ dispatch_presave();
+
+ // then write all the data
+ for (auto &entry : m_entry_list)
+ {
+ u32 totalsize = entry->m_typesize * entry->m_typecount;
+
+ // check bounds before writing
+ if (byte_ptr + totalsize > data + size)
+ return STATERR_WRITE_ERROR;
+
+ memcpy(byte_ptr, entry->m_data, totalsize);
+ byte_ptr += totalsize;
+ }
+ return STATERR_NONE;
+}
+
+
+//-------------------------------------------------
+// load - restore the machine state from the
+// stream
+//-------------------------------------------------
+
+save_error save_manager::read_buffer(u8 *data, size_t size)
+{
+ // if we have illegal registrations, return an error
+ if (m_illegal_regs > 0)
+ return STATERR_ILLEGAL_REGISTRATIONS;
+
+ // verify the buffer length
+ if (size != ram_state::get_size(*this))
+ return STATERR_WRITE_ERROR;
+
+ // read the header
+ u8 header[HEADER_SIZE];
+ memcpy(header, data, sizeof(header));
+
+ // advance the pointer
+ u8 *byte_ptr = data + sizeof(header);
+
+ // verify the header and report an error if it doesn't match
+ u32 sig = signature();
+ if (validate_header(header, machine().system().name, sig, nullptr, "Error: ") != STATERR_NONE)
+ return STATERR_INVALID_HEADER;
+
+ // determine whether or not to flip the data when done
+ bool flip = NATIVE_ENDIAN_VALUE_LE_BE((header[9] & SS_MSB_FIRST) != 0, (header[9] & SS_MSB_FIRST) == 0);
+
+ // read all the data, flipping if necessary
+ for (auto &entry : m_entry_list)
+ {
+ u32 totalsize = entry->m_typesize * entry->m_typecount;
+
+ // check bounds before reading
+ if (byte_ptr + totalsize > data + size)
+ return STATERR_READ_ERROR;
+
+ memcpy(entry->m_data, byte_ptr, totalsize);
+ byte_ptr += totalsize;
+
+ // handle flipping
+ if (flip)
+ entry->flip_data();
+ }
+
+ // call the post-load functions
+ dispatch_postload();
+
+ return STATERR_NONE;
+}
+
+
+//-------------------------------------------------
// signature - compute the signature, which
// is a CRC over the structure of the data
//-------------------------------------------------
diff --git a/src/emu/save.h b/src/emu/save.h
index 3cb00ed79c2..53576dd0d0b 100644
--- a/src/emu/save.h
+++ b/src/emu/save.h
@@ -232,6 +232,9 @@ public:
static save_error check_file(running_machine &machine, emu_file &file, const char *gamename, void (CLIB_DECL *errormsg)(const char *fmt, ...));
save_error write_file(emu_file &file);
save_error read_file(emu_file &file);
+
+ save_error write_buffer(u8 *data, size_t size);
+ save_error read_buffer(u8 *data, size_t size);
private:
// internal helpers
diff --git a/src/frontend/mame/luaengine.cpp b/src/frontend/mame/luaengine.cpp
index e8fe2f2fcb4..b5405f9722d 100644
--- a/src/frontend/mame/luaengine.cpp
+++ b/src/frontend/mame/luaengine.cpp
@@ -1279,6 +1279,8 @@ void lua_engine::initialize()
* machine:soft_reset() - soft reset emulation
* machine:save(filename) - save state to filename
* machine:load(filename) - load state from filename
+ * machine:buffer_save() - return save state buffer as binary string
+ * machine:buffer_load(str) - load state from binary string buffer. returns true on success, otherwise nil
* machine:popmessage(str) - print str as popup
* machine:popmessage() - clear displayed popup message
* machine:logerror(str) - print str to log
@@ -1311,6 +1313,31 @@ void lua_engine::initialize()
machine_type.set("soft_reset", &running_machine::schedule_soft_reset);
machine_type.set("save", &running_machine::schedule_save);
machine_type.set("load", &running_machine::schedule_load);
+ machine_type.set("buffer_save", [](running_machine &m, sol::this_state s) {
+ lua_State *L = s;
+ luaL_Buffer buff;
+ int size = ram_state::get_size(m.save());
+ u8 *ptr = (u8 *)luaL_buffinitsize(L, &buff, size);
+ save_error error = m.save().write_buffer(ptr, size);
+ if (error == STATERR_NONE)
+ {
+ luaL_pushresultsize(&buff, size);
+ return sol::make_reference(L, sol::stack_reference(L, -1));
+ }
+ luaL_error(L, "State save error.");
+ return sol::make_reference(L, nullptr);
+ });
+ machine_type.set("buffer_load", [](running_machine &m, sol::this_state s, std::string str) {
+ lua_State *L = s;
+ save_error error = m.save().read_buffer((u8 *)str.data(), str.size());
+ if (error == STATERR_NONE)
+ return true;
+ else
+ {
+ luaL_error(L,"State load error.");
+ return false;
+ }
+ });
machine_type.set("system", &running_machine::system);
machine_type.set("video", &running_machine::video);
machine_type.set("sound", &running_machine::sound);