mirror of
https://github.com/holub/mame
synced 2025-04-23 17:00:53 +03:00
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:
parent
53250a489d
commit
2d1b881c79
103
src/emu/save.cpp
103
src/emu/save.cpp
@ -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
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user