diff --git a/src/frontend/mame/luaengine.cpp b/src/frontend/mame/luaengine.cpp index b6fc0014a4c..6981ebfe41b 100644 --- a/src/frontend/mame/luaengine.cpp +++ b/src/frontend/mame/luaengine.cpp @@ -95,18 +95,6 @@ template <> struct is_container : std::true_type { }; template <> struct is_container : std::true_type { }; -sol::buffer *sol_lua_get(sol::types, lua_State *L, int index, sol::stack::record &tracking) -{ - return new sol::buffer(stack::get(L, index), L); -} - -int sol_lua_push(sol::types, lua_State *L, buffer *value) -{ - delete value; - return 1; -} - - template struct usertype_container > : lua_engine::immutable_collection_helper, T> { @@ -834,7 +822,15 @@ void lua_engine::initialize() } new (&file) emu_file(path, flags); })); - file_type.set("read", [](emu_file &file, sol::buffer *buff) { buff->set_len(file.read(buff->get_ptr(), buff->get_len())); return buff; }); + file_type.set("read", + [] (emu_file &file, sol::this_state s, size_t len) + { + buffer_helper buf(s); + auto space = buf.prepare(len); + space.add(file.read(space.get(), len)); + buf.push(); + return sol::stack::pop(s); + }); file_type.set("write", [](emu_file &file, const std::string &data) { return file.write(data.data(), data.size()); }); file_type.set("puts", &emu_file::puts); file_type.set("open", static_cast(&emu_file::open)); @@ -1001,16 +997,18 @@ void lua_engine::initialize() } return sol::make_object(sol(), ret); }); - item_type.set("read_block", [](save_item &item, int offset, sol::buffer *buff) { - if(!item.base || ((offset + buff->get_len()) > (item.size * item.count))) + item_type.set("read_block", [](save_item &item, sol::this_state s, int offset, size_t len) { + buffer_helper buf(s); + auto space = buf.prepare(len); + if(!item.base || ((offset + len) > (item.size * item.count))) { - buff->set_len(0); + space.add(0); } else { const uint32_t blocksize = item.size * item.valcount; - uint32_t remaining = buff->get_len(); - uint8_t *dest = reinterpret_cast(buff->get_ptr()); + size_t remaining = len; + uint8_t *dest = reinterpret_cast(space.get()); while(remaining) { const uint32_t blockno = offset / blocksize; @@ -1022,8 +1020,10 @@ void lua_engine::initialize() remaining -= chunk; dest += chunk; } + space.add(len); } - return buff; + buf.push(); + return sol::stack::pop(s); }); item_type.set("write", [](save_item &item, int offset, uint64_t value) { if(!item.base || (offset >= item.count)) diff --git a/src/frontend/mame/luaengine.h b/src/frontend/mame/luaengine.h index b070969f424..6c5f572885d 100644 --- a/src/frontend/mame/luaengine.h +++ b/src/frontend/mame/luaengine.h @@ -21,7 +21,11 @@ #include #include +#ifdef MAME_DEBUG +#define SOL_ALL_SAFETIES_ON 1 +#else #define SOL_SAFE_USERTYPE 1 +#endif #include "sol/sol.hpp" struct lua_State; @@ -30,6 +34,7 @@ class lua_engine { public: // helper structures + class buffer_helper; template struct devenum; template struct simple_list_wrapper; template struct tag_object_ptr_map; diff --git a/src/frontend/mame/luaengine.ipp b/src/frontend/mame/luaengine.ipp index 10d1f55f33f..0dd6d3d8d90 100644 --- a/src/frontend/mame/luaengine.ipp +++ b/src/frontend/mame/luaengine.ipp @@ -16,10 +16,100 @@ #include +#include #include +class lua_engine::buffer_helper +{ +private: + class proxy + { + private: + buffer_helper &m_host; + char *m_space; + size_t const m_size; + + public: + proxy(proxy const &) = delete; + proxy &operator=(proxy const &) = delete; + + proxy(proxy &&that) : m_host(that.m_host), m_space(that.m_space), m_size(that.m_size) + { + that.m_space = nullptr; + } + + proxy(buffer_helper &host, size_t size) : m_host(host), m_space(luaL_prepbuffsize(&host.m_buffer, size)), m_size(size) + { + m_host.m_prepared = true; + } + + ~proxy() + { + if (m_space) + { + assert(m_host.m_prepared); + luaL_addsize(&m_host.m_buffer, 0U); + m_host.m_prepared = false; + } + } + + char *get() + { + return m_space; + } + + void add(size_t size) + { + assert(m_space); + assert(size <= m_size); + assert(m_host.m_prepared); + m_space = nullptr; + luaL_addsize(&m_host.m_buffer, size); + m_host.m_prepared = false; + } + }; + + luaL_Buffer m_buffer; + bool m_valid; + bool m_prepared; + +public: + buffer_helper(buffer_helper const &) = delete; + buffer_helper &operator=(buffer_helper const &) = delete; + + buffer_helper(lua_State *L) + { + luaL_buffinit(L, &m_buffer); + m_valid = true; + m_prepared = false; + } + + ~buffer_helper() + { + assert(!m_prepared); + if (m_valid) + luaL_pushresult(&m_buffer); + } + + void push() + { + assert(m_valid); + assert(!m_prepared); + luaL_pushresult(&m_buffer); + m_valid = false; + } + + proxy prepare(size_t size) + { + assert(m_valid); + assert(!m_prepared); + return proxy(*this, size); + } +}; + + template struct lua_engine::simple_list_wrapper { @@ -40,52 +130,9 @@ struct lua_engine::tag_object_ptr_map namespace sol { -class buffer -{ -public: - // sol does lua_settop(0), save userdata buffer in registry if necessary - buffer(int size, lua_State *L) - { - ptr = luaL_buffinitsize(L, &buff, size); - len = size; - if(buff.b != buff.initb) - { - lua_pushvalue(L, -1); - lua_setfield(L, LUA_REGISTRYINDEX, "sol::buffer_temp"); - } - } - ~buffer() - { - lua_State *L = buff.L; - if(lua_getfield(L, LUA_REGISTRYINDEX, "sol::buffer_temp") != LUA_TNIL) - { - lua_pushnil(L); - lua_setfield(L, LUA_REGISTRYINDEX, "sol::buffer_temp"); - } - else - lua_pop(L, -1); - - luaL_pushresultsize(&buff, len); - } - - void set_len(int size) { len = size; } - int get_len() { return len; } - char *get_ptr() { return ptr; } - -private: - luaL_Buffer buff; - int len; - char *ptr; -}; - - -// don't convert core_optons to a table directly +// don't convert core_options to a table directly template <> struct is_container : std::false_type { }; -// buffer customisation -sol::buffer *sol_lua_get(sol::types, lua_State *L, int index, sol::stack::record &tracking); -int sol_lua_push(sol::types, lua_State *L, buffer *value); - // these things should be treated as containers template struct is_container > : std::true_type { };