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.
This commit is contained in:
feos 2020-02-24 19:25:32 +03:00 committed by GitHub
parent 53250a489d
commit 2d1b881c79
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 133 additions and 0 deletions

View File

@ -340,6 +340,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

View File

@ -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

View File

@ -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);