diff options
Diffstat (limited to 'engines/sword25/util/lua_persist.cpp')
-rw-r--r-- | engines/sword25/util/lua_persist.cpp | 802 |
1 files changed, 0 insertions, 802 deletions
diff --git a/engines/sword25/util/lua_persist.cpp b/engines/sword25/util/lua_persist.cpp deleted file mode 100644 index 03f305b2c5..0000000000 --- a/engines/sword25/util/lua_persist.cpp +++ /dev/null @@ -1,802 +0,0 @@ -/* ScummVM - Graphic Adventure Engine - * - * ScummVM is the legal property of its developers, whose names - * are too numerous to list here. Please refer to the COPYRIGHT - * file distributed with this source distribution. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - */ - -/** - * This code is heavily based on the Pluto code base. Copyright below - */ - -/* Tamed Pluto - Heavy-duty persistence for Lua - * Copyright (C) 2004 by Ben Sunshine-Hill, and released into the public - * domain. People making use of this software as part of an application - * are politely requested to email the author at sneftel@gmail.com - * with a brief description of the application, primarily to satisfy his - * curiosity. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. - * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY - * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, - * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE - * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - * - * Instrumented by Stefan Reich (info@luaos.net) - * for Mobile Lua (http://luaos.net/pages/mobile-lua.php) - */ - - -#include "sword25/util/lua_persistence.h" - -#include "sword25/util/double_serialization.h" -#include "sword25/util/lua_persistence_util.h" - -#include "common/stream.h" - -#include "lua/lobject.h" -#include "lua/lstate.h" -#include "lua/lgc.h" - - -namespace Lua { - -#define PERMANENT_TYPE 101 - -struct SerializationInfo { - lua_State *luaState; - Common::WriteStream *writeStream; - uint counter; -}; - -static void persist(SerializationInfo *info); - -static void persistBoolean(SerializationInfo *info); -static void persistNumber(SerializationInfo *info); -static void persistString(SerializationInfo *info); -static void persistTable(SerializationInfo *info); -static void persistFunction(SerializationInfo *info); -static void persistThread(SerializationInfo *info); -static void persistProto(SerializationInfo *info); -static void persistUpValue(SerializationInfo *info); -static void persistUserData(SerializationInfo *info); - - -void persistLua(lua_State *luaState, Common::WriteStream *writeStream) { - SerializationInfo info; - info.luaState = luaState; - info.writeStream = writeStream; - info.counter = 1u; - - // The process starts with the lua stack as follows: - // >>>>> permTbl rootObj - // That's the table of permanents and the root object to be serialized - - // Make sure there is enough room on the stack - lua_checkstack(luaState, 4); - assert(lua_gettop(luaState) == 2); - // And that the root isn't nil - assert(!lua_isnil(luaState, 2)); - - // Create a table to hold indexes of everything that's serialized - // This allows us to only serialize an object once - // Every other time, just reference the index - lua_newtable(luaState); - // >>>>> permTbl rootObj indexTbl - - // Now we're going to make the table weakly keyed. This prevents the - // GC from visiting it and trying to mark things it doesn't want to - // mark in tables, e.g. upvalues. All objects in the table are - // a priori reachable, so it doesn't matter that we do this. - - // Create the metatable - lua_newtable(luaState); - // >>>>> permTbl rootObj indexTbl metaTbl - - lua_pushstring(luaState, "__mode"); - // >>>>> permTbl rootObj indexTbl metaTbl "__mode" - - lua_pushstring(luaState, "k"); - // >>>>> permTbl rootObj indexTbl metaTbl "__mode" "k" - - lua_settable(luaState, 4); - // >>>>> permTbl rootObj indexTbl metaTbl - - lua_setmetatable(luaState, 3); - // >>>>> permTbl rootObj indexTbl - - // Swap the indexTable and the rootObj - lua_insert(luaState, 2); - // >>>>> permTbl indexTbl rootObj - - // Serialize the root recursively - persist(&info); - - // Return the stack back to the original state - lua_remove(luaState, 2); - // >>>>> permTbl rootObj -} - -static void persist(SerializationInfo *info) { - // The stack can potentially have many things on it - // The object we want to serialize is the item on the top of the stack - // >>>>> permTbl indexTbl rootObj ...... obj - - // Make sure there is enough room on the stack - lua_checkstack(info->luaState, 2); - - // If the object has already been written, don't write it again - // Instead write the index of the object from the indexTbl - - // Check the indexTbl - lua_pushvalue(info->luaState, -1); - // >>>>> permTbl indexTbl rootObj ...... obj obj - - lua_rawget(info->luaState, 2); - // >>>>> permTbl indexTbl rootObj ...... obj ?index? - - // If the index isn't nil, the object has already been written - if (!lua_isnil(info->luaState, -1)) { - // Write out a flag that indicates that it's an index - info->writeStream->writeByte(0); - - // Retrieve the index from the stack - uint *index = (uint *)lua_touserdata(info->luaState, -1); - - // Write out the index - info->writeStream->writeUint32LE(*index); - - // Pop the index off the stack - lua_pop(info->luaState, 1); - - return; - } - - // Pop the index/nil off the stack - lua_pop(info->luaState, 1); - - // If the obj itself is nil, we represent it as an index of 0 - if (lua_isnil(info->luaState, -1)) { - // Write out a flag that indicates that it's an index - info->writeStream->writeByte(0); - // Write out the index - info->writeStream->writeUint32LE(0); - - return; - } - - // Write out a flag that indicates that this is a real object - info->writeStream->writeByte(1); - - // Add the object to the indexTbl - - lua_pushvalue(info->luaState, -1); - // >>>>> permTbl indexTbl rootObj ...... obj obj - - uint *ref = (uint *)lua_newuserdata(info->luaState, sizeof(uint)); - *ref = ++(info->counter); - // >>>>> permTbl indexTbl rootObj ...... obj obj index - - lua_rawset(info->luaState, 2); - // >>>>> permTbl indexTbl rootObj ...... obj - - - // Write out the index - info->writeStream->writeUint32LE(info->counter); - - - // Objects that are in the permanents table are serialized in a special way - - lua_pushvalue(info->luaState, -1); - // >>>>> permTbl indexTbl rootObj ...... obj obj - - lua_gettable(info->luaState, 1); - // >>>>> permTbl indexTbl rootObj ...... obj obj ?permKey? - - if (!lua_isnil(info->luaState, -1)) { - // Write out the type - info->writeStream->writeSint32LE(PERMANENT_TYPE); - - // Serialize the key - persist(info); - - // Pop the key off the stack - lua_pop(info->luaState, 1); - - return; - } - - // Pop the nil off the stack - lua_pop(info->luaState, 1); - - // Query the type of the object - int objType = lua_type(info->luaState, -1); - - // Write it out - info->writeStream->writeSint32LE(objType); - - // Serialize the object by its type - - switch (objType) { - case LUA_TBOOLEAN: - persistBoolean(info); - break; - case LUA_TLIGHTUSERDATA: - // You can't serialize a pointer - // It would be meaningless on the next run - assert(0); - break; - case LUA_TNUMBER: - persistNumber(info); - break; - case LUA_TSTRING: - persistString(info); - break; - case LUA_TTABLE: - persistTable(info); - break; - case LUA_TFUNCTION: - persistFunction(info); - break; - case LUA_TTHREAD: - persistThread(info); - break; - case LUA_TPROTO: - persistProto(info); - break; - case LUA_TUPVAL: - persistUpValue(info); - break; - case LUA_TUSERDATA: - persistUserData(info); - break; - default: - assert(0); - } -} - -static void persistBoolean(SerializationInfo *info) { - int value = lua_toboolean(info->luaState, -1); - - info->writeStream->writeSint32LE(value); -} - -static void persistNumber(SerializationInfo *info) { - lua_Number value = lua_tonumber(info->luaState, -1); - - Util::SerializedDouble serializedValue(Util::encodeDouble(value)); - - info->writeStream->writeUint32LE(serializedValue.significandOne); - info->writeStream->writeUint32LE(serializedValue.signAndSignificandTwo); - info->writeStream->writeSint16LE(serializedValue.exponent); -} - -static void persistString(SerializationInfo *info) { - // Hard cast to a uint32 to force size_t to an explicit size - // *Theoretically* this could truncate, but if we have a 4gb string, we have bigger problems - uint32 length = static_cast<uint32>(lua_strlen(info->luaState, -1)); - info->writeStream->writeUint32LE(length); - - const char *str = lua_tostring(info->luaState, -1); - info->writeStream->write(str, length); -} - -/* Choose whether to do a regular or special persistence based on an object's - * metatable. "default" is whether the object, if it doesn't have a __persist - * entry, is literally persistable or not. - * Pushes the unpersist closure and returns true if special persistence is - * used. */ -static bool serializeSpecialObject(SerializationInfo *info, bool defaction) { - // Make sure there is enough room on the stack - lua_checkstack(info->luaState, 4); - - // Check whether we should persist literally, or via the __persist metafunction - if (!lua_getmetatable(info->luaState, -1)) { - if (defaction) { - // Write out a flag declaring that the object isn't special and should be persisted normally - info->writeStream->writeSint32LE(0); - - return false; - } else { - lua_pushstring(info->luaState, "Type not literally persistable by default"); - lua_error(info->luaState); - - return false; // Not reached - } - } - - // >>>>> permTbl indexTbl ...... obj metaTbl - lua_pushstring(info->luaState, "__persist"); - // >>>>> permTbl indexTbl rootObj ...... obj metaTbl "__persist" - - lua_rawget(info->luaState, -2); - // >>>>> permTbl indexTbl ...... obj metaTbl ?__persist? - - if (lua_isnil(info->luaState, -1)) { - // >>>>> permTbl indexTbl ...... obj metaTbl nil - lua_pop(info->luaState, 2); - // >>>>> permTbl indexTbl ...... obj - - if (defaction) { - // Write out a flag declaring that the object isn't special and should be persisted normally - info->writeStream->writeSint32LE(0); - - return false; - } else { - lua_pushstring(info->luaState, "Type not literally persistable by default"); - lua_error(info->luaState); - - return false; // Return false - } - - } else if (lua_isboolean(info->luaState, -1)) { - // >>>>> permTbl indexTbl ...... obj metaTbl bool - if (lua_toboolean(info->luaState, -1)) { - // Write out a flag declaring that the object isn't special and should be persisted normally - info->writeStream->writeSint32LE(0); - - // >>>>> permTbl indexTbl ...... obj metaTbl true */ - lua_pop(info->luaState, 2); - // >>>>> permTbl indexTbl ...... obj - - return false; - } else { - lua_pushstring(info->luaState, "Metatable forbade persistence"); - lua_error(info->luaState); - - return false; // Not reached - } - } else if (!lua_isfunction(info->luaState, -1)) { - lua_pushstring(info->luaState, "__persist not nil, boolean, or function"); - lua_error(info->luaState); - } - - // >>>>> permTbl indexTbl ...... obj metaTbl __persist - lua_pushvalue(info->luaState, -3); - // >>>>> permTbl indexTbl ...... obj metaTbl __persist obj - - // >>>>> permTbl indexTbl ...... obj metaTbl ?func? - - if (!lua_isfunction(info->luaState, -1)) { - lua_pushstring(info->luaState, "__persist function did not return a function"); - lua_error(info->luaState); - } - - // >>>>> permTbl indexTbl ...... obj metaTbl func - - // Write out a flag that the function exists - info->writeStream->writeSint32LE(1); - - // Serialize the function - persist(info); - - lua_pop(info->luaState, 2); - // >>>>> permTbl indexTbl ...... obj - - return true; -} - -static void persistTable(SerializationInfo *info) { - // >>>>> permTbl indexTbl ...... tbl - - // Make sure there is enough room on the stack - lua_checkstack(info->luaState, 3); - - // Test if the object needs special serialization - if (serializeSpecialObject(info, 1)) { - return; - } - - // >>>>> permTbl indexTbl ...... tbl - - // First, serialize the metatable (if any) - if (!lua_getmetatable(info->luaState, -1)) { - lua_pushnil(info->luaState); - } - - // >>>>> permTbl indexTbl ...... tbl metaTbl/nil */ - persist(info); - - lua_pop(info->luaState, 1); - // >>>>> permTbl indexTbl ...... tbl - - - lua_pushnil(info->luaState); - // >>>>> permTbl indexTbl ...... tbl nil - - // Now, persist all k/v pairs - while (lua_next(info->luaState, -2)) { - // >>>>> permTbl indexTbl ...... tbl k v */ - - lua_pushvalue(info->luaState, -2); - // >>>>> permTbl indexTbl ...... tbl k v k */ - - // Serialize the key - persist(info); - - lua_pop(info->luaState, 1); - // >>>>> permTbl indexTbl ...... tbl k v */ - - // Serialize the value - persist(info); - - lua_pop(info->luaState, 1); - // >>>>> permTbl indexTbl ...... tbl k */ - } - - // >>>>> permTbl indexTbl ...... tbl - - // Terminate the list with a nil - lua_pushnil(info->luaState); - // >>>>> permTbl indexTbl ...... tbl - - persist(info); - - lua_pop(info->luaState, 1); - // >>>>> permTbl indexTbl ...... tbl -} - -static void persistFunction(SerializationInfo *info) { - // >>>>> permTbl indexTbl ...... func - Closure *cl = clvalue(getObject(info->luaState, -1)); - lua_checkstack(info->luaState, 2); - - if (cl->c.isC) { - /* It's a C function. For now, we aren't going to allow - * persistence of C closures, even if the "C proto" is - * already in the permanents table. */ - lua_pushstring(info->luaState, "Attempt to persist a C function"); - lua_error(info->luaState); - } else { - // It's a Lua closure - - // We don't really _NEED_ the number of upvals, but it'll simplify things a bit - info->writeStream->writeByte(cl->l.p->nups); - - // Serialize the prototype - pushProto(info->luaState, cl->l.p); - // >>>>> permTbl indexTbl ...... func proto */ - - persist(info); - - lua_pop(info->luaState, 1); - // >>>>> permTbl indexTbl ...... func - - // Serialize upvalue values (not the upvalue objects themselves) - for (byte i = 0; i < cl->l.p->nups; i++) { - // >>>>> permTbl indexTbl ...... func - pushUpValue(info->luaState, cl->l.upvals[i]); - // >>>>> permTbl indexTbl ...... func upval - - persist(info); - - lua_pop(info->luaState, 1); - // >>>>> permTbl indexTbl ...... func - } - - // >>>>> permTbl indexTbl ...... func - - // Serialize function environment - lua_getfenv(info->luaState, -1); - // >>>>> permTbl indexTbl ...... func fenv - - if (lua_equal(info->luaState, -1, LUA_GLOBALSINDEX)) { - // Function has the default fenv - - // >>>>> permTbl indexTbl ...... func _G - lua_pop(info->luaState, 1); - // >>>>> permTbl indexTbl ...... func - - lua_pushnil(info->luaState); - // >>>>> permTbl indexTbl ...... func nil - } - - // >>>>> permTbl indexTbl ...... func fenv/nil - persist(info); - - lua_pop(info->luaState, 1); - // >>>>> permTbl indexTbl ...... func - } -} - -static void persistThread(SerializationInfo *info) { - // >>>>> permTbl indexTbl ...... thread - lua_State *threadState = lua_tothread(info->luaState, -1); - - // Make sure there is enough room on the stack - lua_checkstack(info->luaState, threadState->top - threadState->stack + 1); - - if (info->luaState == threadState) { - lua_pushstring(info->luaState, "Can't persist currently running thread"); - lua_error(info->luaState); - return; /* not reached */ - } - - // Persist the stack - - // We *could* have truncation here, but if we have more than 4 billion items on a stack, we have bigger problems - uint32 stackSize = static_cast<uint32>(appendStackToStack_reverse(threadState, info->luaState)); - info->writeStream->writeUint32LE(stackSize); - - // >>>>> permTbl indexTbl ...... thread (reversed contents of thread stack) */ - for (; stackSize > 0; --stackSize) { - persist(info); - - lua_pop(info->luaState, 1); - } - - // >>>>> permTbl indexTbl ...... thread - - // Now, serialize the CallInfo stack - - // Again, we *could* have truncation here, but if we have more than 4 billion items on a stack, we have bigger problems - uint32 numFrames = static_cast<uint32>((threadState->ci - threadState->base_ci) + 1); - info->writeStream->writeUint32LE(numFrames); - - for (uint32 i = 0; i < numFrames; i++) { - CallInfo *ci = threadState->base_ci + i; - - // Same argument as above about truncation - uint32 stackBase = static_cast<uint32>(ci->base - threadState->stack); - uint32 stackFunc = static_cast<uint32>(ci->func - threadState->stack); - uint32 stackTop = static_cast<uint32>(ci->top - threadState->stack); - - info->writeStream->writeUint32LE(stackBase); - info->writeStream->writeUint32LE(stackFunc); - info->writeStream->writeUint32LE(stackTop); - - info->writeStream->writeSint32LE(ci->nresults); - - uint32 savedpc = (ci != threadState->base_ci) ? static_cast<uint32>(ci->savedpc - ci_func(ci)->l.p->code) : 0u; - info->writeStream->writeUint32LE(savedpc); - } - - - // Serialize the state's other parameters, with the exception of upval stuff - - assert(threadState->nCcalls <= 1); - info->writeStream->writeByte(threadState->status); - - // Same argument as above about truncation - uint32 stackBase = static_cast<uint32>(threadState->base - threadState->stack); - uint32 stackFunc = static_cast<uint32>(threadState->top - threadState->stack); - info->writeStream->writeUint32LE(stackBase); - info->writeStream->writeUint32LE(stackFunc); - - // Same argument as above about truncation - uint32 stackOffset = static_cast<uint32>(threadState->errfunc); - info->writeStream->writeUint32LE(stackOffset); - - // Finally, record upvalues which need to be reopened - // See the comment above serializeUpVal() for why we do this - - UpVal *upVal; - - // >>>>> permTbl indexTbl ...... thread - for (GCObject *gcObject = threadState->openupval; gcObject != NULL; gcObject = upVal->next) { - upVal = gco2uv(gcObject); - - /* Make sure upvalue is really open */ - assert(upVal->v != &upVal->u.value); - - pushUpValue(info->luaState, upVal); - // >>>>> permTbl indexTbl ...... thread upVal - - persist(info); - - lua_pop(info->luaState, 1); - // >>>>> permTbl indexTbl ...... thread - - // Same argument as above about truncation - uint32 stackpos = static_cast<uint32>(upVal->v - threadState->stack); - info->writeStream->writeUint32LE(stackpos); - } - - // >>>>> permTbl indexTbl ...... thread - lua_pushnil(info->luaState); - // >>>>> permTbl indexTbl ...... thread nil - - // Use nil as a terminator - persist(info); - - lua_pop(info->luaState, 1); - // >>>>> permTbl indexTbl ...... thread -} - -static void persistProto(SerializationInfo *info) { - // >>>>> permTbl indexTbl ...... proto - Proto *proto = gco2p(getObject(info->luaState, -1)->value.gc); - - // Make sure there is enough room on the stack - lua_checkstack(info->luaState, 2); - - // Serialize constant refs */ - info->writeStream->writeSint32LE(proto->sizek); - - for (int i = 0; i < proto->sizek; ++i) { - pushObject(info->luaState, &proto->k[i]); - // >>>>> permTbl indexTbl ...... proto const - - persist(info); - - lua_pop(info->luaState, 1); - // >>>>> permTbl indexTbl ...... proto - } - - // >>>>> permTbl indexTbl ...... proto - - // Serialize inner Proto refs - info->writeStream->writeSint32LE(proto->sizep); - - for (int i = 0; i < proto->sizep; ++i) { - pushProto(info->luaState, proto->p[i]); - // >>>>> permTbl indexTbl ...... proto subProto */ - - persist(info); - - lua_pop(info->luaState, 1); - // >>>>> permTbl indexTbl ...... proto - } - - // >>>>> permTbl indexTbl ...... proto - - // Serialize the code - info->writeStream->writeSint32LE(proto->sizecode); - - uint32 len = static_cast<uint32>(sizeof(Instruction) * proto->sizecode); - info->writeStream->write(proto->code, len); - - - // Serialize upvalue names - info->writeStream->writeSint32LE(proto->sizeupvalues); - - for (int i = 0; i < proto->sizeupvalues; ++i) { - pushString(info->luaState, proto->upvalues[i]); - // >>>>> permTbl indexTbl ...... proto str - - persist(info); - - lua_pop(info->luaState, 1); - // >>>>> permTbl indexTbl ...... proto - } - - - // Serialize local variable infos - info->writeStream->writeSint32LE(proto->sizelocvars); - - for (int i = 0; i < proto->sizelocvars; ++i) { - pushString(info->luaState, proto->locvars[i].varname); - // >>>>> permTbl indexTbl ...... proto str - - persist(info); - - lua_pop(info->luaState, 1); - // >>>>> permTbl indexTbl ...... proto - - info->writeStream->writeSint32LE(proto->locvars[i].startpc); - info->writeStream->writeSint32LE(proto->locvars[i].endpc); - } - - - // Serialize source string - pushString(info->luaState, proto->source); - // >>>>> permTbl indexTbl ...... proto sourceStr - - persist(info); - - lua_pop(info->luaState, 1); - // >>>>> permTbl indexTbl ...... proto - - // Serialize line numbers - info->writeStream->writeSint32LE(proto->sizelineinfo); - - if (proto->sizelineinfo) { - len = static_cast<uint32>(sizeof(int) * proto->sizelineinfo); - info->writeStream->write(proto->lineinfo, len); - } - - // Serialize linedefined and lastlinedefined - info->writeStream->writeSint32LE(proto->linedefined); - info->writeStream->writeSint32LE(proto->lastlinedefined); - - - // Serialize misc values - info->writeStream->writeByte(proto->nups); - info->writeStream->writeByte(proto->numparams); - info->writeStream->writeByte(proto->is_vararg); - info->writeStream->writeByte(proto->maxstacksize); -} - -/* Upvalues are tricky. Here's why. - * - * A particular upvalue may be either "open", in which case its member v - * points into a thread's stack, or "closed" in which case it points to the - * upvalue itself. An upvalue is closed under any of the following conditions: - * -- The function that initially declared the variable "local" returns - * -- The thread in which the closure was created is garbage collected - * - * To make things wackier, just because a thread is reachable by Lua doesn't - * mean it's in our root set. We need to be able to treat an open upvalue - * from an unreachable thread as a closed upvalue. - * - * The solution: - * (a) For the purposes of serializing, don't indicate whether an upvalue is - * closed or not. - * (b) When unserializing, pretend that all upvalues are closed. - * (c) When serializing, persist all open upvalues referenced by a thread - * that is persisted, and tag each one with the corresponding stack position - * (d) When unserializing, "reopen" each of these upvalues as the thread is - * unserialized - */ -static void persistUpValue(SerializationInfo *info) { - // >>>>> permTbl indexTbl ...... upval - assert(ttype(getObject(info->luaState, -1)) == LUA_TUPVAL); - UpVal *upValue = gco2uv(getObject(info->luaState, -1)->value.gc); - - // Make sure there is enough room on the stack - lua_checkstack(info->luaState, 1); - - // We can't permit the upValue to linger around on the stack, as Lua - // will bail if its GC finds it. - - lua_pop(info->luaState, 1); - // >>>>> permTbl indexTbl ...... - - pushObject(info->luaState, upValue->v); - // >>>>> permTbl indexTbl ...... obj - - persist(info); - // >>>>> permTbl indexTbl ...... obj -} - -static void persistUserData(SerializationInfo *info) { - // >>>>> permTbl rootObj ...... udata - - // Make sure there is enough room on the stack - lua_checkstack(info->luaState, 2); - - // Test if the object needs special serialization - if (serializeSpecialObject(info, 0)) { - return; - } - - // Use literal persistence - - // Hard cast to a uint32 length - // This could lead to truncation, but if we have a 4gb block of data, we have bigger problems - uint32 length = static_cast<uint32>(uvalue(getObject(info->luaState, -1))->len); - info->writeStream->writeUint32LE(length); - - info->writeStream->write(lua_touserdata(info->luaState, -1), length); - - // Serialize the metatable (if any) - if (!lua_getmetatable(info->luaState, -1)) { - lua_pushnil(info->luaState); - } - - // >>>>> permTbl rootObj ...... udata metaTbl/nil - persist(info); - - lua_pop(info->luaState, 1); - /* perms reftbl ... udata */ -} - - -} // End of namespace Lua |