[Scummvm-cvs-logs] scummvm master -> 2587852c88e2fbc52bf702f71738e80628eb43fe

sev- sev at scummvm.org
Sun Jan 4 19:49:27 CET 2015


This automated email contains information about 17 new commits which have been
pushed to the 'scummvm' repo located at https://github.com/scummvm/scummvm .

Summary:
ff35d7118c SWORD25: Create a set of functions for manually serializing a double
efcd6196ee SWORD25: Create a function for serializing lua objects
dedfd7aa84 SWORD25: Move common functions to their own set of files so they can be shared
de20880d9d SWORD25: Re-write the pluto unserializing function(s)
2c7a87a4e3 SWORD25: Fix code formatting
2fb116f10e SWORD25: Move all lua serialization helper functions to their own file
0b8482b55f SWORD25: Update module.mk with lua serialization changes
a188b31d15 SWORD25: Use new lua serialization functions to persist state
97c35714ce SWORD25: Rename lua serialization functions to use 'persist' in order to match the rest of the engine
08e3f21a8d SWORD25: Rename double serialization file to better represent what it is
8668707f16 SWORD25: Fix how nils are persisted
67114c3e7e SWORD25: Remove old lua persistence files
eaff6a40f6 SWORD25: Correct include guards to reflect the changes to the file names
8ee75e1dc5 SWORD25: Add Pluto copyright message to new persistence code
9a4d62e76a SWORD25: Change function names to use persist instead of serialize
e4f74b6c34 SWORD25: Remove the option to persist a double as a string
2587852c88 Merge pull request #557 from RichieSams/replace_pluto


Commit: ff35d7118c0a61a472b74d87337ee62eac993ce1
    https://github.com/scummvm/scummvm/commit/ff35d7118c0a61a472b74d87337ee62eac993ce1
Author: Adrian Astley (adastley at gmail.com)
Date: 2014-12-19T11:29:22-06:00

Commit Message:
SWORD25: Create a set of functions for manually serializing a double

Since we can't assume IEEE.

Changed paths:
  A engines/sword25/util/double_serializer.cpp
  A engines/sword25/util/double_serializer.h



diff --git a/engines/sword25/util/double_serializer.cpp b/engines/sword25/util/double_serializer.cpp
new file mode 100644
index 0000000..d7ba4f3
--- /dev/null
+++ b/engines/sword25/util/double_serializer.cpp
@@ -0,0 +1,138 @@
+/* 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.
+ *
+ */
+
+#include "sword25/util/double_serializer.h"
+
+#include "common/scummsys.h"
+
+
+namespace Util {
+
+SerializedDouble encodeDouble(double value) {
+	// Split the value into its significand and exponent
+	int exponent;
+	double significand = frexp(value, &exponent);
+
+	// Shift the the first part of the significand into the integer range
+	double shiftedsignificandPart = ldexp(abs(significand), 32);
+	uint32 significandOne = uint32(floor(shiftedsignificandPart));
+
+	// Shift the remainder of the significand into the integer range
+	shiftedsignificandPart -= significandOne;
+	uint32 significandTwo = (uint32)(ldexp(shiftedsignificandPart, 31));
+
+	SerializedDouble returnValue;
+	returnValue.significandOne = significandOne;                                // SignificandOne
+	returnValue.signAndSignificandTwo = ((uint32)(value < 0 ? 1 : 0) << 31) |   // Sign
+	                                    significandTwo;                         // SignificandTwo
+	returnValue.exponent = (int16)exponent;
+	return returnValue;
+}
+
+double decodeDouble(SerializedDouble value) {
+	// Expand the exponent and the parts of the significand
+	int exponent = (int)value.exponent;
+	double expandedsignificandOne = (double)value.significandOne;
+	double expandedsignificandTwo = (double)(value.signAndSignificandTwo & 0x7FFFFFFF);
+
+	// Deflate the significand
+	double shiftedsignificand = ldexp(expandedsignificandTwo, -21);
+	double significand = ldexp(expandedsignificandOne + shiftedsignificand, -32);
+
+	// Re-calculate the actual double
+	double returnValue = ldexp(significand, exponent);
+
+	// Check the sign bit and return
+	return ((value.signAndSignificandTwo & 0x80000000) == 0x80000000) ? -returnValue : returnValue;
+}
+
+uint64 encodeDouble_64(double value) {
+	// Split the value into its significand and exponent
+	int exponent;
+	double significand = frexp(value, &exponent);
+
+	// Shift the significand into the integer range
+	double shiftedsignificand = ldexp(abs(significand), 53);
+
+	// Combine everything using the IEEE standard
+	uint64 uintsignificand = (uint64)shiftedsignificand;
+	return ((uint64)(value < 0 ? 1 : 0) << 63) |        // Sign
+	       ((uint64)(exponent + 1023) << 52) |          // Exponent stored as an offset to 1023
+	       (uintsignificand & 0x000FFFFFFFFFFFFF);      // significand with MSB inferred
+}
+
+double decodeDouble_64(uint64 value) {
+	// Expand the exponent and significand
+	int exponent = (int)((value >> 52) & 0x7FF) - 1023;
+	double expandedsignificand = (double)(0x10000000000000 /* Inferred MSB */ | (value & 0x000FFFFFFFFFFFFF));
+
+	// Deflate the significand
+	int temp;
+	double significand = frexp(expandedsignificand, &temp);
+
+	// Re-calculate the actual double
+	double returnValue = ldexp(significand, exponent);
+
+	// Check the sign bit and return
+	return ((value & 0x8000000000000000) == 0x8000000000000000) ? -returnValue : returnValue;
+}
+
+CompactSerializedDouble encodeDouble_Compact(double value) {
+	// Split the value into its significand and exponent
+	int exponent;
+	double significand = frexp(value, &exponent);
+
+	// Shift the the first part of the significand into the integer range
+	double shiftedsignificandPart = ldexp(abs(significand), 32);
+	uint32 significandOne = uint32(floor(shiftedsignificandPart));
+
+	// Shift the remainder of the significand into the integer range
+	shiftedsignificandPart -= significandOne;
+	uint32 significandTwo = (uint32)(ldexp(shiftedsignificandPart, 21));
+
+	CompactSerializedDouble returnValue;
+	returnValue.signAndSignificandOne = ((uint32)(value < 0 ? 1 : 0) << 31) |   // Sign
+	                                    (significandOne & 0x7FFFFFFF);          // significandOne with MSB inferred
+	// Exponent stored as an offset to 1023
+	returnValue.exponentAndSignificandTwo = ((uint32)(exponent + 1023) << 21) | significandTwo;
+
+	return returnValue;
+}
+
+double decodeDouble_Compact(CompactSerializedDouble value) {
+	// Expand the exponent and the parts of the significand
+	int exponent = (int)(value.exponentAndSignificandTwo >> 21) - 1023;
+	double expandedsignificandOne = (double)(0x80000000 /* Inferred MSB */ | (value.signAndSignificandOne & 0x7FFFFFFF));
+	double expandedsignificandTwo = (double)(value.exponentAndSignificandTwo & 0x1FFFFF);
+
+	// Deflate the significand
+	double shiftedsignificand = ldexp(expandedsignificandTwo, -21);
+	double significand = ldexp(expandedsignificandOne + shiftedsignificand, -32);
+
+	// Re-calculate the actual double
+	double returnValue = ldexp(significand, exponent);
+
+	// Check the sign bit and return
+	return ((value.signAndSignificandOne & 0x80000000) == 0x80000000) ? -returnValue : returnValue;
+}
+
+} // End of namespace Sword25
diff --git a/engines/sword25/util/double_serializer.h b/engines/sword25/util/double_serializer.h
new file mode 100644
index 0000000..e90338c
--- /dev/null
+++ b/engines/sword25/util/double_serializer.h
@@ -0,0 +1,95 @@
+/* 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.
+ *
+ */
+
+#ifndef DOUBLE_SERIALIZATION_H
+#define DOUBLE_SERIALIZATION_H
+
+#include "common/types.h"
+
+
+namespace Util {
+
+struct SerializedDouble {
+	uint32 significandOne;
+	uint32 signAndSignificandTwo;
+	int16 exponent;
+};
+
+struct CompactSerializedDouble {
+	uint32 signAndSignificandOne;
+	uint32 exponentAndSignificandTwo;
+};
+
+/**
+ * Encodes a double as two uint32 and a one int16
+ *
+ * Supports denormalized numbers. Does NOT support NaN, or Inf
+ *
+ * @param value    The value to encode
+ * @return         The encoded value
+ */
+SerializedDouble encodeDouble(double value);
+/**
+ * Decodes a previously encoded double
+ *
+ * @param value    The value to decode
+ * @return         The decoded value
+ */
+double decodeDouble(SerializedDouble value);
+
+/**
+ * Encodes a double as a uint64
+ *
+ * Does NOT support denormalized numbers. Does NOT support NaN, or Inf
+ *
+ * @param value    The value to encode
+ * @return         The encoded value
+ */
+uint64 encodeDouble_64(double value);
+/**
+ * Decodes a previously encoded double
+ *
+ * @param value    The value to decode
+ * @return         The decoded value
+ */
+double decodeDouble_64(uint64 value);
+
+/**
+ * Encodes a double as two uint32
+ *
+ * Does NOT support denormalized numbers. Does NOT support NaN, or Inf
+ *
+ * @param value    The value to encode
+ * @return         The encoded value
+ */
+CompactSerializedDouble encodeDouble_Compact(double value);
+/**
+ * Decodes a previously encoded double
+ *
+ * @param value    The value to decode
+ * @return         The decoded value
+ */
+double decodeDouble_Compact(CompactSerializedDouble value);
+
+} // End of namespace Sword25
+
+#endif


Commit: efcd6196eeaa2bff468bbed8d07040e60ca3c136
    https://github.com/scummvm/scummvm/commit/efcd6196eeaa2bff468bbed8d07040e60ca3c136
Author: Adrian Astley (adastley at gmail.com)
Date: 2014-12-19T11:29:22-06:00

Commit Message:
SWORD25: Create a function for serializing lua objects

This function is very similar to the Pluto function. However, this code
is much cleaner and is endian-safe

Changed paths:
  A engines/sword25/util/lua_serialization.h
  A engines/sword25/util/lua_serializer.cpp



diff --git a/engines/sword25/util/lua_serialization.h b/engines/sword25/util/lua_serialization.h
new file mode 100644
index 0000000..0f0c3bd
--- /dev/null
+++ b/engines/sword25/util/lua_serialization.h
@@ -0,0 +1,42 @@
+/* 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.
+ *
+ */
+
+#ifndef LUA_SERIALIZATION_H
+#define LUA_SERIALIZATION_H
+
+#include "sword25/util/lua/lua.h"
+
+
+namespace Common {
+class WriteStream;
+}
+
+
+namespace Lua {
+
+#define PERMANENT_TYPE 101
+
+void serializeLua(lua_State *luaState, Common::WriteStream *writeStream);
+
+} // End of namespace Lua
+
+#endif
diff --git a/engines/sword25/util/lua_serializer.cpp b/engines/sword25/util/lua_serializer.cpp
new file mode 100644
index 0000000..b2bbca6
--- /dev/null
+++ b/engines/sword25/util/lua_serializer.cpp
@@ -0,0 +1,852 @@
+/* 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.
+ *
+ */
+
+#include "sword25/util/lua_serialization.h"
+
+#include "sword25/util/double_serializer.h"
+
+#include "common/stream.h"
+
+#include "lua/lobject.h"
+#include "lua/lstate.h"
+
+
+namespace Lua {
+
+#define NUMTYPES 9
+
+static const char* typenames[] = {
+	"nil",
+	"boolean",
+	"lightuserdata",
+	"number",
+	"string",
+	"table",
+	"function",
+	"userdata",
+	"thread"
+};
+
+#define PERMANENT_TYPE 101
+
+/* A simple reimplementation of the unfortunately static function luaA_index.
+ * Does not support the global table, registry, or upvalues. */
+static StkId getobject(lua_State *luaState, int stackpos) {
+	if(stackpos > 0) {
+		lua_assert(luaState->base+stackpos-1 < luaState->top);
+		return luaState->base+stackpos-1;
+	} else {
+		lua_assert(L->top-stackpos >= L->base);
+		return luaState->top+stackpos;
+	}
+}
+
+
+struct SerializationInfo {
+	lua_State *luaState;
+	Common::WriteStream *writeStream;
+	uint counter;
+};
+
+static void serializeObject(SerializationInfo *info);
+
+static void serializeBoolean(SerializationInfo *info);
+static void serializeLightUserData(SerializationInfo *info);
+static void serializeNumber(SerializationInfo *info);
+static void serializeString(SerializationInfo *info);
+static void serializeTable(SerializationInfo *info);
+static void serializeFunction(SerializationInfo *info);
+static void serializeThread(SerializationInfo *info);
+static void serializeProto(SerializationInfo *info);
+static void serializeUpValue(SerializationInfo *info);
+static void serializeUserData(SerializationInfo *info);
+
+
+void serializeLua(lua_State *luaState, Common::WriteStream *writeStream) {
+	SerializationInfo info;
+	info.luaState = luaState;
+	info.writeStream = writeStream;
+	info.counter = 0u;
+
+	// 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
+	serializeObject(&info);
+
+	// Return the stack back to the original state
+	lua_remove(luaState, 2);
+	// >>>>> permTbl rootObj
+}
+
+static void serializeObject(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 nil off the stack
+	lua_pop(info->luaState, 1);
+
+	// Write out a flag that indicates that this is a real object
+	info->writeStream->writeByte(1);
+
+	// If the object itself is nil, then write out a zero as a placeholder
+	if (lua_isnil(info->luaState, -1)) {
+		info->writeStream->writeByte(0);
+
+		return;
+	}
+
+	// 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
+		serializeObject(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:
+		serializeBoolean(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:
+		serializeNumber(info);
+		break;
+	case LUA_TSTRING:
+		serializeString(info);
+		break;
+	case LUA_TTABLE:
+		serializeTable(info);
+		break;
+	case LUA_TFUNCTION:
+		serializeFunction(info);
+		break;
+	case LUA_TTHREAD:
+		serializeThread(info);
+		break;
+	case LUA_TPROTO:
+		serializeProto(info);
+		break;
+	case LUA_TUPVAL:
+		serializeUpValue(info);
+		break;
+	case LUA_TUSERDATA:
+		serializeUserData(info);
+		break;
+	default:
+		assert(0);
+	}
+}
+
+static void serializeBoolean(SerializationInfo *info) {
+	int value = lua_toboolean(info->luaState, -1);
+
+	info->writeStream->writeSint32LE(value);
+}
+
+static void serializeNumber(SerializationInfo *info) {
+	lua_Number value = lua_tonumber(info->luaState, -1);
+	
+#if 1
+	Util::SerializedDouble serializedValue(Util::encodeDouble(value));
+
+	info->writeStream->writeUint32LE(serializedValue.significandOne);
+	info->writeStream->writeUint32LE(serializedValue.signAndSignificandTwo);
+	info->writeStream->writeSint16LE(serializedValue.exponent);
+#else
+	// NOTE: We need to store a double. Unfortunately, we have to accommodate endianness. 
+	// Also, I don't know if we can assume all compilers use IEEE double
+	// Therefore, I have chosen to store the double as a string. 
+	Common::String buffer = Common::String::format("%f", value);
+
+	info->writeStream->write(buffer.c_str(), buffer.size());
+#endif
+	
+}
+
+static void serializeString(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 metatable doesn't exist
+			info->writeStream->writeSint32LE(0);
+
+			return false;
+		} else {
+			lua_pushstring(info->luaState, "Type not literally persistable by default");
+			lua_error(info->luaState);
+		}
+	}
+
+	// >>>>> 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 there is no persistence metafunction
+			info->writeStream->writeSint32LE(0);
+
+			return 0;
+		} else {
+			lua_pushstring(info->luaState, "Type not literally persistable by default");
+			lua_error(info->luaState);
+
+			return 0; /* not reached */
+		}
+
+	} else if (lua_isboolean(info->luaState, -1)) {
+		// >>>>> permTbl indexTbl ...... obj metaTbl bool
+		if (lua_toboolean(info->luaState, -1)) {
+			// Write out a flag declaring such
+			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
+	serializeObject(info);
+					
+	lua_pop(info->luaState, 2);
+	// >>>>> permTbl indexTbl ...... obj
+
+	return true;
+}
+
+static void serializeTable(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 */
+	serializeObject(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
+		serializeObject(info);
+
+		lua_pop(info->luaState, 1);
+		// >>>>> permTbl indexTbl ...... tbl k v */
+
+		// Serialize the value
+		serializeObject(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
+
+	serializeObject(info);
+
+	lua_pop(info->luaState, 1);
+	// >>>>> permTbl indexTbl ...... tbl
+}
+
+static void pushObject(lua_State *luaState, TValue *obj) {
+	setobj2s(luaState, luaState->top, obj);
+
+	api_check(luaState, luaState->top < luaState->ci->top);
+	luaState->top++;
+}
+
+static void pushProto(lua_State *luaState, Proto *proto) {
+	TValue obj;
+	setptvalue(luaState, &obj, proto);
+
+	pushObject(luaState, &obj);
+}
+
+static void pushUpVal(lua_State *luaState, UpVal *upval) {
+	TValue obj;
+
+	obj.value.gc = cast(GCObject *, upval); 
+	obj.tt = LUA_TUPVAL;
+	checkliveness(G(L), obj);
+	
+	pushObject(luaState, &obj);
+}
+
+static void pushString(lua_State *luaState, TString *str) {
+	TValue o;
+	setsvalue(luaState, &o, str);
+
+	pushObject(luaState, &o);
+}
+
+static void serializeFunction(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 */
+		
+		serializeObject(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
+			pushUpVal(info->luaState, cl->l.upvals[i]);
+			// >>>>> permTbl indexTbl ...... func upval
+
+			serializeObject(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
+		serializeObject(info);
+
+		lua_pop(info->luaState, 1);
+		// >>>>> permTbl indexTbl ...... func
+	}
+}
+
+/* Appends one stack to another stack, but the stack is reversed in the process */
+static size_t appendStackToStack_rev(lua_State *from, lua_State *to) {
+	for (StkId id = from->top - 1; id >= from->stack; --id) {
+		setobj2s(to, to->top, id);
+		to->top++;
+	}
+
+	return from->top - from->stack;
+}
+
+static void serializeThread(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
+	uint stackSize = static_cast<uint32>(appendStackToStack_rev(threadState, info->luaState));
+	info->writeStream->writeUint32LE(stackSize);
+
+	// >>>>> permTbl indexTbl ...... thread (reversed contents of thread stack) */
+	for (; stackSize > 0; --stackSize) {
+		serializeObject(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);
+
+		pushUpVal(info->luaState, upVal);
+		// >>>>> permTbl indexTbl ...... thread upVal
+
+		serializeObject(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
+	serializeObject(info);
+
+	lua_pop(info->luaState, 1);
+	// >>>>> permTbl indexTbl ...... thread
+}
+
+static void serializeProto(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
+
+		serializeObject(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 */
+
+		serializeObject(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
+
+		serializeObject(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
+
+		serializeObject(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
+
+	serializeObject(info);
+
+	lua_pop(info->luaState, 1);
+	// >>>>> permTbl indexTbl ...... proto
+
+	// Serialize line numbers
+	info->writeStream->writeSint32LE(proto->sizelineinfo);
+
+	if (proto->sizelineinfo) {
+		uint32 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 serializeUpValue(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
+
+	serializeObject(info);
+	// >>>>> permTbl indexTbl ...... obj
+}
+
+static void serializeUserData(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
+	serializeObject(info);
+
+	lua_pop(info->luaState, 1);
+	/* perms reftbl ... udata */
+}
+
+
+} // End of namespace Lua


Commit: dedfd7aa84360b5950b653109b3679c7f469aebc
    https://github.com/scummvm/scummvm/commit/dedfd7aa84360b5950b653109b3679c7f469aebc
Author: Adrian Astley (adastley at gmail.com)
Date: 2014-12-19T13:38:56-06:00

Commit Message:
SWORD25: Move common functions to their own set of files so they can be shared

Changed paths:
  A engines/sword25/util/lua_serialization_util.cpp
  A engines/sword25/util/lua_serialization_util.h
    engines/sword25/util/lua_serializer.cpp



diff --git a/engines/sword25/util/lua_serialization_util.cpp b/engines/sword25/util/lua_serialization_util.cpp
new file mode 100644
index 0000000..80009af
--- /dev/null
+++ b/engines/sword25/util/lua_serialization_util.cpp
@@ -0,0 +1,77 @@
+/* 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 distri8buted 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.
+ *
+ */
+
+#include "sword25/util/lua_serialization_util.h"
+
+#include "common/scummsys.h"
+
+#include "lua/lobject.h"
+#include "lua/lstate.h"
+#include "lua/lgc.h"
+
+
+namespace Lua {
+
+void pushObject(lua_State *luaState, TValue *obj) {
+	setobj2s(luaState, luaState->top, obj);
+
+	api_check(luaState, luaState->top < luaState->ci->top);
+	luaState->top++;
+}
+
+void pushProto(lua_State *luaState, Proto *proto) {
+	TValue obj;
+	setptvalue(luaState, &obj, proto);
+
+	pushObject(luaState, &obj);
+}
+
+void pushUpValue(lua_State *luaState, UpVal *upval) {
+	TValue obj;
+
+	obj.value.gc = cast(GCObject *, upval);
+	obj.tt = LUA_TUPVAL;
+	checkliveness(G(L), obj);
+
+	pushObject(luaState, &obj);
+}
+
+void pushString(lua_State *luaState, TString *str) {
+	TValue o;
+	setsvalue(luaState, &o, str);
+
+	pushObject(luaState, &o);
+}
+
+/* A simple reimplementation of the unfortunately static function luaA_index.
+ * Does not support the global table, registry, or upvalues. */
+StkId getObject(lua_State *luaState, int stackpos) {
+	if(stackpos > 0) {
+		lua_assert(luaState->base+stackpos-1 < luaState->top);
+		return luaState->base+stackpos-1;
+	} else {
+		lua_assert(L->top-stackpos >= L->base);
+		return luaState->top+stackpos;
+	}
+}
+
+} // End of namespace Lua
diff --git a/engines/sword25/util/lua_serialization_util.h b/engines/sword25/util/lua_serialization_util.h
new file mode 100644
index 0000000..6c55d0d
--- /dev/null
+++ b/engines/sword25/util/lua_serialization_util.h
@@ -0,0 +1,43 @@
+/* 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 distri8buted 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.
+ *
+ */
+
+#ifndef LUA_SERIALIZATION_UTIL_H
+#define LUA_SERIALIZATION_UTIL_H
+
+
+struct lua_State;
+
+#include "lua/lobject.h"
+
+typedef TValue *StkId;
+
+namespace Lua {
+
+void pushObject(lua_State *luaState, TValue *obj);
+void pushProto(lua_State *luaState, Proto *proto);
+void pushUpValue(lua_State *luaState, UpVal *upval);
+void pushString(lua_State *luaState, TString *str);
+StkId getObject(lua_State *luaState, int stackpos);
+
+} // End of namespace Lua
+
+#endif
diff --git a/engines/sword25/util/lua_serializer.cpp b/engines/sword25/util/lua_serializer.cpp
index b2bbca6..8c61383 100644
--- a/engines/sword25/util/lua_serializer.cpp
+++ b/engines/sword25/util/lua_serializer.cpp
@@ -23,44 +23,19 @@
 #include "sword25/util/lua_serialization.h"
 
 #include "sword25/util/double_serializer.h"
+#include "sword25/util/lua_serialization_util.h"
 
 #include "common/stream.h"
 
 #include "lua/lobject.h"
 #include "lua/lstate.h"
+#include "lua/lgc.h"
 
 
 namespace Lua {
 
-#define NUMTYPES 9
-
-static const char* typenames[] = {
-	"nil",
-	"boolean",
-	"lightuserdata",
-	"number",
-	"string",
-	"table",
-	"function",
-	"userdata",
-	"thread"
-};
-
 #define PERMANENT_TYPE 101
 
-/* A simple reimplementation of the unfortunately static function luaA_index.
- * Does not support the global table, registry, or upvalues. */
-static StkId getobject(lua_State *luaState, int stackpos) {
-	if(stackpos > 0) {
-		lua_assert(luaState->base+stackpos-1 < luaState->top);
-		return luaState->base+stackpos-1;
-	} else {
-		lua_assert(L->top-stackpos >= L->base);
-		return luaState->top+stackpos;
-	}
-}
-
-
 struct SerializationInfo {
 	lua_State *luaState;
 	Common::WriteStream *writeStream;
@@ -70,7 +45,6 @@ struct SerializationInfo {
 static void serializeObject(SerializationInfo *info);
 
 static void serializeBoolean(SerializationInfo *info);
-static void serializeLightUserData(SerializationInfo *info);
 static void serializeNumber(SerializationInfo *info);
 static void serializeString(SerializationInfo *info);
 static void serializeTable(SerializationInfo *info);
@@ -319,13 +293,15 @@ static bool serializeSpecialObject(SerializationInfo *info, bool defaction) {
 	// 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 metatable doesn't exist
+			// 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
 		}
 	}
 
@@ -342,21 +318,21 @@ static bool serializeSpecialObject(SerializationInfo *info, bool defaction) {
 		// >>>>> permTbl indexTbl ...... obj
 
 		if (defaction) {
-			// Write out a flag declaring there is no persistence metafunction
+			// Write out a flag declaring that the object isn't special and should be persisted normally
 			info->writeStream->writeSint32LE(0);
 
-			return 0;
+			return false;
 		} else {
 			lua_pushstring(info->luaState, "Type not literally persistable by default");
 			lua_error(info->luaState);
 
-			return 0; /* not reached */
+			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 such
+			// 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 */
@@ -368,7 +344,7 @@ static bool serializeSpecialObject(SerializationInfo *info, bool defaction) {
 			lua_pushstring(info->luaState, "Metatable forbade persistence");
 			lua_error(info->luaState);
 
-			return false; /* not reached */
+			return false; // Not reached
 		}
 	} else if (!lua_isfunction(info->luaState, -1)) {
 		lua_pushstring(info->luaState, "__persist not nil, boolean, or function");
@@ -460,40 +436,9 @@ static void serializeTable(SerializationInfo *info) {
 	// >>>>> permTbl indexTbl ...... tbl
 }
 
-static void pushObject(lua_State *luaState, TValue *obj) {
-	setobj2s(luaState, luaState->top, obj);
-
-	api_check(luaState, luaState->top < luaState->ci->top);
-	luaState->top++;
-}
-
-static void pushProto(lua_State *luaState, Proto *proto) {
-	TValue obj;
-	setptvalue(luaState, &obj, proto);
-
-	pushObject(luaState, &obj);
-}
-
-static void pushUpVal(lua_State *luaState, UpVal *upval) {
-	TValue obj;
-
-	obj.value.gc = cast(GCObject *, upval); 
-	obj.tt = LUA_TUPVAL;
-	checkliveness(G(L), obj);
-	
-	pushObject(luaState, &obj);
-}
-
-static void pushString(lua_State *luaState, TString *str) {
-	TValue o;
-	setsvalue(luaState, &o, str);
-
-	pushObject(luaState, &o);
-}
-
 static void serializeFunction(SerializationInfo *info) {
 	// >>>>> permTbl indexTbl ...... func
-	Closure *cl = clvalue(getobject(info->luaState, -1));
+	Closure *cl = clvalue(getObject(info->luaState, -1));
 	lua_checkstack(info->luaState, 2);
 
 	if (cl->c.isC) {
@@ -520,7 +465,7 @@ static void serializeFunction(SerializationInfo *info) {
 		// Serialize upvalue values (not the upvalue objects themselves)
 		for (byte i=0; i<cl->l.p->nups; i++) {
 			// >>>>> permTbl indexTbl ...... func
-			pushUpVal(info->luaState, cl->l.upvals[i]);
+			pushUpValue(info->luaState, cl->l.upvals[i]);
 			// >>>>> permTbl indexTbl ...... func upval
 
 			serializeObject(info);
@@ -580,7 +525,7 @@ static void serializeThread(SerializationInfo *info) {
 	// Persist the stack
 
 	// We *could* have truncation here, but if we have more than 4 billion items on a stack, we have bigger problems
-	uint stackSize = static_cast<uint32>(appendStackToStack_rev(threadState, info->luaState));
+	uint32 stackSize = static_cast<uint32>(appendStackToStack_rev(threadState, info->luaState));
 	info->writeStream->writeUint32LE(stackSize);
 
 	// >>>>> permTbl indexTbl ...... thread (reversed contents of thread stack) */
@@ -644,7 +589,7 @@ static void serializeThread(SerializationInfo *info) {
 		/* Make sure upvalue is really open */
 		assert(upVal->v != &upVal->u.value);
 
-		pushUpVal(info->luaState, upVal);
+		pushUpValue(info->luaState, upVal);
 		// >>>>> permTbl indexTbl ...... thread upVal
 
 		serializeObject(info);
@@ -670,7 +615,7 @@ static void serializeThread(SerializationInfo *info) {
 
 static void serializeProto(SerializationInfo *info) {
 	// >>>>> permTbl indexTbl ...... proto
-	Proto *proto = gco2p(getobject(info->luaState, -1)->value.gc);
+	Proto *proto = gco2p(getObject(info->luaState, -1)->value.gc);
 
 	// Make sure there is enough room on the stack
 	lua_checkstack(info->luaState, 2);
@@ -797,8 +742,8 @@ static void serializeProto(SerializationInfo *info) {
  */
 static void serializeUpValue(SerializationInfo *info) {
 	// >>>>> permTbl indexTbl ...... upval
-	assert(ttype(getobject(info->luaState, -1)) == LUA_TUPVAL);
-	UpVal *upValue = gco2uv(getobject(info->luaState, -1)->value.gc);
+	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);
@@ -831,7 +776,7 @@ static void serializeUserData(SerializationInfo *info) {
 
 	// 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);
+	uint32 length = static_cast<uint32>(uvalue(getObject(info->luaState, -1))->len);
 	info->writeStream->writeUint32LE(length);
 
 	info->writeStream->write(lua_touserdata(info->luaState, -1), length);


Commit: de20880d9d3dbe9ebbc26848d7a672c104495aeb
    https://github.com/scummvm/scummvm/commit/de20880d9d3dbe9ebbc26848d7a672c104495aeb
Author: Adrian Astley (adastley at gmail.com)
Date: 2014-12-19T13:41:58-06:00

Commit Message:
SWORD25: Re-write the pluto unserializing function(s)

Changed paths:
  A engines/sword25/util/lua_unserializer.cpp
    engines/sword25/util/lua_serialization.h



diff --git a/engines/sword25/util/lua_serialization.h b/engines/sword25/util/lua_serialization.h
index 0f0c3bd..549ea79 100644
--- a/engines/sword25/util/lua_serialization.h
+++ b/engines/sword25/util/lua_serialization.h
@@ -28,6 +28,7 @@
 
 namespace Common {
 class WriteStream;
+class ReadStream;
 }
 
 
@@ -36,6 +37,7 @@ namespace Lua {
 #define PERMANENT_TYPE 101
 
 void serializeLua(lua_State *luaState, Common::WriteStream *writeStream);
+void unserializeLua(lua_State *luaState, Common::ReadStream *readStream);
 
 } // End of namespace Lua
 
diff --git a/engines/sword25/util/lua_unserializer.cpp b/engines/sword25/util/lua_unserializer.cpp
new file mode 100644
index 0000000..c561a3d
--- /dev/null
+++ b/engines/sword25/util/lua_unserializer.cpp
@@ -0,0 +1,1007 @@
+/* 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.
+ *
+ */
+
+#include "sword25/util/lua_serialization.h"
+
+#include "sword25/util/double_serializer.h"
+#include "sword25/util/lua_serialization_util.h"
+
+#include "common/stream.h"
+
+#include "lua/lobject.h"
+#include "lua/lstate.h"
+#include "lua/lgc.h"
+#include "lua/lopcodes.h"
+
+
+namespace Lua {
+
+struct UnSerializationInfo {
+	lua_State *luaState;
+	Common::ReadStream *readStream;
+};
+
+static void unserializeObject(UnSerializationInfo *info);
+
+static void unserializeBoolean(UnSerializationInfo *info);
+static void unserializeNumber(UnSerializationInfo *info);
+static void unserializeString(UnSerializationInfo *info);
+static void unserializeTable(UnSerializationInfo *info, int index);
+static void unserializeFunction(UnSerializationInfo *info, int index);
+static void unserializeThread(UnSerializationInfo *info, int index);
+static void unserializeProto(UnSerializationInfo *info, int index);
+static void unserializeUpValue(UnSerializationInfo *info, int index);
+static void unserializeUserData(UnSerializationInfo *info, int index);
+static void unserializePermanent(UnSerializationInfo *info, int index);
+
+
+void unserializeLua(lua_State *luaState, Common::ReadStream *readStream) {
+	UnSerializationInfo info;
+	info.luaState = luaState;
+	info.readStream = readStream;
+
+	// The process starts with the lua stack as follows:
+	// >>>>> permTbl
+	// That's the table of permanents
+
+	// Make sure there is enough room on the stack
+	lua_checkstack(luaState, 3);
+
+	// Create a table to hold indexes of everything thats already been read
+	lua_newtable(luaState);
+	// >>>>> permTbl indexTbl
+
+	// Prevent garbage collection while we unserialize
+	lua_gc(luaState, LUA_GCSTOP, 0);
+
+	// Unserialize the root object
+	unserializeObject(&info);
+	// >>>>> permTbl indexTbl rootObj
+
+	// Re-start garbage collection
+	lua_gc(luaState, LUA_GCRESTART, 0);
+	
+	// Remove the indexTbl
+	lua_replace(luaState, 2);
+	// >>>>> permTbl rootObj
+}
+
+/* The object is left on the stack. This is primarily used by unpersist, but
+ * may be used by GCed objects that may incur cycles in order to preregister
+ * the object. */
+static void registerObjectInIndexTable(UnSerializationInfo *info, int index) {
+	// >>>>> permTbl indexTbl ...... obj
+
+	// Make sure there is enough room on the stack
+	lua_checkstack(info->luaState, 2);
+
+	lua_pushlightuserdata(info->luaState, (void *)index);
+	// >>>>> permTbl indexTbl ...... obj index
+
+	lua_pushvalue(info->luaState, -2);
+	// >>>>> permTbl indexTbl ...... obj index obj
+
+	// Push the k/v pair into the indexTbl
+	lua_settable(info->luaState, 2);
+	// >>>>> permTbl indexTbl ...... obj
+}
+
+static void unserializeObject(UnSerializationInfo *info) {
+	// >>>>> permTbl indexTbl ...... 
+
+	// Make sure there is enough room on the stack
+	lua_checkstack(info->luaState, 2);
+
+	byte isARealValue = info->readStream->readByte();
+	if(isARealValue) {
+		int index = info->readStream->readSint32LE();
+		int type = info->readStream->readSint32LE();
+
+		switch(type) {
+		case LUA_TBOOLEAN:
+			unserializeBoolean(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:
+			unserializeNumber(info);
+			break;
+		case LUA_TSTRING:
+			unserializeString(info);
+			break;
+		case LUA_TTABLE:
+			unserializeTable(info, index);
+			break;
+		case LUA_TFUNCTION:
+			unserializeFunction(info, index);
+			break;
+		case LUA_TTHREAD:
+			unserializeThread(info, index);
+			break;
+		case LUA_TPROTO:
+			unserializeProto(info, index);
+			break;
+		case LUA_TUPVAL:
+			unserializeUpValue(info, index);
+			break;
+		case LUA_TUSERDATA:
+			unserializeUserData(info, index);
+			break;
+		case PERMANENT_TYPE:
+			unserializePermanent(info, index);
+			break;
+		default:
+			assert(0);
+		}
+
+		
+		// >>>>> permTbl indexTbl ...... obj
+		assert(lua_type(info->luaState, -1) == type || 
+		       type == PERMANENT_TYPE ||
+		       // Remember, upvalues get a special dispensation, as described in boxUpValue
+		       (lua_type(info->luaState, -1) == LUA_TFUNCTION && type == LUA_TUPVAL));
+
+		registerObjectInIndexTable(info, index);
+		// >>>>> permTbl indexTbl ...... obj
+	} else {
+		int index = info->readStream->readSint32LE();
+
+		if(index == 0) {
+			lua_pushnil(info->luaState);
+			// >>>>> permTbl indexTbl ...... nil
+		} else {
+			// Fetch the object from the indexTbl
+
+			lua_pushlightuserdata(info->luaState, (void *)index);
+			// >>>>> permTbl indexTbl ...... index
+
+			lua_gettable(info->luaState, 2);
+			// >>>>> permTbl indexTbl ...... ?obj?
+
+			assert(!lua_isnil(info->luaState, -1));
+		}
+		// >>>>> permTbl indexTbl ...... obj/nil
+	}
+	
+	// >>>>> permTbl indexTbl ...... obj/nil
+}
+
+static void unserializeBoolean(UnSerializationInfo *info) {
+	// >>>>> permTbl indexTbl ......
+
+	// Make sure there is enough room on the stack
+	lua_checkstack(info->luaState, 1);
+
+	int value = info->readStream->readSint32LE();
+
+	lua_pushboolean(info->luaState, value);
+	// >>>>> permTbl indexTbl ...... bool
+}
+
+static void unserializeNumber(UnSerializationInfo *info) {
+	// >>>>> permTbl indexTbl ...... 
+	
+	// Make sure there is enough room on the stack
+	lua_checkstack(info->luaState, 1);
+
+	// Read the serialized double
+	Util::SerializedDouble serializedValue;
+	serializedValue.significandOne = info->readStream->readUint32LE();
+	serializedValue.signAndSignificandTwo = info->readStream->readUint32LE();
+	serializedValue.exponent = info->readStream->readSint16LE();
+
+	lua_Number value = Util::decodeDouble(serializedValue);
+
+	lua_pushnumber(info->luaState, value);
+	// >>>>> permTbl indexTbl ...... num
+}
+
+static void unserializeString(UnSerializationInfo *info) {
+	// >>>>> permTbl indexTbl ......
+	
+	// Make sure there is enough room on the stack
+	lua_checkstack(info->luaState, 1);
+
+	uint32 length = info->readStream->readUint32LE();
+	char *string = new char[length];
+
+	info->readStream->read(string, length);
+	lua_pushlstring(info->luaState, string, length);
+
+	// >>>>> permTbl indexTbl ...... string
+	
+	delete[] string;
+}
+
+static void unserializeSpecialTable(UnSerializationInfo *info, int index) {
+	// >>>>> permTbl indexTbl ......
+
+	// Make sure there is enough room on the stack
+	lua_checkstack(info->luaState, 1);
+
+	unserializeObject(info);
+
+	// >>>>> permTbl indexTbl ...... spfunc
+	lua_call(info->luaState, 0, 1);
+	// >>>>> permTbl indexTbl ...... tbl
+}
+
+static void unserializeLiteralTable(UnSerializationInfo *info, int index) {
+	// >>>>> permTbl indexTbl ......
+
+	// Make sure there is enough room on the stack
+	lua_checkstack(info->luaState, 3);
+
+	// Preregister table for handling of cycles
+	lua_newtable(info->luaState);
+
+	// >>>>> permTbl indexTbl ...... tbl
+	registerObjectInIndexTable(info, index);
+	// >>>>> permTbl indexTbl ...... tbl
+
+	// Unserialize metatable
+	unserializeObject(info);
+	// >>>>> permTbl indexTbl ...... tbl ?metaTbl/nil?
+	
+	if (lua_istable(info->luaState, -1)) {
+		// >>>>> permTbl indexTbl ...... tbl metaTbl
+		lua_setmetatable(info->luaState, -2);
+		// >>>>> permTbl indexTbl ...... tbl
+	} else {
+		// >>>>> permTbl indexTbl ...... tbl nil
+		lua_pop(info->luaState, 1);
+		// >>>>> permTbl indexTbl ...... tbl
+	}
+	// >>>>> permTbl indexTbl ...... tbl
+
+
+	while (1) {
+		// >>>>> permTbl indexTbl ...... tbl
+		unserializeObject(info);
+		// >>>>> permTbl indexTbl ...... tbl key/nil
+
+		// The table serialization is nil terminated
+		if (lua_isnil(info->luaState, -1)) {
+			// >>>>> permTbl indexTbl ...... tbl nil
+			lua_pop(info->luaState, 1);
+			// >>>>> permTbl indexTbl ...... tbl
+
+			break;
+		}
+
+		// >>>>> permTbl indexTbl ...... tbl key
+		unserializeObject(info);
+		// >>>>> permTbl indexTbl ...... tbl value
+
+		lua_rawset(info->luaState, -3);
+		// >>>>> permTbl indexTbl ...... tbl
+	}
+}
+
+void unserializeTable(UnSerializationInfo *info, int index) {
+	// >>>>> permTbl indexTbl ......
+
+	// Make sure there is enough room on the stack
+	lua_checkstack(info->luaState, 1);
+
+	int isSpecial = info->readStream->readSint32LE();
+
+	if (isSpecial) {
+		unserializeSpecialTable(info, index);
+		// >>>>> permTbl indexTbl ...... tbl
+	} else {
+		unserializeLiteralTable(info, index);
+		// >>>>> permTbl indexTbl ...... tbl
+	}
+}
+
+
+
+void *lua_realloc(lua_State *luaState, void *block, size_t osize, size_t nsize) {
+	global_State *globalState = G(luaState);
+
+	block = (*globalState->frealloc)(globalState->ud, block, osize, nsize);
+	globalState->totalbytes = (globalState->totalbytes - osize) + nsize;
+
+	return block;
+}
+
+#define lua_malloc(luaState, nsize) lua_realloc(luaState, nullptr, 0, nsize)
+#define lua_reallocv(luaState, block, on, n, e) lua_realloc(luaState, block, (on) * (e), (n) * (e))
+#define lua_reallocvector(luaState, vec, oldn, n, T) ((vec) = (T *)(lua_reallocv(luaState, vec, oldn, n, sizeof(T))))
+#define lua_newVector(luaState, num, T) ((T *)lua_reallocv(luaState, nullptr, 0, num, sizeof(T)))
+#define lua_new(luaState,T) (T *)lua_malloc(luaState, sizeof(T))
+
+void lua_linkObjToGC(lua_State *luaState, GCObject *obj, lu_byte type) {
+	global_State *globalState = G(luaState);
+
+	obj->gch.next = globalState->rootgc;
+	globalState->rootgc = obj;
+	obj->gch.marked = luaC_white(globalState);
+	obj->gch.tt = type;
+}
+
+#define sizeLclosure(n)	((sizeof(LClosure)) + sizeof(TValue *) * ((n) - 1))
+
+Closure *newLClosure(lua_State *luaState, byte numUpValues, Table *env) {
+	Closure *newClosure = (Closure *)lua_malloc(luaState, sizeLclosure(numUpValues));
+
+	lua_linkObjToGC(luaState, obj2gco(newClosure), LUA_TFUNCTION);
+
+	newClosure->l.isC = 0;
+	newClosure->l.env = env;
+	newClosure->l.nupvalues = numUpValues;
+
+	while (numUpValues--) {
+		newClosure->l.upvals[numUpValues] = NULL; 
+	}
+
+	return newClosure;
+}
+
+static void pushClosure(lua_State *luaState, Closure *closure) {
+	TValue obj;
+	setclvalue(luaState, &obj, closure);
+	pushObject(luaState, &obj);
+}
+
+Proto *createProto(lua_State *luaState) {
+	Proto *newProto = (Proto *)lua_malloc(luaState, sizeof(Proto));
+	lua_linkObjToGC(luaState, obj2gco(newProto), LUA_TPROTO);
+
+	newProto->k = NULL;
+	newProto->sizek = 0;
+	newProto->p = NULL;
+	newProto->sizep = 0;
+	newProto->code = NULL;
+	newProto->sizecode = 0;
+	newProto->sizelineinfo = 0;
+	newProto->sizeupvalues = 0;
+	newProto->nups = 0;
+	newProto->upvalues = NULL;
+	newProto->numparams = 0;
+	newProto->is_vararg = 0;
+	newProto->maxstacksize = 0;
+	newProto->lineinfo = NULL;
+	newProto->sizelocvars = 0;
+	newProto->locvars = NULL;
+	newProto->linedefined = 0;
+	newProto->lastlinedefined = 0;
+	newProto->source = NULL;
+
+	return newProto;
+}
+
+TString *createString(lua_State *luaState, const char *str, size_t len) {
+	TString *res;
+	lua_pushlstring(luaState, str, len);
+
+	res = rawtsvalue(luaState->top - 1);
+	lua_pop(luaState, 1);
+
+	return res;
+}
+
+static Proto *makeFakeProto(lua_State *L, lu_byte nups) {
+	Proto *p = createProto(L);
+
+	p->sizelineinfo = 1;
+	p->lineinfo = lua_newVector(L, 1, int);
+	p->lineinfo[0] = 1;
+	p->sizecode = 1;
+	p->code = lua_newVector(L, 1, Instruction);
+	p->code[0] = CREATE_ABC(OP_RETURN, 0, 1, 0);
+	p->source = createString(L, "", 0);
+	p->maxstacksize = 2;
+	p->nups = nups;
+	p->sizek = 0;
+	p->sizep = 0;
+
+	return p;
+}
+
+static UpVal *createUpValue(lua_State *luaState, int stackpos) {
+	UpVal *upValue = (UpVal *)lua_malloc(luaState, sizeof(UpVal));
+	lua_linkObjToGC(luaState, (GCObject *)upValue, LUA_TUPVAL);
+	upValue->tt = LUA_TUPVAL;
+	upValue->v = &upValue->u.value;
+	upValue->u.l.prev = NULL;
+	upValue->u.l.next = NULL;
+
+	const TValue *o2 = (TValue *)getObject(luaState, stackpos);
+	upValue->v->value = o2->value; upValue->v->tt = o2->tt;
+	checkliveness(G(L), upValue->v);
+
+	return upValue;
+}
+
+static void unboxUpValue(lua_State *luaState) {
+	// >>>>> ...... func
+	LClosure *lcl;
+	UpVal *uv;
+
+	lcl = (LClosure *)clvalue(getObject(luaState, -1));
+	uv = lcl->upvals[0];
+
+	lua_pop(luaState, 1);
+	// >>>>> ......
+
+	pushUpValue(luaState, uv);
+	// >>>>> ...... upValue
+}
+
+void unserializeFunction(UnSerializationInfo *info, int index) {
+	// >>>>> permTbl indexTbl ......
+
+	// Make sure there is enough room on the stack
+	lua_checkstack(info->luaState, 2);
+
+	byte numUpValues = info->readStream->readByte();
+
+	LClosure *lclosure = (LClosure *)newLClosure(info->luaState, numUpValues, hvalue(&info->luaState->l_gt));
+	pushClosure(info->luaState, (Closure *)lclosure);
+	// >>>>> permTbl indexTbl ...... func
+
+	// Put *some* proto in the closure, before the GC can find it
+	lclosure->p = makeFakeProto(info->luaState, numUpValues);
+
+	//Also, we need to temporarily fill the upvalues
+	lua_pushnil(info->luaState);
+	// >>>>> permTbl indexTbl ...... func nil
+
+	for(byte i = 0; i < numUpValues; ++i) {
+		lclosure->upvals[i] = createUpValue(info->luaState, -1);
+	}
+
+	lua_pop(info->luaState, 1);
+	// >>>>> permTbl indexTbl ...... func
+
+	// I can't see offhand how a function would ever get to be self-
+	// referential, but just in case let's register it early
+	registerObjectInIndexTable(info, index);
+
+	// Now that it's safe, we can get the real proto
+	unserializeObject(info);
+	// >>>>> permTbl indexTbl ...... func proto
+
+	lclosure->p = gco2p(getObject(info->luaState, -1)->value.gc);
+
+	lua_pop(info->luaState, 1);
+	// >>>>> permTbl indexTbl ...... func
+
+	for(byte i = 0; i < numUpValues; ++i) {
+		// >>>>> permTbl indexTbl ...... func
+		unserializeObject(info);
+		// >>>>> permTbl indexTbl ...... func func2
+
+		unboxUpValue(info->luaState);
+		// >>>>> permTbl indexTbl ...... func upValue
+		lclosure->upvals[i] = gco2uv(getObject(info->luaState, -1)->value.gc);
+
+		lua_pop(info->luaState, 1);
+		// >>>>> permTbl indexTbl ...... func
+	}
+
+	// Finally, the fenv
+	unserializeObject(info);
+
+	// >>>>> permTbl indexTbl ...... func ?fenv/nil?
+	if(!lua_isnil(info->luaState, -1)) {
+		// >>>>> permTbl indexTbl ...... func fenv
+		lua_setfenv(info->luaState, -2);
+		// >>>>> permTbl indexTbl ...... func
+	} else {
+		// >>>>> permTbl indexTbl ...... func nil
+		lua_pop(info->luaState, 1);
+		// >>>>> permTbl indexTbl ...... func
+	}
+	
+	// >>>>> permTbl indexTbl ...... func
+}
+
+static void correctStack(lua_State *L, TValue *oldstack) {
+	CallInfo *ci;
+	GCObject *up;
+	L->top = (L->top - oldstack) + L->stack;
+	for (up = L->openupval; up != NULL; up = up->gch.next)
+		gco2uv(up)->v = (gco2uv(up)->v - oldstack) + L->stack;
+	for (ci = L->base_ci; ci <= L->ci; ci++) {
+		ci->top = (ci->top - oldstack) + L->stack;
+		ci->base = (ci->base - oldstack) + L->stack;
+		ci->func = (ci->func - oldstack) + L->stack;
+	}
+	L->base = (L->base - oldstack) + L->stack;
+}
+
+void lua_reallocstack(lua_State *L, int newsize) {
+	TValue *oldstack = L->stack;
+	int realsize = newsize + 1 + EXTRA_STACK;
+
+	lua_reallocvector(L, L->stack, L->stacksize, realsize, TValue);
+	L->stacksize = realsize;
+	L->stack_last = L->stack + newsize;
+	correctStack(L, oldstack);
+}
+
+void lua_growstack(lua_State *L, int n) {
+	// Double size is enough?
+	if (n <= L->stacksize) { 
+		lua_reallocstack(L, 2 * L->stacksize);
+	} else {
+		lua_reallocstack(L, L->stacksize + n);
+	}
+}
+
+void lua_reallocCallInfo(lua_State *lauState, int newsize) {
+	CallInfo *oldci = lauState->base_ci;
+	lua_reallocvector(lauState, lauState->base_ci, lauState->size_ci, newsize, CallInfo);
+
+	lauState->size_ci = newsize;
+	lauState->ci = (lauState->ci - oldci) + lauState->base_ci;
+	lauState->end_ci = lauState->base_ci + lauState->size_ci - 1;
+}
+
+void unboxUpVal(lua_State *luaState) {
+	// >>>>> ... func
+	LClosure *lcl;
+	UpVal *uv;
+
+	lcl = (LClosure *)(&getObject(luaState, -1)->value.gc->cl);
+	uv = lcl->upvals[0];
+	lua_pop(luaState, 1);
+	// >>>>> ...
+	pushUpValue(luaState, uv);
+	// >>>>> ... upVal
+}
+
+/* Does basically the opposite of luaC_link().
+ * Right now this function is rather inefficient; it requires traversing the
+ * entire root GC set in order to find one object. If the GC list were doubly
+ * linked this would be much easier, but there's no reason for Lua to have
+ * that. */
+static void GCUnlink(lua_State *luaState, GCObject *gco) {
+	GCObject *prevslot;
+	if(G(luaState)->rootgc == gco) {
+		G(luaState)->rootgc = G(luaState)->rootgc->gch.next;
+		return;
+	}
+
+	prevslot = G(luaState)->rootgc;
+	while(prevslot->gch.next != gco) {
+		prevslot = prevslot->gch.next;
+	}
+
+	prevslot->gch.next = prevslot->gch.next->gch.next;
+}
+
+void unserializeThread(UnSerializationInfo *info, int index) {
+	// >>>>> permTbl indexTbl ......
+
+	lua_State *L2;
+	uint32 stacklimit = 0;
+
+	L2 = lua_newthread(info->luaState);
+	lua_checkstack(info->luaState, 3);
+	
+	// L1: permTbl indexTbl ...... thread
+	// L2: (empty)
+	registerObjectInIndexTable(info, index);
+
+	// First, deserialize the object stack
+	uint32 stackSize = info->readStream->readUint32LE();
+	lua_growstack(info->luaState, (int)stackSize);
+	
+	// Make sure that the first stack element (a nil, representing
+	// the imaginary top-level C function) is written to the very,
+	// very bottom of the stack
+	L2->top--;
+	for(uint32 i = 0; i < stackSize; ++i) {
+		unserializeObject(info);
+		// L1: permTbl indexTbl ...... thread obj* 
+	}
+
+	lua_xmove(info->luaState, L2, stackSize);
+	// L1: permTbl indexTbl ...... thread
+	// L2: obj*
+
+	// Hereafter, stacks refer to L1
+
+	
+	// Now, deserialize the CallInfo stack
+
+	uint32 numFrames = info->readStream->readUint32LE();
+
+	lua_reallocCallInfo(L2, numFrames*2);
+	for(uint32 i = 0; i < numFrames; ++i) {
+		CallInfo *ci = L2->base_ci + i;
+		uint32 stackbase = info->readStream->readUint32LE();
+		uint32 stackfunc = info->readStream->readUint32LE();
+		uint32 stacktop = info->readStream->readUint32LE();
+		
+		ci->nresults = info->readStream->readSint32LE();
+
+		uint32 savedpc = info->readStream->readUint32LE();
+
+		if (stacklimit < stacktop) {
+			stacklimit = stacktop;
+		}
+
+		ci->base = L2->stack + stackbase;
+		ci->func = L2->stack + stackfunc;
+		ci->top = L2->stack + stacktop;
+		ci->savedpc = (ci != L2->base_ci) ? ci_func(ci)->l.p->code + savedpc : 0;
+		ci->tailcalls = 0;
+		
+		// Update the pointer each time, to keep the GC happy
+		L2->ci = ci;
+	}
+
+	// >>>>> permTbl indexTbl ...... thread
+	// Deserialize the state's other parameters, with the exception of upval stuff
+
+	L2->savedpc = L2->ci->savedpc;
+	L2->status = info->readStream->readByte();
+	uint32 stackbase = info->readStream->readUint32LE();
+	uint32 stacktop = info->readStream->readUint32LE();
+
+
+	L2->errfunc = info->readStream->readUint32LE();
+	
+	L2->base = L2->stack + stackbase;
+	L2->top = L2->stack + stacktop;
+
+	// Finally, "reopen" upvalues. See serializeUpVal() for why we do this		
+	UpVal* uv;
+	GCObject **nextslot = &L2->openupval;
+	global_State *g = G(L2);
+
+	while (true) {
+		unserializeObject(info);
+		// >>>>> permTbl indexTbl ...... thread upVal/nil
+
+		// The list is terminated by a nil
+		if (lua_isnil(info->luaState, -1)) {
+			// >>>>> permTbl indexTbl ...... thread nil
+			lua_pop(info->luaState, 1);
+			// >>>>> permTbl indexTbl ...... thread
+			break;
+		}
+		
+		// >>>>> permTbl indexTbl ...... thread boxedUpVal
+		unboxUpVal(info->luaState);
+		// >>>>> permTbl indexTbl ...... thread boxedUpVal
+
+		uv = &(getObject(info->luaState, -1)->value.gc->uv);
+		lua_pop(info->luaState, 1);
+		// >>>>> permTbl indexTbl ...... thread
+
+		uint32 stackpos = info->readStream->readUint32LE();
+		uv->v = L2->stack + stackpos;
+
+		GCUnlink(info->luaState, (GCObject *)uv);
+
+		uv->marked = luaC_white(g);
+		*nextslot = (GCObject *)uv;
+		nextslot = &uv->next;
+		uv->u.l.prev = &G(L2)->uvhead;
+		uv->u.l.next = G(L2)->uvhead.u.l.next;
+		uv->u.l.next->u.l.prev = uv;
+		G(L2)->uvhead.u.l.next = uv;
+		lua_assert(uv->u.l.next->u.l.prev == uv && uv->u.l.prev->u.l.next == uv);
+	}
+	*nextslot = NULL;
+
+	// The stack must be valid at least to the highest value among the CallInfos
+	// 'top' and the values up to there must be filled with 'nil'
+	lua_checkstack(L2, (int)stacklimit);
+	for (StkId o = L2->top; o <= L2->top + stacklimit; ++o) {
+		setnilvalue(o);
+	}
+}
+
+TString *lua_newlstr(lua_State *luaState, const char *str, size_t len) {
+	lua_pushlstring(luaState, str, len);
+	TString *luaStr = &(luaState->top - 1)->value.gc->ts;
+
+	lua_pop(luaState, 1);
+
+	return luaStr;
+}
+
+void lua_link(lua_State *luaState, GCObject *o, lu_byte tt) {
+	global_State *g = G(luaState);
+	o->gch.next = g->rootgc;
+	g->rootgc = o;
+	o->gch.marked = luaC_white(g);
+	o->gch.tt = tt;
+}
+
+Proto *lua_newproto(lua_State *luaState) {
+	Proto *f = (Proto *)lua_malloc(luaState, sizeof(Proto));
+	lua_link(luaState, obj2gco(f), LUA_TPROTO);
+	f->k = NULL;
+	f->sizek = 0;
+	f->p = NULL;
+	f->sizep = 0;
+	f->code = NULL;
+	f->sizecode = 0;
+	f->sizelineinfo = 0;
+	f->sizeupvalues = 0;
+	f->nups = 0;
+	f->upvalues = NULL;
+	f->numparams = 0;
+	f->is_vararg = 0;
+	f->maxstacksize = 0;
+	f->lineinfo = NULL;
+	f->sizelocvars = 0;
+	f->locvars = NULL;
+	f->linedefined = 0;
+	f->lastlinedefined = 0;
+	f->source = NULL;
+	return f;
+}
+
+void unserializeProto(UnSerializationInfo *info, int index) {
+	// >>>>> permTbl indexTbl ......
+	
+	// We have to be careful. The GC expects a lot out of protos. In particular, we need 
+	// to give the function a valid string for its source, and valid code, even before we 
+	// actually read in the real code. 
+	TString *source = lua_newlstr(info->luaState, "", 0);
+	Proto *p = lua_newproto(info->luaState);
+	p->source = source;
+	p->sizecode=1;
+	p->code =  (Instruction *)lua_reallocv(info->luaState, NULL, 0, 1, sizeof(Instruction));
+	p->code[0] = CREATE_ABC(OP_RETURN, 0, 1, 0);
+	p->maxstacksize = 2;
+	p->sizek = 0;
+	p->sizep = 0;
+
+	lua_checkstack(info->luaState, 2);
+
+	pushProto(info->luaState, p);
+	// >>>>> permTbl indexTbl ...... proto 
+
+	// We don't need to register early, since protos can never ever be
+	// involved in cyclic references 
+
+	// Read in constant references
+	int sizek = info->readStream->readSint32LE();
+	lua_reallocvector(info->luaState, p->k, 0, sizek, TValue);
+	for(int i = 0; i < sizek; ++i) {
+		// >>>>> permTbl indexTbl ...... proto 
+		unserializeObject(info);
+		// >>>>> permTbl indexTbl ...... proto  k 
+
+		setobj2s(info->luaState, &p->k[i], getObject(info->luaState, -1));
+		p->sizek++;
+
+		lua_pop(info->luaState, 1);
+		// >>>>> permTbl indexTbl ...... proto
+	}
+	// >>>>> permTbl indexTbl ...... proto
+
+	// Read in sub-proto references
+
+	int sizep = info->readStream->readSint32LE();
+	lua_reallocvector(info->luaState, p->p, 0, sizep, Proto *);
+	for(int i = 0; i < sizep; ++i) {
+		// >>>>> permTbl indexTbl ...... proto 
+		unserializeObject(info);
+		// >>>>> permTbl indexTbl ...... proto  subproto
+
+		p->p[i] = (Proto *)getObject(info->luaState, -1)->value.gc;
+		p->sizep++;
+
+		lua_pop(info->luaState, 1);
+		// >>>>> permTbl indexTbl ...... proto 
+	}
+	// >>>>> permTbl indexTbl ...... proto 
+
+
+	// Read in code
+	p->sizecode = info->readStream->readSint32LE();
+	lua_reallocvector(info->luaState, p->code, 1, p->sizecode, Instruction);
+	info->readStream->read(p->code, sizeof(Instruction) * p->sizecode);
+	
+
+	/* Read in upvalue names */
+	p->sizeupvalues = info->readStream->readSint32LE();
+	if (p->sizeupvalues) {
+		lua_reallocvector(info->luaState, p->upvalues, 0, p->sizeupvalues, TString *);
+		for(int i = 0; i < p->sizeupvalues; ++i) {
+			// >>>>> permTbl indexTbl ...... proto
+			unserializeObject(info);
+			// >>>>> permTbl indexTbl ...... proto str
+
+			p->upvalues[i] = lua_newlstr(info->luaState, lua_tostring(info->luaState, -1), strlen(lua_tostring(info->luaState, -1)));
+			lua_pop(info->luaState, 1);
+			// >>>>> permTbl indexTbl ...... proto
+		}
+	}
+	// >>>>> permTbl indexTbl ...... proto
+
+	// Read in local variable infos
+	p->sizelocvars = info->readStream->readSint32LE();
+	if (p->sizelocvars) {
+		lua_reallocvector(info->luaState, p->locvars, 0, p->sizelocvars, LocVar);
+		for(int i = 0; i < p->sizelocvars; ++i) {
+			// >>>>> permTbl indexTbl ...... proto
+			unserializeObject(info);
+			// >>>>> permTbl indexTbl ...... proto str
+
+			p->locvars[i].varname = lua_newlstr(info->luaState, lua_tostring(info->luaState, -1), strlen(lua_tostring(info->luaState, -1)));
+			lua_pop(info->luaState, 1);
+			// >>>>> permTbl indexTbl ...... proto
+
+			p->locvars[i].startpc = info->readStream->readSint32LE();
+			p->locvars[i].endpc = info->readStream->readSint32LE();
+		}
+	}
+	// >>>>> permTbl indexTbl ...... proto
+
+	// Read in source string
+	unserializeObject(info);
+	// >>>>> permTbl indexTbl ...... proto sourceStr
+
+	p->source = lua_newlstr(info->luaState, lua_tostring(info->luaState, -1), strlen(lua_tostring(info->luaState, -1)));
+	lua_pop(info->luaState, 1);
+	// >>>>> permTbl indexTbl ...... proto
+
+	// Read in line numbers
+	p->sizelineinfo = info->readStream->readSint32LE();
+	if (p->sizelineinfo) {
+		lua_reallocvector(info->luaState, p->lineinfo, 0, p->sizelineinfo, int);
+		info->readStream->read(p->lineinfo, sizeof(int) * p->sizelineinfo);
+	}
+	
+
+	/* Read in linedefined and lastlinedefined */
+	p->linedefined = info->readStream->readSint32LE();
+	p->lastlinedefined = info->readStream->readSint32LE();
+
+	// Read in misc values
+	p->nups = info->readStream->readByte();
+	p->numparams = info->readStream->readByte();
+	p->is_vararg = info->readStream->readByte();
+	p->maxstacksize = info->readStream->readByte();
+}
+
+Closure *lua_newLclosure(lua_State *luaState, int numElements, Table *elementTable) {
+	Closure *c = (Closure *)lua_malloc(luaState, sizeLclosure(numElements));
+	lua_link(luaState, obj2gco(c), LUA_TFUNCTION);
+	c->l.isC = 0;
+	c->l.env = elementTable;
+	c->l.nupvalues = cast_byte(numElements);
+	
+	while (numElements--) {
+		c->l.upvals[numElements] = NULL;
+	}
+
+	return c;
+}
+
+static UpVal *makeUpVal(lua_State *luaState, int stackPos) {
+	UpVal *uv = lua_new(luaState, UpVal);
+	lua_link(luaState, (GCObject *)uv, LUA_TUPVAL);
+	uv->tt = LUA_TUPVAL;
+	uv->v = &uv->u.value;
+	uv->u.l.prev = NULL;
+	uv->u.l.next = NULL;
+
+	setobj(luaState, uv->v, getObject(luaState, stackPos));
+
+	return uv;
+}
+
+/** 
+ * The GC is not fond of finding upvalues in tables. We get around this
+ * during persistence using a weakly keyed table, so that the GC doesn't
+ * bother to mark them. This won't work in unpersisting, however, since
+ * if we make the values weak they'll be collected (since nothing else
+ * references them). Our solution, during unpersisting, is to represent
+ * upvalues as dummy functions, each with one upvalue. 
+ */
+static void boxupval_start(lua_State *luaState) {
+	LClosure *closure;
+	closure = (LClosure *)lua_newLclosure(luaState, 1, hvalue(&luaState->l_gt));
+	pushClosure(luaState, (Closure *)closure);
+	// >>>>> ...... func
+	closure->p = makeFakeProto(luaState, 1);
+
+	// Temporarily initialize the upvalue to nil 
+	lua_pushnil(luaState);
+	closure->upvals[0] = makeUpVal(luaState, -1);
+	lua_pop(luaState, 1);
+}
+
+static void boxupval_finish(lua_State *luaState) {
+	// >>>>> ...... func obj
+	LClosure *lcl = (LClosure *)clvalue(getObject(luaState, -2));
+
+	lcl->upvals[0]->u.value = *getObject(luaState, -1);
+	lua_pop(luaState, 1);
+	// >>>>> ...... func
+}
+
+void unserializeUpValue(UnSerializationInfo *info, int index) {
+	// >>>>> permTbl indexTbl ...... 
+	lua_checkstack(upi->L, 2);
+
+	boxupval_start(upi->L);
+	// >>>>> permTbl indexTbl ...... func
+	registerObjectInIndexTable(info, index);
+
+	unserializeObject(info);
+	// >>>>> permTbl indexTbl ...... func obj
+
+	boxupval_finish(upi->L);
+	// >>>>> permTbl indexTbl ...... func
+}
+
+void unserializeUserData(UnSerializationInfo *info, int index) {
+	// >>>>> permTbl indexTbl ......
+
+	// Make sure there is enough room on the stack
+	lua_checkstack(info->luaState, 2);
+	
+	int isspecial = info->readStream->readSint32LE();
+	if(isspecial) {
+		unserializeObject(info);
+		// >>>>> permTbl indexTbl ...... specialFunc
+
+		lua_call(info->luaState, 0, 1);
+		// >>>>> permTbl indexTbl ...... udata
+	} else {
+		uint32 length = info->readStream->readUint32LE();
+		lua_newuserdata(info->luaState, length);
+		// >>>>> permTbl indexTbl ...... udata
+		registerObjectInIndexTable(info, index);
+
+		info->readStream->read(lua_touserdata(upi->L, -1), length);
+
+		unserializeObject(info);
+		// >>>>> permTbl indexTbl ...... udata metaTable/nil
+
+		lua_setmetatable(upi->L, -2);
+		// >>>>> permTbl indexTbl ...... udata
+	}
+	// >>>>> permTbl indexTbl ...... udata
+}
+
+void unserializePermanent(UnSerializationInfo *info, int index) {
+	// >>>>> permTbl indexTbl ......
+
+	// Make sure there is enough room on the stack
+	lua_checkstack(info->luaState, 2);
+	
+	unserializeObject(info);
+	// >>>>> permTbl indexTbl ...... permKey
+
+	lua_gettable(info->luaState, 1);
+	// >>>>> permTbl indexTbl ...... perm
+}
+
+} // End of namespace Lua


Commit: 2c7a87a4e3181f228c43b92ffb15ae47401f64a7
    https://github.com/scummvm/scummvm/commit/2c7a87a4e3181f228c43b92ffb15ae47401f64a7
Author: Adrian Astley (adastley at gmail.com)
Date: 2014-12-19T14:51:00-06:00

Commit Message:
SWORD25: Fix code formatting

... with AStyle

Changed paths:
    engines/sword25/util/lua_serialization_util.cpp
    engines/sword25/util/lua_serializer.cpp
    engines/sword25/util/lua_unserializer.cpp



diff --git a/engines/sword25/util/lua_serialization_util.cpp b/engines/sword25/util/lua_serialization_util.cpp
index 80009af..80c5f86 100644
--- a/engines/sword25/util/lua_serialization_util.cpp
+++ b/engines/sword25/util/lua_serialization_util.cpp
@@ -65,12 +65,12 @@ void pushString(lua_State *luaState, TString *str) {
 /* A simple reimplementation of the unfortunately static function luaA_index.
  * Does not support the global table, registry, or upvalues. */
 StkId getObject(lua_State *luaState, int stackpos) {
-	if(stackpos > 0) {
-		lua_assert(luaState->base+stackpos-1 < luaState->top);
-		return luaState->base+stackpos-1;
+	if (stackpos > 0) {
+		lua_assert(luaState->base + stackpos - 1 < luaState->top);
+		return luaState->base + stackpos - 1;
 	} else {
-		lua_assert(L->top-stackpos >= L->base);
-		return luaState->top+stackpos;
+		lua_assert(L->top - stackpos >= L->base);
+		return luaState->top + stackpos;
 	}
 }
 
diff --git a/engines/sword25/util/lua_serializer.cpp b/engines/sword25/util/lua_serializer.cpp
index 8c61383..c6c5f99 100644
--- a/engines/sword25/util/lua_serializer.cpp
+++ b/engines/sword25/util/lua_serializer.cpp
@@ -81,7 +81,7 @@ void serializeLua(lua_State *luaState, Common::WriteStream *writeStream) {
 	// 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
@@ -253,22 +253,22 @@ static void serializeBoolean(SerializationInfo *info) {
 
 static void serializeNumber(SerializationInfo *info) {
 	lua_Number value = lua_tonumber(info->luaState, -1);
-	
-#if 1
-	Util::SerializedDouble serializedValue(Util::encodeDouble(value));
-
-	info->writeStream->writeUint32LE(serializedValue.significandOne);
-	info->writeStream->writeUint32LE(serializedValue.signAndSignificandTwo);
-	info->writeStream->writeSint16LE(serializedValue.exponent);
-#else
-	// NOTE: We need to store a double. Unfortunately, we have to accommodate endianness. 
-	// Also, I don't know if we can assume all compilers use IEEE double
-	// Therefore, I have chosen to store the double as a string. 
-	Common::String buffer = Common::String::format("%f", value);
-
-	info->writeStream->write(buffer.c_str(), buffer.size());
-#endif
-	
+
+	#if 1
+		Util::SerializedDouble serializedValue(Util::encodeDouble(value));
+
+		info->writeStream->writeUint32LE(serializedValue.significandOne);
+		info->writeStream->writeUint32LE(serializedValue.signAndSignificandTwo);
+		info->writeStream->writeSint16LE(serializedValue.exponent);
+	#else
+		// NOTE: We need to store a double. Unfortunately, we have to accommodate endianness.
+		// Also, I don't know if we can assume all compilers use IEEE double
+		// Therefore, I have chosen to store the double as a string.
+		Common::String buffer = Common::String::format("%f", value);
+
+		info->writeStream->write(buffer.c_str(), buffer.size());
+	#endif
+
 }
 
 static void serializeString(SerializationInfo *info) {
@@ -277,7 +277,7 @@ static void serializeString(SerializationInfo *info) {
 	uint32 length = static_cast<uint32>(lua_strlen(info->luaState, -1));
 	info->writeStream->writeUint32LE(length);
 
-	const char* str = lua_tostring(info->luaState, -1);
+	const char *str = lua_tostring(info->luaState, -1);
 	info->writeStream->write(str, length);
 }
 
@@ -350,7 +350,7 @@ static bool serializeSpecialObject(SerializationInfo *info, bool defaction) {
 		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
@@ -369,7 +369,7 @@ static bool serializeSpecialObject(SerializationInfo *info, bool defaction) {
 
 	// Serialize the function
 	serializeObject(info);
-					
+
 	lua_pop(info->luaState, 2);
 	// >>>>> permTbl indexTbl ...... obj
 
@@ -396,11 +396,11 @@ static void serializeTable(SerializationInfo *info) {
 
 	// >>>>> permTbl indexTbl ...... tbl metaTbl/nil */
 	serializeObject(info);
-	
+
 	lua_pop(info->luaState, 1);
 	// >>>>> permTbl indexTbl ...... tbl
 
-	
+
 	lua_pushnil(info->luaState);
 	// >>>>> permTbl indexTbl ...... tbl nil
 
@@ -456,14 +456,14 @@ static void serializeFunction(SerializationInfo *info) {
 		// Serialize the prototype
 		pushProto(info->luaState, cl->l.p);
 		// >>>>> permTbl indexTbl ...... func proto */
-		
+
 		serializeObject(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++) {
+		for (byte i = 0; i < cl->l.p->nups; i++) {
 			// >>>>> permTbl indexTbl ...... func
 			pushUpValue(info->luaState, cl->l.upvals[i]);
 			// >>>>> permTbl indexTbl ...... func upval
@@ -536,7 +536,7 @@ static void serializeThread(SerializationInfo *info) {
 	}
 
 	// >>>>> 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
@@ -550,7 +550,7 @@ static void serializeThread(SerializationInfo *info) {
 		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);
@@ -560,7 +560,7 @@ static void serializeThread(SerializationInfo *info) {
 		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
 
@@ -671,9 +671,9 @@ static void serializeProto(SerializationInfo *info) {
 		lua_pop(info->luaState, 1);
 		// >>>>> permTbl indexTbl ...... proto
 	}
-	
 
-	// Serialize local variable infos 
+
+	// Serialize local variable infos
 	info->writeStream->writeSint32LE(proto->sizelocvars);
 
 	for (int i = 0; i < proto->sizelocvars; ++i) {
@@ -748,7 +748,7 @@ static void serializeUpValue(SerializationInfo *info) {
 	// 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 
+	// 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);
diff --git a/engines/sword25/util/lua_unserializer.cpp b/engines/sword25/util/lua_unserializer.cpp
index c561a3d..69cb764 100644
--- a/engines/sword25/util/lua_unserializer.cpp
+++ b/engines/sword25/util/lua_unserializer.cpp
@@ -79,7 +79,7 @@ void unserializeLua(lua_State *luaState, Common::ReadStream *readStream) {
 
 	// Re-start garbage collection
 	lua_gc(luaState, LUA_GCRESTART, 0);
-	
+
 	// Remove the indexTbl
 	lua_replace(luaState, 2);
 	// >>>>> permTbl rootObj
@@ -106,17 +106,17 @@ static void registerObjectInIndexTable(UnSerializationInfo *info, int index) {
 }
 
 static void unserializeObject(UnSerializationInfo *info) {
-	// >>>>> permTbl indexTbl ...... 
+	// >>>>> permTbl indexTbl ......
 
 	// Make sure there is enough room on the stack
 	lua_checkstack(info->luaState, 2);
 
 	byte isARealValue = info->readStream->readByte();
-	if(isARealValue) {
+	if (isARealValue) {
 		int index = info->readStream->readSint32LE();
 		int type = info->readStream->readSint32LE();
 
-		switch(type) {
+		switch (type) {
 		case LUA_TBOOLEAN:
 			unserializeBoolean(info);
 			break;
@@ -156,9 +156,9 @@ static void unserializeObject(UnSerializationInfo *info) {
 			assert(0);
 		}
 
-		
+
 		// >>>>> permTbl indexTbl ...... obj
-		assert(lua_type(info->luaState, -1) == type || 
+		assert(lua_type(info->luaState, -1) == type ||
 		       type == PERMANENT_TYPE ||
 		       // Remember, upvalues get a special dispensation, as described in boxUpValue
 		       (lua_type(info->luaState, -1) == LUA_TFUNCTION && type == LUA_TUPVAL));
@@ -168,7 +168,7 @@ static void unserializeObject(UnSerializationInfo *info) {
 	} else {
 		int index = info->readStream->readSint32LE();
 
-		if(index == 0) {
+		if (index == 0) {
 			lua_pushnil(info->luaState);
 			// >>>>> permTbl indexTbl ...... nil
 		} else {
@@ -184,7 +184,7 @@ static void unserializeObject(UnSerializationInfo *info) {
 		}
 		// >>>>> permTbl indexTbl ...... obj/nil
 	}
-	
+
 	// >>>>> permTbl indexTbl ...... obj/nil
 }
 
@@ -201,8 +201,8 @@ static void unserializeBoolean(UnSerializationInfo *info) {
 }
 
 static void unserializeNumber(UnSerializationInfo *info) {
-	// >>>>> permTbl indexTbl ...... 
-	
+	// >>>>> permTbl indexTbl ......
+
 	// Make sure there is enough room on the stack
 	lua_checkstack(info->luaState, 1);
 
@@ -220,7 +220,7 @@ static void unserializeNumber(UnSerializationInfo *info) {
 
 static void unserializeString(UnSerializationInfo *info) {
 	// >>>>> permTbl indexTbl ......
-	
+
 	// Make sure there is enough room on the stack
 	lua_checkstack(info->luaState, 1);
 
@@ -231,7 +231,7 @@ static void unserializeString(UnSerializationInfo *info) {
 	lua_pushlstring(info->luaState, string, length);
 
 	// >>>>> permTbl indexTbl ...... string
-	
+
 	delete[] string;
 }
 
@@ -264,7 +264,7 @@ static void unserializeLiteralTable(UnSerializationInfo *info, int index) {
 	// Unserialize metatable
 	unserializeObject(info);
 	// >>>>> permTbl indexTbl ...... tbl ?metaTbl/nil?
-	
+
 	if (lua_istable(info->luaState, -1)) {
 		// >>>>> permTbl indexTbl ...... tbl metaTbl
 		lua_setmetatable(info->luaState, -2);
@@ -343,7 +343,7 @@ void lua_linkObjToGC(lua_State *luaState, GCObject *obj, lu_byte type) {
 	obj->gch.tt = type;
 }
 
-#define sizeLclosure(n)	((sizeof(LClosure)) + sizeof(TValue *) * ((n) - 1))
+#define sizeLclosure(n) ((sizeof(LClosure)) + sizeof(TValue *) * ((n) - 1))
 
 Closure *newLClosure(lua_State *luaState, byte numUpValues, Table *env) {
 	Closure *newClosure = (Closure *)lua_malloc(luaState, sizeLclosure(numUpValues));
@@ -355,7 +355,7 @@ Closure *newLClosure(lua_State *luaState, byte numUpValues, Table *env) {
 	newClosure->l.nupvalues = numUpValues;
 
 	while (numUpValues--) {
-		newClosure->l.upvals[numUpValues] = NULL; 
+		newClosure->l.upvals[numUpValues] = NULL;
 	}
 
 	return newClosure;
@@ -431,7 +431,8 @@ static UpVal *createUpValue(lua_State *luaState, int stackpos) {
 	upValue->u.l.next = NULL;
 
 	const TValue *o2 = (TValue *)getObject(luaState, stackpos);
-	upValue->v->value = o2->value; upValue->v->tt = o2->tt;
+	upValue->v->value = o2->value;
+	upValue->v->tt = o2->tt;
 	checkliveness(G(L), upValue->v);
 
 	return upValue;
@@ -471,7 +472,7 @@ void unserializeFunction(UnSerializationInfo *info, int index) {
 	lua_pushnil(info->luaState);
 	// >>>>> permTbl indexTbl ...... func nil
 
-	for(byte i = 0; i < numUpValues; ++i) {
+	for (byte i = 0; i < numUpValues; ++i) {
 		lclosure->upvals[i] = createUpValue(info->luaState, -1);
 	}
 
@@ -491,7 +492,7 @@ void unserializeFunction(UnSerializationInfo *info, int index) {
 	lua_pop(info->luaState, 1);
 	// >>>>> permTbl indexTbl ...... func
 
-	for(byte i = 0; i < numUpValues; ++i) {
+	for (byte i = 0; i < numUpValues; ++i) {
 		// >>>>> permTbl indexTbl ...... func
 		unserializeObject(info);
 		// >>>>> permTbl indexTbl ...... func func2
@@ -508,7 +509,7 @@ void unserializeFunction(UnSerializationInfo *info, int index) {
 	unserializeObject(info);
 
 	// >>>>> permTbl indexTbl ...... func ?fenv/nil?
-	if(!lua_isnil(info->luaState, -1)) {
+	if (!lua_isnil(info->luaState, -1)) {
 		// >>>>> permTbl indexTbl ...... func fenv
 		lua_setfenv(info->luaState, -2);
 		// >>>>> permTbl indexTbl ...... func
@@ -517,7 +518,7 @@ void unserializeFunction(UnSerializationInfo *info, int index) {
 		lua_pop(info->luaState, 1);
 		// >>>>> permTbl indexTbl ...... func
 	}
-	
+
 	// >>>>> permTbl indexTbl ...... func
 }
 
@@ -547,7 +548,7 @@ void lua_reallocstack(lua_State *L, int newsize) {
 
 void lua_growstack(lua_State *L, int n) {
 	// Double size is enough?
-	if (n <= L->stacksize) { 
+	if (n <= L->stacksize) {
 		lua_reallocstack(L, 2 * L->stacksize);
 	} else {
 		lua_reallocstack(L, L->stacksize + n);
@@ -583,13 +584,13 @@ void unboxUpVal(lua_State *luaState) {
  * that. */
 static void GCUnlink(lua_State *luaState, GCObject *gco) {
 	GCObject *prevslot;
-	if(G(luaState)->rootgc == gco) {
+	if (G(luaState)->rootgc == gco) {
 		G(luaState)->rootgc = G(luaState)->rootgc->gch.next;
 		return;
 	}
 
 	prevslot = G(luaState)->rootgc;
-	while(prevslot->gch.next != gco) {
+	while (prevslot->gch.next != gco) {
 		prevslot = prevslot->gch.next;
 	}
 
@@ -604,7 +605,7 @@ void unserializeThread(UnSerializationInfo *info, int index) {
 
 	L2 = lua_newthread(info->luaState);
 	lua_checkstack(info->luaState, 3);
-	
+
 	// L1: permTbl indexTbl ...... thread
 	// L2: (empty)
 	registerObjectInIndexTable(info, index);
@@ -612,14 +613,14 @@ void unserializeThread(UnSerializationInfo *info, int index) {
 	// First, deserialize the object stack
 	uint32 stackSize = info->readStream->readUint32LE();
 	lua_growstack(info->luaState, (int)stackSize);
-	
+
 	// Make sure that the first stack element (a nil, representing
 	// the imaginary top-level C function) is written to the very,
 	// very bottom of the stack
 	L2->top--;
-	for(uint32 i = 0; i < stackSize; ++i) {
+	for (uint32 i = 0; i < stackSize; ++i) {
 		unserializeObject(info);
-		// L1: permTbl indexTbl ...... thread obj* 
+		// L1: permTbl indexTbl ...... thread obj*
 	}
 
 	lua_xmove(info->luaState, L2, stackSize);
@@ -628,18 +629,18 @@ void unserializeThread(UnSerializationInfo *info, int index) {
 
 	// Hereafter, stacks refer to L1
 
-	
+
 	// Now, deserialize the CallInfo stack
 
 	uint32 numFrames = info->readStream->readUint32LE();
 
-	lua_reallocCallInfo(L2, numFrames*2);
-	for(uint32 i = 0; i < numFrames; ++i) {
+	lua_reallocCallInfo(L2, numFrames * 2);
+	for (uint32 i = 0; i < numFrames; ++i) {
 		CallInfo *ci = L2->base_ci + i;
 		uint32 stackbase = info->readStream->readUint32LE();
 		uint32 stackfunc = info->readStream->readUint32LE();
 		uint32 stacktop = info->readStream->readUint32LE();
-		
+
 		ci->nresults = info->readStream->readSint32LE();
 
 		uint32 savedpc = info->readStream->readUint32LE();
@@ -653,7 +654,7 @@ void unserializeThread(UnSerializationInfo *info, int index) {
 		ci->top = L2->stack + stacktop;
 		ci->savedpc = (ci != L2->base_ci) ? ci_func(ci)->l.p->code + savedpc : 0;
 		ci->tailcalls = 0;
-		
+
 		// Update the pointer each time, to keep the GC happy
 		L2->ci = ci;
 	}
@@ -668,12 +669,12 @@ void unserializeThread(UnSerializationInfo *info, int index) {
 
 
 	L2->errfunc = info->readStream->readUint32LE();
-	
+
 	L2->base = L2->stack + stackbase;
 	L2->top = L2->stack + stacktop;
 
-	// Finally, "reopen" upvalues. See serializeUpVal() for why we do this		
-	UpVal* uv;
+	// Finally, "reopen" upvalues. See serializeUpVal() for why we do this
+	UpVal *uv;
 	GCObject **nextslot = &L2->openupval;
 	global_State *g = G(L2);
 
@@ -688,7 +689,7 @@ void unserializeThread(UnSerializationInfo *info, int index) {
 			// >>>>> permTbl indexTbl ...... thread
 			break;
 		}
-		
+
 		// >>>>> permTbl indexTbl ...... thread boxedUpVal
 		unboxUpVal(info->luaState);
 		// >>>>> permTbl indexTbl ...... thread boxedUpVal
@@ -765,15 +766,15 @@ Proto *lua_newproto(lua_State *luaState) {
 
 void unserializeProto(UnSerializationInfo *info, int index) {
 	// >>>>> permTbl indexTbl ......
-	
-	// We have to be careful. The GC expects a lot out of protos. In particular, we need 
-	// to give the function a valid string for its source, and valid code, even before we 
-	// actually read in the real code. 
+
+	// We have to be careful. The GC expects a lot out of protos. In particular, we need
+	// to give the function a valid string for its source, and valid code, even before we
+	// actually read in the real code.
 	TString *source = lua_newlstr(info->luaState, "", 0);
 	Proto *p = lua_newproto(info->luaState);
 	p->source = source;
-	p->sizecode=1;
-	p->code =  (Instruction *)lua_reallocv(info->luaState, NULL, 0, 1, sizeof(Instruction));
+	p->sizecode = 1;
+	p->code = (Instruction *)lua_reallocv(info->luaState, NULL, 0, 1, sizeof(Instruction));
 	p->code[0] = CREATE_ABC(OP_RETURN, 0, 1, 0);
 	p->maxstacksize = 2;
 	p->sizek = 0;
@@ -782,18 +783,18 @@ void unserializeProto(UnSerializationInfo *info, int index) {
 	lua_checkstack(info->luaState, 2);
 
 	pushProto(info->luaState, p);
-	// >>>>> permTbl indexTbl ...... proto 
+	// >>>>> permTbl indexTbl ...... proto
 
 	// We don't need to register early, since protos can never ever be
-	// involved in cyclic references 
+	// involved in cyclic references
 
 	// Read in constant references
 	int sizek = info->readStream->readSint32LE();
 	lua_reallocvector(info->luaState, p->k, 0, sizek, TValue);
-	for(int i = 0; i < sizek; ++i) {
-		// >>>>> permTbl indexTbl ...... proto 
+	for (int i = 0; i < sizek; ++i) {
+		// >>>>> permTbl indexTbl ...... proto
 		unserializeObject(info);
-		// >>>>> permTbl indexTbl ...... proto  k 
+		// >>>>> permTbl indexTbl ...... proto  k
 
 		setobj2s(info->luaState, &p->k[i], getObject(info->luaState, -1));
 		p->sizek++;
@@ -807,8 +808,8 @@ void unserializeProto(UnSerializationInfo *info, int index) {
 
 	int sizep = info->readStream->readSint32LE();
 	lua_reallocvector(info->luaState, p->p, 0, sizep, Proto *);
-	for(int i = 0; i < sizep; ++i) {
-		// >>>>> permTbl indexTbl ...... proto 
+	for (int i = 0; i < sizep; ++i) {
+		// >>>>> permTbl indexTbl ...... proto
 		unserializeObject(info);
 		// >>>>> permTbl indexTbl ...... proto  subproto
 
@@ -816,22 +817,22 @@ void unserializeProto(UnSerializationInfo *info, int index) {
 		p->sizep++;
 
 		lua_pop(info->luaState, 1);
-		// >>>>> permTbl indexTbl ...... proto 
+		// >>>>> permTbl indexTbl ...... proto
 	}
-	// >>>>> permTbl indexTbl ...... proto 
+	// >>>>> permTbl indexTbl ...... proto
 
 
 	// Read in code
 	p->sizecode = info->readStream->readSint32LE();
 	lua_reallocvector(info->luaState, p->code, 1, p->sizecode, Instruction);
 	info->readStream->read(p->code, sizeof(Instruction) * p->sizecode);
-	
+
 
 	/* Read in upvalue names */
 	p->sizeupvalues = info->readStream->readSint32LE();
 	if (p->sizeupvalues) {
 		lua_reallocvector(info->luaState, p->upvalues, 0, p->sizeupvalues, TString *);
-		for(int i = 0; i < p->sizeupvalues; ++i) {
+		for (int i = 0; i < p->sizeupvalues; ++i) {
 			// >>>>> permTbl indexTbl ...... proto
 			unserializeObject(info);
 			// >>>>> permTbl indexTbl ...... proto str
@@ -847,7 +848,7 @@ void unserializeProto(UnSerializationInfo *info, int index) {
 	p->sizelocvars = info->readStream->readSint32LE();
 	if (p->sizelocvars) {
 		lua_reallocvector(info->luaState, p->locvars, 0, p->sizelocvars, LocVar);
-		for(int i = 0; i < p->sizelocvars; ++i) {
+		for (int i = 0; i < p->sizelocvars; ++i) {
 			// >>>>> permTbl indexTbl ...... proto
 			unserializeObject(info);
 			// >>>>> permTbl indexTbl ...... proto str
@@ -876,7 +877,7 @@ void unserializeProto(UnSerializationInfo *info, int index) {
 		lua_reallocvector(info->luaState, p->lineinfo, 0, p->sizelineinfo, int);
 		info->readStream->read(p->lineinfo, sizeof(int) * p->sizelineinfo);
 	}
-	
+
 
 	/* Read in linedefined and lastlinedefined */
 	p->linedefined = info->readStream->readSint32LE();
@@ -895,7 +896,7 @@ Closure *lua_newLclosure(lua_State *luaState, int numElements, Table *elementTab
 	c->l.isC = 0;
 	c->l.env = elementTable;
 	c->l.nupvalues = cast_byte(numElements);
-	
+
 	while (numElements--) {
 		c->l.upvals[numElements] = NULL;
 	}
@@ -916,13 +917,13 @@ static UpVal *makeUpVal(lua_State *luaState, int stackPos) {
 	return uv;
 }
 
-/** 
+/**
  * The GC is not fond of finding upvalues in tables. We get around this
  * during persistence using a weakly keyed table, so that the GC doesn't
  * bother to mark them. This won't work in unpersisting, however, since
  * if we make the values weak they'll be collected (since nothing else
  * references them). Our solution, during unpersisting, is to represent
- * upvalues as dummy functions, each with one upvalue. 
+ * upvalues as dummy functions, each with one upvalue.
  */
 static void boxupval_start(lua_State *luaState) {
 	LClosure *closure;
@@ -931,7 +932,7 @@ static void boxupval_start(lua_State *luaState) {
 	// >>>>> ...... func
 	closure->p = makeFakeProto(luaState, 1);
 
-	// Temporarily initialize the upvalue to nil 
+	// Temporarily initialize the upvalue to nil
 	lua_pushnil(luaState);
 	closure->upvals[0] = makeUpVal(luaState, -1);
 	lua_pop(luaState, 1);
@@ -947,7 +948,7 @@ static void boxupval_finish(lua_State *luaState) {
 }
 
 void unserializeUpValue(UnSerializationInfo *info, int index) {
-	// >>>>> permTbl indexTbl ...... 
+	// >>>>> permTbl indexTbl ......
 	lua_checkstack(upi->L, 2);
 
 	boxupval_start(upi->L);
@@ -966,9 +967,9 @@ void unserializeUserData(UnSerializationInfo *info, int index) {
 
 	// Make sure there is enough room on the stack
 	lua_checkstack(info->luaState, 2);
-	
+
 	int isspecial = info->readStream->readSint32LE();
-	if(isspecial) {
+	if (isspecial) {
 		unserializeObject(info);
 		// >>>>> permTbl indexTbl ...... specialFunc
 
@@ -996,7 +997,7 @@ void unserializePermanent(UnSerializationInfo *info, int index) {
 
 	// Make sure there is enough room on the stack
 	lua_checkstack(info->luaState, 2);
-	
+
 	unserializeObject(info);
 	// >>>>> permTbl indexTbl ...... permKey
 


Commit: 2fb116f10eaa1bf682a220c33016fc61492af4fe
    https://github.com/scummvm/scummvm/commit/2fb116f10eaa1bf682a220c33016fc61492af4fe
Author: RichieSams (adastley at gmail.com)
Date: 2014-12-30T13:41:24-06:00

Commit Message:
SWORD25: Move all lua serialization helper functions to their own file

Changed paths:
    engines/sword25/util/lua_serialization_util.cpp
    engines/sword25/util/lua_serialization_util.h
    engines/sword25/util/lua_serializer.cpp
    engines/sword25/util/lua_unserializer.cpp



diff --git a/engines/sword25/util/lua_serialization_util.cpp b/engines/sword25/util/lua_serialization_util.cpp
index 80c5f86..fc3f73e 100644
--- a/engines/sword25/util/lua_serialization_util.cpp
+++ b/engines/sword25/util/lua_serialization_util.cpp
@@ -27,10 +27,20 @@
 #include "lua/lobject.h"
 #include "lua/lstate.h"
 #include "lua/lgc.h"
+#include "lua/lopcodes.h"
 
 
 namespace Lua {
 
+void *lua_realloc(lua_State *luaState, void *block, size_t osize, size_t nsize) {
+	global_State *globalState = G(luaState);
+
+	block = (*globalState->frealloc)(globalState->ud, block, osize, nsize);
+	globalState->totalbytes = (globalState->totalbytes - osize) + nsize;
+
+	return block;
+}
+
 void pushObject(lua_State *luaState, TValue *obj) {
 	setobj2s(luaState, luaState->top, obj);
 
@@ -74,4 +84,263 @@ StkId getObject(lua_State *luaState, int stackpos) {
 	}
 }
 
+void lua_linkObjToGC(lua_State *luaState, GCObject *obj, lu_byte type) {
+	global_State *globalState = G(luaState);
+
+	obj->gch.next = globalState->rootgc;
+	globalState->rootgc = obj;
+	obj->gch.marked = luaC_white(globalState);
+	obj->gch.tt = type;
+}
+
+Closure *lua_newLclosure(lua_State *luaState, int numElements, Table *elementTable) {
+	Closure *c = (Closure *)lua_malloc(luaState, sizeLclosure(numElements));
+	lua_linkObjToGC(luaState, obj2gco(c), LUA_TFUNCTION);
+
+	c->l.isC = 0;
+	c->l.env = elementTable;
+	c->l.nupvalues = cast_byte(numElements);
+
+	while (numElements--) {
+		c->l.upvals[numElements] = NULL;
+	}
+
+	return c;
+}
+
+void pushClosure(lua_State *luaState, Closure *closure) {
+	TValue obj;
+	setclvalue(luaState, &obj, closure);
+	pushObject(luaState, &obj);
+}
+
+Proto *createProto(lua_State *luaState) {
+	Proto *newProto = (Proto *)lua_malloc(luaState, sizeof(Proto));
+	lua_linkObjToGC(luaState, obj2gco(newProto), LUA_TPROTO);
+
+	newProto->k = NULL;
+	newProto->sizek = 0;
+	newProto->p = NULL;
+	newProto->sizep = 0;
+	newProto->code = NULL;
+	newProto->sizecode = 0;
+	newProto->sizelineinfo = 0;
+	newProto->sizeupvalues = 0;
+	newProto->nups = 0;
+	newProto->upvalues = NULL;
+	newProto->numparams = 0;
+	newProto->is_vararg = 0;
+	newProto->maxstacksize = 0;
+	newProto->lineinfo = NULL;
+	newProto->sizelocvars = 0;
+	newProto->locvars = NULL;
+	newProto->linedefined = 0;
+	newProto->lastlinedefined = 0;
+	newProto->source = NULL;
+
+	return newProto;
+}
+
+TString *createString(lua_State *luaState, const char *str, size_t len) {
+	TString *res;
+	lua_pushlstring(luaState, str, len);
+
+	res = rawtsvalue(luaState->top - 1);
+	lua_pop(luaState, 1);
+
+	return res;
+}
+
+Proto *makeFakeProto(lua_State *L, lu_byte nups) {
+	Proto *p = createProto(L);
+
+	p->sizelineinfo = 1;
+	p->lineinfo = lua_newVector(L, 1, int);
+	p->lineinfo[0] = 1;
+	p->sizecode = 1;
+	p->code = lua_newVector(L, 1, Instruction);
+	p->code[0] = CREATE_ABC(OP_RETURN, 0, 1, 0);
+	p->source = createString(L, "", 0);
+	p->maxstacksize = 2;
+	p->nups = nups;
+	p->sizek = 0;
+	p->sizep = 0;
+
+	return p;
+}
+
+UpVal *createUpValue(lua_State *luaState, int stackpos) {
+	UpVal *upValue = (UpVal *)lua_malloc(luaState, sizeof(UpVal));
+	lua_linkObjToGC(luaState, (GCObject *)upValue, LUA_TUPVAL);
+	upValue->tt = LUA_TUPVAL;
+	upValue->v = &upValue->u.value;
+	upValue->u.l.prev = NULL;
+	upValue->u.l.next = NULL;
+
+	const TValue *o2 = (TValue *)getObject(luaState, stackpos);
+	upValue->v->value = o2->value;
+	upValue->v->tt = o2->tt;
+	checkliveness(G(L), upValue->v);
+
+	return upValue;
+}
+
+void unboxUpValue(lua_State *luaState) {
+	// >>>>> ...... func
+	LClosure *lcl;
+	UpVal *uv;
+
+	lcl = (LClosure *)clvalue(getObject(luaState, -1));
+	uv = lcl->upvals[0];
+
+	lua_pop(luaState, 1);
+	// >>>>> ......
+
+	pushUpValue(luaState, uv);
+	// >>>>> ...... upValue
+}
+
+size_t appendStackToStack_reverse(lua_State *from, lua_State *to) {
+	for (StkId id = from->top - 1; id >= from->stack; --id) {
+		setobj2s(to, to->top, id);
+		to->top++;
+	}
+
+	return from->top - from->stack;
+}
+
+void correctStack(lua_State *L, TValue *oldstack) {
+	CallInfo *ci;
+	GCObject *up;
+	L->top = (L->top - oldstack) + L->stack;
+	for (up = L->openupval; up != NULL; up = up->gch.next)
+		gco2uv(up)->v = (gco2uv(up)->v - oldstack) + L->stack;
+	for (ci = L->base_ci; ci <= L->ci; ci++) {
+		ci->top = (ci->top - oldstack) + L->stack;
+		ci->base = (ci->base - oldstack) + L->stack;
+		ci->func = (ci->func - oldstack) + L->stack;
+	}
+	L->base = (L->base - oldstack) + L->stack;
+}
+
+void lua_reallocstack(lua_State *L, int newsize) {
+	TValue *oldstack = L->stack;
+	int realsize = newsize + 1 + EXTRA_STACK;
+
+	lua_reallocvector(L, L->stack, L->stacksize, realsize, TValue);
+	L->stacksize = realsize;
+	L->stack_last = L->stack + newsize;
+	correctStack(L, oldstack);
+}
+
+void lua_growstack(lua_State *L, int n) {
+	// Double size is enough?
+	if (n <= L->stacksize) {
+		lua_reallocstack(L, 2 * L->stacksize);
+	} else {
+		lua_reallocstack(L, L->stacksize + n);
+	}
+}
+
+void lua_reallocCallInfo(lua_State *lauState, int newsize) {
+	CallInfo *oldci = lauState->base_ci;
+	lua_reallocvector(lauState, lauState->base_ci, lauState->size_ci, newsize, CallInfo);
+
+	lauState->size_ci = newsize;
+	lauState->ci = (lauState->ci - oldci) + lauState->base_ci;
+	lauState->end_ci = lauState->base_ci + lauState->size_ci - 1;
+}
+
+void GCUnlink(lua_State *luaState, GCObject *gco) {
+	GCObject *prevslot;
+	if (G(luaState)->rootgc == gco) {
+		G(luaState)->rootgc = G(luaState)->rootgc->gch.next;
+		return;
+	}
+
+	prevslot = G(luaState)->rootgc;
+	while (prevslot->gch.next != gco) {
+		prevslot = prevslot->gch.next;
+	}
+
+	prevslot->gch.next = prevslot->gch.next->gch.next;
+}
+
+TString *lua_newlstr(lua_State *luaState, const char *str, size_t len) {
+	lua_pushlstring(luaState, str, len);
+	TString *luaStr = &(luaState->top - 1)->value.gc->ts;
+
+	lua_pop(luaState, 1);
+
+	return luaStr;
+}
+
+void lua_link(lua_State *luaState, GCObject *o, lu_byte tt) {
+	global_State *g = G(luaState);
+	o->gch.next = g->rootgc;
+	g->rootgc = o;
+	o->gch.marked = luaC_white(g);
+	o->gch.tt = tt;
+}
+
+Proto *lua_newproto(lua_State *luaState) {
+	Proto *f = (Proto *)lua_malloc(luaState, sizeof(Proto));
+	lua_link(luaState, obj2gco(f), LUA_TPROTO);
+	f->k = NULL;
+	f->sizek = 0;
+	f->p = NULL;
+	f->sizep = 0;
+	f->code = NULL;
+	f->sizecode = 0;
+	f->sizelineinfo = 0;
+	f->sizeupvalues = 0;
+	f->nups = 0;
+	f->upvalues = NULL;
+	f->numparams = 0;
+	f->is_vararg = 0;
+	f->maxstacksize = 0;
+	f->lineinfo = NULL;
+	f->sizelocvars = 0;
+	f->locvars = NULL;
+	f->linedefined = 0;
+	f->lastlinedefined = 0;
+	f->source = NULL;
+	return f;
+}
+
+UpVal *makeUpValue(lua_State *luaState, int stackPos) {
+	UpVal *uv = lua_new(luaState, UpVal);
+	lua_link(luaState, (GCObject *)uv, LUA_TUPVAL);
+	uv->tt = LUA_TUPVAL;
+	uv->v = &uv->u.value;
+	uv->u.l.prev = NULL;
+	uv->u.l.next = NULL;
+
+	setobj(luaState, uv->v, getObject(luaState, stackPos));
+
+	return uv;
+}
+
+void boxUpValue_start(lua_State *luaState) {
+	LClosure *closure;
+	closure = (LClosure *)lua_newLclosure(luaState, 1, hvalue(&luaState->l_gt));
+	pushClosure(luaState, (Closure *)closure);
+	// >>>>> ...... func
+	closure->p = makeFakeProto(luaState, 1);
+
+	// Temporarily initialize the upvalue to nil
+	lua_pushnil(luaState);
+	closure->upvals[0] = makeUpValue(luaState, -1);
+	lua_pop(luaState, 1);
+}
+
+void boxUpValue_finish(lua_State *luaState) {
+	// >>>>> ...... func obj
+	LClosure *lcl = (LClosure *)clvalue(getObject(luaState, -2));
+
+	lcl->upvals[0]->u.value = *getObject(luaState, -1);
+	lua_pop(luaState, 1);
+	// >>>>> ...... func
+}
+
 } // End of namespace Lua
diff --git a/engines/sword25/util/lua_serialization_util.h b/engines/sword25/util/lua_serialization_util.h
index 6c55d0d..345996f 100644
--- a/engines/sword25/util/lua_serialization_util.h
+++ b/engines/sword25/util/lua_serialization_util.h
@@ -32,12 +32,67 @@ typedef TValue *StkId;
 
 namespace Lua {
 
+#define lua_malloc(luaState, nsize) lua_realloc(luaState, nullptr, 0, nsize)
+#define lua_reallocv(luaState, block, on, n, e) lua_realloc(luaState, block, (on) * (e), (n) * (e))
+#define lua_reallocvector(luaState, vec, oldn, n, T) ((vec) = (T *)(lua_reallocv(luaState, vec, oldn, n, sizeof(T))))
+#define lua_newVector(luaState, num, T) ((T *)lua_reallocv(luaState, nullptr, 0, num, sizeof(T)))
+#define lua_new(luaState,T) (T *)lua_malloc(luaState, sizeof(T))
+
+void *lua_realloc(lua_State *luaState, void *block, size_t osize, size_t nsize);
+
 void pushObject(lua_State *luaState, TValue *obj);
 void pushProto(lua_State *luaState, Proto *proto);
 void pushUpValue(lua_State *luaState, UpVal *upval);
 void pushString(lua_State *luaState, TString *str);
+
 StkId getObject(lua_State *luaState, int stackpos);
 
+void lua_linkObjToGC(lua_State *luaState, GCObject *obj, lu_byte type);
+
+#define sizeLclosure(n) ((sizeof(LClosure)) + sizeof(TValue *) * ((n) - 1))
+
+Closure *lua_newLclosure(lua_State *luaState, int numElements, Table *elementTable);
+void pushClosure(lua_State *luaState, Closure *closure);
+
+Proto *createProto(lua_State *luaState);
+Proto *makeFakeProto(lua_State *L, lu_byte nups);
+
+TString *createString(lua_State *luaState, const char *str, size_t len);
+
+UpVal *createUpValue(lua_State *luaState, int stackpos);
+void unboxUpValue(lua_State *luaState);
+
+/* Appends one stack to another stack, but the stack is reversed in the process */
+size_t appendStackToStack_reverse(lua_State *from, lua_State *to);
+void correctStack(lua_State *L, TValue *oldstack);
+void lua_reallocstack(lua_State *L, int newsize);
+void lua_growstack(lua_State *L, int n);
+
+void lua_reallocCallInfo(lua_State *lauState, int newsize);
+
+/* Does basically the opposite of luaC_link().
+ * Right now this function is rather inefficient; it requires traversing the
+ * entire root GC set in order to find one object. If the GC list were doubly
+ * linked this would be much easier, but there's no reason for Lua to have
+ * that. */
+void GCUnlink(lua_State *luaState, GCObject *gco);
+
+TString *lua_newlstr(lua_State *luaState, const char *str, size_t len);
+void lua_link(lua_State *luaState, GCObject *o, lu_byte tt);
+Proto *lua_newproto(lua_State *luaState) ;
+
+UpVal *makeUpValue(lua_State *luaState, int stackPos);
+/**
+ * The GC is not fond of finding upvalues in tables. We get around this
+ * during persistence using a weakly keyed table, so that the GC doesn't
+ * bother to mark them. This won't work in unpersisting, however, since
+ * if we make the values weak they'll be collected (since nothing else
+ * references them). Our solution, during unpersisting, is to represent
+ * upvalues as dummy functions, each with one upvalue.
+ */
+void boxUpValue_start(lua_State *luaState);
+void boxUpValue_finish(lua_State *luaState);
+
 } // End of namespace Lua
 
 #endif
diff --git a/engines/sword25/util/lua_serializer.cpp b/engines/sword25/util/lua_serializer.cpp
index c6c5f99..55b6257 100644
--- a/engines/sword25/util/lua_serializer.cpp
+++ b/engines/sword25/util/lua_serializer.cpp
@@ -42,7 +42,7 @@ struct SerializationInfo {
 	uint counter;
 };
 
-static void serializeObject(SerializationInfo *info);
+static void serialize(SerializationInfo *info);
 
 static void serializeBoolean(SerializationInfo *info);
 static void serializeNumber(SerializationInfo *info);
@@ -103,14 +103,14 @@ void serializeLua(lua_State *luaState, Common::WriteStream *writeStream) {
 	// >>>>> permTbl indexTbl rootObj
 
 	// Serialize the root recursively
-	serializeObject(&info);
+	serialize(&info);
 
 	// Return the stack back to the original state
 	lua_remove(luaState, 2);
 	// >>>>> permTbl rootObj
 }
 
-static void serializeObject(SerializationInfo *info) {
+static void serialize(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
@@ -188,7 +188,7 @@ static void serializeObject(SerializationInfo *info) {
 		info->writeStream->writeSint32LE(PERMANENT_TYPE);
 
 		// Serialize the key
-		serializeObject(info);
+		serialize(info);
 
 		// Pop the key off the stack
 		lua_pop(info->luaState, 1);
@@ -368,7 +368,7 @@ static bool serializeSpecialObject(SerializationInfo *info, bool defaction) {
 	info->writeStream->writeSint32LE(1);
 
 	// Serialize the function
-	serializeObject(info);
+	serialize(info);
 
 	lua_pop(info->luaState, 2);
 	// >>>>> permTbl indexTbl ...... obj
@@ -395,7 +395,7 @@ static void serializeTable(SerializationInfo *info) {
 	}
 
 	// >>>>> permTbl indexTbl ...... tbl metaTbl/nil */
-	serializeObject(info);
+	serialize(info);
 
 	lua_pop(info->luaState, 1);
 	// >>>>> permTbl indexTbl ...... tbl
@@ -412,13 +412,13 @@ static void serializeTable(SerializationInfo *info) {
 		// >>>>> permTbl indexTbl ...... tbl k v k */
 
 		// Serialize the key
-		serializeObject(info);
+		serialize(info);
 
 		lua_pop(info->luaState, 1);
 		// >>>>> permTbl indexTbl ...... tbl k v */
 
 		// Serialize the value
-		serializeObject(info);
+		serialize(info);
 
 		lua_pop(info->luaState, 1);
 		// >>>>> permTbl indexTbl ...... tbl k */
@@ -430,7 +430,7 @@ static void serializeTable(SerializationInfo *info) {
 	lua_pushnil(info->luaState);
 	// >>>>> permTbl indexTbl ...... tbl
 
-	serializeObject(info);
+	serialize(info);
 
 	lua_pop(info->luaState, 1);
 	// >>>>> permTbl indexTbl ...... tbl
@@ -457,7 +457,7 @@ static void serializeFunction(SerializationInfo *info) {
 		pushProto(info->luaState, cl->l.p);
 		// >>>>> permTbl indexTbl ...... func proto */
 
-		serializeObject(info);
+		serialize(info);
 
 		lua_pop(info->luaState, 1);
 		// >>>>> permTbl indexTbl ...... func
@@ -468,7 +468,7 @@ static void serializeFunction(SerializationInfo *info) {
 			pushUpValue(info->luaState, cl->l.upvals[i]);
 			// >>>>> permTbl indexTbl ...... func upval
 
-			serializeObject(info);
+			serialize(info);
 
 			lua_pop(info->luaState, 1);
 			// >>>>> permTbl indexTbl ...... func
@@ -492,23 +492,13 @@ static void serializeFunction(SerializationInfo *info) {
 		}
 
 		// >>>>> permTbl indexTbl ...... func fenv/nil
-		serializeObject(info);
+		serialize(info);
 
 		lua_pop(info->luaState, 1);
 		// >>>>> permTbl indexTbl ...... func
 	}
 }
 
-/* Appends one stack to another stack, but the stack is reversed in the process */
-static size_t appendStackToStack_rev(lua_State *from, lua_State *to) {
-	for (StkId id = from->top - 1; id >= from->stack; --id) {
-		setobj2s(to, to->top, id);
-		to->top++;
-	}
-
-	return from->top - from->stack;
-}
-
 static void serializeThread(SerializationInfo *info) {
 	// >>>>> permTbl indexTbl ...... thread
 	lua_State *threadState = lua_tothread(info->luaState, -1);
@@ -525,12 +515,12 @@ static void serializeThread(SerializationInfo *info) {
 	// 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_rev(threadState, info->luaState));
+	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) {
-		serializeObject(info);
+		serialize(info);
 
 		lua_pop(info->luaState, 1);
 	}
@@ -592,7 +582,7 @@ static void serializeThread(SerializationInfo *info) {
 		pushUpValue(info->luaState, upVal);
 		// >>>>> permTbl indexTbl ...... thread upVal
 
-		serializeObject(info);
+		serialize(info);
 
 		lua_pop(info->luaState, 1);
 		// >>>>> permTbl indexTbl ...... thread
@@ -607,7 +597,7 @@ static void serializeThread(SerializationInfo *info) {
 	// >>>>> permTbl indexTbl ...... thread nil
 
 	// Use nil as a terminator
-	serializeObject(info);
+	serialize(info);
 
 	lua_pop(info->luaState, 1);
 	// >>>>> permTbl indexTbl ...... thread
@@ -627,7 +617,7 @@ static void serializeProto(SerializationInfo *info) {
 		pushObject(info->luaState, &proto->k[i]);
 		// >>>>> permTbl indexTbl ...... proto const
 
-		serializeObject(info);
+		serialize(info);
 
 		lua_pop(info->luaState, 1);
 		// >>>>> permTbl indexTbl ...... proto
@@ -643,7 +633,7 @@ static void serializeProto(SerializationInfo *info) {
 		pushProto(info->luaState, proto->p[i]);
 		// >>>>> permTbl indexTbl ...... proto subProto */
 
-		serializeObject(info);
+		serialize(info);
 
 		lua_pop(info->luaState, 1);
 		// >>>>> permTbl indexTbl ...... proto
@@ -666,7 +656,7 @@ static void serializeProto(SerializationInfo *info) {
 		pushString(info->luaState, proto->upvalues[i]);
 		// >>>>> permTbl indexTbl ...... proto str
 
-		serializeObject(info);
+		serialize(info);
 
 		lua_pop(info->luaState, 1);
 		// >>>>> permTbl indexTbl ...... proto
@@ -680,7 +670,7 @@ static void serializeProto(SerializationInfo *info) {
 		pushString(info->luaState, proto->locvars[i].varname);
 		// >>>>> permTbl indexTbl ...... proto str
 
-		serializeObject(info);
+		serialize(info);
 
 		lua_pop(info->luaState, 1);
 		// >>>>> permTbl indexTbl ...... proto
@@ -694,7 +684,7 @@ static void serializeProto(SerializationInfo *info) {
 	pushString(info->luaState, proto->source);
 	// >>>>> permTbl indexTbl ...... proto sourceStr
 
-	serializeObject(info);
+	serialize(info);
 
 	lua_pop(info->luaState, 1);
 	// >>>>> permTbl indexTbl ...... proto
@@ -757,7 +747,7 @@ static void serializeUpValue(SerializationInfo *info) {
 	pushObject(info->luaState, upValue->v);
 	// >>>>> permTbl indexTbl ...... obj
 
-	serializeObject(info);
+	serialize(info);
 	// >>>>> permTbl indexTbl ...... obj
 }
 
@@ -787,7 +777,7 @@ static void serializeUserData(SerializationInfo *info) {
 	}
 
 	// >>>>> permTbl rootObj ...... udata metaTbl/nil
-	serializeObject(info);
+	serialize(info);
 
 	lua_pop(info->luaState, 1);
 	/* perms reftbl ... udata */
diff --git a/engines/sword25/util/lua_unserializer.cpp b/engines/sword25/util/lua_unserializer.cpp
index 69cb764..803c79c 100644
--- a/engines/sword25/util/lua_unserializer.cpp
+++ b/engines/sword25/util/lua_unserializer.cpp
@@ -40,7 +40,7 @@ struct UnSerializationInfo {
 	Common::ReadStream *readStream;
 };
 
-static void unserializeObject(UnSerializationInfo *info);
+static void unserialize(UnSerializationInfo *info);
 
 static void unserializeBoolean(UnSerializationInfo *info);
 static void unserializeNumber(UnSerializationInfo *info);
@@ -74,7 +74,7 @@ void unserializeLua(lua_State *luaState, Common::ReadStream *readStream) {
 	lua_gc(luaState, LUA_GCSTOP, 0);
 
 	// Unserialize the root object
-	unserializeObject(&info);
+	unserialize(&info);
 	// >>>>> permTbl indexTbl rootObj
 
 	// Re-start garbage collection
@@ -85,7 +85,7 @@ void unserializeLua(lua_State *luaState, Common::ReadStream *readStream) {
 	// >>>>> permTbl rootObj
 }
 
-/* The object is left on the stack. This is primarily used by unpersist, but
+/* The object is left on the stack. This is primarily used by unserialize, but
  * may be used by GCed objects that may incur cycles in order to preregister
  * the object. */
 static void registerObjectInIndexTable(UnSerializationInfo *info, int index) {
@@ -105,7 +105,7 @@ static void registerObjectInIndexTable(UnSerializationInfo *info, int index) {
 	// >>>>> permTbl indexTbl ...... obj
 }
 
-static void unserializeObject(UnSerializationInfo *info) {
+static void unserialize(UnSerializationInfo *info) {
 	// >>>>> permTbl indexTbl ......
 
 	// Make sure there is enough room on the stack
@@ -241,7 +241,7 @@ static void unserializeSpecialTable(UnSerializationInfo *info, int index) {
 	// Make sure there is enough room on the stack
 	lua_checkstack(info->luaState, 1);
 
-	unserializeObject(info);
+	unserialize(info);
 
 	// >>>>> permTbl indexTbl ...... spfunc
 	lua_call(info->luaState, 0, 1);
@@ -262,7 +262,7 @@ static void unserializeLiteralTable(UnSerializationInfo *info, int index) {
 	// >>>>> permTbl indexTbl ...... tbl
 
 	// Unserialize metatable
-	unserializeObject(info);
+	unserialize(info);
 	// >>>>> permTbl indexTbl ...... tbl ?metaTbl/nil?
 
 	if (lua_istable(info->luaState, -1)) {
@@ -279,7 +279,7 @@ static void unserializeLiteralTable(UnSerializationInfo *info, int index) {
 
 	while (1) {
 		// >>>>> permTbl indexTbl ...... tbl
-		unserializeObject(info);
+		unserialize(info);
 		// >>>>> permTbl indexTbl ...... tbl key/nil
 
 		// The table serialization is nil terminated
@@ -292,7 +292,7 @@ static void unserializeLiteralTable(UnSerializationInfo *info, int index) {
 		}
 
 		// >>>>> permTbl indexTbl ...... tbl key
-		unserializeObject(info);
+		unserialize(info);
 		// >>>>> permTbl indexTbl ...... tbl value
 
 		lua_rawset(info->luaState, -3);
@@ -317,142 +317,6 @@ void unserializeTable(UnSerializationInfo *info, int index) {
 	}
 }
 
-
-
-void *lua_realloc(lua_State *luaState, void *block, size_t osize, size_t nsize) {
-	global_State *globalState = G(luaState);
-
-	block = (*globalState->frealloc)(globalState->ud, block, osize, nsize);
-	globalState->totalbytes = (globalState->totalbytes - osize) + nsize;
-
-	return block;
-}
-
-#define lua_malloc(luaState, nsize) lua_realloc(luaState, nullptr, 0, nsize)
-#define lua_reallocv(luaState, block, on, n, e) lua_realloc(luaState, block, (on) * (e), (n) * (e))
-#define lua_reallocvector(luaState, vec, oldn, n, T) ((vec) = (T *)(lua_reallocv(luaState, vec, oldn, n, sizeof(T))))
-#define lua_newVector(luaState, num, T) ((T *)lua_reallocv(luaState, nullptr, 0, num, sizeof(T)))
-#define lua_new(luaState,T) (T *)lua_malloc(luaState, sizeof(T))
-
-void lua_linkObjToGC(lua_State *luaState, GCObject *obj, lu_byte type) {
-	global_State *globalState = G(luaState);
-
-	obj->gch.next = globalState->rootgc;
-	globalState->rootgc = obj;
-	obj->gch.marked = luaC_white(globalState);
-	obj->gch.tt = type;
-}
-
-#define sizeLclosure(n) ((sizeof(LClosure)) + sizeof(TValue *) * ((n) - 1))
-
-Closure *newLClosure(lua_State *luaState, byte numUpValues, Table *env) {
-	Closure *newClosure = (Closure *)lua_malloc(luaState, sizeLclosure(numUpValues));
-
-	lua_linkObjToGC(luaState, obj2gco(newClosure), LUA_TFUNCTION);
-
-	newClosure->l.isC = 0;
-	newClosure->l.env = env;
-	newClosure->l.nupvalues = numUpValues;
-
-	while (numUpValues--) {
-		newClosure->l.upvals[numUpValues] = NULL;
-	}
-
-	return newClosure;
-}
-
-static void pushClosure(lua_State *luaState, Closure *closure) {
-	TValue obj;
-	setclvalue(luaState, &obj, closure);
-	pushObject(luaState, &obj);
-}
-
-Proto *createProto(lua_State *luaState) {
-	Proto *newProto = (Proto *)lua_malloc(luaState, sizeof(Proto));
-	lua_linkObjToGC(luaState, obj2gco(newProto), LUA_TPROTO);
-
-	newProto->k = NULL;
-	newProto->sizek = 0;
-	newProto->p = NULL;
-	newProto->sizep = 0;
-	newProto->code = NULL;
-	newProto->sizecode = 0;
-	newProto->sizelineinfo = 0;
-	newProto->sizeupvalues = 0;
-	newProto->nups = 0;
-	newProto->upvalues = NULL;
-	newProto->numparams = 0;
-	newProto->is_vararg = 0;
-	newProto->maxstacksize = 0;
-	newProto->lineinfo = NULL;
-	newProto->sizelocvars = 0;
-	newProto->locvars = NULL;
-	newProto->linedefined = 0;
-	newProto->lastlinedefined = 0;
-	newProto->source = NULL;
-
-	return newProto;
-}
-
-TString *createString(lua_State *luaState, const char *str, size_t len) {
-	TString *res;
-	lua_pushlstring(luaState, str, len);
-
-	res = rawtsvalue(luaState->top - 1);
-	lua_pop(luaState, 1);
-
-	return res;
-}
-
-static Proto *makeFakeProto(lua_State *L, lu_byte nups) {
-	Proto *p = createProto(L);
-
-	p->sizelineinfo = 1;
-	p->lineinfo = lua_newVector(L, 1, int);
-	p->lineinfo[0] = 1;
-	p->sizecode = 1;
-	p->code = lua_newVector(L, 1, Instruction);
-	p->code[0] = CREATE_ABC(OP_RETURN, 0, 1, 0);
-	p->source = createString(L, "", 0);
-	p->maxstacksize = 2;
-	p->nups = nups;
-	p->sizek = 0;
-	p->sizep = 0;
-
-	return p;
-}
-
-static UpVal *createUpValue(lua_State *luaState, int stackpos) {
-	UpVal *upValue = (UpVal *)lua_malloc(luaState, sizeof(UpVal));
-	lua_linkObjToGC(luaState, (GCObject *)upValue, LUA_TUPVAL);
-	upValue->tt = LUA_TUPVAL;
-	upValue->v = &upValue->u.value;
-	upValue->u.l.prev = NULL;
-	upValue->u.l.next = NULL;
-
-	const TValue *o2 = (TValue *)getObject(luaState, stackpos);
-	upValue->v->value = o2->value;
-	upValue->v->tt = o2->tt;
-	checkliveness(G(L), upValue->v);
-
-	return upValue;
-}
-
-static void unboxUpValue(lua_State *luaState) {
-	// >>>>> ...... func
-	LClosure *lcl;
-	UpVal *uv;
-
-	lcl = (LClosure *)clvalue(getObject(luaState, -1));
-	uv = lcl->upvals[0];
-
-	lua_pop(luaState, 1);
-	// >>>>> ......
-
-	pushUpValue(luaState, uv);
-	// >>>>> ...... upValue
-}
-
 void unserializeFunction(UnSerializationInfo *info, int index) {
 	// >>>>> permTbl indexTbl ......
 
@@ -461,7 +325,7 @@ void unserializeFunction(UnSerializationInfo *info, int index) {
 
 	byte numUpValues = info->readStream->readByte();
 
-	LClosure *lclosure = (LClosure *)newLClosure(info->luaState, numUpValues, hvalue(&info->luaState->l_gt));
+	LClosure *lclosure = (LClosure *)lua_newLclosure(info->luaState, numUpValues, hvalue(&info->luaState->l_gt));
 	pushClosure(info->luaState, (Closure *)lclosure);
 	// >>>>> permTbl indexTbl ...... func
 
@@ -484,7 +348,7 @@ void unserializeFunction(UnSerializationInfo *info, int index) {
 	registerObjectInIndexTable(info, index);
 
 	// Now that it's safe, we can get the real proto
-	unserializeObject(info);
+	unserialize(info);
 	// >>>>> permTbl indexTbl ...... func proto
 
 	lclosure->p = gco2p(getObject(info->luaState, -1)->value.gc);
@@ -494,7 +358,7 @@ void unserializeFunction(UnSerializationInfo *info, int index) {
 
 	for (byte i = 0; i < numUpValues; ++i) {
 		// >>>>> permTbl indexTbl ...... func
-		unserializeObject(info);
+		unserialize(info);
 		// >>>>> permTbl indexTbl ...... func func2
 
 		unboxUpValue(info->luaState);
@@ -506,7 +370,7 @@ void unserializeFunction(UnSerializationInfo *info, int index) {
 	}
 
 	// Finally, the fenv
-	unserializeObject(info);
+	unserialize(info);
 
 	// >>>>> permTbl indexTbl ...... func ?fenv/nil?
 	if (!lua_isnil(info->luaState, -1)) {
@@ -522,81 +386,6 @@ void unserializeFunction(UnSerializationInfo *info, int index) {
 	// >>>>> permTbl indexTbl ...... func
 }
 
-static void correctStack(lua_State *L, TValue *oldstack) {
-	CallInfo *ci;
-	GCObject *up;
-	L->top = (L->top - oldstack) + L->stack;
-	for (up = L->openupval; up != NULL; up = up->gch.next)
-		gco2uv(up)->v = (gco2uv(up)->v - oldstack) + L->stack;
-	for (ci = L->base_ci; ci <= L->ci; ci++) {
-		ci->top = (ci->top - oldstack) + L->stack;
-		ci->base = (ci->base - oldstack) + L->stack;
-		ci->func = (ci->func - oldstack) + L->stack;
-	}
-	L->base = (L->base - oldstack) + L->stack;
-}
-
-void lua_reallocstack(lua_State *L, int newsize) {
-	TValue *oldstack = L->stack;
-	int realsize = newsize + 1 + EXTRA_STACK;
-
-	lua_reallocvector(L, L->stack, L->stacksize, realsize, TValue);
-	L->stacksize = realsize;
-	L->stack_last = L->stack + newsize;
-	correctStack(L, oldstack);
-}
-
-void lua_growstack(lua_State *L, int n) {
-	// Double size is enough?
-	if (n <= L->stacksize) {
-		lua_reallocstack(L, 2 * L->stacksize);
-	} else {
-		lua_reallocstack(L, L->stacksize + n);
-	}
-}
-
-void lua_reallocCallInfo(lua_State *lauState, int newsize) {
-	CallInfo *oldci = lauState->base_ci;
-	lua_reallocvector(lauState, lauState->base_ci, lauState->size_ci, newsize, CallInfo);
-
-	lauState->size_ci = newsize;
-	lauState->ci = (lauState->ci - oldci) + lauState->base_ci;
-	lauState->end_ci = lauState->base_ci + lauState->size_ci - 1;
-}
-
-void unboxUpVal(lua_State *luaState) {
-	// >>>>> ... func
-	LClosure *lcl;
-	UpVal *uv;
-
-	lcl = (LClosure *)(&getObject(luaState, -1)->value.gc->cl);
-	uv = lcl->upvals[0];
-	lua_pop(luaState, 1);
-	// >>>>> ...
-	pushUpValue(luaState, uv);
-	// >>>>> ... upVal
-}
-
-/* Does basically the opposite of luaC_link().
- * Right now this function is rather inefficient; it requires traversing the
- * entire root GC set in order to find one object. If the GC list were doubly
- * linked this would be much easier, but there's no reason for Lua to have
- * that. */
-static void GCUnlink(lua_State *luaState, GCObject *gco) {
-	GCObject *prevslot;
-	if (G(luaState)->rootgc == gco) {
-		G(luaState)->rootgc = G(luaState)->rootgc->gch.next;
-		return;
-	}
-
-	prevslot = G(luaState)->rootgc;
-	while (prevslot->gch.next != gco) {
-		prevslot = prevslot->gch.next;
-	}
-
-	prevslot->gch.next = prevslot->gch.next->gch.next;
-}
-
 void unserializeThread(UnSerializationInfo *info, int index) {
 	// >>>>> permTbl indexTbl ......
 
@@ -619,7 +408,7 @@ void unserializeThread(UnSerializationInfo *info, int index) {
 	// very bottom of the stack
 	L2->top--;
 	for (uint32 i = 0; i < stackSize; ++i) {
-		unserializeObject(info);
+		unserialize(info);
 		// L1: permTbl indexTbl ...... thread obj*
 	}
 
@@ -679,7 +468,7 @@ void unserializeThread(UnSerializationInfo *info, int index) {
 	global_State *g = G(L2);
 
 	while (true) {
-		unserializeObject(info);
+		unserialize(info);
 		// >>>>> permTbl indexTbl ...... thread upVal/nil
 
 		// The list is terminated by a nil
@@ -691,7 +480,7 @@ void unserializeThread(UnSerializationInfo *info, int index) {
 		}
 
 		// >>>>> permTbl indexTbl ...... thread boxedUpVal
-		unboxUpVal(info->luaState);
+		unboxUpValue(info->luaState);
 		// >>>>> permTbl indexTbl ...... thread boxedUpVal
 
 		uv = &(getObject(info->luaState, -1)->value.gc->uv);
@@ -722,48 +511,6 @@ void unserializeThread(UnSerializationInfo *info, int index) {
 	}
 }
 
-TString *lua_newlstr(lua_State *luaState, const char *str, size_t len) {
-	lua_pushlstring(luaState, str, len);
-	TString *luaStr = &(luaState->top - 1)->value.gc->ts;
-
-	lua_pop(luaState, 1);
-
-	return luaStr;
-}
-
-void lua_link(lua_State *luaState, GCObject *o, lu_byte tt) {
-	global_State *g = G(luaState);
-	o->gch.next = g->rootgc;
-	g->rootgc = o;
-	o->gch.marked = luaC_white(g);
-	o->gch.tt = tt;
-}
-
-Proto *lua_newproto(lua_State *luaState) {
-	Proto *f = (Proto *)lua_malloc(luaState, sizeof(Proto));
-	lua_link(luaState, obj2gco(f), LUA_TPROTO);
-	f->k = NULL;
-	f->sizek = 0;
-	f->p = NULL;
-	f->sizep = 0;
-	f->code = NULL;
-	f->sizecode = 0;
-	f->sizelineinfo = 0;
-	f->sizeupvalues = 0;
-	f->nups = 0;
-	f->upvalues = NULL;
-	f->numparams = 0;
-	f->is_vararg = 0;
-	f->maxstacksize = 0;
-	f->lineinfo = NULL;
-	f->sizelocvars = 0;
-	f->locvars = NULL;
-	f->linedefined = 0;
-	f->lastlinedefined = 0;
-	f->source = NULL;
-	return f;
-}
-
 void unserializeProto(UnSerializationInfo *info, int index) {
 	// >>>>> permTbl indexTbl ......
 
@@ -793,7 +540,7 @@ void unserializeProto(UnSerializationInfo *info, int index) {
 	lua_reallocvector(info->luaState, p->k, 0, sizek, TValue);
 	for (int i = 0; i < sizek; ++i) {
 		// >>>>> permTbl indexTbl ...... proto
-		unserializeObject(info);
+		unserialize(info);
 		// >>>>> permTbl indexTbl ...... proto  k
 
 		setobj2s(info->luaState, &p->k[i], getObject(info->luaState, -1));
@@ -810,7 +557,7 @@ void unserializeProto(UnSerializationInfo *info, int index) {
 	lua_reallocvector(info->luaState, p->p, 0, sizep, Proto *);
 	for (int i = 0; i < sizep; ++i) {
 		// >>>>> permTbl indexTbl ...... proto
-		unserializeObject(info);
+		unserialize(info);
 		// >>>>> permTbl indexTbl ...... proto  subproto
 
 		p->p[i] = (Proto *)getObject(info->luaState, -1)->value.gc;
@@ -834,7 +581,7 @@ void unserializeProto(UnSerializationInfo *info, int index) {
 		lua_reallocvector(info->luaState, p->upvalues, 0, p->sizeupvalues, TString *);
 		for (int i = 0; i < p->sizeupvalues; ++i) {
 			// >>>>> permTbl indexTbl ...... proto
-			unserializeObject(info);
+			unserialize(info);
 			// >>>>> permTbl indexTbl ...... proto str
 
 			p->upvalues[i] = lua_newlstr(info->luaState, lua_tostring(info->luaState, -1), strlen(lua_tostring(info->luaState, -1)));
@@ -850,7 +597,7 @@ void unserializeProto(UnSerializationInfo *info, int index) {
 		lua_reallocvector(info->luaState, p->locvars, 0, p->sizelocvars, LocVar);
 		for (int i = 0; i < p->sizelocvars; ++i) {
 			// >>>>> permTbl indexTbl ...... proto
-			unserializeObject(info);
+			unserialize(info);
 			// >>>>> permTbl indexTbl ...... proto str
 
 			p->locvars[i].varname = lua_newlstr(info->luaState, lua_tostring(info->luaState, -1), strlen(lua_tostring(info->luaState, -1)));
@@ -864,7 +611,7 @@ void unserializeProto(UnSerializationInfo *info, int index) {
 	// >>>>> permTbl indexTbl ...... proto
 
 	// Read in source string
-	unserializeObject(info);
+	unserialize(info);
 	// >>>>> permTbl indexTbl ...... proto sourceStr
 
 	p->source = lua_newlstr(info->luaState, lua_tostring(info->luaState, -1), strlen(lua_tostring(info->luaState, -1)));
@@ -890,75 +637,18 @@ void unserializeProto(UnSerializationInfo *info, int index) {
 	p->maxstacksize = info->readStream->readByte();
 }
 
-Closure *lua_newLclosure(lua_State *luaState, int numElements, Table *elementTable) {
-	Closure *c = (Closure *)lua_malloc(luaState, sizeLclosure(numElements));
-	lua_link(luaState, obj2gco(c), LUA_TFUNCTION);
-	c->l.isC = 0;
-	c->l.env = elementTable;
-	c->l.nupvalues = cast_byte(numElements);
-
-	while (numElements--) {
-		c->l.upvals[numElements] = NULL;
-	}
-
-	return c;
-}
-
-static UpVal *makeUpVal(lua_State *luaState, int stackPos) {
-	UpVal *uv = lua_new(luaState, UpVal);
-	lua_link(luaState, (GCObject *)uv, LUA_TUPVAL);
-	uv->tt = LUA_TUPVAL;
-	uv->v = &uv->u.value;
-	uv->u.l.prev = NULL;
-	uv->u.l.next = NULL;
-
-	setobj(luaState, uv->v, getObject(luaState, stackPos));
-
-	return uv;
-}
-
-/**
- * The GC is not fond of finding upvalues in tables. We get around this
- * during persistence using a weakly keyed table, so that the GC doesn't
- * bother to mark them. This won't work in unpersisting, however, since
- * if we make the values weak they'll be collected (since nothing else
- * references them). Our solution, during unpersisting, is to represent
- * upvalues as dummy functions, each with one upvalue.
- */
-static void boxupval_start(lua_State *luaState) {
-	LClosure *closure;
-	closure = (LClosure *)lua_newLclosure(luaState, 1, hvalue(&luaState->l_gt));
-	pushClosure(luaState, (Closure *)closure);
-	// >>>>> ...... func
-	closure->p = makeFakeProto(luaState, 1);
-
-	// Temporarily initialize the upvalue to nil
-	lua_pushnil(luaState);
-	closure->upvals[0] = makeUpVal(luaState, -1);
-	lua_pop(luaState, 1);
-}
-
-static void boxupval_finish(lua_State *luaState) {
-	// >>>>> ...... func obj
-	LClosure *lcl = (LClosure *)clvalue(getObject(luaState, -2));
-
-	lcl->upvals[0]->u.value = *getObject(luaState, -1);
-	lua_pop(luaState, 1);
-	// >>>>> ...... func
-}
-
 void unserializeUpValue(UnSerializationInfo *info, int index) {
 	// >>>>> permTbl indexTbl ......
-	lua_checkstack(upi->L, 2);
+	lua_checkstack(info->luaState, 2);
 
-	boxupval_start(upi->L);
+	boxUpValue_start(info->luaState);
 	// >>>>> permTbl indexTbl ...... func
 	registerObjectInIndexTable(info, index);
 
-	unserializeObject(info);
+	unserialize(info);
 	// >>>>> permTbl indexTbl ...... func obj
 
-	boxupval_finish(upi->L);
+	boxUpValue_finish(info->luaState);
 	// >>>>> permTbl indexTbl ...... func
 }
 
@@ -970,7 +660,7 @@ void unserializeUserData(UnSerializationInfo *info, int index) {
 
 	int isspecial = info->readStream->readSint32LE();
 	if (isspecial) {
-		unserializeObject(info);
+		unserialize(info);
 		// >>>>> permTbl indexTbl ...... specialFunc
 
 		lua_call(info->luaState, 0, 1);
@@ -981,12 +671,12 @@ void unserializeUserData(UnSerializationInfo *info, int index) {
 		// >>>>> permTbl indexTbl ...... udata
 		registerObjectInIndexTable(info, index);
 
-		info->readStream->read(lua_touserdata(upi->L, -1), length);
+		info->readStream->read(lua_touserdata(info->luaState, -1), length);
 
-		unserializeObject(info);
+		unserialize(info);
 		// >>>>> permTbl indexTbl ...... udata metaTable/nil
 
-		lua_setmetatable(upi->L, -2);
+		lua_setmetatable(info->luaState, -2);
 		// >>>>> permTbl indexTbl ...... udata
 	}
 	// >>>>> permTbl indexTbl ...... udata
@@ -998,7 +688,7 @@ void unserializePermanent(UnSerializationInfo *info, int index) {
 	// Make sure there is enough room on the stack
 	lua_checkstack(info->luaState, 2);
 
-	unserializeObject(info);
+	unserialize(info);
 	// >>>>> permTbl indexTbl ...... permKey
 
 	lua_gettable(info->luaState, 1);


Commit: 0b8482b55fb38147927d2c27478aae59c0f98dab
    https://github.com/scummvm/scummvm/commit/0b8482b55fb38147927d2c27478aae59c0f98dab
Author: RichieSams (adastley at gmail.com)
Date: 2014-12-30T13:42:02-06:00

Commit Message:
SWORD25: Update module.mk with lua serialization changes

Changed paths:
    engines/sword25/module.mk



diff --git a/engines/sword25/module.mk b/engines/sword25/module.mk
index 234baec..0135f53 100644
--- a/engines/sword25/module.mk
+++ b/engines/sword25/module.mk
@@ -82,9 +82,10 @@ MODULE_OBJS := \
 	util/lua/lvm.o \
 	util/lua/lzio.o \
 	util/lua/scummvm_file.o \
-	util/pluto/pdep.o \
-	util/pluto/pluto.o \
-	util/pluto/plzio.o
+	util/double_serializer.o \
+	util/lua_serialization_util.o \
+	util/lua_serializer.o \
+	util/lua_unserializer.o
 
 # This module can be built as a plugin
 ifeq ($(ENABLE_SWORD25), DYNAMIC_PLUGIN)


Commit: a188b31d15711bd86725ca4feb0dc36fb2ab71ac
    https://github.com/scummvm/scummvm/commit/a188b31d15711bd86725ca4feb0dc36fb2ab71ac
Author: RichieSams (adastley at gmail.com)
Date: 2014-12-30T13:42:45-06:00

Commit Message:
SWORD25: Use new lua serialization functions to persist state

Changed paths:
    engines/sword25/kernel/outputpersistenceblock.cpp
    engines/sword25/kernel/outputpersistenceblock.h
    engines/sword25/script/luascript.cpp



diff --git a/engines/sword25/kernel/outputpersistenceblock.cpp b/engines/sword25/kernel/outputpersistenceblock.cpp
index 9003b5d..3e25fce 100644
--- a/engines/sword25/kernel/outputpersistenceblock.cpp
+++ b/engines/sword25/kernel/outputpersistenceblock.cpp
@@ -41,6 +41,13 @@ OutputPersistenceBlock::OutputPersistenceBlock() {
 	_data.reserve(INITIAL_BUFFER_SIZE);
 }
 
+void OutputPersistenceBlock::write(const void *data, uint32 size) {
+	writeMarker(BLOCK_MARKER);
+
+	write(size);
+	rawWrite(data, size);
+}
+
 void OutputPersistenceBlock::write(int32 value) {
 	writeMarker(SINT_MARKER);
 	value = TO_LE_32(value);
diff --git a/engines/sword25/kernel/outputpersistenceblock.h b/engines/sword25/kernel/outputpersistenceblock.h
index c7d8dfc..bdbd20d 100644
--- a/engines/sword25/kernel/outputpersistenceblock.h
+++ b/engines/sword25/kernel/outputpersistenceblock.h
@@ -41,6 +41,7 @@ class OutputPersistenceBlock : public PersistenceBlock {
 public:
 	OutputPersistenceBlock();
 
+	void write(const void *data, uint32 size);
 	void write(int32 value);
 	void write(uint32 value);
 	void write(float value);
diff --git a/engines/sword25/script/luascript.cpp b/engines/sword25/script/luascript.cpp
index f62a080..6cf287c 100644
--- a/engines/sword25/script/luascript.cpp
+++ b/engines/sword25/script/luascript.cpp
@@ -29,7 +29,7 @@
  *
  */
 
-#include "common/array.h"
+#include "common/memstream.h"
 #include "common/debug-channels.h"
 
 #include "sword25/sword25.h"
@@ -43,7 +43,7 @@
 #include "sword25/util/lua/lua.h"
 #include "sword25/util/lua/lualib.h"
 #include "sword25/util/lua/lauxlib.h"
-#include "sword25/util/pluto/pluto.h"
+#include "sword25/util/lua_serialization.h"
 
 namespace Sword25 {
 
@@ -112,10 +112,6 @@ bool LuaScriptEngine::init() {
 	// Place the error handler function in the Lua registry, and remember the index
 	_pcallErrorhandlerRegistryIndex = luaL_ref(_state, LUA_REGISTRYINDEX);
 
-	// Initialize the Pluto-Persistence library
-	luaopen_pluto(_state);
-	lua_pop(_state, 1);
-
 	// Initialize debugging callback
 	if (DebugMan.isDebugChannelEnabled(kDebugScript)) {
 		int mask = 0;
@@ -383,19 +379,8 @@ bool pushPermanentsTable(lua_State *L, PERMANENT_TABLE_TYPE tableType) {
 
 	return true;
 }
-}
-
-namespace {
-int chunkwriter(lua_State *L, const void *p, size_t sz, void *ud) {
-	Common::Array<byte> & chunkData = *reinterpret_cast<Common::Array<byte> * >(ud);
-	const byte *buffer = reinterpret_cast<const byte *>(p);
 
-	while (sz--)
-		chunkData.push_back(*buffer++);
-
-	return 1;
-}
-}
+} // End of anonymous namespace
 
 bool LuaScriptEngine::persist(OutputPersistenceBlock &writer) {
 	// Empty the Lua stack. pluto_persist() xepects that the stack is empty except for its parameters
@@ -409,12 +394,12 @@ bool LuaScriptEngine::persist(OutputPersistenceBlock &writer) {
 	pushPermanentsTable(_state, PTT_PERSIST);
 	lua_getglobal(_state, "_G");
 
-	// Lua persists and stores the data in a Common::Array
-	Common::Array<byte> chunkData;
-	pluto_persist(_state, chunkwriter, &chunkData);
+	// Lua persists and stores the data in a WriteStream
+	Common::MemoryWriteStreamDynamic writeStream;
+	Lua::serializeLua(_state, &writeStream);
 
 	// Persistenzdaten in den Writer schreiben.
-	writer.writeByteArray(chunkData);
+	writer.write(writeStream.getData(), writeStream.size());
 
 	// Die beiden Tabellen vom Stack nehmen.
 	lua_pop(_state, 2);
@@ -424,24 +409,6 @@ bool LuaScriptEngine::persist(OutputPersistenceBlock &writer) {
 
 namespace {
 
-struct ChunkreaderData {
-	void   *BufferPtr;
-	size_t  Size;
-	bool    BufferReturned;
-};
-
-const char *chunkreader(lua_State *L, void *ud, size_t *sz) {
-	ChunkreaderData &cd = *reinterpret_cast<ChunkreaderData *>(ud);
-
-	if (!cd.BufferReturned) {
-		cd.BufferReturned = true;
-		*sz = cd.Size;
-		return reinterpret_cast<const char *>(cd.BufferPtr);
-	} else {
-		return 0;
-	}
-}
-
 void clearGlobalTable(lua_State *L, const char **exceptions) {
 	// Iterate over all elements of the global table
 	lua_pushvalue(L, LUA_GLOBALSINDEX);
@@ -479,7 +446,8 @@ void clearGlobalTable(lua_State *L, const char **exceptions) {
 	// Perform garbage collection, so that all removed elements are deleted
 	lua_gc(L, LUA_GCCOLLECT, 0);
 }
-}
+
+} // End of anonymous namespace
 
 bool LuaScriptEngine::unpersist(InputPersistenceBlock &reader) {
 	// Empty the Lua stack. pluto_persist() xepects that the stack is empty except for its parameters
@@ -512,14 +480,9 @@ bool LuaScriptEngine::unpersist(InputPersistenceBlock &reader) {
 	// Persisted Lua data
 	Common::Array<byte> chunkData;
 	reader.readByteArray(chunkData);
+	Common::MemoryReadStream readStream(&chunkData[0], chunkData.size(), DisposeAfterUse::NO);
 
-	// Chunk-Reader initialisation. It is used with pluto_unpersist to restore read data
-	ChunkreaderData cd;
-	cd.BufferPtr = &chunkData[0];
-	cd.Size = chunkData.size();
-	cd.BufferReturned = false;
-
-	pluto_unpersist(_state, chunkreader, &cd);
+	Lua::unserializeLua(_state, &readStream);
 
 	// Permanents-Table is removed from stack
 	lua_remove(_state, -2);
@@ -527,7 +490,7 @@ bool LuaScriptEngine::unpersist(InputPersistenceBlock &reader) {
 	// The read elements in the global table about
 	lua_pushnil(_state);
 	while (lua_next(_state, -2) != 0) {
-		// The referenec to the global table (_G) must not be overwritten, or ticks from Lua total
+		// The reference to the global table (_G) must not be overwritten, or ticks from Lua total
 		bool isGlobalReference = lua_isstring(_state, -2) && strcmp(lua_tostring(_state, -2), "_G") == 0;
 		if (!isGlobalReference) {
 			lua_pushvalue(_state, -2);


Commit: 97c35714ce3986b99848a780f6b195a63f8910b7
    https://github.com/scummvm/scummvm/commit/97c35714ce3986b99848a780f6b195a63f8910b7
Author: RichieSams (adastley at gmail.com)
Date: 2014-12-30T15:40:29-06:00

Commit Message:
SWORD25: Rename lua serialization functions to use 'persist' in order to match the rest of the engine

Changed paths:
  A engines/sword25/util/lua_persist.cpp
  A engines/sword25/util/lua_persistence.h
  A engines/sword25/util/lua_persistence_util.cpp
  A engines/sword25/util/lua_persistence_util.h
  A engines/sword25/util/lua_unpersist.cpp
  R engines/sword25/util/lua_serialization.h
  R engines/sword25/util/lua_serialization_util.cpp
  R engines/sword25/util/lua_serialization_util.h
  R engines/sword25/util/lua_serializer.cpp
  R engines/sword25/util/lua_unserializer.cpp
    engines/sword25/module.mk
    engines/sword25/script/luascript.cpp



diff --git a/engines/sword25/module.mk b/engines/sword25/module.mk
index 0135f53..129b4f0 100644
--- a/engines/sword25/module.mk
+++ b/engines/sword25/module.mk
@@ -83,9 +83,9 @@ MODULE_OBJS := \
 	util/lua/lzio.o \
 	util/lua/scummvm_file.o \
 	util/double_serializer.o \
-	util/lua_serialization_util.o \
-	util/lua_serializer.o \
-	util/lua_unserializer.o
+	util/lua_persistence_util.o \
+	util/lua_persist.o \
+	util/lua_unpersist.o
 
 # This module can be built as a plugin
 ifeq ($(ENABLE_SWORD25), DYNAMIC_PLUGIN)
diff --git a/engines/sword25/script/luascript.cpp b/engines/sword25/script/luascript.cpp
index 6cf287c..e932895 100644
--- a/engines/sword25/script/luascript.cpp
+++ b/engines/sword25/script/luascript.cpp
@@ -43,7 +43,7 @@
 #include "sword25/util/lua/lua.h"
 #include "sword25/util/lua/lualib.h"
 #include "sword25/util/lua/lauxlib.h"
-#include "sword25/util/lua_serialization.h"
+#include "sword25/util/lua_persistence.h"
 
 namespace Sword25 {
 
@@ -396,7 +396,7 @@ bool LuaScriptEngine::persist(OutputPersistenceBlock &writer) {
 
 	// Lua persists and stores the data in a WriteStream
 	Common::MemoryWriteStreamDynamic writeStream;
-	Lua::serializeLua(_state, &writeStream);
+	Lua::persistLua(_state, &writeStream);
 
 	// Persistenzdaten in den Writer schreiben.
 	writer.write(writeStream.getData(), writeStream.size());
@@ -482,7 +482,7 @@ bool LuaScriptEngine::unpersist(InputPersistenceBlock &reader) {
 	reader.readByteArray(chunkData);
 	Common::MemoryReadStream readStream(&chunkData[0], chunkData.size(), DisposeAfterUse::NO);
 
-	Lua::unserializeLua(_state, &readStream);
+	Lua::unpersistLua(_state, &readStream);
 
 	// Permanents-Table is removed from stack
 	lua_remove(_state, -2);
diff --git a/engines/sword25/util/lua_persist.cpp b/engines/sword25/util/lua_persist.cpp
new file mode 100644
index 0000000..b9c0b13
--- /dev/null
+++ b/engines/sword25/util/lua_persist.cpp
@@ -0,0 +1,787 @@
+/* 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.
+ *
+ */
+
+#include "sword25/util/lua_persistence.h"
+
+#include "sword25/util/double_serializer.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 serialize(SerializationInfo *info);
+
+static void serializeBoolean(SerializationInfo *info);
+static void serializeNumber(SerializationInfo *info);
+static void serializeString(SerializationInfo *info);
+static void serializeTable(SerializationInfo *info);
+static void serializeFunction(SerializationInfo *info);
+static void serializeThread(SerializationInfo *info);
+static void serializeProto(SerializationInfo *info);
+static void serializeUpValue(SerializationInfo *info);
+static void serializeUserData(SerializationInfo *info);
+
+
+void persistLua(lua_State *luaState, Common::WriteStream *writeStream) {
+	SerializationInfo info;
+	info.luaState = luaState;
+	info.writeStream = writeStream;
+	info.counter = 0u;
+
+	// 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
+	serialize(&info);
+
+	// Return the stack back to the original state
+	lua_remove(luaState, 2);
+	// >>>>> permTbl rootObj
+}
+
+static void serialize(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 nil off the stack
+	lua_pop(info->luaState, 1);
+
+	// Write out a flag that indicates that this is a real object
+	info->writeStream->writeByte(1);
+
+	// If the object itself is nil, then write out a zero as a placeholder
+	if (lua_isnil(info->luaState, -1)) {
+		info->writeStream->writeByte(0);
+
+		return;
+	}
+
+	// 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
+		serialize(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:
+		serializeBoolean(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:
+		serializeNumber(info);
+		break;
+	case LUA_TSTRING:
+		serializeString(info);
+		break;
+	case LUA_TTABLE:
+		serializeTable(info);
+		break;
+	case LUA_TFUNCTION:
+		serializeFunction(info);
+		break;
+	case LUA_TTHREAD:
+		serializeThread(info);
+		break;
+	case LUA_TPROTO:
+		serializeProto(info);
+		break;
+	case LUA_TUPVAL:
+		serializeUpValue(info);
+		break;
+	case LUA_TUSERDATA:
+		serializeUserData(info);
+		break;
+	default:
+		assert(0);
+	}
+}
+
+static void serializeBoolean(SerializationInfo *info) {
+	int value = lua_toboolean(info->luaState, -1);
+
+	info->writeStream->writeSint32LE(value);
+}
+
+static void serializeNumber(SerializationInfo *info) {
+	lua_Number value = lua_tonumber(info->luaState, -1);
+
+	#if 1
+		Util::SerializedDouble serializedValue(Util::encodeDouble(value));
+
+		info->writeStream->writeUint32LE(serializedValue.significandOne);
+		info->writeStream->writeUint32LE(serializedValue.signAndSignificandTwo);
+		info->writeStream->writeSint16LE(serializedValue.exponent);
+	#else
+		// NOTE: We need to store a double. Unfortunately, we have to accommodate endianness.
+		// Also, I don't know if we can assume all compilers use IEEE double
+		// Therefore, I have chosen to store the double as a string.
+		Common::String buffer = Common::String::format("%f", value);
+
+		info->writeStream->write(buffer.c_str(), buffer.size());
+	#endif
+
+}
+
+static void serializeString(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
+	serialize(info);
+
+	lua_pop(info->luaState, 2);
+	// >>>>> permTbl indexTbl ...... obj
+
+	return true;
+}
+
+static void serializeTable(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 */
+	serialize(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
+		serialize(info);
+
+		lua_pop(info->luaState, 1);
+		// >>>>> permTbl indexTbl ...... tbl k v */
+
+		// Serialize the value
+		serialize(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
+
+	serialize(info);
+
+	lua_pop(info->luaState, 1);
+	// >>>>> permTbl indexTbl ...... tbl
+}
+
+static void serializeFunction(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 */
+
+		serialize(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
+
+			serialize(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
+		serialize(info);
+
+		lua_pop(info->luaState, 1);
+		// >>>>> permTbl indexTbl ...... func
+	}
+}
+
+static void serializeThread(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) {
+		serialize(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
+
+		serialize(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
+	serialize(info);
+
+	lua_pop(info->luaState, 1);
+	// >>>>> permTbl indexTbl ...... thread
+}
+
+static void serializeProto(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
+
+		serialize(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 */
+
+		serialize(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
+
+		serialize(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
+
+		serialize(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
+
+	serialize(info);
+
+	lua_pop(info->luaState, 1);
+	// >>>>> permTbl indexTbl ...... proto
+
+	// Serialize line numbers
+	info->writeStream->writeSint32LE(proto->sizelineinfo);
+
+	if (proto->sizelineinfo) {
+		uint32 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 serializeUpValue(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
+
+	serialize(info);
+	// >>>>> permTbl indexTbl ...... obj
+}
+
+static void serializeUserData(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
+	serialize(info);
+
+	lua_pop(info->luaState, 1);
+	/* perms reftbl ... udata */
+}
+
+
+} // End of namespace Lua
diff --git a/engines/sword25/util/lua_persistence.h b/engines/sword25/util/lua_persistence.h
new file mode 100644
index 0000000..cf7d7e0
--- /dev/null
+++ b/engines/sword25/util/lua_persistence.h
@@ -0,0 +1,44 @@
+/* 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.
+ *
+ */
+
+#ifndef LUA_SERIALIZATION_H
+#define LUA_SERIALIZATION_H
+
+#include "sword25/util/lua/lua.h"
+
+
+namespace Common {
+class WriteStream;
+class ReadStream;
+}
+
+
+namespace Lua {
+
+#define PERMANENT_TYPE 101
+
+void persistLua(lua_State *luaState, Common::WriteStream *writeStream);
+void unpersistLua(lua_State *luaState, Common::ReadStream *readStream);
+
+} // End of namespace Lua
+
+#endif
diff --git a/engines/sword25/util/lua_persistence_util.cpp b/engines/sword25/util/lua_persistence_util.cpp
new file mode 100644
index 0000000..8365f5d
--- /dev/null
+++ b/engines/sword25/util/lua_persistence_util.cpp
@@ -0,0 +1,346 @@
+/* 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 distri8buted 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.
+ *
+ */
+
+#include "sword25/util/lua_persistence_util.h"
+
+#include "common/scummsys.h"
+
+#include "lua/lobject.h"
+#include "lua/lstate.h"
+#include "lua/lgc.h"
+#include "lua/lopcodes.h"
+
+
+namespace Lua {
+
+void *lua_realloc(lua_State *luaState, void *block, size_t osize, size_t nsize) {
+	global_State *globalState = G(luaState);
+
+	block = (*globalState->frealloc)(globalState->ud, block, osize, nsize);
+	globalState->totalbytes = (globalState->totalbytes - osize) + nsize;
+
+	return block;
+}
+
+void pushObject(lua_State *luaState, TValue *obj) {
+	setobj2s(luaState, luaState->top, obj);
+
+	api_check(luaState, luaState->top < luaState->ci->top);
+	luaState->top++;
+}
+
+void pushProto(lua_State *luaState, Proto *proto) {
+	TValue obj;
+	setptvalue(luaState, &obj, proto);
+
+	pushObject(luaState, &obj);
+}
+
+void pushUpValue(lua_State *luaState, UpVal *upval) {
+	TValue obj;
+
+	obj.value.gc = cast(GCObject *, upval);
+	obj.tt = LUA_TUPVAL;
+	checkliveness(G(L), obj);
+
+	pushObject(luaState, &obj);
+}
+
+void pushString(lua_State *luaState, TString *str) {
+	TValue o;
+	setsvalue(luaState, &o, str);
+
+	pushObject(luaState, &o);
+}
+
+/* A simple reimplementation of the unfortunately static function luaA_index.
+ * Does not support the global table, registry, or upvalues. */
+StkId getObject(lua_State *luaState, int stackpos) {
+	if (stackpos > 0) {
+		lua_assert(luaState->base + stackpos - 1 < luaState->top);
+		return luaState->base + stackpos - 1;
+	} else {
+		lua_assert(L->top - stackpos >= L->base);
+		return luaState->top + stackpos;
+	}
+}
+
+void lua_linkObjToGC(lua_State *luaState, GCObject *obj, lu_byte type) {
+	global_State *globalState = G(luaState);
+
+	obj->gch.next = globalState->rootgc;
+	globalState->rootgc = obj;
+	obj->gch.marked = luaC_white(globalState);
+	obj->gch.tt = type;
+}
+
+Closure *lua_newLclosure(lua_State *luaState, int numElements, Table *elementTable) {
+	Closure *c = (Closure *)lua_malloc(luaState, sizeLclosure(numElements));
+	lua_linkObjToGC(luaState, obj2gco(c), LUA_TFUNCTION);
+
+	c->l.isC = 0;
+	c->l.env = elementTable;
+	c->l.nupvalues = cast_byte(numElements);
+
+	while (numElements--) {
+		c->l.upvals[numElements] = NULL;
+	}
+
+	return c;
+}
+
+void pushClosure(lua_State *luaState, Closure *closure) {
+	TValue obj;
+	setclvalue(luaState, &obj, closure);
+	pushObject(luaState, &obj);
+}
+
+Proto *createProto(lua_State *luaState) {
+	Proto *newProto = (Proto *)lua_malloc(luaState, sizeof(Proto));
+	lua_linkObjToGC(luaState, obj2gco(newProto), LUA_TPROTO);
+
+	newProto->k = NULL;
+	newProto->sizek = 0;
+	newProto->p = NULL;
+	newProto->sizep = 0;
+	newProto->code = NULL;
+	newProto->sizecode = 0;
+	newProto->sizelineinfo = 0;
+	newProto->sizeupvalues = 0;
+	newProto->nups = 0;
+	newProto->upvalues = NULL;
+	newProto->numparams = 0;
+	newProto->is_vararg = 0;
+	newProto->maxstacksize = 0;
+	newProto->lineinfo = NULL;
+	newProto->sizelocvars = 0;
+	newProto->locvars = NULL;
+	newProto->linedefined = 0;
+	newProto->lastlinedefined = 0;
+	newProto->source = NULL;
+
+	return newProto;
+}
+
+TString *createString(lua_State *luaState, const char *str, size_t len) {
+	TString *res;
+	lua_pushlstring(luaState, str, len);
+
+	res = rawtsvalue(luaState->top - 1);
+	lua_pop(luaState, 1);
+
+	return res;
+}
+
+Proto *makeFakeProto(lua_State *L, lu_byte nups) {
+	Proto *p = createProto(L);
+
+	p->sizelineinfo = 1;
+	p->lineinfo = lua_newVector(L, 1, int);
+	p->lineinfo[0] = 1;
+	p->sizecode = 1;
+	p->code = lua_newVector(L, 1, Instruction);
+	p->code[0] = CREATE_ABC(OP_RETURN, 0, 1, 0);
+	p->source = createString(L, "", 0);
+	p->maxstacksize = 2;
+	p->nups = nups;
+	p->sizek = 0;
+	p->sizep = 0;
+
+	return p;
+}
+
+UpVal *createUpValue(lua_State *luaState, int stackpos) {
+	UpVal *upValue = (UpVal *)lua_malloc(luaState, sizeof(UpVal));
+	lua_linkObjToGC(luaState, (GCObject *)upValue, LUA_TUPVAL);
+	upValue->tt = LUA_TUPVAL;
+	upValue->v = &upValue->u.value;
+	upValue->u.l.prev = NULL;
+	upValue->u.l.next = NULL;
+
+	const TValue *o2 = (TValue *)getObject(luaState, stackpos);
+	upValue->v->value = o2->value;
+	upValue->v->tt = o2->tt;
+	checkliveness(G(L), upValue->v);
+
+	return upValue;
+}
+
+void unboxUpValue(lua_State *luaState) {
+	// >>>>> ...... func
+	LClosure *lcl;
+	UpVal *uv;
+
+	lcl = (LClosure *)clvalue(getObject(luaState, -1));
+	uv = lcl->upvals[0];
+
+	lua_pop(luaState, 1);
+	// >>>>> ......
+
+	pushUpValue(luaState, uv);
+	// >>>>> ...... upValue
+}
+
+size_t appendStackToStack_reverse(lua_State *from, lua_State *to) {
+	for (StkId id = from->top - 1; id >= from->stack; --id) {
+		setobj2s(to, to->top, id);
+		to->top++;
+	}
+
+	return from->top - from->stack;
+}
+
+void correctStack(lua_State *L, TValue *oldstack) {
+	CallInfo *ci;
+	GCObject *up;
+	L->top = (L->top - oldstack) + L->stack;
+	for (up = L->openupval; up != NULL; up = up->gch.next)
+		gco2uv(up)->v = (gco2uv(up)->v - oldstack) + L->stack;
+	for (ci = L->base_ci; ci <= L->ci; ci++) {
+		ci->top = (ci->top - oldstack) + L->stack;
+		ci->base = (ci->base - oldstack) + L->stack;
+		ci->func = (ci->func - oldstack) + L->stack;
+	}
+	L->base = (L->base - oldstack) + L->stack;
+}
+
+void lua_reallocstack(lua_State *L, int newsize) {
+	TValue *oldstack = L->stack;
+	int realsize = newsize + 1 + EXTRA_STACK;
+
+	lua_reallocvector(L, L->stack, L->stacksize, realsize, TValue);
+	L->stacksize = realsize;
+	L->stack_last = L->stack + newsize;
+	correctStack(L, oldstack);
+}
+
+void lua_growstack(lua_State *L, int n) {
+	// Double size is enough?
+	if (n <= L->stacksize) {
+		lua_reallocstack(L, 2 * L->stacksize);
+	} else {
+		lua_reallocstack(L, L->stacksize + n);
+	}
+}
+
+void lua_reallocCallInfo(lua_State *lauState, int newsize) {
+	CallInfo *oldci = lauState->base_ci;
+	lua_reallocvector(lauState, lauState->base_ci, lauState->size_ci, newsize, CallInfo);
+
+	lauState->size_ci = newsize;
+	lauState->ci = (lauState->ci - oldci) + lauState->base_ci;
+	lauState->end_ci = lauState->base_ci + lauState->size_ci - 1;
+}
+
+void GCUnlink(lua_State *luaState, GCObject *gco) {
+	GCObject *prevslot;
+	if (G(luaState)->rootgc == gco) {
+		G(luaState)->rootgc = G(luaState)->rootgc->gch.next;
+		return;
+	}
+
+	prevslot = G(luaState)->rootgc;
+	while (prevslot->gch.next != gco) {
+		prevslot = prevslot->gch.next;
+	}
+
+	prevslot->gch.next = prevslot->gch.next->gch.next;
+}
+
+TString *lua_newlstr(lua_State *luaState, const char *str, size_t len) {
+	lua_pushlstring(luaState, str, len);
+	TString *luaStr = &(luaState->top - 1)->value.gc->ts;
+
+	lua_pop(luaState, 1);
+
+	return luaStr;
+}
+
+void lua_link(lua_State *luaState, GCObject *o, lu_byte tt) {
+	global_State *g = G(luaState);
+	o->gch.next = g->rootgc;
+	g->rootgc = o;
+	o->gch.marked = luaC_white(g);
+	o->gch.tt = tt;
+}
+
+Proto *lua_newproto(lua_State *luaState) {
+	Proto *f = (Proto *)lua_malloc(luaState, sizeof(Proto));
+	lua_link(luaState, obj2gco(f), LUA_TPROTO);
+	f->k = NULL;
+	f->sizek = 0;
+	f->p = NULL;
+	f->sizep = 0;
+	f->code = NULL;
+	f->sizecode = 0;
+	f->sizelineinfo = 0;
+	f->sizeupvalues = 0;
+	f->nups = 0;
+	f->upvalues = NULL;
+	f->numparams = 0;
+	f->is_vararg = 0;
+	f->maxstacksize = 0;
+	f->lineinfo = NULL;
+	f->sizelocvars = 0;
+	f->locvars = NULL;
+	f->linedefined = 0;
+	f->lastlinedefined = 0;
+	f->source = NULL;
+	return f;
+}
+
+UpVal *makeUpValue(lua_State *luaState, int stackPos) {
+	UpVal *uv = lua_new(luaState, UpVal);
+	lua_link(luaState, (GCObject *)uv, LUA_TUPVAL);
+	uv->tt = LUA_TUPVAL;
+	uv->v = &uv->u.value;
+	uv->u.l.prev = NULL;
+	uv->u.l.next = NULL;
+
+	setobj(luaState, uv->v, getObject(luaState, stackPos));
+
+	return uv;
+}
+
+void boxUpValue_start(lua_State *luaState) {
+	LClosure *closure;
+	closure = (LClosure *)lua_newLclosure(luaState, 1, hvalue(&luaState->l_gt));
+	pushClosure(luaState, (Closure *)closure);
+	// >>>>> ...... func
+	closure->p = makeFakeProto(luaState, 1);
+
+	// Temporarily initialize the upvalue to nil
+	lua_pushnil(luaState);
+	closure->upvals[0] = makeUpValue(luaState, -1);
+	lua_pop(luaState, 1);
+}
+
+void boxUpValue_finish(lua_State *luaState) {
+	// >>>>> ...... func obj
+	LClosure *lcl = (LClosure *)clvalue(getObject(luaState, -2));
+
+	lcl->upvals[0]->u.value = *getObject(luaState, -1);
+	lua_pop(luaState, 1);
+	// >>>>> ...... func
+}
+
+} // End of namespace Lua
diff --git a/engines/sword25/util/lua_persistence_util.h b/engines/sword25/util/lua_persistence_util.h
new file mode 100644
index 0000000..345996f
--- /dev/null
+++ b/engines/sword25/util/lua_persistence_util.h
@@ -0,0 +1,98 @@
+/* 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 distri8buted 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.
+ *
+ */
+
+#ifndef LUA_SERIALIZATION_UTIL_H
+#define LUA_SERIALIZATION_UTIL_H
+
+
+struct lua_State;
+
+#include "lua/lobject.h"
+
+typedef TValue *StkId;
+
+namespace Lua {
+
+#define lua_malloc(luaState, nsize) lua_realloc(luaState, nullptr, 0, nsize)
+#define lua_reallocv(luaState, block, on, n, e) lua_realloc(luaState, block, (on) * (e), (n) * (e))
+#define lua_reallocvector(luaState, vec, oldn, n, T) ((vec) = (T *)(lua_reallocv(luaState, vec, oldn, n, sizeof(T))))
+#define lua_newVector(luaState, num, T) ((T *)lua_reallocv(luaState, nullptr, 0, num, sizeof(T)))
+#define lua_new(luaState,T) (T *)lua_malloc(luaState, sizeof(T))
+
+void *lua_realloc(lua_State *luaState, void *block, size_t osize, size_t nsize);
+
+void pushObject(lua_State *luaState, TValue *obj);
+void pushProto(lua_State *luaState, Proto *proto);
+void pushUpValue(lua_State *luaState, UpVal *upval);
+void pushString(lua_State *luaState, TString *str);
+
+StkId getObject(lua_State *luaState, int stackpos);
+
+void lua_linkObjToGC(lua_State *luaState, GCObject *obj, lu_byte type);
+
+#define sizeLclosure(n) ((sizeof(LClosure)) + sizeof(TValue *) * ((n) - 1))
+
+Closure *lua_newLclosure(lua_State *luaState, int numElements, Table *elementTable);
+void pushClosure(lua_State *luaState, Closure *closure);
+
+Proto *createProto(lua_State *luaState);
+Proto *makeFakeProto(lua_State *L, lu_byte nups);
+
+TString *createString(lua_State *luaState, const char *str, size_t len);
+
+UpVal *createUpValue(lua_State *luaState, int stackpos);
+void unboxUpValue(lua_State *luaState);
+
+/* Appends one stack to another stack, but the stack is reversed in the process */
+size_t appendStackToStack_reverse(lua_State *from, lua_State *to);
+void correctStack(lua_State *L, TValue *oldstack);
+void lua_reallocstack(lua_State *L, int newsize);
+void lua_growstack(lua_State *L, int n);
+
+void lua_reallocCallInfo(lua_State *lauState, int newsize);
+
+/* Does basically the opposite of luaC_link().
+ * Right now this function is rather inefficient; it requires traversing the
+ * entire root GC set in order to find one object. If the GC list were doubly
+ * linked this would be much easier, but there's no reason for Lua to have
+ * that. */
+void GCUnlink(lua_State *luaState, GCObject *gco);
+
+TString *lua_newlstr(lua_State *luaState, const char *str, size_t len);
+void lua_link(lua_State *luaState, GCObject *o, lu_byte tt);
+Proto *lua_newproto(lua_State *luaState) ;
+
+UpVal *makeUpValue(lua_State *luaState, int stackPos);
+/**
+ * The GC is not fond of finding upvalues in tables. We get around this
+ * during persistence using a weakly keyed table, so that the GC doesn't
+ * bother to mark them. This won't work in unpersisting, however, since
+ * if we make the values weak they'll be collected (since nothing else
+ * references them). Our solution, during unpersisting, is to represent
+ * upvalues as dummy functions, each with one upvalue.
+ */
+void boxUpValue_start(lua_State *luaState);
+void boxUpValue_finish(lua_State *luaState);
+
+} // End of namespace Lua
+
+#endif
diff --git a/engines/sword25/util/lua_serialization.h b/engines/sword25/util/lua_serialization.h
deleted file mode 100644
index 549ea79..0000000
--- a/engines/sword25/util/lua_serialization.h
+++ /dev/null
@@ -1,44 +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.
- *
- */
-
-#ifndef LUA_SERIALIZATION_H
-#define LUA_SERIALIZATION_H
-
-#include "sword25/util/lua/lua.h"
-
-
-namespace Common {
-class WriteStream;
-class ReadStream;
-}
-
-
-namespace Lua {
-
-#define PERMANENT_TYPE 101
-
-void serializeLua(lua_State *luaState, Common::WriteStream *writeStream);
-void unserializeLua(lua_State *luaState, Common::ReadStream *readStream);
-
-} // End of namespace Lua
-
-#endif
diff --git a/engines/sword25/util/lua_serialization_util.cpp b/engines/sword25/util/lua_serialization_util.cpp
deleted file mode 100644
index fc3f73e..0000000
--- a/engines/sword25/util/lua_serialization_util.cpp
+++ /dev/null
@@ -1,346 +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 distri8buted 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.
- *
- */
-
-#include "sword25/util/lua_serialization_util.h"
-
-#include "common/scummsys.h"
-
-#include "lua/lobject.h"
-#include "lua/lstate.h"
-#include "lua/lgc.h"
-#include "lua/lopcodes.h"
-
-
-namespace Lua {
-
-void *lua_realloc(lua_State *luaState, void *block, size_t osize, size_t nsize) {
-	global_State *globalState = G(luaState);
-
-	block = (*globalState->frealloc)(globalState->ud, block, osize, nsize);
-	globalState->totalbytes = (globalState->totalbytes - osize) + nsize;
-
-	return block;
-}
-
-void pushObject(lua_State *luaState, TValue *obj) {
-	setobj2s(luaState, luaState->top, obj);
-
-	api_check(luaState, luaState->top < luaState->ci->top);
-	luaState->top++;
-}
-
-void pushProto(lua_State *luaState, Proto *proto) {
-	TValue obj;
-	setptvalue(luaState, &obj, proto);
-
-	pushObject(luaState, &obj);
-}
-
-void pushUpValue(lua_State *luaState, UpVal *upval) {
-	TValue obj;
-
-	obj.value.gc = cast(GCObject *, upval);
-	obj.tt = LUA_TUPVAL;
-	checkliveness(G(L), obj);
-
-	pushObject(luaState, &obj);
-}
-
-void pushString(lua_State *luaState, TString *str) {
-	TValue o;
-	setsvalue(luaState, &o, str);
-
-	pushObject(luaState, &o);
-}
-
-/* A simple reimplementation of the unfortunately static function luaA_index.
- * Does not support the global table, registry, or upvalues. */
-StkId getObject(lua_State *luaState, int stackpos) {
-	if (stackpos > 0) {
-		lua_assert(luaState->base + stackpos - 1 < luaState->top);
-		return luaState->base + stackpos - 1;
-	} else {
-		lua_assert(L->top - stackpos >= L->base);
-		return luaState->top + stackpos;
-	}
-}
-
-void lua_linkObjToGC(lua_State *luaState, GCObject *obj, lu_byte type) {
-	global_State *globalState = G(luaState);
-
-	obj->gch.next = globalState->rootgc;
-	globalState->rootgc = obj;
-	obj->gch.marked = luaC_white(globalState);
-	obj->gch.tt = type;
-}
-
-Closure *lua_newLclosure(lua_State *luaState, int numElements, Table *elementTable) {
-	Closure *c = (Closure *)lua_malloc(luaState, sizeLclosure(numElements));
-	lua_linkObjToGC(luaState, obj2gco(c), LUA_TFUNCTION);
-
-	c->l.isC = 0;
-	c->l.env = elementTable;
-	c->l.nupvalues = cast_byte(numElements);
-
-	while (numElements--) {
-		c->l.upvals[numElements] = NULL;
-	}
-
-	return c;
-}
-
-void pushClosure(lua_State *luaState, Closure *closure) {
-	TValue obj;
-	setclvalue(luaState, &obj, closure);
-	pushObject(luaState, &obj);
-}
-
-Proto *createProto(lua_State *luaState) {
-	Proto *newProto = (Proto *)lua_malloc(luaState, sizeof(Proto));
-	lua_linkObjToGC(luaState, obj2gco(newProto), LUA_TPROTO);
-
-	newProto->k = NULL;
-	newProto->sizek = 0;
-	newProto->p = NULL;
-	newProto->sizep = 0;
-	newProto->code = NULL;
-	newProto->sizecode = 0;
-	newProto->sizelineinfo = 0;
-	newProto->sizeupvalues = 0;
-	newProto->nups = 0;
-	newProto->upvalues = NULL;
-	newProto->numparams = 0;
-	newProto->is_vararg = 0;
-	newProto->maxstacksize = 0;
-	newProto->lineinfo = NULL;
-	newProto->sizelocvars = 0;
-	newProto->locvars = NULL;
-	newProto->linedefined = 0;
-	newProto->lastlinedefined = 0;
-	newProto->source = NULL;
-
-	return newProto;
-}
-
-TString *createString(lua_State *luaState, const char *str, size_t len) {
-	TString *res;
-	lua_pushlstring(luaState, str, len);
-
-	res = rawtsvalue(luaState->top - 1);
-	lua_pop(luaState, 1);
-
-	return res;
-}
-
-Proto *makeFakeProto(lua_State *L, lu_byte nups) {
-	Proto *p = createProto(L);
-
-	p->sizelineinfo = 1;
-	p->lineinfo = lua_newVector(L, 1, int);
-	p->lineinfo[0] = 1;
-	p->sizecode = 1;
-	p->code = lua_newVector(L, 1, Instruction);
-	p->code[0] = CREATE_ABC(OP_RETURN, 0, 1, 0);
-	p->source = createString(L, "", 0);
-	p->maxstacksize = 2;
-	p->nups = nups;
-	p->sizek = 0;
-	p->sizep = 0;
-
-	return p;
-}
-
-UpVal *createUpValue(lua_State *luaState, int stackpos) {
-	UpVal *upValue = (UpVal *)lua_malloc(luaState, sizeof(UpVal));
-	lua_linkObjToGC(luaState, (GCObject *)upValue, LUA_TUPVAL);
-	upValue->tt = LUA_TUPVAL;
-	upValue->v = &upValue->u.value;
-	upValue->u.l.prev = NULL;
-	upValue->u.l.next = NULL;
-
-	const TValue *o2 = (TValue *)getObject(luaState, stackpos);
-	upValue->v->value = o2->value;
-	upValue->v->tt = o2->tt;
-	checkliveness(G(L), upValue->v);
-
-	return upValue;
-}
-
-void unboxUpValue(lua_State *luaState) {
-	// >>>>> ...... func
-	LClosure *lcl;
-	UpVal *uv;
-
-	lcl = (LClosure *)clvalue(getObject(luaState, -1));
-	uv = lcl->upvals[0];
-
-	lua_pop(luaState, 1);
-	// >>>>> ......
-
-	pushUpValue(luaState, uv);
-	// >>>>> ...... upValue
-}
-
-size_t appendStackToStack_reverse(lua_State *from, lua_State *to) {
-	for (StkId id = from->top - 1; id >= from->stack; --id) {
-		setobj2s(to, to->top, id);
-		to->top++;
-	}
-
-	return from->top - from->stack;
-}
-
-void correctStack(lua_State *L, TValue *oldstack) {
-	CallInfo *ci;
-	GCObject *up;
-	L->top = (L->top - oldstack) + L->stack;
-	for (up = L->openupval; up != NULL; up = up->gch.next)
-		gco2uv(up)->v = (gco2uv(up)->v - oldstack) + L->stack;
-	for (ci = L->base_ci; ci <= L->ci; ci++) {
-		ci->top = (ci->top - oldstack) + L->stack;
-		ci->base = (ci->base - oldstack) + L->stack;
-		ci->func = (ci->func - oldstack) + L->stack;
-	}
-	L->base = (L->base - oldstack) + L->stack;
-}
-
-void lua_reallocstack(lua_State *L, int newsize) {
-	TValue *oldstack = L->stack;
-	int realsize = newsize + 1 + EXTRA_STACK;
-
-	lua_reallocvector(L, L->stack, L->stacksize, realsize, TValue);
-	L->stacksize = realsize;
-	L->stack_last = L->stack + newsize;
-	correctStack(L, oldstack);
-}
-
-void lua_growstack(lua_State *L, int n) {
-	// Double size is enough?
-	if (n <= L->stacksize) {
-		lua_reallocstack(L, 2 * L->stacksize);
-	} else {
-		lua_reallocstack(L, L->stacksize + n);
-	}
-}
-
-void lua_reallocCallInfo(lua_State *lauState, int newsize) {
-	CallInfo *oldci = lauState->base_ci;
-	lua_reallocvector(lauState, lauState->base_ci, lauState->size_ci, newsize, CallInfo);
-
-	lauState->size_ci = newsize;
-	lauState->ci = (lauState->ci - oldci) + lauState->base_ci;
-	lauState->end_ci = lauState->base_ci + lauState->size_ci - 1;
-}
-
-void GCUnlink(lua_State *luaState, GCObject *gco) {
-	GCObject *prevslot;
-	if (G(luaState)->rootgc == gco) {
-		G(luaState)->rootgc = G(luaState)->rootgc->gch.next;
-		return;
-	}
-
-	prevslot = G(luaState)->rootgc;
-	while (prevslot->gch.next != gco) {
-		prevslot = prevslot->gch.next;
-	}
-
-	prevslot->gch.next = prevslot->gch.next->gch.next;
-}
-
-TString *lua_newlstr(lua_State *luaState, const char *str, size_t len) {
-	lua_pushlstring(luaState, str, len);
-	TString *luaStr = &(luaState->top - 1)->value.gc->ts;
-
-	lua_pop(luaState, 1);
-
-	return luaStr;
-}
-
-void lua_link(lua_State *luaState, GCObject *o, lu_byte tt) {
-	global_State *g = G(luaState);
-	o->gch.next = g->rootgc;
-	g->rootgc = o;
-	o->gch.marked = luaC_white(g);
-	o->gch.tt = tt;
-}
-
-Proto *lua_newproto(lua_State *luaState) {
-	Proto *f = (Proto *)lua_malloc(luaState, sizeof(Proto));
-	lua_link(luaState, obj2gco(f), LUA_TPROTO);
-	f->k = NULL;
-	f->sizek = 0;
-	f->p = NULL;
-	f->sizep = 0;
-	f->code = NULL;
-	f->sizecode = 0;
-	f->sizelineinfo = 0;
-	f->sizeupvalues = 0;
-	f->nups = 0;
-	f->upvalues = NULL;
-	f->numparams = 0;
-	f->is_vararg = 0;
-	f->maxstacksize = 0;
-	f->lineinfo = NULL;
-	f->sizelocvars = 0;
-	f->locvars = NULL;
-	f->linedefined = 0;
-	f->lastlinedefined = 0;
-	f->source = NULL;
-	return f;
-}
-
-UpVal *makeUpValue(lua_State *luaState, int stackPos) {
-	UpVal *uv = lua_new(luaState, UpVal);
-	lua_link(luaState, (GCObject *)uv, LUA_TUPVAL);
-	uv->tt = LUA_TUPVAL;
-	uv->v = &uv->u.value;
-	uv->u.l.prev = NULL;
-	uv->u.l.next = NULL;
-
-	setobj(luaState, uv->v, getObject(luaState, stackPos));
-
-	return uv;
-}
-
-void boxUpValue_start(lua_State *luaState) {
-	LClosure *closure;
-	closure = (LClosure *)lua_newLclosure(luaState, 1, hvalue(&luaState->l_gt));
-	pushClosure(luaState, (Closure *)closure);
-	// >>>>> ...... func
-	closure->p = makeFakeProto(luaState, 1);
-
-	// Temporarily initialize the upvalue to nil
-	lua_pushnil(luaState);
-	closure->upvals[0] = makeUpValue(luaState, -1);
-	lua_pop(luaState, 1);
-}
-
-void boxUpValue_finish(lua_State *luaState) {
-	// >>>>> ...... func obj
-	LClosure *lcl = (LClosure *)clvalue(getObject(luaState, -2));
-
-	lcl->upvals[0]->u.value = *getObject(luaState, -1);
-	lua_pop(luaState, 1);
-	// >>>>> ...... func
-}
-
-} // End of namespace Lua
diff --git a/engines/sword25/util/lua_serialization_util.h b/engines/sword25/util/lua_serialization_util.h
deleted file mode 100644
index 345996f..0000000
--- a/engines/sword25/util/lua_serialization_util.h
+++ /dev/null
@@ -1,98 +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 distri8buted 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.
- *
- */
-
-#ifndef LUA_SERIALIZATION_UTIL_H
-#define LUA_SERIALIZATION_UTIL_H
-
-
-struct lua_State;
-
-#include "lua/lobject.h"
-
-typedef TValue *StkId;
-
-namespace Lua {
-
-#define lua_malloc(luaState, nsize) lua_realloc(luaState, nullptr, 0, nsize)
-#define lua_reallocv(luaState, block, on, n, e) lua_realloc(luaState, block, (on) * (e), (n) * (e))
-#define lua_reallocvector(luaState, vec, oldn, n, T) ((vec) = (T *)(lua_reallocv(luaState, vec, oldn, n, sizeof(T))))
-#define lua_newVector(luaState, num, T) ((T *)lua_reallocv(luaState, nullptr, 0, num, sizeof(T)))
-#define lua_new(luaState,T) (T *)lua_malloc(luaState, sizeof(T))
-
-void *lua_realloc(lua_State *luaState, void *block, size_t osize, size_t nsize);
-
-void pushObject(lua_State *luaState, TValue *obj);
-void pushProto(lua_State *luaState, Proto *proto);
-void pushUpValue(lua_State *luaState, UpVal *upval);
-void pushString(lua_State *luaState, TString *str);
-
-StkId getObject(lua_State *luaState, int stackpos);
-
-void lua_linkObjToGC(lua_State *luaState, GCObject *obj, lu_byte type);
-
-#define sizeLclosure(n) ((sizeof(LClosure)) + sizeof(TValue *) * ((n) - 1))
-
-Closure *lua_newLclosure(lua_State *luaState, int numElements, Table *elementTable);
-void pushClosure(lua_State *luaState, Closure *closure);
-
-Proto *createProto(lua_State *luaState);
-Proto *makeFakeProto(lua_State *L, lu_byte nups);
-
-TString *createString(lua_State *luaState, const char *str, size_t len);
-
-UpVal *createUpValue(lua_State *luaState, int stackpos);
-void unboxUpValue(lua_State *luaState);
-
-/* Appends one stack to another stack, but the stack is reversed in the process */
-size_t appendStackToStack_reverse(lua_State *from, lua_State *to);
-void correctStack(lua_State *L, TValue *oldstack);
-void lua_reallocstack(lua_State *L, int newsize);
-void lua_growstack(lua_State *L, int n);
-
-void lua_reallocCallInfo(lua_State *lauState, int newsize);
-
-/* Does basically the opposite of luaC_link().
- * Right now this function is rather inefficient; it requires traversing the
- * entire root GC set in order to find one object. If the GC list were doubly
- * linked this would be much easier, but there's no reason for Lua to have
- * that. */
-void GCUnlink(lua_State *luaState, GCObject *gco);
-
-TString *lua_newlstr(lua_State *luaState, const char *str, size_t len);
-void lua_link(lua_State *luaState, GCObject *o, lu_byte tt);
-Proto *lua_newproto(lua_State *luaState) ;
-
-UpVal *makeUpValue(lua_State *luaState, int stackPos);
-/**
- * The GC is not fond of finding upvalues in tables. We get around this
- * during persistence using a weakly keyed table, so that the GC doesn't
- * bother to mark them. This won't work in unpersisting, however, since
- * if we make the values weak they'll be collected (since nothing else
- * references them). Our solution, during unpersisting, is to represent
- * upvalues as dummy functions, each with one upvalue.
- */
-void boxUpValue_start(lua_State *luaState);
-void boxUpValue_finish(lua_State *luaState);
-
-} // End of namespace Lua
-
-#endif
diff --git a/engines/sword25/util/lua_serializer.cpp b/engines/sword25/util/lua_serializer.cpp
deleted file mode 100644
index 55b6257..0000000
--- a/engines/sword25/util/lua_serializer.cpp
+++ /dev/null
@@ -1,787 +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.
- *
- */
-
-#include "sword25/util/lua_serialization.h"
-
-#include "sword25/util/double_serializer.h"
-#include "sword25/util/lua_serialization_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 serialize(SerializationInfo *info);
-
-static void serializeBoolean(SerializationInfo *info);
-static void serializeNumber(SerializationInfo *info);
-static void serializeString(SerializationInfo *info);
-static void serializeTable(SerializationInfo *info);
-static void serializeFunction(SerializationInfo *info);
-static void serializeThread(SerializationInfo *info);
-static void serializeProto(SerializationInfo *info);
-static void serializeUpValue(SerializationInfo *info);
-static void serializeUserData(SerializationInfo *info);
-
-
-void serializeLua(lua_State *luaState, Common::WriteStream *writeStream) {
-	SerializationInfo info;
-	info.luaState = luaState;
-	info.writeStream = writeStream;
-	info.counter = 0u;
-
-	// 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
-	serialize(&info);
-
-	// Return the stack back to the original state
-	lua_remove(luaState, 2);
-	// >>>>> permTbl rootObj
-}
-
-static void serialize(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 nil off the stack
-	lua_pop(info->luaState, 1);
-
-	// Write out a flag that indicates that this is a real object
-	info->writeStream->writeByte(1);
-
-	// If the object itself is nil, then write out a zero as a placeholder
-	if (lua_isnil(info->luaState, -1)) {
-		info->writeStream->writeByte(0);
-
-		return;
-	}
-
-	// 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
-		serialize(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:
-		serializeBoolean(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:
-		serializeNumber(info);
-		break;
-	case LUA_TSTRING:
-		serializeString(info);
-		break;
-	case LUA_TTABLE:
-		serializeTable(info);
-		break;
-	case LUA_TFUNCTION:
-		serializeFunction(info);
-		break;
-	case LUA_TTHREAD:
-		serializeThread(info);
-		break;
-	case LUA_TPROTO:
-		serializeProto(info);
-		break;
-	case LUA_TUPVAL:
-		serializeUpValue(info);
-		break;
-	case LUA_TUSERDATA:
-		serializeUserData(info);
-		break;
-	default:
-		assert(0);
-	}
-}
-
-static void serializeBoolean(SerializationInfo *info) {
-	int value = lua_toboolean(info->luaState, -1);
-
-	info->writeStream->writeSint32LE(value);
-}
-
-static void serializeNumber(SerializationInfo *info) {
-	lua_Number value = lua_tonumber(info->luaState, -1);
-
-	#if 1
-		Util::SerializedDouble serializedValue(Util::encodeDouble(value));
-
-		info->writeStream->writeUint32LE(serializedValue.significandOne);
-		info->writeStream->writeUint32LE(serializedValue.signAndSignificandTwo);
-		info->writeStream->writeSint16LE(serializedValue.exponent);
-	#else
-		// NOTE: We need to store a double. Unfortunately, we have to accommodate endianness.
-		// Also, I don't know if we can assume all compilers use IEEE double
-		// Therefore, I have chosen to store the double as a string.
-		Common::String buffer = Common::String::format("%f", value);
-
-		info->writeStream->write(buffer.c_str(), buffer.size());
-	#endif
-
-}
-
-static void serializeString(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
-	serialize(info);
-
-	lua_pop(info->luaState, 2);
-	// >>>>> permTbl indexTbl ...... obj
-
-	return true;
-}
-
-static void serializeTable(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 */
-	serialize(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
-		serialize(info);
-
-		lua_pop(info->luaState, 1);
-		// >>>>> permTbl indexTbl ...... tbl k v */
-
-		// Serialize the value
-		serialize(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
-
-	serialize(info);
-
-	lua_pop(info->luaState, 1);
-	// >>>>> permTbl indexTbl ...... tbl
-}
-
-static void serializeFunction(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 */
-
-		serialize(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
-
-			serialize(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
-		serialize(info);
-
-		lua_pop(info->luaState, 1);
-		// >>>>> permTbl indexTbl ...... func
-	}
-}
-
-static void serializeThread(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) {
-		serialize(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
-
-		serialize(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
-	serialize(info);
-
-	lua_pop(info->luaState, 1);
-	// >>>>> permTbl indexTbl ...... thread
-}
-
-static void serializeProto(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
-
-		serialize(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 */
-
-		serialize(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
-
-		serialize(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
-
-		serialize(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
-
-	serialize(info);
-
-	lua_pop(info->luaState, 1);
-	// >>>>> permTbl indexTbl ...... proto
-
-	// Serialize line numbers
-	info->writeStream->writeSint32LE(proto->sizelineinfo);
-
-	if (proto->sizelineinfo) {
-		uint32 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 serializeUpValue(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
-
-	serialize(info);
-	// >>>>> permTbl indexTbl ...... obj
-}
-
-static void serializeUserData(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
-	serialize(info);
-
-	lua_pop(info->luaState, 1);
-	/* perms reftbl ... udata */
-}
-
-
-} // End of namespace Lua
diff --git a/engines/sword25/util/lua_unpersist.cpp b/engines/sword25/util/lua_unpersist.cpp
new file mode 100644
index 0000000..aa924ff
--- /dev/null
+++ b/engines/sword25/util/lua_unpersist.cpp
@@ -0,0 +1,698 @@
+/* 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.
+ *
+ */
+
+#include "sword25/util/lua_persistence.h"
+
+#include "sword25/util/double_serializer.h"
+#include "sword25/util/lua_persistence_util.h"
+
+#include "common/stream.h"
+
+#include "lua/lobject.h"
+#include "lua/lstate.h"
+#include "lua/lgc.h"
+#include "lua/lopcodes.h"
+
+
+namespace Lua {
+
+struct UnSerializationInfo {
+	lua_State *luaState;
+	Common::ReadStream *readStream;
+};
+
+static void unserialize(UnSerializationInfo *info);
+
+static void unserializeBoolean(UnSerializationInfo *info);
+static void unserializeNumber(UnSerializationInfo *info);
+static void unserializeString(UnSerializationInfo *info);
+static void unserializeTable(UnSerializationInfo *info, int index);
+static void unserializeFunction(UnSerializationInfo *info, int index);
+static void unserializeThread(UnSerializationInfo *info, int index);
+static void unserializeProto(UnSerializationInfo *info, int index);
+static void unserializeUpValue(UnSerializationInfo *info, int index);
+static void unserializeUserData(UnSerializationInfo *info, int index);
+static void unserializePermanent(UnSerializationInfo *info, int index);
+
+
+void unpersistLua(lua_State *luaState, Common::ReadStream *readStream) {
+	UnSerializationInfo info;
+	info.luaState = luaState;
+	info.readStream = readStream;
+
+	// The process starts with the lua stack as follows:
+	// >>>>> permTbl
+	// That's the table of permanents
+
+	// Make sure there is enough room on the stack
+	lua_checkstack(luaState, 3);
+
+	// Create a table to hold indexes of everything thats already been read
+	lua_newtable(luaState);
+	// >>>>> permTbl indexTbl
+
+	// Prevent garbage collection while we unserialize
+	lua_gc(luaState, LUA_GCSTOP, 0);
+
+	// Unserialize the root object
+	unserialize(&info);
+	// >>>>> permTbl indexTbl rootObj
+
+	// Re-start garbage collection
+	lua_gc(luaState, LUA_GCRESTART, 0);
+
+	// Remove the indexTbl
+	lua_replace(luaState, 2);
+	// >>>>> permTbl rootObj
+}
+
+/* The object is left on the stack. This is primarily used by unserialize, but
+ * may be used by GCed objects that may incur cycles in order to preregister
+ * the object. */
+static void registerObjectInIndexTable(UnSerializationInfo *info, int index) {
+	// >>>>> permTbl indexTbl ...... obj
+
+	// Make sure there is enough room on the stack
+	lua_checkstack(info->luaState, 2);
+
+	lua_pushlightuserdata(info->luaState, (void *)index);
+	// >>>>> permTbl indexTbl ...... obj index
+
+	lua_pushvalue(info->luaState, -2);
+	// >>>>> permTbl indexTbl ...... obj index obj
+
+	// Push the k/v pair into the indexTbl
+	lua_settable(info->luaState, 2);
+	// >>>>> permTbl indexTbl ...... obj
+}
+
+static void unserialize(UnSerializationInfo *info) {
+	// >>>>> permTbl indexTbl ......
+
+	// Make sure there is enough room on the stack
+	lua_checkstack(info->luaState, 2);
+
+	byte isARealValue = info->readStream->readByte();
+	if (isARealValue) {
+		int index = info->readStream->readSint32LE();
+		int type = info->readStream->readSint32LE();
+
+		switch (type) {
+		case LUA_TBOOLEAN:
+			unserializeBoolean(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:
+			unserializeNumber(info);
+			break;
+		case LUA_TSTRING:
+			unserializeString(info);
+			break;
+		case LUA_TTABLE:
+			unserializeTable(info, index);
+			break;
+		case LUA_TFUNCTION:
+			unserializeFunction(info, index);
+			break;
+		case LUA_TTHREAD:
+			unserializeThread(info, index);
+			break;
+		case LUA_TPROTO:
+			unserializeProto(info, index);
+			break;
+		case LUA_TUPVAL:
+			unserializeUpValue(info, index);
+			break;
+		case LUA_TUSERDATA:
+			unserializeUserData(info, index);
+			break;
+		case PERMANENT_TYPE:
+			unserializePermanent(info, index);
+			break;
+		default:
+			assert(0);
+		}
+
+
+		// >>>>> permTbl indexTbl ...... obj
+		assert(lua_type(info->luaState, -1) == type ||
+		       type == PERMANENT_TYPE ||
+		       // Remember, upvalues get a special dispensation, as described in boxUpValue
+		       (lua_type(info->luaState, -1) == LUA_TFUNCTION && type == LUA_TUPVAL));
+
+		registerObjectInIndexTable(info, index);
+		// >>>>> permTbl indexTbl ...... obj
+	} else {
+		int index = info->readStream->readSint32LE();
+
+		if (index == 0) {
+			lua_pushnil(info->luaState);
+			// >>>>> permTbl indexTbl ...... nil
+		} else {
+			// Fetch the object from the indexTbl
+
+			lua_pushlightuserdata(info->luaState, (void *)index);
+			// >>>>> permTbl indexTbl ...... index
+
+			lua_gettable(info->luaState, 2);
+			// >>>>> permTbl indexTbl ...... ?obj?
+
+			assert(!lua_isnil(info->luaState, -1));
+		}
+		// >>>>> permTbl indexTbl ...... obj/nil
+	}
+
+	// >>>>> permTbl indexTbl ...... obj/nil
+}
+
+static void unserializeBoolean(UnSerializationInfo *info) {
+	// >>>>> permTbl indexTbl ......
+
+	// Make sure there is enough room on the stack
+	lua_checkstack(info->luaState, 1);
+
+	int value = info->readStream->readSint32LE();
+
+	lua_pushboolean(info->luaState, value);
+	// >>>>> permTbl indexTbl ...... bool
+}
+
+static void unserializeNumber(UnSerializationInfo *info) {
+	// >>>>> permTbl indexTbl ......
+
+	// Make sure there is enough room on the stack
+	lua_checkstack(info->luaState, 1);
+
+	// Read the serialized double
+	Util::SerializedDouble serializedValue;
+	serializedValue.significandOne = info->readStream->readUint32LE();
+	serializedValue.signAndSignificandTwo = info->readStream->readUint32LE();
+	serializedValue.exponent = info->readStream->readSint16LE();
+
+	lua_Number value = Util::decodeDouble(serializedValue);
+
+	lua_pushnumber(info->luaState, value);
+	// >>>>> permTbl indexTbl ...... num
+}
+
+static void unserializeString(UnSerializationInfo *info) {
+	// >>>>> permTbl indexTbl ......
+
+	// Make sure there is enough room on the stack
+	lua_checkstack(info->luaState, 1);
+
+	uint32 length = info->readStream->readUint32LE();
+	char *string = new char[length];
+
+	info->readStream->read(string, length);
+	lua_pushlstring(info->luaState, string, length);
+
+	// >>>>> permTbl indexTbl ...... string
+
+	delete[] string;
+}
+
+static void unserializeSpecialTable(UnSerializationInfo *info, int index) {
+	// >>>>> permTbl indexTbl ......
+
+	// Make sure there is enough room on the stack
+	lua_checkstack(info->luaState, 1);
+
+	unserialize(info);
+
+	// >>>>> permTbl indexTbl ...... spfunc
+	lua_call(info->luaState, 0, 1);
+	// >>>>> permTbl indexTbl ...... tbl
+}
+
+static void unserializeLiteralTable(UnSerializationInfo *info, int index) {
+	// >>>>> permTbl indexTbl ......
+
+	// Make sure there is enough room on the stack
+	lua_checkstack(info->luaState, 3);
+
+	// Preregister table for handling of cycles
+	lua_newtable(info->luaState);
+
+	// >>>>> permTbl indexTbl ...... tbl
+	registerObjectInIndexTable(info, index);
+	// >>>>> permTbl indexTbl ...... tbl
+
+	// Unserialize metatable
+	unserialize(info);
+	// >>>>> permTbl indexTbl ...... tbl ?metaTbl/nil?
+
+	if (lua_istable(info->luaState, -1)) {
+		// >>>>> permTbl indexTbl ...... tbl metaTbl
+		lua_setmetatable(info->luaState, -2);
+		// >>>>> permTbl indexTbl ...... tbl
+	} else {
+		// >>>>> permTbl indexTbl ...... tbl nil
+		lua_pop(info->luaState, 1);
+		// >>>>> permTbl indexTbl ...... tbl
+	}
+	// >>>>> permTbl indexTbl ...... tbl
+
+
+	while (1) {
+		// >>>>> permTbl indexTbl ...... tbl
+		unserialize(info);
+		// >>>>> permTbl indexTbl ...... tbl key/nil
+
+		// The table serialization is nil terminated
+		if (lua_isnil(info->luaState, -1)) {
+			// >>>>> permTbl indexTbl ...... tbl nil
+			lua_pop(info->luaState, 1);
+			// >>>>> permTbl indexTbl ...... tbl
+
+			break;
+		}
+
+		// >>>>> permTbl indexTbl ...... tbl key
+		unserialize(info);
+		// >>>>> permTbl indexTbl ...... tbl value
+
+		lua_rawset(info->luaState, -3);
+		// >>>>> permTbl indexTbl ...... tbl
+	}
+}
+
+void unserializeTable(UnSerializationInfo *info, int index) {
+	// >>>>> permTbl indexTbl ......
+
+	// Make sure there is enough room on the stack
+	lua_checkstack(info->luaState, 1);
+
+	int isSpecial = info->readStream->readSint32LE();
+
+	if (isSpecial) {
+		unserializeSpecialTable(info, index);
+		// >>>>> permTbl indexTbl ...... tbl
+	} else {
+		unserializeLiteralTable(info, index);
+		// >>>>> permTbl indexTbl ...... tbl
+	}
+}
+
+void unserializeFunction(UnSerializationInfo *info, int index) {
+	// >>>>> permTbl indexTbl ......
+
+	// Make sure there is enough room on the stack
+	lua_checkstack(info->luaState, 2);
+
+	byte numUpValues = info->readStream->readByte();
+
+	LClosure *lclosure = (LClosure *)lua_newLclosure(info->luaState, numUpValues, hvalue(&info->luaState->l_gt));
+	pushClosure(info->luaState, (Closure *)lclosure);
+	// >>>>> permTbl indexTbl ...... func
+
+	// Put *some* proto in the closure, before the GC can find it
+	lclosure->p = makeFakeProto(info->luaState, numUpValues);
+
+	//Also, we need to temporarily fill the upvalues
+	lua_pushnil(info->luaState);
+	// >>>>> permTbl indexTbl ...... func nil
+
+	for (byte i = 0; i < numUpValues; ++i) {
+		lclosure->upvals[i] = createUpValue(info->luaState, -1);
+	}
+
+	lua_pop(info->luaState, 1);
+	// >>>>> permTbl indexTbl ...... func
+
+	// I can't see offhand how a function would ever get to be self-
+	// referential, but just in case let's register it early
+	registerObjectInIndexTable(info, index);
+
+	// Now that it's safe, we can get the real proto
+	unserialize(info);
+	// >>>>> permTbl indexTbl ...... func proto
+
+	lclosure->p = gco2p(getObject(info->luaState, -1)->value.gc);
+
+	lua_pop(info->luaState, 1);
+	// >>>>> permTbl indexTbl ...... func
+
+	for (byte i = 0; i < numUpValues; ++i) {
+		// >>>>> permTbl indexTbl ...... func
+		unserialize(info);
+		// >>>>> permTbl indexTbl ...... func func2
+
+		unboxUpValue(info->luaState);
+		// >>>>> permTbl indexTbl ...... func upValue
+		lclosure->upvals[i] = gco2uv(getObject(info->luaState, -1)->value.gc);
+
+		lua_pop(info->luaState, 1);
+		// >>>>> permTbl indexTbl ...... func
+	}
+
+	// Finally, the fenv
+	unserialize(info);
+
+	// >>>>> permTbl indexTbl ...... func ?fenv/nil?
+	if (!lua_isnil(info->luaState, -1)) {
+		// >>>>> permTbl indexTbl ...... func fenv
+		lua_setfenv(info->luaState, -2);
+		// >>>>> permTbl indexTbl ...... func
+	} else {
+		// >>>>> permTbl indexTbl ...... func nil
+		lua_pop(info->luaState, 1);
+		// >>>>> permTbl indexTbl ...... func
+	}
+
+	// >>>>> permTbl indexTbl ...... func
+}
+
+void unserializeThread(UnSerializationInfo *info, int index) {
+	// >>>>> permTbl indexTbl ......
+
+	lua_State *L2;
+	uint32 stacklimit = 0;
+
+	L2 = lua_newthread(info->luaState);
+	lua_checkstack(info->luaState, 3);
+
+	// L1: permTbl indexTbl ...... thread
+	// L2: (empty)
+	registerObjectInIndexTable(info, index);
+
+	// First, deserialize the object stack
+	uint32 stackSize = info->readStream->readUint32LE();
+	lua_growstack(info->luaState, (int)stackSize);
+
+	// Make sure that the first stack element (a nil, representing
+	// the imaginary top-level C function) is written to the very,
+	// very bottom of the stack
+	L2->top--;
+	for (uint32 i = 0; i < stackSize; ++i) {
+		unserialize(info);
+		// L1: permTbl indexTbl ...... thread obj*
+	}
+
+	lua_xmove(info->luaState, L2, stackSize);
+	// L1: permTbl indexTbl ...... thread
+	// L2: obj*
+
+	// Hereafter, stacks refer to L1
+
+
+	// Now, deserialize the CallInfo stack
+
+	uint32 numFrames = info->readStream->readUint32LE();
+
+	lua_reallocCallInfo(L2, numFrames * 2);
+	for (uint32 i = 0; i < numFrames; ++i) {
+		CallInfo *ci = L2->base_ci + i;
+		uint32 stackbase = info->readStream->readUint32LE();
+		uint32 stackfunc = info->readStream->readUint32LE();
+		uint32 stacktop = info->readStream->readUint32LE();
+
+		ci->nresults = info->readStream->readSint32LE();
+
+		uint32 savedpc = info->readStream->readUint32LE();
+
+		if (stacklimit < stacktop) {
+			stacklimit = stacktop;
+		}
+
+		ci->base = L2->stack + stackbase;
+		ci->func = L2->stack + stackfunc;
+		ci->top = L2->stack + stacktop;
+		ci->savedpc = (ci != L2->base_ci) ? ci_func(ci)->l.p->code + savedpc : 0;
+		ci->tailcalls = 0;
+
+		// Update the pointer each time, to keep the GC happy
+		L2->ci = ci;
+	}
+
+	// >>>>> permTbl indexTbl ...... thread
+	// Deserialize the state's other parameters, with the exception of upval stuff
+
+	L2->savedpc = L2->ci->savedpc;
+	L2->status = info->readStream->readByte();
+	uint32 stackbase = info->readStream->readUint32LE();
+	uint32 stacktop = info->readStream->readUint32LE();
+
+
+	L2->errfunc = info->readStream->readUint32LE();
+
+	L2->base = L2->stack + stackbase;
+	L2->top = L2->stack + stacktop;
+
+	// Finally, "reopen" upvalues. See serializeUpVal() for why we do this
+	UpVal *uv;
+	GCObject **nextslot = &L2->openupval;
+	global_State *g = G(L2);
+
+	while (true) {
+		unserialize(info);
+		// >>>>> permTbl indexTbl ...... thread upVal/nil
+
+		// The list is terminated by a nil
+		if (lua_isnil(info->luaState, -1)) {
+			// >>>>> permTbl indexTbl ...... thread nil
+			lua_pop(info->luaState, 1);
+			// >>>>> permTbl indexTbl ...... thread
+			break;
+		}
+
+		// >>>>> permTbl indexTbl ...... thread boxedUpVal
+		unboxUpValue(info->luaState);
+		// >>>>> permTbl indexTbl ...... thread boxedUpVal
+
+		uv = &(getObject(info->luaState, -1)->value.gc->uv);
+		lua_pop(info->luaState, 1);
+		// >>>>> permTbl indexTbl ...... thread
+
+		uint32 stackpos = info->readStream->readUint32LE();
+		uv->v = L2->stack + stackpos;
+
+		GCUnlink(info->luaState, (GCObject *)uv);
+
+		uv->marked = luaC_white(g);
+		*nextslot = (GCObject *)uv;
+		nextslot = &uv->next;
+		uv->u.l.prev = &G(L2)->uvhead;
+		uv->u.l.next = G(L2)->uvhead.u.l.next;
+		uv->u.l.next->u.l.prev = uv;
+		G(L2)->uvhead.u.l.next = uv;
+		lua_assert(uv->u.l.next->u.l.prev == uv && uv->u.l.prev->u.l.next == uv);
+	}
+	*nextslot = NULL;
+
+	// The stack must be valid at least to the highest value among the CallInfos
+	// 'top' and the values up to there must be filled with 'nil'
+	lua_checkstack(L2, (int)stacklimit);
+	for (StkId o = L2->top; o <= L2->top + stacklimit; ++o) {
+		setnilvalue(o);
+	}
+}
+
+void unserializeProto(UnSerializationInfo *info, int index) {
+	// >>>>> permTbl indexTbl ......
+
+	// We have to be careful. The GC expects a lot out of protos. In particular, we need
+	// to give the function a valid string for its source, and valid code, even before we
+	// actually read in the real code.
+	TString *source = lua_newlstr(info->luaState, "", 0);
+	Proto *p = lua_newproto(info->luaState);
+	p->source = source;
+	p->sizecode = 1;
+	p->code = (Instruction *)lua_reallocv(info->luaState, NULL, 0, 1, sizeof(Instruction));
+	p->code[0] = CREATE_ABC(OP_RETURN, 0, 1, 0);
+	p->maxstacksize = 2;
+	p->sizek = 0;
+	p->sizep = 0;
+
+	lua_checkstack(info->luaState, 2);
+
+	pushProto(info->luaState, p);
+	// >>>>> permTbl indexTbl ...... proto
+
+	// We don't need to register early, since protos can never ever be
+	// involved in cyclic references
+
+	// Read in constant references
+	int sizek = info->readStream->readSint32LE();
+	lua_reallocvector(info->luaState, p->k, 0, sizek, TValue);
+	for (int i = 0; i < sizek; ++i) {
+		// >>>>> permTbl indexTbl ...... proto
+		unserialize(info);
+		// >>>>> permTbl indexTbl ...... proto  k
+
+		setobj2s(info->luaState, &p->k[i], getObject(info->luaState, -1));
+		p->sizek++;
+
+		lua_pop(info->luaState, 1);
+		// >>>>> permTbl indexTbl ...... proto
+	}
+	// >>>>> permTbl indexTbl ...... proto
+
+	// Read in sub-proto references
+
+	int sizep = info->readStream->readSint32LE();
+	lua_reallocvector(info->luaState, p->p, 0, sizep, Proto *);
+	for (int i = 0; i < sizep; ++i) {
+		// >>>>> permTbl indexTbl ...... proto
+		unserialize(info);
+		// >>>>> permTbl indexTbl ...... proto  subproto
+
+		p->p[i] = (Proto *)getObject(info->luaState, -1)->value.gc;
+		p->sizep++;
+
+		lua_pop(info->luaState, 1);
+		// >>>>> permTbl indexTbl ...... proto
+	}
+	// >>>>> permTbl indexTbl ...... proto
+
+
+	// Read in code
+	p->sizecode = info->readStream->readSint32LE();
+	lua_reallocvector(info->luaState, p->code, 1, p->sizecode, Instruction);
+	info->readStream->read(p->code, sizeof(Instruction) * p->sizecode);
+
+
+	/* Read in upvalue names */
+	p->sizeupvalues = info->readStream->readSint32LE();
+	if (p->sizeupvalues) {
+		lua_reallocvector(info->luaState, p->upvalues, 0, p->sizeupvalues, TString *);
+		for (int i = 0; i < p->sizeupvalues; ++i) {
+			// >>>>> permTbl indexTbl ...... proto
+			unserialize(info);
+			// >>>>> permTbl indexTbl ...... proto str
+
+			p->upvalues[i] = lua_newlstr(info->luaState, lua_tostring(info->luaState, -1), strlen(lua_tostring(info->luaState, -1)));
+			lua_pop(info->luaState, 1);
+			// >>>>> permTbl indexTbl ...... proto
+		}
+	}
+	// >>>>> permTbl indexTbl ...... proto
+
+	// Read in local variable infos
+	p->sizelocvars = info->readStream->readSint32LE();
+	if (p->sizelocvars) {
+		lua_reallocvector(info->luaState, p->locvars, 0, p->sizelocvars, LocVar);
+		for (int i = 0; i < p->sizelocvars; ++i) {
+			// >>>>> permTbl indexTbl ...... proto
+			unserialize(info);
+			// >>>>> permTbl indexTbl ...... proto str
+
+			p->locvars[i].varname = lua_newlstr(info->luaState, lua_tostring(info->luaState, -1), strlen(lua_tostring(info->luaState, -1)));
+			lua_pop(info->luaState, 1);
+			// >>>>> permTbl indexTbl ...... proto
+
+			p->locvars[i].startpc = info->readStream->readSint32LE();
+			p->locvars[i].endpc = info->readStream->readSint32LE();
+		}
+	}
+	// >>>>> permTbl indexTbl ...... proto
+
+	// Read in source string
+	unserialize(info);
+	// >>>>> permTbl indexTbl ...... proto sourceStr
+
+	p->source = lua_newlstr(info->luaState, lua_tostring(info->luaState, -1), strlen(lua_tostring(info->luaState, -1)));
+	lua_pop(info->luaState, 1);
+	// >>>>> permTbl indexTbl ...... proto
+
+	// Read in line numbers
+	p->sizelineinfo = info->readStream->readSint32LE();
+	if (p->sizelineinfo) {
+		lua_reallocvector(info->luaState, p->lineinfo, 0, p->sizelineinfo, int);
+		info->readStream->read(p->lineinfo, sizeof(int) * p->sizelineinfo);
+	}
+
+
+	/* Read in linedefined and lastlinedefined */
+	p->linedefined = info->readStream->readSint32LE();
+	p->lastlinedefined = info->readStream->readSint32LE();
+
+	// Read in misc values
+	p->nups = info->readStream->readByte();
+	p->numparams = info->readStream->readByte();
+	p->is_vararg = info->readStream->readByte();
+	p->maxstacksize = info->readStream->readByte();
+}
+
+void unserializeUpValue(UnSerializationInfo *info, int index) {
+	// >>>>> permTbl indexTbl ......
+	lua_checkstack(info->luaState, 2);
+
+	boxUpValue_start(info->luaState);
+	// >>>>> permTbl indexTbl ...... func
+	registerObjectInIndexTable(info, index);
+
+	unserialize(info);
+	// >>>>> permTbl indexTbl ...... func obj
+
+	boxUpValue_finish(info->luaState);
+	// >>>>> permTbl indexTbl ...... func
+}
+
+void unserializeUserData(UnSerializationInfo *info, int index) {
+	// >>>>> permTbl indexTbl ......
+
+	// Make sure there is enough room on the stack
+	lua_checkstack(info->luaState, 2);
+
+	int isspecial = info->readStream->readSint32LE();
+	if (isspecial) {
+		unserialize(info);
+		// >>>>> permTbl indexTbl ...... specialFunc
+
+		lua_call(info->luaState, 0, 1);
+		// >>>>> permTbl indexTbl ...... udata
+	} else {
+		uint32 length = info->readStream->readUint32LE();
+		lua_newuserdata(info->luaState, length);
+		// >>>>> permTbl indexTbl ...... udata
+		registerObjectInIndexTable(info, index);
+
+		info->readStream->read(lua_touserdata(info->luaState, -1), length);
+
+		unserialize(info);
+		// >>>>> permTbl indexTbl ...... udata metaTable/nil
+
+		lua_setmetatable(info->luaState, -2);
+		// >>>>> permTbl indexTbl ...... udata
+	}
+	// >>>>> permTbl indexTbl ...... udata
+}
+
+void unserializePermanent(UnSerializationInfo *info, int index) {
+	// >>>>> permTbl indexTbl ......
+
+	// Make sure there is enough room on the stack
+	lua_checkstack(info->luaState, 2);
+
+	unserialize(info);
+	// >>>>> permTbl indexTbl ...... permKey
+
+	lua_gettable(info->luaState, 1);
+	// >>>>> permTbl indexTbl ...... perm
+}
+
+} // End of namespace Lua
diff --git a/engines/sword25/util/lua_unserializer.cpp b/engines/sword25/util/lua_unserializer.cpp
deleted file mode 100644
index 803c79c..0000000
--- a/engines/sword25/util/lua_unserializer.cpp
+++ /dev/null
@@ -1,698 +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.
- *
- */
-
-#include "sword25/util/lua_serialization.h"
-
-#include "sword25/util/double_serializer.h"
-#include "sword25/util/lua_serialization_util.h"
-
-#include "common/stream.h"
-
-#include "lua/lobject.h"
-#include "lua/lstate.h"
-#include "lua/lgc.h"
-#include "lua/lopcodes.h"
-
-
-namespace Lua {
-
-struct UnSerializationInfo {
-	lua_State *luaState;
-	Common::ReadStream *readStream;
-};
-
-static void unserialize(UnSerializationInfo *info);
-
-static void unserializeBoolean(UnSerializationInfo *info);
-static void unserializeNumber(UnSerializationInfo *info);
-static void unserializeString(UnSerializationInfo *info);
-static void unserializeTable(UnSerializationInfo *info, int index);
-static void unserializeFunction(UnSerializationInfo *info, int index);
-static void unserializeThread(UnSerializationInfo *info, int index);
-static void unserializeProto(UnSerializationInfo *info, int index);
-static void unserializeUpValue(UnSerializationInfo *info, int index);
-static void unserializeUserData(UnSerializationInfo *info, int index);
-static void unserializePermanent(UnSerializationInfo *info, int index);
-
-
-void unserializeLua(lua_State *luaState, Common::ReadStream *readStream) {
-	UnSerializationInfo info;
-	info.luaState = luaState;
-	info.readStream = readStream;
-
-	// The process starts with the lua stack as follows:
-	// >>>>> permTbl
-	// That's the table of permanents
-
-	// Make sure there is enough room on the stack
-	lua_checkstack(luaState, 3);
-
-	// Create a table to hold indexes of everything thats already been read
-	lua_newtable(luaState);
-	// >>>>> permTbl indexTbl
-
-	// Prevent garbage collection while we unserialize
-	lua_gc(luaState, LUA_GCSTOP, 0);
-
-	// Unserialize the root object
-	unserialize(&info);
-	// >>>>> permTbl indexTbl rootObj
-
-	// Re-start garbage collection
-	lua_gc(luaState, LUA_GCRESTART, 0);
-
-	// Remove the indexTbl
-	lua_replace(luaState, 2);
-	// >>>>> permTbl rootObj
-}
-
-/* The object is left on the stack. This is primarily used by unserialize, but
- * may be used by GCed objects that may incur cycles in order to preregister
- * the object. */
-static void registerObjectInIndexTable(UnSerializationInfo *info, int index) {
-	// >>>>> permTbl indexTbl ...... obj
-
-	// Make sure there is enough room on the stack
-	lua_checkstack(info->luaState, 2);
-
-	lua_pushlightuserdata(info->luaState, (void *)index);
-	// >>>>> permTbl indexTbl ...... obj index
-
-	lua_pushvalue(info->luaState, -2);
-	// >>>>> permTbl indexTbl ...... obj index obj
-
-	// Push the k/v pair into the indexTbl
-	lua_settable(info->luaState, 2);
-	// >>>>> permTbl indexTbl ...... obj
-}
-
-static void unserialize(UnSerializationInfo *info) {
-	// >>>>> permTbl indexTbl ......
-
-	// Make sure there is enough room on the stack
-	lua_checkstack(info->luaState, 2);
-
-	byte isARealValue = info->readStream->readByte();
-	if (isARealValue) {
-		int index = info->readStream->readSint32LE();
-		int type = info->readStream->readSint32LE();
-
-		switch (type) {
-		case LUA_TBOOLEAN:
-			unserializeBoolean(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:
-			unserializeNumber(info);
-			break;
-		case LUA_TSTRING:
-			unserializeString(info);
-			break;
-		case LUA_TTABLE:
-			unserializeTable(info, index);
-			break;
-		case LUA_TFUNCTION:
-			unserializeFunction(info, index);
-			break;
-		case LUA_TTHREAD:
-			unserializeThread(info, index);
-			break;
-		case LUA_TPROTO:
-			unserializeProto(info, index);
-			break;
-		case LUA_TUPVAL:
-			unserializeUpValue(info, index);
-			break;
-		case LUA_TUSERDATA:
-			unserializeUserData(info, index);
-			break;
-		case PERMANENT_TYPE:
-			unserializePermanent(info, index);
-			break;
-		default:
-			assert(0);
-		}
-
-
-		// >>>>> permTbl indexTbl ...... obj
-		assert(lua_type(info->luaState, -1) == type ||
-		       type == PERMANENT_TYPE ||
-		       // Remember, upvalues get a special dispensation, as described in boxUpValue
-		       (lua_type(info->luaState, -1) == LUA_TFUNCTION && type == LUA_TUPVAL));
-
-		registerObjectInIndexTable(info, index);
-		// >>>>> permTbl indexTbl ...... obj
-	} else {
-		int index = info->readStream->readSint32LE();
-
-		if (index == 0) {
-			lua_pushnil(info->luaState);
-			// >>>>> permTbl indexTbl ...... nil
-		} else {
-			// Fetch the object from the indexTbl
-
-			lua_pushlightuserdata(info->luaState, (void *)index);
-			// >>>>> permTbl indexTbl ...... index
-
-			lua_gettable(info->luaState, 2);
-			// >>>>> permTbl indexTbl ...... ?obj?
-
-			assert(!lua_isnil(info->luaState, -1));
-		}
-		// >>>>> permTbl indexTbl ...... obj/nil
-	}
-
-	// >>>>> permTbl indexTbl ...... obj/nil
-}
-
-static void unserializeBoolean(UnSerializationInfo *info) {
-	// >>>>> permTbl indexTbl ......
-
-	// Make sure there is enough room on the stack
-	lua_checkstack(info->luaState, 1);
-
-	int value = info->readStream->readSint32LE();
-
-	lua_pushboolean(info->luaState, value);
-	// >>>>> permTbl indexTbl ...... bool
-}
-
-static void unserializeNumber(UnSerializationInfo *info) {
-	// >>>>> permTbl indexTbl ......
-
-	// Make sure there is enough room on the stack
-	lua_checkstack(info->luaState, 1);
-
-	// Read the serialized double
-	Util::SerializedDouble serializedValue;
-	serializedValue.significandOne = info->readStream->readUint32LE();
-	serializedValue.signAndSignificandTwo = info->readStream->readUint32LE();
-	serializedValue.exponent = info->readStream->readSint16LE();
-
-	lua_Number value = Util::decodeDouble(serializedValue);
-
-	lua_pushnumber(info->luaState, value);
-	// >>>>> permTbl indexTbl ...... num
-}
-
-static void unserializeString(UnSerializationInfo *info) {
-	// >>>>> permTbl indexTbl ......
-
-	// Make sure there is enough room on the stack
-	lua_checkstack(info->luaState, 1);
-
-	uint32 length = info->readStream->readUint32LE();
-	char *string = new char[length];
-
-	info->readStream->read(string, length);
-	lua_pushlstring(info->luaState, string, length);
-
-	// >>>>> permTbl indexTbl ...... string
-
-	delete[] string;
-}
-
-static void unserializeSpecialTable(UnSerializationInfo *info, int index) {
-	// >>>>> permTbl indexTbl ......
-
-	// Make sure there is enough room on the stack
-	lua_checkstack(info->luaState, 1);
-
-	unserialize(info);
-
-	// >>>>> permTbl indexTbl ...... spfunc
-	lua_call(info->luaState, 0, 1);
-	// >>>>> permTbl indexTbl ...... tbl
-}
-
-static void unserializeLiteralTable(UnSerializationInfo *info, int index) {
-	// >>>>> permTbl indexTbl ......
-
-	// Make sure there is enough room on the stack
-	lua_checkstack(info->luaState, 3);
-
-	// Preregister table for handling of cycles
-	lua_newtable(info->luaState);
-
-	// >>>>> permTbl indexTbl ...... tbl
-	registerObjectInIndexTable(info, index);
-	// >>>>> permTbl indexTbl ...... tbl
-
-	// Unserialize metatable
-	unserialize(info);
-	// >>>>> permTbl indexTbl ...... tbl ?metaTbl/nil?
-
-	if (lua_istable(info->luaState, -1)) {
-		// >>>>> permTbl indexTbl ...... tbl metaTbl
-		lua_setmetatable(info->luaState, -2);
-		// >>>>> permTbl indexTbl ...... tbl
-	} else {
-		// >>>>> permTbl indexTbl ...... tbl nil
-		lua_pop(info->luaState, 1);
-		// >>>>> permTbl indexTbl ...... tbl
-	}
-	// >>>>> permTbl indexTbl ...... tbl
-
-
-	while (1) {
-		// >>>>> permTbl indexTbl ...... tbl
-		unserialize(info);
-		// >>>>> permTbl indexTbl ...... tbl key/nil
-
-		// The table serialization is nil terminated
-		if (lua_isnil(info->luaState, -1)) {
-			// >>>>> permTbl indexTbl ...... tbl nil
-			lua_pop(info->luaState, 1);
-			// >>>>> permTbl indexTbl ...... tbl
-
-			break;
-		}
-
-		// >>>>> permTbl indexTbl ...... tbl key
-		unserialize(info);
-		// >>>>> permTbl indexTbl ...... tbl value
-
-		lua_rawset(info->luaState, -3);
-		// >>>>> permTbl indexTbl ...... tbl
-	}
-}
-
-void unserializeTable(UnSerializationInfo *info, int index) {
-	// >>>>> permTbl indexTbl ......
-
-	// Make sure there is enough room on the stack
-	lua_checkstack(info->luaState, 1);
-
-	int isSpecial = info->readStream->readSint32LE();
-
-	if (isSpecial) {
-		unserializeSpecialTable(info, index);
-		// >>>>> permTbl indexTbl ...... tbl
-	} else {
-		unserializeLiteralTable(info, index);
-		// >>>>> permTbl indexTbl ...... tbl
-	}
-}
-
-void unserializeFunction(UnSerializationInfo *info, int index) {
-	// >>>>> permTbl indexTbl ......
-
-	// Make sure there is enough room on the stack
-	lua_checkstack(info->luaState, 2);
-
-	byte numUpValues = info->readStream->readByte();
-
-	LClosure *lclosure = (LClosure *)lua_newLclosure(info->luaState, numUpValues, hvalue(&info->luaState->l_gt));
-	pushClosure(info->luaState, (Closure *)lclosure);
-	// >>>>> permTbl indexTbl ...... func
-
-	// Put *some* proto in the closure, before the GC can find it
-	lclosure->p = makeFakeProto(info->luaState, numUpValues);
-
-	//Also, we need to temporarily fill the upvalues
-	lua_pushnil(info->luaState);
-	// >>>>> permTbl indexTbl ...... func nil
-
-	for (byte i = 0; i < numUpValues; ++i) {
-		lclosure->upvals[i] = createUpValue(info->luaState, -1);
-	}
-
-	lua_pop(info->luaState, 1);
-	// >>>>> permTbl indexTbl ...... func
-
-	// I can't see offhand how a function would ever get to be self-
-	// referential, but just in case let's register it early
-	registerObjectInIndexTable(info, index);
-
-	// Now that it's safe, we can get the real proto
-	unserialize(info);
-	// >>>>> permTbl indexTbl ...... func proto
-
-	lclosure->p = gco2p(getObject(info->luaState, -1)->value.gc);
-
-	lua_pop(info->luaState, 1);
-	// >>>>> permTbl indexTbl ...... func
-
-	for (byte i = 0; i < numUpValues; ++i) {
-		// >>>>> permTbl indexTbl ...... func
-		unserialize(info);
-		// >>>>> permTbl indexTbl ...... func func2
-
-		unboxUpValue(info->luaState);
-		// >>>>> permTbl indexTbl ...... func upValue
-		lclosure->upvals[i] = gco2uv(getObject(info->luaState, -1)->value.gc);
-
-		lua_pop(info->luaState, 1);
-		// >>>>> permTbl indexTbl ...... func
-	}
-
-	// Finally, the fenv
-	unserialize(info);
-
-	// >>>>> permTbl indexTbl ...... func ?fenv/nil?
-	if (!lua_isnil(info->luaState, -1)) {
-		// >>>>> permTbl indexTbl ...... func fenv
-		lua_setfenv(info->luaState, -2);
-		// >>>>> permTbl indexTbl ...... func
-	} else {
-		// >>>>> permTbl indexTbl ...... func nil
-		lua_pop(info->luaState, 1);
-		// >>>>> permTbl indexTbl ...... func
-	}
-
-	// >>>>> permTbl indexTbl ...... func
-}
-
-void unserializeThread(UnSerializationInfo *info, int index) {
-	// >>>>> permTbl indexTbl ......
-
-	lua_State *L2;
-	uint32 stacklimit = 0;
-
-	L2 = lua_newthread(info->luaState);
-	lua_checkstack(info->luaState, 3);
-
-	// L1: permTbl indexTbl ...... thread
-	// L2: (empty)
-	registerObjectInIndexTable(info, index);
-
-	// First, deserialize the object stack
-	uint32 stackSize = info->readStream->readUint32LE();
-	lua_growstack(info->luaState, (int)stackSize);
-
-	// Make sure that the first stack element (a nil, representing
-	// the imaginary top-level C function) is written to the very,
-	// very bottom of the stack
-	L2->top--;
-	for (uint32 i = 0; i < stackSize; ++i) {
-		unserialize(info);
-		// L1: permTbl indexTbl ...... thread obj*
-	}
-
-	lua_xmove(info->luaState, L2, stackSize);
-	// L1: permTbl indexTbl ...... thread
-	// L2: obj*
-
-	// Hereafter, stacks refer to L1
-
-
-	// Now, deserialize the CallInfo stack
-
-	uint32 numFrames = info->readStream->readUint32LE();
-
-	lua_reallocCallInfo(L2, numFrames * 2);
-	for (uint32 i = 0; i < numFrames; ++i) {
-		CallInfo *ci = L2->base_ci + i;
-		uint32 stackbase = info->readStream->readUint32LE();
-		uint32 stackfunc = info->readStream->readUint32LE();
-		uint32 stacktop = info->readStream->readUint32LE();
-
-		ci->nresults = info->readStream->readSint32LE();
-
-		uint32 savedpc = info->readStream->readUint32LE();
-
-		if (stacklimit < stacktop) {
-			stacklimit = stacktop;
-		}
-
-		ci->base = L2->stack + stackbase;
-		ci->func = L2->stack + stackfunc;
-		ci->top = L2->stack + stacktop;
-		ci->savedpc = (ci != L2->base_ci) ? ci_func(ci)->l.p->code + savedpc : 0;
-		ci->tailcalls = 0;
-
-		// Update the pointer each time, to keep the GC happy
-		L2->ci = ci;
-	}
-
-	// >>>>> permTbl indexTbl ...... thread
-	// Deserialize the state's other parameters, with the exception of upval stuff
-
-	L2->savedpc = L2->ci->savedpc;
-	L2->status = info->readStream->readByte();
-	uint32 stackbase = info->readStream->readUint32LE();
-	uint32 stacktop = info->readStream->readUint32LE();
-
-
-	L2->errfunc = info->readStream->readUint32LE();
-
-	L2->base = L2->stack + stackbase;
-	L2->top = L2->stack + stacktop;
-
-	// Finally, "reopen" upvalues. See serializeUpVal() for why we do this
-	UpVal *uv;
-	GCObject **nextslot = &L2->openupval;
-	global_State *g = G(L2);
-
-	while (true) {
-		unserialize(info);
-		// >>>>> permTbl indexTbl ...... thread upVal/nil
-
-		// The list is terminated by a nil
-		if (lua_isnil(info->luaState, -1)) {
-			// >>>>> permTbl indexTbl ...... thread nil
-			lua_pop(info->luaState, 1);
-			// >>>>> permTbl indexTbl ...... thread
-			break;
-		}
-
-		// >>>>> permTbl indexTbl ...... thread boxedUpVal
-		unboxUpValue(info->luaState);
-		// >>>>> permTbl indexTbl ...... thread boxedUpVal
-
-		uv = &(getObject(info->luaState, -1)->value.gc->uv);
-		lua_pop(info->luaState, 1);
-		// >>>>> permTbl indexTbl ...... thread
-
-		uint32 stackpos = info->readStream->readUint32LE();
-		uv->v = L2->stack + stackpos;
-
-		GCUnlink(info->luaState, (GCObject *)uv);
-
-		uv->marked = luaC_white(g);
-		*nextslot = (GCObject *)uv;
-		nextslot = &uv->next;
-		uv->u.l.prev = &G(L2)->uvhead;
-		uv->u.l.next = G(L2)->uvhead.u.l.next;
-		uv->u.l.next->u.l.prev = uv;
-		G(L2)->uvhead.u.l.next = uv;
-		lua_assert(uv->u.l.next->u.l.prev == uv && uv->u.l.prev->u.l.next == uv);
-	}
-	*nextslot = NULL;
-
-	// The stack must be valid at least to the highest value among the CallInfos
-	// 'top' and the values up to there must be filled with 'nil'
-	lua_checkstack(L2, (int)stacklimit);
-	for (StkId o = L2->top; o <= L2->top + stacklimit; ++o) {
-		setnilvalue(o);
-	}
-}
-
-void unserializeProto(UnSerializationInfo *info, int index) {
-	// >>>>> permTbl indexTbl ......
-
-	// We have to be careful. The GC expects a lot out of protos. In particular, we need
-	// to give the function a valid string for its source, and valid code, even before we
-	// actually read in the real code.
-	TString *source = lua_newlstr(info->luaState, "", 0);
-	Proto *p = lua_newproto(info->luaState);
-	p->source = source;
-	p->sizecode = 1;
-	p->code = (Instruction *)lua_reallocv(info->luaState, NULL, 0, 1, sizeof(Instruction));
-	p->code[0] = CREATE_ABC(OP_RETURN, 0, 1, 0);
-	p->maxstacksize = 2;
-	p->sizek = 0;
-	p->sizep = 0;
-
-	lua_checkstack(info->luaState, 2);
-
-	pushProto(info->luaState, p);
-	// >>>>> permTbl indexTbl ...... proto
-
-	// We don't need to register early, since protos can never ever be
-	// involved in cyclic references
-
-	// Read in constant references
-	int sizek = info->readStream->readSint32LE();
-	lua_reallocvector(info->luaState, p->k, 0, sizek, TValue);
-	for (int i = 0; i < sizek; ++i) {
-		// >>>>> permTbl indexTbl ...... proto
-		unserialize(info);
-		// >>>>> permTbl indexTbl ...... proto  k
-
-		setobj2s(info->luaState, &p->k[i], getObject(info->luaState, -1));
-		p->sizek++;
-
-		lua_pop(info->luaState, 1);
-		// >>>>> permTbl indexTbl ...... proto
-	}
-	// >>>>> permTbl indexTbl ...... proto
-
-	// Read in sub-proto references
-
-	int sizep = info->readStream->readSint32LE();
-	lua_reallocvector(info->luaState, p->p, 0, sizep, Proto *);
-	for (int i = 0; i < sizep; ++i) {
-		// >>>>> permTbl indexTbl ...... proto
-		unserialize(info);
-		// >>>>> permTbl indexTbl ...... proto  subproto
-
-		p->p[i] = (Proto *)getObject(info->luaState, -1)->value.gc;
-		p->sizep++;
-
-		lua_pop(info->luaState, 1);
-		// >>>>> permTbl indexTbl ...... proto
-	}
-	// >>>>> permTbl indexTbl ...... proto
-
-
-	// Read in code
-	p->sizecode = info->readStream->readSint32LE();
-	lua_reallocvector(info->luaState, p->code, 1, p->sizecode, Instruction);
-	info->readStream->read(p->code, sizeof(Instruction) * p->sizecode);
-
-
-	/* Read in upvalue names */
-	p->sizeupvalues = info->readStream->readSint32LE();
-	if (p->sizeupvalues) {
-		lua_reallocvector(info->luaState, p->upvalues, 0, p->sizeupvalues, TString *);
-		for (int i = 0; i < p->sizeupvalues; ++i) {
-			// >>>>> permTbl indexTbl ...... proto
-			unserialize(info);
-			// >>>>> permTbl indexTbl ...... proto str
-
-			p->upvalues[i] = lua_newlstr(info->luaState, lua_tostring(info->luaState, -1), strlen(lua_tostring(info->luaState, -1)));
-			lua_pop(info->luaState, 1);
-			// >>>>> permTbl indexTbl ...... proto
-		}
-	}
-	// >>>>> permTbl indexTbl ...... proto
-
-	// Read in local variable infos
-	p->sizelocvars = info->readStream->readSint32LE();
-	if (p->sizelocvars) {
-		lua_reallocvector(info->luaState, p->locvars, 0, p->sizelocvars, LocVar);
-		for (int i = 0; i < p->sizelocvars; ++i) {
-			// >>>>> permTbl indexTbl ...... proto
-			unserialize(info);
-			// >>>>> permTbl indexTbl ...... proto str
-
-			p->locvars[i].varname = lua_newlstr(info->luaState, lua_tostring(info->luaState, -1), strlen(lua_tostring(info->luaState, -1)));
-			lua_pop(info->luaState, 1);
-			// >>>>> permTbl indexTbl ...... proto
-
-			p->locvars[i].startpc = info->readStream->readSint32LE();
-			p->locvars[i].endpc = info->readStream->readSint32LE();
-		}
-	}
-	// >>>>> permTbl indexTbl ...... proto
-
-	// Read in source string
-	unserialize(info);
-	// >>>>> permTbl indexTbl ...... proto sourceStr
-
-	p->source = lua_newlstr(info->luaState, lua_tostring(info->luaState, -1), strlen(lua_tostring(info->luaState, -1)));
-	lua_pop(info->luaState, 1);
-	// >>>>> permTbl indexTbl ...... proto
-
-	// Read in line numbers
-	p->sizelineinfo = info->readStream->readSint32LE();
-	if (p->sizelineinfo) {
-		lua_reallocvector(info->luaState, p->lineinfo, 0, p->sizelineinfo, int);
-		info->readStream->read(p->lineinfo, sizeof(int) * p->sizelineinfo);
-	}
-
-
-	/* Read in linedefined and lastlinedefined */
-	p->linedefined = info->readStream->readSint32LE();
-	p->lastlinedefined = info->readStream->readSint32LE();
-
-	// Read in misc values
-	p->nups = info->readStream->readByte();
-	p->numparams = info->readStream->readByte();
-	p->is_vararg = info->readStream->readByte();
-	p->maxstacksize = info->readStream->readByte();
-}
-
-void unserializeUpValue(UnSerializationInfo *info, int index) {
-	// >>>>> permTbl indexTbl ......
-	lua_checkstack(info->luaState, 2);
-
-	boxUpValue_start(info->luaState);
-	// >>>>> permTbl indexTbl ...... func
-	registerObjectInIndexTable(info, index);
-
-	unserialize(info);
-	// >>>>> permTbl indexTbl ...... func obj
-
-	boxUpValue_finish(info->luaState);
-	// >>>>> permTbl indexTbl ...... func
-}
-
-void unserializeUserData(UnSerializationInfo *info, int index) {
-	// >>>>> permTbl indexTbl ......
-
-	// Make sure there is enough room on the stack
-	lua_checkstack(info->luaState, 2);
-
-	int isspecial = info->readStream->readSint32LE();
-	if (isspecial) {
-		unserialize(info);
-		// >>>>> permTbl indexTbl ...... specialFunc
-
-		lua_call(info->luaState, 0, 1);
-		// >>>>> permTbl indexTbl ...... udata
-	} else {
-		uint32 length = info->readStream->readUint32LE();
-		lua_newuserdata(info->luaState, length);
-		// >>>>> permTbl indexTbl ...... udata
-		registerObjectInIndexTable(info, index);
-
-		info->readStream->read(lua_touserdata(info->luaState, -1), length);
-
-		unserialize(info);
-		// >>>>> permTbl indexTbl ...... udata metaTable/nil
-
-		lua_setmetatable(info->luaState, -2);
-		// >>>>> permTbl indexTbl ...... udata
-	}
-	// >>>>> permTbl indexTbl ...... udata
-}
-
-void unserializePermanent(UnSerializationInfo *info, int index) {
-	// >>>>> permTbl indexTbl ......
-
-	// Make sure there is enough room on the stack
-	lua_checkstack(info->luaState, 2);
-
-	unserialize(info);
-	// >>>>> permTbl indexTbl ...... permKey
-
-	lua_gettable(info->luaState, 1);
-	// >>>>> permTbl indexTbl ...... perm
-}
-
-} // End of namespace Lua


Commit: 08e3f21a8df184bc697e6c03adf968d0cbdbac21
    https://github.com/scummvm/scummvm/commit/08e3f21a8df184bc697e6c03adf968d0cbdbac21
Author: RichieSams (adastley at gmail.com)
Date: 2014-12-30T15:40:33-06:00

Commit Message:
SWORD25: Rename double serialization file to better represent what it is

AKA functions, rather than a class

Changed paths:
  A engines/sword25/util/double_serialization.cpp
  A engines/sword25/util/double_serialization.h
  R engines/sword25/util/double_serializer.cpp
  R engines/sword25/util/double_serializer.h
    engines/sword25/module.mk
    engines/sword25/util/lua_persist.cpp
    engines/sword25/util/lua_unpersist.cpp



diff --git a/engines/sword25/module.mk b/engines/sword25/module.mk
index 129b4f0..0842eb9 100644
--- a/engines/sword25/module.mk
+++ b/engines/sword25/module.mk
@@ -82,7 +82,7 @@ MODULE_OBJS := \
 	util/lua/lvm.o \
 	util/lua/lzio.o \
 	util/lua/scummvm_file.o \
-	util/double_serializer.o \
+	util/double_serialization.o \
 	util/lua_persistence_util.o \
 	util/lua_persist.o \
 	util/lua_unpersist.o
diff --git a/engines/sword25/util/double_serialization.cpp b/engines/sword25/util/double_serialization.cpp
new file mode 100644
index 0000000..48fd75c
--- /dev/null
+++ b/engines/sword25/util/double_serialization.cpp
@@ -0,0 +1,138 @@
+/* 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.
+ *
+ */
+
+#include "sword25/util/double_serialization.h"
+
+#include "common/scummsys.h"
+
+
+namespace Util {
+
+SerializedDouble encodeDouble(double value) {
+	// Split the value into its significand and exponent
+	int exponent;
+	double significand = frexp(value, &exponent);
+
+	// Shift the the first part of the significand into the integer range
+	double shiftedsignificandPart = ldexp(abs(significand), 32);
+	uint32 significandOne = uint32(floor(shiftedsignificandPart));
+
+	// Shift the remainder of the significand into the integer range
+	shiftedsignificandPart -= significandOne;
+	uint32 significandTwo = (uint32)(ldexp(shiftedsignificandPart, 31));
+
+	SerializedDouble returnValue;
+	returnValue.significandOne = significandOne;                                // SignificandOne
+	returnValue.signAndSignificandTwo = ((uint32)(value < 0 ? 1 : 0) << 31) |   // Sign
+	                                    significandTwo;                         // SignificandTwo
+	returnValue.exponent = (int16)exponent;
+	return returnValue;
+}
+
+double decodeDouble(SerializedDouble value) {
+	// Expand the exponent and the parts of the significand
+	int exponent = (int)value.exponent;
+	double expandedsignificandOne = (double)value.significandOne;
+	double expandedsignificandTwo = (double)(value.signAndSignificandTwo & 0x7FFFFFFF);
+
+	// Deflate the significand
+	double shiftedsignificand = ldexp(expandedsignificandTwo, -21);
+	double significand = ldexp(expandedsignificandOne + shiftedsignificand, -32);
+
+	// Re-calculate the actual double
+	double returnValue = ldexp(significand, exponent);
+
+	// Check the sign bit and return
+	return ((value.signAndSignificandTwo & 0x80000000) == 0x80000000) ? -returnValue : returnValue;
+}
+
+uint64 encodeDouble_64(double value) {
+	// Split the value into its significand and exponent
+	int exponent;
+	double significand = frexp(value, &exponent);
+
+	// Shift the significand into the integer range
+	double shiftedsignificand = ldexp(abs(significand), 53);
+
+	// Combine everything using the IEEE standard
+	uint64 uintsignificand = (uint64)shiftedsignificand;
+	return ((uint64)(value < 0 ? 1 : 0) << 63) |        // Sign
+	       ((uint64)(exponent + 1023) << 52) |          // Exponent stored as an offset to 1023
+	       (uintsignificand & 0x000FFFFFFFFFFFFF);      // significand with MSB inferred
+}
+
+double decodeDouble_64(uint64 value) {
+	// Expand the exponent and significand
+	int exponent = (int)((value >> 52) & 0x7FF) - 1023;
+	double expandedsignificand = (double)(0x10000000000000 /* Inferred MSB */ | (value & 0x000FFFFFFFFFFFFF));
+
+	// Deflate the significand
+	int temp;
+	double significand = frexp(expandedsignificand, &temp);
+
+	// Re-calculate the actual double
+	double returnValue = ldexp(significand, exponent);
+
+	// Check the sign bit and return
+	return ((value & 0x8000000000000000) == 0x8000000000000000) ? -returnValue : returnValue;
+}
+
+CompactSerializedDouble encodeDouble_Compact(double value) {
+	// Split the value into its significand and exponent
+	int exponent;
+	double significand = frexp(value, &exponent);
+
+	// Shift the the first part of the significand into the integer range
+	double shiftedsignificandPart = ldexp(abs(significand), 32);
+	uint32 significandOne = uint32(floor(shiftedsignificandPart));
+
+	// Shift the remainder of the significand into the integer range
+	shiftedsignificandPart -= significandOne;
+	uint32 significandTwo = (uint32)(ldexp(shiftedsignificandPart, 21));
+
+	CompactSerializedDouble returnValue;
+	returnValue.signAndSignificandOne = ((uint32)(value < 0 ? 1 : 0) << 31) |   // Sign
+	                                    (significandOne & 0x7FFFFFFF);          // significandOne with MSB inferred
+	// Exponent stored as an offset to 1023
+	returnValue.exponentAndSignificandTwo = ((uint32)(exponent + 1023) << 21) | significandTwo;
+
+	return returnValue;
+}
+
+double decodeDouble_Compact(CompactSerializedDouble value) {
+	// Expand the exponent and the parts of the significand
+	int exponent = (int)(value.exponentAndSignificandTwo >> 21) - 1023;
+	double expandedsignificandOne = (double)(0x80000000 /* Inferred MSB */ | (value.signAndSignificandOne & 0x7FFFFFFF));
+	double expandedsignificandTwo = (double)(value.exponentAndSignificandTwo & 0x1FFFFF);
+
+	// Deflate the significand
+	double shiftedsignificand = ldexp(expandedsignificandTwo, -21);
+	double significand = ldexp(expandedsignificandOne + shiftedsignificand, -32);
+
+	// Re-calculate the actual double
+	double returnValue = ldexp(significand, exponent);
+
+	// Check the sign bit and return
+	return ((value.signAndSignificandOne & 0x80000000) == 0x80000000) ? -returnValue : returnValue;
+}
+
+} // End of namespace Sword25
diff --git a/engines/sword25/util/double_serialization.h b/engines/sword25/util/double_serialization.h
new file mode 100644
index 0000000..e90338c
--- /dev/null
+++ b/engines/sword25/util/double_serialization.h
@@ -0,0 +1,95 @@
+/* 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.
+ *
+ */
+
+#ifndef DOUBLE_SERIALIZATION_H
+#define DOUBLE_SERIALIZATION_H
+
+#include "common/types.h"
+
+
+namespace Util {
+
+struct SerializedDouble {
+	uint32 significandOne;
+	uint32 signAndSignificandTwo;
+	int16 exponent;
+};
+
+struct CompactSerializedDouble {
+	uint32 signAndSignificandOne;
+	uint32 exponentAndSignificandTwo;
+};
+
+/**
+ * Encodes a double as two uint32 and a one int16
+ *
+ * Supports denormalized numbers. Does NOT support NaN, or Inf
+ *
+ * @param value    The value to encode
+ * @return         The encoded value
+ */
+SerializedDouble encodeDouble(double value);
+/**
+ * Decodes a previously encoded double
+ *
+ * @param value    The value to decode
+ * @return         The decoded value
+ */
+double decodeDouble(SerializedDouble value);
+
+/**
+ * Encodes a double as a uint64
+ *
+ * Does NOT support denormalized numbers. Does NOT support NaN, or Inf
+ *
+ * @param value    The value to encode
+ * @return         The encoded value
+ */
+uint64 encodeDouble_64(double value);
+/**
+ * Decodes a previously encoded double
+ *
+ * @param value    The value to decode
+ * @return         The decoded value
+ */
+double decodeDouble_64(uint64 value);
+
+/**
+ * Encodes a double as two uint32
+ *
+ * Does NOT support denormalized numbers. Does NOT support NaN, or Inf
+ *
+ * @param value    The value to encode
+ * @return         The encoded value
+ */
+CompactSerializedDouble encodeDouble_Compact(double value);
+/**
+ * Decodes a previously encoded double
+ *
+ * @param value    The value to decode
+ * @return         The decoded value
+ */
+double decodeDouble_Compact(CompactSerializedDouble value);
+
+} // End of namespace Sword25
+
+#endif
diff --git a/engines/sword25/util/double_serializer.cpp b/engines/sword25/util/double_serializer.cpp
deleted file mode 100644
index d7ba4f3..0000000
--- a/engines/sword25/util/double_serializer.cpp
+++ /dev/null
@@ -1,138 +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.
- *
- */
-
-#include "sword25/util/double_serializer.h"
-
-#include "common/scummsys.h"
-
-
-namespace Util {
-
-SerializedDouble encodeDouble(double value) {
-	// Split the value into its significand and exponent
-	int exponent;
-	double significand = frexp(value, &exponent);
-
-	// Shift the the first part of the significand into the integer range
-	double shiftedsignificandPart = ldexp(abs(significand), 32);
-	uint32 significandOne = uint32(floor(shiftedsignificandPart));
-
-	// Shift the remainder of the significand into the integer range
-	shiftedsignificandPart -= significandOne;
-	uint32 significandTwo = (uint32)(ldexp(shiftedsignificandPart, 31));
-
-	SerializedDouble returnValue;
-	returnValue.significandOne = significandOne;                                // SignificandOne
-	returnValue.signAndSignificandTwo = ((uint32)(value < 0 ? 1 : 0) << 31) |   // Sign
-	                                    significandTwo;                         // SignificandTwo
-	returnValue.exponent = (int16)exponent;
-	return returnValue;
-}
-
-double decodeDouble(SerializedDouble value) {
-	// Expand the exponent and the parts of the significand
-	int exponent = (int)value.exponent;
-	double expandedsignificandOne = (double)value.significandOne;
-	double expandedsignificandTwo = (double)(value.signAndSignificandTwo & 0x7FFFFFFF);
-
-	// Deflate the significand
-	double shiftedsignificand = ldexp(expandedsignificandTwo, -21);
-	double significand = ldexp(expandedsignificandOne + shiftedsignificand, -32);
-
-	// Re-calculate the actual double
-	double returnValue = ldexp(significand, exponent);
-
-	// Check the sign bit and return
-	return ((value.signAndSignificandTwo & 0x80000000) == 0x80000000) ? -returnValue : returnValue;
-}
-
-uint64 encodeDouble_64(double value) {
-	// Split the value into its significand and exponent
-	int exponent;
-	double significand = frexp(value, &exponent);
-
-	// Shift the significand into the integer range
-	double shiftedsignificand = ldexp(abs(significand), 53);
-
-	// Combine everything using the IEEE standard
-	uint64 uintsignificand = (uint64)shiftedsignificand;
-	return ((uint64)(value < 0 ? 1 : 0) << 63) |        // Sign
-	       ((uint64)(exponent + 1023) << 52) |          // Exponent stored as an offset to 1023
-	       (uintsignificand & 0x000FFFFFFFFFFFFF);      // significand with MSB inferred
-}
-
-double decodeDouble_64(uint64 value) {
-	// Expand the exponent and significand
-	int exponent = (int)((value >> 52) & 0x7FF) - 1023;
-	double expandedsignificand = (double)(0x10000000000000 /* Inferred MSB */ | (value & 0x000FFFFFFFFFFFFF));
-
-	// Deflate the significand
-	int temp;
-	double significand = frexp(expandedsignificand, &temp);
-
-	// Re-calculate the actual double
-	double returnValue = ldexp(significand, exponent);
-
-	// Check the sign bit and return
-	return ((value & 0x8000000000000000) == 0x8000000000000000) ? -returnValue : returnValue;
-}
-
-CompactSerializedDouble encodeDouble_Compact(double value) {
-	// Split the value into its significand and exponent
-	int exponent;
-	double significand = frexp(value, &exponent);
-
-	// Shift the the first part of the significand into the integer range
-	double shiftedsignificandPart = ldexp(abs(significand), 32);
-	uint32 significandOne = uint32(floor(shiftedsignificandPart));
-
-	// Shift the remainder of the significand into the integer range
-	shiftedsignificandPart -= significandOne;
-	uint32 significandTwo = (uint32)(ldexp(shiftedsignificandPart, 21));
-
-	CompactSerializedDouble returnValue;
-	returnValue.signAndSignificandOne = ((uint32)(value < 0 ? 1 : 0) << 31) |   // Sign
-	                                    (significandOne & 0x7FFFFFFF);          // significandOne with MSB inferred
-	// Exponent stored as an offset to 1023
-	returnValue.exponentAndSignificandTwo = ((uint32)(exponent + 1023) << 21) | significandTwo;
-
-	return returnValue;
-}
-
-double decodeDouble_Compact(CompactSerializedDouble value) {
-	// Expand the exponent and the parts of the significand
-	int exponent = (int)(value.exponentAndSignificandTwo >> 21) - 1023;
-	double expandedsignificandOne = (double)(0x80000000 /* Inferred MSB */ | (value.signAndSignificandOne & 0x7FFFFFFF));
-	double expandedsignificandTwo = (double)(value.exponentAndSignificandTwo & 0x1FFFFF);
-
-	// Deflate the significand
-	double shiftedsignificand = ldexp(expandedsignificandTwo, -21);
-	double significand = ldexp(expandedsignificandOne + shiftedsignificand, -32);
-
-	// Re-calculate the actual double
-	double returnValue = ldexp(significand, exponent);
-
-	// Check the sign bit and return
-	return ((value.signAndSignificandOne & 0x80000000) == 0x80000000) ? -returnValue : returnValue;
-}
-
-} // End of namespace Sword25
diff --git a/engines/sword25/util/double_serializer.h b/engines/sword25/util/double_serializer.h
deleted file mode 100644
index e90338c..0000000
--- a/engines/sword25/util/double_serializer.h
+++ /dev/null
@@ -1,95 +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.
- *
- */
-
-#ifndef DOUBLE_SERIALIZATION_H
-#define DOUBLE_SERIALIZATION_H
-
-#include "common/types.h"
-
-
-namespace Util {
-
-struct SerializedDouble {
-	uint32 significandOne;
-	uint32 signAndSignificandTwo;
-	int16 exponent;
-};
-
-struct CompactSerializedDouble {
-	uint32 signAndSignificandOne;
-	uint32 exponentAndSignificandTwo;
-};
-
-/**
- * Encodes a double as two uint32 and a one int16
- *
- * Supports denormalized numbers. Does NOT support NaN, or Inf
- *
- * @param value    The value to encode
- * @return         The encoded value
- */
-SerializedDouble encodeDouble(double value);
-/**
- * Decodes a previously encoded double
- *
- * @param value    The value to decode
- * @return         The decoded value
- */
-double decodeDouble(SerializedDouble value);
-
-/**
- * Encodes a double as a uint64
- *
- * Does NOT support denormalized numbers. Does NOT support NaN, or Inf
- *
- * @param value    The value to encode
- * @return         The encoded value
- */
-uint64 encodeDouble_64(double value);
-/**
- * Decodes a previously encoded double
- *
- * @param value    The value to decode
- * @return         The decoded value
- */
-double decodeDouble_64(uint64 value);
-
-/**
- * Encodes a double as two uint32
- *
- * Does NOT support denormalized numbers. Does NOT support NaN, or Inf
- *
- * @param value    The value to encode
- * @return         The encoded value
- */
-CompactSerializedDouble encodeDouble_Compact(double value);
-/**
- * Decodes a previously encoded double
- *
- * @param value    The value to decode
- * @return         The decoded value
- */
-double decodeDouble_Compact(CompactSerializedDouble value);
-
-} // End of namespace Sword25
-
-#endif
diff --git a/engines/sword25/util/lua_persist.cpp b/engines/sword25/util/lua_persist.cpp
index b9c0b13..939dbf3 100644
--- a/engines/sword25/util/lua_persist.cpp
+++ b/engines/sword25/util/lua_persist.cpp
@@ -22,7 +22,7 @@
 
 #include "sword25/util/lua_persistence.h"
 
-#include "sword25/util/double_serializer.h"
+#include "sword25/util/double_serialization.h"
 #include "sword25/util/lua_persistence_util.h"
 
 #include "common/stream.h"
diff --git a/engines/sword25/util/lua_unpersist.cpp b/engines/sword25/util/lua_unpersist.cpp
index aa924ff..8d64430 100644
--- a/engines/sword25/util/lua_unpersist.cpp
+++ b/engines/sword25/util/lua_unpersist.cpp
@@ -22,7 +22,7 @@
 
 #include "sword25/util/lua_persistence.h"
 
-#include "sword25/util/double_serializer.h"
+#include "sword25/util/double_serialization.h"
 #include "sword25/util/lua_persistence_util.h"
 
 #include "common/stream.h"


Commit: 8668707f160fa171edfa68df036f28c7ba4e9a88
    https://github.com/scummvm/scummvm/commit/8668707f160fa171edfa68df036f28c7ba4e9a88
Author: RichieSams (adastley at gmail.com)
Date: 2014-12-30T15:40:33-06:00

Commit Message:
SWORD25: Fix how nils are persisted

The unpersist code expects nils to be represented as an index with value 0.
The persist code incorrectly wrote out this data

Changed paths:
    engines/sword25/util/lua_persist.cpp



diff --git a/engines/sword25/util/lua_persist.cpp b/engines/sword25/util/lua_persist.cpp
index 939dbf3..6d75806 100644
--- a/engines/sword25/util/lua_persist.cpp
+++ b/engines/sword25/util/lua_persist.cpp
@@ -59,7 +59,7 @@ void persistLua(lua_State *luaState, Common::WriteStream *writeStream) {
 	SerializationInfo info;
 	info.luaState = luaState;
 	info.writeStream = writeStream;
-	info.counter = 0u;
+	info.counter = 1u;
 
 	// The process starts with the lua stack as follows:
 	// >>>>> permTbl rootObj
@@ -145,19 +145,22 @@ static void serialize(SerializationInfo *info) {
 		return;
 	}
 
-	// Pop the nil off the stack
+	// Pop the index/nil off the stack
 	lua_pop(info->luaState, 1);
 
-	// Write out a flag that indicates that this is a real object
-	info->writeStream->writeByte(1);
-
-	// If the object itself is nil, then write out a zero as a placeholder
+	// 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);


Commit: 67114c3e7eafdd6ba8c7bc799a40f789acc1efa3
    https://github.com/scummvm/scummvm/commit/67114c3e7eafdd6ba8c7bc799a40f789acc1efa3
Author: RichieSams (adastley at gmail.com)
Date: 2014-12-30T15:40:33-06:00

Commit Message:
SWORD25: Remove old lua persistence files

Changed paths:
  R engines/sword25/util/pluto/CHANGELOG
  R engines/sword25/util/pluto/FILEFORMAT
  R engines/sword25/util/pluto/README
  R engines/sword25/util/pluto/THANKS
  R engines/sword25/util/pluto/pdep.cpp
  R engines/sword25/util/pluto/pdep/README
  R engines/sword25/util/pluto/pdep/lzio.h
  R engines/sword25/util/pluto/pdep/pdep.h
  R engines/sword25/util/pluto/pluto.cpp
  R engines/sword25/util/pluto/pluto.h
  R engines/sword25/util/pluto/plzio.cpp



diff --git a/engines/sword25/util/pluto/CHANGELOG b/engines/sword25/util/pluto/CHANGELOG
deleted file mode 100644
index 1be321f..0000000
--- a/engines/sword25/util/pluto/CHANGELOG
+++ /dev/null
@@ -1,37 +0,0 @@
-$Id$
-
--- 2.4 --
-* Changed upval unboxing to allow upvals which contain func-housed cycles
-* Added stack checking to all stack-growing functions
-* Serialized debug information for functions
-
--- 2.3 --
-* Added LUALIB_API declaration for luaopen_pluto
-
--- 2.2 --
-* Rolled all internal Lua dependencies into the Pluto distribution
-* Made the unit tests depend on dynamically loading Pluto
-
--- 2.1 --
-* Various fixes to make the GC happy
-* stack size always expanded where necessary
-* fixed some memory leaks
-* GC disabled during unpersist
-* callstack initialized for traversal
-
-This changelog is maintained as of version 2.0alpha1. 
-Earlier versions are changelogged on the LuaForge site.
-
--- 2.0 --
-* Fixed a few format changes to 5.1.3
-* Fixed myriad warnings
-* GCC compliance: not incrementing cast results
-* Fix for self-referring upvals
-* Renamed loading function to work with Lua module system
-* Loading tables with __newindex works
-* unpersist makes buffer copy
-
--- 2.0alpha1 --
-* Fixed all outstanding 5.0->5.1 conversion issues
-* Made heavier use of size_t in preference to int
-* Fixed GC/Upval issue (thanks to Eric Jacobs)
diff --git a/engines/sword25/util/pluto/FILEFORMAT b/engines/sword25/util/pluto/FILEFORMAT
deleted file mode 100644
index e771667..0000000
--- a/engines/sword25/util/pluto/FILEFORMAT
+++ /dev/null
@@ -1,168 +0,0 @@
-$Id$
-
-pluto_persist() produces a "hunk" of objects. Here's the file format adhered
-to by the function, and expected by pluto_unpersist(). 
-
-As a developer, I feel that where file format information is given it is of
-utmost importance that that information precisely and accurately reflects the
-actual operation of the application. Therefore, if you find any discrepancy
-between this and actual operation, please lambast me thoroughly over email.
-
-Pseudo-C is used to express the file format. Padding is assumed to be
-nonexistent. The keyword "one_of" is used to express a concept similar to
-"union", except that its size is the size of the actual datatype chosen. Thus,
-objects which contain, directly or indirectly, a one_of, may vary  in size.
-
-
-struct Object {
-	int firstTime;		/* Whether this is the first time the object
-				is being referenced */
-	one_of {
-		RealObject o;	/* if firstTime == 1 */
-		Reference r;	/* if firstTime == 0 */
-	};
-};
-
-struct Reference {
-	int ref;	/* The index the object was registered with */
-};
-
-struct RealObject {
-	int type;		/* The type of the object */
-	one_of {
-		Boolean b;	/* If type == LUA_TBOOLEAN */
-		LightUserData l;	/* If type == LUA_TLIGHTUSERDATA */
-		Number n;	/* If type == LUA_TNUMBER */
-		String s;	/* If type == LUA_TSTRING */
-		Table t;	/* If type == LUA_TTABLE */
-		Function f;	/* If type == LUA_TFUNCTION */
-		Userdata u;	/* If type == LUA_TUSERDATA */
-		Thread th;	/* If type == LUA_TTHREAD */
-		Proto p;	/* If type == LUA_TPROTO (from lobject.h) */
-		Upval uv;	/* If type == LUA_TUPVAL (from lobject.h) */
-	};			/* The actual object */
-};
-
-struct Boolean {
-	int32 bvalue;		/* 0 for false, 1 for true */
-};
-
-struct LightUserData {
-	void* luvalue;		/* The actual, literal pointer */
-};
-
-struct Number {
-	lua_Number nvalue;	/* The actual number */
-};
-
-struct String {
-	int length;		/* The length of the string */
-	char str[length];	/* The actual string (not null terminated) */
-};
-
-struct Table {
-	int isspecial;		/* 1 if SP is used; 0 otherwise */
-	one_of {
-		Closure c;	/* if isspecial == 1; closure to refill the table */
-		LiteralTable t;	/* if isspecial == 0; literal table info */
-	};
-};
-
-struct LiteralTable {
-	Object metatable;	/* nil for default metatable */
-	Pair p[];		/* key/value pairs */
-	Object nil = nil;	/* Nil reference to terminate */
-};
-
-struct Pair {
-	Object key;
-	Object value;
-};
-
-struct Function { 		/* Actually a closure */
-	lu_byte nups;		/* Number of upvalues the function uses */
-	Object proto;		/* The proto this function uses */
-	Object upvals[nups];	/* All upvalues */
-	Object fenv;		/* The FEnv (nil for the global table)
-};
-
-struct Upval {
-	Object obj;		/* The object this upval refers to */
-}
-
-struct Userdata {
-	int isSpecial; 		/* 1 for special persistence, 0 for literal
-	one_of {
-		LiteralUserdata lu;	/* if is_special is 0 */
-		SpecialUserdata su;	/* if is_special is 1 */
-	};
-};
-
-struct LiteralUserdata {
-	Object metatable;		/* The metatable (nil for default) */
-	int length;		/* Size of the data */
-	char data[length];	/* The actual data */
-};
-
-struct SpecialUserdata {
-	int length;		/* The size of the data */
-	Object func;		/* The closure used to fill the userdata */
-};
-
-struct Thread {
-	int stacksize;		/* The size of the stack filled with objects,
-				 * including the "nil" that is hidden below
-				 * the bottom of the stack visible to C */
-	Object stack[stacksize];/* Indices of all stack values, bottom up */
-	int callinfosize;	/* Number of elements in the CallInfo stack */
-	CallInfo callinfostack[callinfosize];	/* The CallInfo stack */
-	int base;		/* base = L->base - L->stack; */
-	int top;		/* top = L->top - L->stack; */
-	OpenUpval openupvals[]; /* Upvalues to open */
-	Object nil = nil;	/* To terminate the open upvalues list */
-};
-
-struct OpenUpval {
-	Object upval;		/* The upvalue */
-	int stackpos;		/* The stack position to "reopen" it to */
-
-};
-
-struct CallInfo {
-	int base;		/* base = ci->base - L->stack; */
-	int top;		/* top = ci->top - L->stack; */
-	int pc;			/* pc = ci->pc - proto->code; */
-	int state;		/* flags used by the CallInfo */
-};
-
-struct Proto {
-	int sizek;		/* Number of constants referenced */
-	Object k[sizek];	/* Constants referenced */
-	int sizep;		/* Number of inner Protos referenced */
-	Object p[sizep];	/* Inner Protos referenced */
-	int sizecode;		/* Number of instructions in code */
-	Instruction code[sizecode];	/* The proto's code */
-	ProtoDebug debuginfo;	/* Debug information for the proto */
-	lu_byte nups;		/* Number of upvalues used */
-	lu_byte numparams;	/* Number of parameters taken */
-	lu_byte is_vararg;	/* 1 if function accepts varargs, 0 otherwise */
-	lu_byte maxstacksize;	/* Size of stack reserved for the function */
-};
-
-struct ProtoDebug {
-	int sizeupvals;		/* Number of upvalue names */
-	Object upvals;		/* Upvalue names */
-	int sizelocvars;	/* Number of local variable names */
-	LocVar[sizelocvars];	/* Local variable names */
-	Object source;		/* The source code */
-	int sizelineinfo;	/* Number of opcode-line mappings */
-	int lineinfo[sizelineinfo];	/* opcode-line mappings */
-	int linedefined;	/* Start of line range */
-	int lastlinedefined;	/* End of line range */
-};
-
-struct LocVar {
-	Object name;		/* Name of the local variable */
-	int startpc;		/* Point where variable is active */
-	int endpc;		/* Point where variable is dead */
-};
diff --git a/engines/sword25/util/pluto/README b/engines/sword25/util/pluto/README
deleted file mode 100644
index 838fce4..0000000
--- a/engines/sword25/util/pluto/README
+++ /dev/null
@@ -1,133 +0,0 @@
-$Id$
-
-PLUTO - Heavy duty persistence for Lua
-
-Pluto is a library which allows users to write arbitrarily large portions
-of the "Lua universe" into a flat file, and later read them back into the
-same or a different Lua universe. Object references are appropriately
-handled, such that the file contains everything needed to recreate the
-objects in question.
-
-Pluto has the following major features: 
-* Can persist any Lua function
-* Can persist threads 
-* Works with any Lua chunkreader/chunkwriter 
-* Support for "invariant" permanent objects, of all datatypes
-* Can invoke metafunctions for custom persistence of tables and userdata
-
-Pluto 2.2 requires Lua 5.1.3. If you need to use Pluto with Lua
-5.0, please use version 1.2 of Pluto.
-
-Starting with version 2.2, Pluto no longer depends on the Lua sources.
-Instead, it subsumes the required headers into its own codebase.
-As a result, it may not work properly with Lua version 5.1.4 or later.
-
-Pluto may have bugs. Users are advised to define lua_assert in 
-luaconf.h to something useful when compiling in debug mode, to catch
-assertions by Pluto and Lua.
-
-The Pluto library consists of two public functions.
-
-int pluto_persist(lua_State *L, lua_Chunkwriter writer, void *ud)
-
-This function recursively persists the Lua object in stack position 2
-and all other objects which are directly or indirectly referenced by
-it, except those referenced in the permanent object table. The data
-is written using the chunk-writer given, and that writer is passed
-the arbitrary pointer value ud.
-
-The Lua stack must contain exactly and only these two items, in order:
-
-1. A table of permanent objects, that should not be persisted. For each
-permanent object, the object itself should be the key, and a unique
-object of any type should be the value. Likely candidates for this table 
-include Lua functions (including those in the Lua libraries) that are 
-loaded at load-time. It must include all non-persistable objects that 
-are referenced by the object to be persisted. The table is not modified 
-by the function. Objects in this table are considered "opaque" and are 
-not examined or descended into. Objects should not appear in the table 
-multiple times; the result of doing this is undefined (though probably 
-harmless). NOTE: If you are planning to persist threads, keep in mind 
-that all yielded threads have coroutine.yield on the tops of their 
-stacks. Since it's a C function, it should be put here.  For complex 
-permanents, it may be a good idea to use the __index meta-function of 
-the permanents table to "search" for permanents.
-
-2. The single object to be persisted. In many cases, this will be the
-global table. For more flexibility, however, it may be something like a
-table built for the occasion, with various values to keep track of. The
-object may not be nil.
-
-
-int pluto_unpersist(lua_State *L, lua_Chunkreader reader, void *ud)
-
-This function loads in a Lua object and places it on top of the stack. All
-objects directly or indirectly referenced by it are also loaded.
-
-The Lua stack must contain, as its top value, a table of permanent
-objects. This table should be like the permanent object table used when
-persisting, but with the key and value of each pair reversed. These 
-objects are used as substitutes for those referenced in their positions 
-when persisting, and under most circumstances should be identical objects
-to those referenced in the permanents table used for persisting. It's 
-okay for multiple keys to refer to the same object.
-
-
-RUNNING PLUTO FROM LUA:
-It is also possible to invoke pluto from a Lua script. The C function
-pluto_open() will register pluto.persist and pluto.unpersist, lua functions
-which operate on strings. The first takes a permanents table and a root 
-object, and returns a string; the second takes a permanents table and a 
-string, and returns the root object.
-
-An error will be raised if pluto.persist is called from a thread which is
-itself referenced by the root object.
-
-SPECIAL PERSISTENCE:
-Tables and userdata have special persistence semantics. These semantics are
-keyed to the value of the object's metatable's __persist member, if any. This
-member may be any of the following four values:
-1. Boolean "true": The table or userdata is persisted literally; tables are
-persisted member-by-member, and userdata are written out as literal data.
-2. Boolean "false": An error is returned, indicating that the object cannot
-be persisted.
-3. A function: This function should take one argument, the object in question,
-and return one result, a closure. This "fixup closure", in turn, will be 
-persisted, and during unpersistence will be called. The closure will be 
-responsible for recreating the object with the appropriate data, based on 
-its upvalues.
-4. Nil, or no metatable. In the case of tables, the table is literally
-persisted. In the case of userdata, an error is returned.
-
-Here's an example of special persistence for a simple 3d vector object:
-
-vec = { x = 2, y = 1, z = 4 }
-setmetatable(vec, { __persist = function(oldtbl)
-	local x = oldtbl.x
-	local y = oldtbl.y
-	local z = oldtbl.z
-	local mt = getmetatable(oldtbl)
-	return function()
-		newtbl = {}
-		newtbl.x = x
-		newtbl.y = y
-		newtbl.z = z
-		setmetatable(newtbl, mt)
-		return newtbl
-	end
-end })
-
-Note how x, y, z, and the mt are explicitly pulled out of the table. It is 
-important that the fixup closure returned not reference the original table 
-directly, as that table would again be persisted as an upvalue, leading to an 
-infinite loop. Also note that the object's metatable is NOT automatically 
-persisted; it is necessary for the fixup closure to reset it, if it wants.
-
-LIMITATIONS/TODO: 
-* Light userdata are persisted literally, as their pointer values. This 
-may or may not be what you want.  
-* Closures of C functions may not be persisted. Once it becomes possible
-to specify a C function "proto" as a permanent object, this restriction
-will be relaxed.
-
-BUGS: None known. Emphasis on the 'known'.
diff --git a/engines/sword25/util/pluto/THANKS b/engines/sword25/util/pluto/THANKS
deleted file mode 100644
index 443713f..0000000
--- a/engines/sword25/util/pluto/THANKS
+++ /dev/null
@@ -1,9 +0,0 @@
-Pluto is surprisingly robust and useful. This would not be the case without
-the hard work and helpfulness of the following people, mentioned in no
-particular order:
-
-Ivko Stanilov
-Goran Adrinek
-Eric Jacobs
-Anolan Milanes
-Malte Thiesen
diff --git a/engines/sword25/util/pluto/pdep.cpp b/engines/sword25/util/pluto/pdep.cpp
deleted file mode 100644
index a32c43b..0000000
--- a/engines/sword25/util/pluto/pdep.cpp
+++ /dev/null
@@ -1,112 +0,0 @@
-/* This file is derived from the Lua source code. Please see lua.h for
-the copyright statement.
-*/
-
-#include "pdep/pdep.h"
-
-#define api_incr_top(L)   {api_check(L, L->top < L->ci->top); L->top++;}
-
-void pdep_pushobject (lua_State *L, const TValue *o) {
-	setobj2s(L, L->top, o);
-	api_incr_top(L);
-}
-
-void *pdep_realloc_ (lua_State *L, void *block, size_t osize, size_t nsize) {
-	global_State *g = G(L);
-	lua_assert((osize == 0) == (block == NULL));
-	block = (*g->frealloc)(g->ud, block, osize, nsize);
-	lua_assert((nsize == 0) == (block == NULL));
-	g->totalbytes = (g->totalbytes - osize) + nsize;
-	return block;
-}
-
-void pdep_link (lua_State *L, GCObject *o, lu_byte tt) {
-	global_State *g = G(L);
-	o->gch.next = g->rootgc;
-	g->rootgc = o;
-	o->gch.marked = luaC_white(g);
-	o->gch.tt = tt;
-}
-
-Proto *pdep_newproto (lua_State *L) {
-	Proto *f = pdep_new(L, Proto);
-	pdep_link(L, obj2gco(f), LUA_TPROTO);
-	f->k = NULL;
-	f->sizek = 0;
-	f->p = NULL;
-	f->sizep = 0;
-	f->code = NULL;
-	f->sizecode = 0;
-	f->sizelineinfo = 0;
-	f->sizeupvalues = 0;
-	f->nups = 0;
-	f->upvalues = NULL;
-	f->numparams = 0;
-	f->is_vararg = 0;
-	f->maxstacksize = 0;
-	f->lineinfo = NULL;
-	f->sizelocvars = 0;
-	f->locvars = NULL;
-	f->linedefined = 0;
-	f->lastlinedefined = 0;
-	f->source = NULL;
-	return f;
-}
-
-Closure *pdep_newLclosure (lua_State *L, int nelems, Table *e) {
-	Closure *c = cast(Closure *, pdep_malloc(L, sizeLclosure(nelems)));
-	pdep_link(L, obj2gco(c), LUA_TFUNCTION);
-	c->l.isC = 0;
-	c->l.env = e;
-	c->l.nupvalues = cast_byte(nelems);
-	while (nelems--) c->l.upvals[nelems] = NULL;
-	return c;
-}
-
-static void correctstack (lua_State *L, TValue *oldstack) {
-  CallInfo *ci;
-  GCObject *up;
-  L->top = (L->top - oldstack) + L->stack;
-  for (up = L->openupval; up != NULL; up = up->gch.next)
-    gco2uv(up)->v = (gco2uv(up)->v - oldstack) + L->stack;
-  for (ci = L->base_ci; ci <= L->ci; ci++) {
-    ci->top = (ci->top - oldstack) + L->stack;
-    ci->base = (ci->base - oldstack) + L->stack;
-    ci->func = (ci->func - oldstack) + L->stack;
-  }
-  L->base = (L->base - oldstack) + L->stack;
-}
-
-
-void pdep_reallocstack (lua_State *L, int newsize) {
-	TValue *oldstack = L->stack;
-	int realsize = newsize + 1 + EXTRA_STACK;
-	lua_assert(L->stack_last - L->stack == L->stacksize - EXTRA_STACK - 1);
-	pdep_reallocvector(L, L->stack, L->stacksize, realsize, TValue);
-	L->stacksize = realsize;
-	L->stack_last = L->stack+newsize;
-	correctstack(L, oldstack);
-}
-
-void pdep_growstack (lua_State *L, int n) {
-	if (n <= L->stacksize)  /* double size is enough? */
-		pdep_reallocstack(L, 2*L->stacksize);
-	else
-		pdep_reallocstack(L, L->stacksize + n);
-}
-
-void pdep_reallocCI (lua_State *L, int newsize) {
-	CallInfo *oldci = L->base_ci;
-	pdep_reallocvector(L, L->base_ci, L->size_ci, newsize, CallInfo);
-	L->size_ci = newsize;
-	L->ci = (L->ci - oldci) + L->base_ci;
-	L->end_ci = L->base_ci + L->size_ci - 1;
-}
-
-TString *pdep_newlstr (lua_State *L, const char *str, size_t l) {
-	TString *res;
-	lua_pushlstring(L, str, l);
-	res = rawtsvalue(L->top-1);
-	lua_pop(L, 1);
-	return res;
-}
diff --git a/engines/sword25/util/pluto/pdep/README b/engines/sword25/util/pluto/pdep/README
deleted file mode 100644
index 3592754..0000000
--- a/engines/sword25/util/pluto/pdep/README
+++ /dev/null
@@ -1,5 +0,0 @@
-These files are directly copied from the Lua distribution, with the
-exception of lzio.h, which is s/lua{ZM}/pdep/g and has an include removed.
-
-As such, unlike the rest of Pluto, they are released under the
-same terms as Lua. See "lua.h" for the copyright notice.
diff --git a/engines/sword25/util/pluto/pdep/lzio.h b/engines/sword25/util/pluto/pdep/lzio.h
deleted file mode 100644
index 2e37f8d..0000000
--- a/engines/sword25/util/pluto/pdep/lzio.h
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
-** $Id$
-** Buffered streams
-** See Copyright Notice in lua.h
-*/
-
-
-#ifndef lzio_h
-#define lzio_h
-
-#include "sword25/util/lua/lua.h"
-
-
-#define EOZ	(-1)			/* end of stream */
-
-typedef struct Zio ZIO;
-
-#define char2int(c)	cast(int, cast(unsigned char, (c)))
-
-#define zgetc(z)  (((z)->n--)>0 ?  char2int(*(z)->p++) : pdep_fill(z))
-
-typedef struct Mbuffer {
-  char *buffer;
-  size_t n;
-  size_t buffsize;
-} Mbuffer;
-
-#define pdep_initbuffer(L, buff) ((buff)->buffer = NULL, (buff)->buffsize = 0)
-
-#define pdep_buffer(buff)	((buff)->buffer)
-#define pdep_sizebuffer(buff)	((buff)->buffsize)
-#define pdep_bufflen(buff)	((buff)->n)
-
-#define pdep_resetbuffer(buff) ((buff)->n = 0)
-
-
-#define pdep_resizebuffer(L, buff, size) \
-	(pdep_reallocvector(L, (buff)->buffer, (buff)->buffsize, size, char), \
-	(buff)->buffsize = size)
-
-#define pdep_freebuffer(L, buff)	pdep_resizebuffer(L, buff, 0)
-
-
-LUAI_FUNC char *pdep_openspace (lua_State *L, Mbuffer *buff, size_t n);
-LUAI_FUNC void pdep_init (lua_State *L, ZIO *z, lua_Reader reader,
-                                        void *data);
-LUAI_FUNC size_t pdep_read (ZIO* z, void* b, size_t n);	/* read next n bytes */
-LUAI_FUNC int pdep_lookahead (ZIO *z);
-
-
-
-/* --------- Private Part ------------------ */
-
-struct Zio {
-  size_t n;			/* bytes still unread */
-  const char *p;		/* current position in buffer */
-  lua_Reader reader;
-  void* data;			/* additional data */
-  lua_State *L;			/* Lua state (for reader) */
-};
-
-
-LUAI_FUNC int pdep_fill (ZIO *z);
-
-#endif
diff --git a/engines/sword25/util/pluto/pdep/pdep.h b/engines/sword25/util/pluto/pdep/pdep.h
deleted file mode 100644
index 664fc81..0000000
--- a/engines/sword25/util/pluto/pdep/pdep.h
+++ /dev/null
@@ -1,42 +0,0 @@
-#ifndef PDEP_H
-#define PDEP_H
-
-#include "sword25/util/lua/lua.h"
-#include "sword25/util/pluto/pdep/lzio.h"
-#include "sword25/util/lua/ldo.h"
-#include "sword25/util/lua/lfunc.h"
-#include "sword25/util/lua/lgc.h"
-#include "sword25/util/lua/llimits.h"
-#include "sword25/util/lua/lobject.h"
-#include "sword25/util/lua/lopcodes.h"
-#include "sword25/util/lua/lstate.h"
-#include "sword25/util/lua/lstring.h"
-#include "sword25/util/lua/lauxlib.h"
-
-
-#define pdep_reallocv(L,b,on,n,e) \
-	pdep_realloc_(L, (b), (on)*(e), (n)*(e))
-#define pdep_reallocvector(L, v,oldn,n,t) \
-	((v)=cast(t *, pdep_reallocv(L, v, oldn, n, sizeof(t))))
-#define pdep_freearray(L, b, n, t)   pdep_reallocv(L, (b), n, 0, sizeof(t))
-#define pdep_newvector(L,n,t) \
-	cast(t *, pdep_reallocv(L, NULL, 0, n, sizeof(t)))
-#define pdep_new(L,t)		cast(t *, pdep_malloc(L, sizeof(t)))
-#define pdep_malloc(L,t)	pdep_realloc_(L, NULL, 0, (t))
-#define pdep_checkstack(L,n)	\
-  if ((char *)L->stack_last - (char *)L->top <= (n)*(int)sizeof(TValue)) \
-    pdep_growstack(L, n); \
-  else pdep_reallocstack(L, L->stacksize - EXTRA_STACK - 1);
-
-
-void pdep_pushobject (lua_State *L, const TValue *o);
-void *pdep_realloc_ (lua_State *L, void *block, size_t osize, size_t nsize);
-void pdep_link (lua_State *L, GCObject *o, lu_byte tt);
-Proto *pdep_newproto (lua_State *L);
-Closure *pdep_newLclosure (lua_State *L, int nelems, Table *e);
-void pdep_reallocstack (lua_State *L, int newsize);
-void pdep_growstack (lua_State *L, int n);
-void pdep_reallocCI (lua_State *L, int newsize);
-TString *pdep_newlstr (lua_State *L, const char *str, size_t l);
-
-#endif
diff --git a/engines/sword25/util/pluto/pluto.cpp b/engines/sword25/util/pluto/pluto.cpp
deleted file mode 100644
index cbe16b0..0000000
--- a/engines/sword25/util/pluto/pluto.cpp
+++ /dev/null
@@ -1,2083 +0,0 @@
-/* $Id$ */
-
-/* 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 at 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 at luaos.net)
- * for Mobile Lua (http://luaos.net/pages/mobile-lua.php)
- */
-
-#include "sword25/util/lua/lua.h"
-#include "pluto.h"
-
-#undef TOTEXT
-
-#define USE_PDEP
-
-#ifdef USE_PDEP
-#include "pdep/pdep.h"
-#define LIF(prefix, name) pdep ## _ ## name
-#else
-#include "lapi.h"
-#include "ldo.h"
-#include "lfunc.h"
-#include "lgc.h"
-#include "llimits.h"
-#include "lmem.h"
-#include "lobject.h"
-#include "lopcodes.h"
-#include "lstate.h"
-#include "lstring.h"
-#include "lauxlib.h"
-#define LIF(prefix, name) lua ## prefix ## _ ## name
-#endif
-
-#include <string.h>
-
-
-/* Define this if you want size_t values to be written in 64-bit
-   (even on 32-bit systems). Should eliminate at least one source of
-   32/64 bit incompatibility. */
-#define SIZES64
-
-
-/* #define PLUTO_DEBUG */
-
-
-#ifdef SIZES64
-#define VERSION "Tamed Pluto 1.0 with SIZES64 flag"
-#else
-#define VERSION "Tamed Pluto 1.0"
-#endif
-
-
-#ifdef PLUTO_DEBUG
-#include <stdio.h>
-#endif
-
-#define PLUTO_TPERMANENT 101
-
-#define verify(x) { int v = (int)((x)); v=v; lua_assert(v); }
-
-#define NUMTYPES 9
-static const char* typenames[] = {
-	"nil",
-	"boolean",
-	"lightuserdata",
-	"number",
-	"string",
-	"table",
-	"function",
-	"userdata",
-	"thread"
-};
-
-static int humanReadable = 0;
-#define hrBufSize 200
-static char hrBuf[hrBufSize];
-
-typedef struct PersistInfo_t {
-	lua_State *L;
-	int counter;
-	lua_Chunkwriter writer;
-	void *ud;
-#ifdef PLUTO_DEBUG
-	int level;
-#endif
-} PersistInfo;
-
-#ifdef PLUTO_DEBUG
-void printindent(int indent)
-{
-	int il;
-	for(il=0; il<indent; il++) {
-		printf("  ");
-	}
-}
-#endif
-
-/* lua_Chunkwriter signature: (lua_State *L, const void *p, size_t sz, void *ud).
-   ud is a pointer to the WriterInfo struct (holds the buffer pointer)
-*/
-
-static void pi_write(PersistInfo *pi, const void *p, size_t size, void *ud) {
-	if (humanReadable) {
-		uint i;
-		snprintf(hrBuf, hrBufSize, "  pi_write %d ", (int) size);
-		pi->writer(pi->L, hrBuf, strlen(hrBuf), ud);
-		for (i = 0; i < size; i++) {
-			char b = ((char *)p)[i];
-			snprintf(hrBuf, hrBufSize, "%X%X", (b >> 4) & 0xF, b & 0xF);
-			pi->writer(pi->L, hrBuf, strlen(hrBuf), ud);
-		}
-		snprintf(hrBuf, hrBufSize, "\n");
-		pi->writer(pi->L, hrBuf, strlen(hrBuf), ud);
-	} else {
-		pi->writer(pi->L, p, size, ud);
-	}
-#ifdef TOTEXT
-	int i;
-	printf("  pi_write %d ", (int) size);
-	for (i = 0; i < size; i++) {
-		char b = ((char *)p)[i];
-		printf("%X%X", (b >> 4) & 0xF, b & 0xF);
-	}
-	printf("\n");
-#endif
-}
-
-static void hrOut(PersistInfo *pi) {
-	pi->writer(pi->L, hrBuf, strlen(hrBuf), pi->ud);
-}
-
-static void write_size(PersistInfo *pi, size_t *val)
-{
-#ifdef SIZES64
-	int64 longval; /* yeah, you really need long long to get 8 bytes on win32... duh. */
-	longval = *val;
-	pi_write(pi, &longval, 8, pi->ud);
-	if (humanReadable) {
-		snprintf(hrBuf, hrBufSize, "write_size64 %ld\n", longval);
-		hrOut(pi);
-	}
-#ifdef TOTEXT
-	printf("write_size64 %ld\n", longval);
-#endif
-#else
-	pi_write(pi, val, sizeof(size_t), pi->ud);
-	if (humanReadable) {
-		snprintf(hrBuf, hrBufSize, "write_size %ld\n", *((size_t *)val));
-		hrOut(pi);
-	}
-#ifdef TOTEXT
-	printf("write_size %ld\n", *val);
-#endif
-#endif
-}
-
-static void read_size(ZIO *zio, size_t *val)
-{
-#ifdef SIZES64
-	int64 longval;
-	verify(LIF(Z,read)(zio, &longval, 8) == 0);
-	*val = longval;
-#else
-	verify(LIF(Z,read)(zio, val, sizeof(size_t)) == 0);
-#endif
-}
-
-
-/* Mutual recursion requires prototype */
-static void persist(PersistInfo *pi);
-
-/* A simple reimplementation of the unfortunately static function luaA_index.
- * Does not support the global table, registry, or upvalues. */
-static StkId getobject(lua_State *L, int stackpos)
-{
-	if(stackpos > 0) {
-		lua_assert(L->base+stackpos-1 < L->top);
-		return L->base+stackpos-1;
-	} else {
-		lua_assert(L->top-stackpos >= L->base);
-		return L->top+stackpos;
-	}
-}
-
-/* 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 int persistspecialobject(PersistInfo *pi, int defaction)
-{
-					/* perms reftbl ... obj */
-	lua_checkstack(pi->L, 4);
-	/* Check whether we should persist literally, or via the __persist
-	 * metafunction */
-	if(!lua_getmetatable(pi->L, -1)) {
-		if(defaction) {
-			{
-				int zero = 0;
-				pi_write(pi, &zero, sizeof(int), pi->ud);
-				if (humanReadable) {
-					snprintf(hrBuf, hrBufSize, "persistspecialobject_write_zero\n");
-					hrOut(pi);
-				}
-#ifdef TOTEXT
-				printf("persistspecialobject_write_zero\n");
-#endif
-			}
-			return 0;
-		} else {
-			lua_pushstring(pi->L, "Type not literally persistable by default");
-			lua_error(pi->L);
-		}
-	}
-					/* perms reftbl sptbl ... obj mt */
-	lua_pushstring(pi->L, "__persist");
-					/* perms reftbl sptbl ... obj mt "__persist" */
-	lua_rawget(pi->L, -2);
-					/* perms reftbl sptbl ... obj mt __persist? */
-	if(lua_isnil(pi->L, -1)) {
-					/* perms reftbl sptbl ... obj mt nil */
-		lua_pop(pi->L, 2);
-					/* perms reftbl sptbl ... obj */
-		if(defaction) {
-			{
-				int zero = 0;
-				pi_write(pi, &zero, sizeof(int), pi->ud);
-				if (humanReadable) {
-					snprintf(hrBuf, hrBufSize, "persistspecialobject_write_zero2\n");
-					hrOut(pi);
-				}
-#ifdef TOTEXT
-				printf("persistspecialobject_write_zero2\n");
-#endif
-			}
-			return 0;
-		} else {
-			lua_pushstring(pi->L, "Type not literally persistable by default");
-			lua_error(pi->L);
-			return 0; /* not reached */
-		}
-	} else if(lua_isboolean(pi->L, -1)) {
-					/* perms reftbl sptbl ... obj mt bool */
-		if(lua_toboolean(pi->L, -1)) {
-					/* perms reftbl sptbl ... obj mt true */
-			lua_pop(pi->L, 2);
-					/* perms reftbl sptbl ... obj */
-			{
-				int zero = 0;
-				pi_write(pi, &zero, sizeof(int), pi->ud);
-				if (humanReadable) {
-					snprintf(hrBuf, hrBufSize, "persistspecialobject_write_zero3\n");
-					hrOut(pi);
-				}
-#ifdef TOTEXT
-				printf("persistspecialobject_write_zero3\n");
-#endif
-			}
-			return 0;
-		} else {
-			lua_pushstring(pi->L, "Metatable forbade persistence");
-			lua_error(pi->L);
-			return 0; /* not reached */
-		}
-	} else if(!lua_isfunction(pi->L, -1)) {
-		lua_pushstring(pi->L, "__persist not nil, boolean, or function");
-		lua_error(pi->L);
-	}
-					/* perms reftbl ... obj mt __persist */
-	lua_pushvalue(pi->L, -3);
-					/* perms reftbl ... obj mt __persist obj */
-#ifdef PLUTO_PASS_USERDATA_TO_PERSIST
-	lua_pushlightuserdata(pi->L, (void *)pi->writer);
-	lua_pushlightuserdata(pi->L, pi->ud);
-					/* perms reftbl ... obj mt __persist obj ud */
-	lua_call(pi->L, 3, 1);
-					/* perms reftbl ... obj mt func? */
-#else
-	lua_call(pi->L, 1, 1);
-					/* perms reftbl ... obj mt func? */
-#endif
-					/* perms reftbl ... obj mt func? */
-	if(!lua_isfunction(pi->L, -1)) {
-		lua_pushstring(pi->L, "__persist function did not return a function");
-		lua_error(pi->L);
-	}
-					/* perms reftbl ... obj mt func */
-	{
-		int one = 1;
-		pi_write(pi, &one, sizeof(int), pi->ud);
-		if (humanReadable) {
-			snprintf(hrBuf, hrBufSize, "persistspecialobject_write_one\n");
-			hrOut(pi);
-		}
-#ifdef TOTEXT
-		printf("persistspecialobject_write_one\n");
-#endif
-	}
-	persist(pi);
-					/* perms reftbl ... obj mt func */
-	lua_pop(pi->L, 2);
-					/* perms reftbl ... obj */
-	return 1;
-}
-
-static void persisttable(PersistInfo *pi)
-{
-	if (humanReadable) {
-		snprintf(hrBuf, hrBufSize, "persisttable\n");
-		hrOut(pi);
-	}
-#ifdef TOTEXT
-	printf("persisttable\n");
-#endif
-
-					/* perms reftbl ... tbl */
-	lua_checkstack(pi->L, 3);
-	if(persistspecialobject(pi, 1)) {
-					/* perms reftbl ... tbl */
-		return;
-	}
-					/* perms reftbl ... tbl */
-	/* First, persist the metatable (if any) */
-	if(!lua_getmetatable(pi->L, -1)) {
-		lua_pushnil(pi->L);
-	}
-					/* perms reftbl ... tbl mt/nil */
-	persist(pi);
-	lua_pop(pi->L, 1);
-					/* perms reftbl ... tbl */
-
-	/* Now, persist all k/v pairs */
-	lua_pushnil(pi->L);
-					/* perms reftbl ... tbl nil */
-	while(lua_next(pi->L, -2)) {
-					/* perms reftbl ... tbl k v */
-		lua_pushvalue(pi->L, -2);
-					/* perms reftbl ... tbl k v k */
-		persist(pi);
-		lua_pop(pi->L, 1);
-					/* perms reftbl ... tbl k v */
-		persist(pi);
-		lua_pop(pi->L, 1);
-					/* perms reftbl ... tbl k */
-	}
-					/* perms reftbl ... tbl */
-	/* Terminate list */
-	lua_pushnil(pi->L);
-					/* perms reftbl ... tbl nil */
-	persist(pi);
-	lua_pop(pi->L, 1);
-					/* perms reftbl ... tbl */
-}
-
-static void persistuserdata(PersistInfo *pi) {
-					/* perms reftbl ... udata */
-	lua_checkstack(pi->L, 2);
-	if(persistspecialobject(pi, 0)) {
-					/* perms reftbl ... udata */
-		return;
-	} else {
-	/* Use literal persistence */
-		size_t length = uvalue(getobject(pi->L, -1))->len;
-		write_size(pi, &length);
-		pi_write(pi, lua_touserdata(pi->L, -1), length, pi->ud);
-		if (humanReadable) {
-			snprintf(hrBuf, hrBufSize, "persistuserdata %ld\n", (long) length);
-			hrOut(pi);
-		}
-#ifdef TOTEXT
-		printf("persistuserdata %ld\n", (long) length);
-#endif
-		if(!lua_getmetatable(pi->L, -1)) {
-					/* perms reftbl ... udata */
-			lua_pushnil(pi->L);
-					/* perms reftbl ... udata mt/nil */
-		}
-		persist(pi);
-		lua_pop(pi->L, 1);
-					/* perms reftbl ... udata */
-	}
-}
-
-
-static Proto *toproto(lua_State *L, int stackpos)
-{
-	return gco2p(getobject(L, stackpos)->value.gc);
-}
-
-static UpVal *toupval(lua_State *L, int stackpos)
-{
-	lua_assert(ttype(getobject(L, stackpos)) == LUA_TUPVAL);
-	return gco2uv(getobject(L, stackpos)->value.gc);
-}
-
-static void pushproto(lua_State *L, Proto *proto)
-{
-	TValue o;
-	setptvalue(L, &o, proto);
-	LIF(A,pushobject)(L, &o);
-}
-
-#define setuvvalue(L,obj,x) \
-  { TValue *i_o=(obj); \
-	i_o->value.gc=cast(GCObject *, (x)); i_o->tt=LUA_TUPVAL; \
-	checkliveness(G(L),i_o); }
-
-static void pushupval(lua_State *L, UpVal *upval)
-{
-	TValue o;
-	setuvvalue(L, &o, upval);
-	LIF(A,pushobject)(L, &o);
-}
-
-static void pushclosure(lua_State *L, Closure *closure)
-{
-	TValue o;
-	setclvalue(L, &o, closure);
-	LIF(A,pushobject)(L, &o);
-}
-
-static void pushstring(lua_State *L, TString *s)
-{
-	TValue o;
-	setsvalue(L, &o, s);
-	LIF(A,pushobject)(L, &o);
-}
-
-static void persistfunction(PersistInfo *pi)
-{
-					/* perms reftbl ... func */
-	Closure *cl = clvalue(getobject(pi->L, -1));
-	lua_checkstack(pi->L, 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(pi->L, "Attempt to persist a C function");
-		lua_error(pi->L);
-	} else {
-		/* It's a Lua closure. */
-		{
-			/* We don't really _NEED_ the number of upvals,
-			 * but it'll simplify things a bit */
-			pi_write(pi, &cl->l.p->nups, sizeof(lu_byte), pi->ud);
-			if (humanReadable) {
-				snprintf(hrBuf, hrBufSize, "persistfunction_number_upvalues %d\n", (int) cl->l.p->nups);
-				hrOut(pi);
-			}
-#ifdef TOTEXT
-			printf("persistfunction_number_upvalues %d\n", (int) cl->l.p->nups);
-#endif
-		}
-		/* Persist prototype */
-		{
-			pushproto(pi->L, cl->l.p);
-					/* perms reftbl ... func proto */
-			persist(pi);
-			lua_pop(pi->L, 1);
-					/* perms reftbl ... func */
-		}
-		/* Persist upvalue values (not the upvalue objects
-		 * themselves) */
-		{
-			int i;
-			for(i=0; i<cl->l.p->nups; i++) {
-					/* perms reftbl ... func */
-				pushupval(pi->L, cl->l.upvals[i]);
-					/* perms reftbl ... func upval */
-				persist(pi);
-				lua_pop(pi->L, 1);
-					/* perms reftbl ... func */
-			}
-					/* perms reftbl ... func */
-		}
-		/* Persist function environment */
-		{
-			lua_getfenv(pi->L, -1);
-					/* perms reftbl ... func fenv */
-			if(lua_equal(pi->L, -1, LUA_GLOBALSINDEX)) {
-				/* Function has the default fenv */
-					/* perms reftbl ... func _G */
-				lua_pop(pi->L, 1);
-					/* perms reftbl ... func */
-				lua_pushnil(pi->L);
-					/* perms reftbl ... func nil */
-			}
-					/* perms reftbl ... func fenv/nil */
-			persist(pi);
-			lua_pop(pi->L, 1);
-					/* perms reftbl ... func */
-		}
-	}
-}
-
-
-/* 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 persisting, don't indicate whether an upvalue is
- * closed or not.
- * (b) When unpersisting, pretend that all upvalues are closed.
- * (c) When persisting, persist all open upvalues referenced by a thread
- * that is persisted, and tag each one with the corresponding stack position
- * (d) When unpersisting, "reopen" each of these upvalues as the thread is
- * unpersisted
- */
-static void persistupval(PersistInfo *pi)
-{
-					/* perms reftbl ... upval */
-	UpVal *uv = toupval(pi->L, -1);
-	lua_checkstack(pi->L, 1);
-
-	/* We can't permit the upval to linger around on the stack, as Lua
-	* will bail if its GC finds it. */
-
-	lua_pop(pi->L, 1);
-					/* perms reftbl ... */
-	LIF(A,pushobject)(pi->L, uv->v);
-					/* perms reftbl ... obj */
-	persist(pi);
-					/* perms reftbl ... obj */
-}
-
-static void persistproto(PersistInfo *pi)
-{
-					/* perms reftbl ... proto */
-	Proto *p = toproto(pi->L, -1);
-	lua_checkstack(pi->L, 2);
-
-	/* Persist constant refs */
-	{
-		int i;
-		pi_write(pi, &p->sizek, sizeof(int), pi->ud);
-	if (humanReadable) {
-	  snprintf(hrBuf, hrBufSize, "persistproto_sizek %d\n", p->sizek);
-	  hrOut(pi);
-	}
-	#ifdef TOTEXT
-	  printf("persistproto_sizek %d\n", p->sizek);
-	#endif
-		for(i=0; i<p->sizek; i++) {
-			LIF(A,pushobject)(pi->L, &p->k[i]);
-					/* perms reftbl ... proto const */
-			persist(pi);
-			lua_pop(pi->L, 1);
-					/* perms reftbl ... proto */
-		}
-	}
-					/* perms reftbl ... proto */
-
-	/* serialize inner Proto refs */
-	{
-		int i;
-		pi_write(pi, &p->sizep, sizeof(int), pi->ud);
-		if (humanReadable) {
-			snprintf(hrBuf, hrBufSize, "persistproto_sizep %d\n", p->sizep);
-			hrOut(pi);
-		}
-#ifdef TOTEXT
-		printf("persistproto_sizep %d\n", p->sizep);
-#endif
-		for(i=0; i<p->sizep; i++)
-		{
-			pushproto(pi->L, p->p[i]);
-					/* perms reftbl ... proto subproto */
-			persist(pi);
-			lua_pop(pi->L, 1);
-					/* perms reftbl ... proto */
-		}
-	}
-					/* perms reftbl ... proto */
-
-	/* Serialize code */
-	{
-		int len;
-		pi_write(pi, &p->sizecode, sizeof(int), pi->ud);
-		if (humanReadable) {
-			snprintf(hrBuf, hrBufSize, "persistproto_sizecode %d\n", p->sizecode);
-			hrOut(pi);
-		}
-#ifdef TOTEXT
-		printf("persistproto_sizecode %d\n", p->sizecode);
-#endif
-		len = sizeof(Instruction) * p->sizecode;
-		pi_write(pi, p->code, len, pi->ud);
-		if (humanReadable) {
-			snprintf(hrBuf, hrBufSize, "persistproto_code %d\n", len);
-			hrOut(pi);
-		}
-#ifdef TOTEXT
-		printf("persistproto_code %d\n", len);
-#endif
-	}
-
-	/* Serialize upvalue names */
-	{
-		int i;
-		pi_write(pi, &p->sizeupvalues, sizeof(int), pi->ud);
-		if (humanReadable) {
-			snprintf(hrBuf, hrBufSize, "persistproto_upvalues %d\n", p->sizeupvalues);
-			hrOut(pi);
-		}
-#ifdef TOTEXT
-		printf("persistproto_upvalues %d\n", p->sizeupvalues);
-#endif
-		for(i=0; i<p->sizeupvalues; i++)
-		{
-			pushstring(pi->L, p->upvalues[i]);
-			persist(pi);
-			lua_pop(pi->L, 1);
-		}
-	}
-	/* Serialize local variable infos */
-	{
-		int i;
-		pi_write(pi, &p->sizelocvars, sizeof(int), pi->ud);
-		if (humanReadable) {
-			snprintf(hrBuf, hrBufSize, "persistproto_sizelocvars %d\n", p->sizelocvars);
-			hrOut(pi);
-		}
-#ifdef TOTEXT
-		printf("persistproto_sizelocvars %d\n", p->sizelocvars);
-#endif
-		for(i=0; i<p->sizelocvars; i++)
-		{
-			pushstring(pi->L, p->locvars[i].varname);
-			persist(pi);
-			lua_pop(pi->L, 1);
-
-			pi_write(pi, &p->locvars[i].startpc, sizeof(int), pi->ud);
-			if (humanReadable) {
-				snprintf(hrBuf, hrBufSize, "persistproto_startpc %d\n", p->locvars[i].startpc);
-				hrOut(pi);
-			}
-#ifdef TOTEXT
-			printf("persistproto_startpc %d\n", p->locvars[i].startpc);
-#endif
-			pi_write(pi, &p->locvars[i].endpc, sizeof(int), pi->ud);
-			if (humanReadable) {
-				snprintf(hrBuf, hrBufSize, "persistproto_endpc %d\n", p->locvars[i].endpc);
-				hrOut(pi);
-			}
-#ifdef TOTEXT
-			printf("persistproto_endpc %d\n", p->locvars[i].endpc);
-#endif
-		}
-	}
-
-	/* Serialize source string */
-	pushstring(pi->L, p->source);
-	persist(pi);
-	lua_pop(pi->L, 1);
-
-	/* Serialize line numbers */
-	{
-		pi_write(pi, &p->sizelineinfo, sizeof(int), pi->ud);
-		if (humanReadable) {
-			snprintf(hrBuf, hrBufSize, "persistproto_sizelineinfo %d\n", p->sizelineinfo);
-			hrOut(pi);
-		}
-#ifdef TOTEXT
-		printf("persistproto_sizelineinfo %d\n", p->sizelineinfo);
-#endif
-		if (p->sizelineinfo)
-		{
-			int len;
-			len = sizeof(int) * p->sizelineinfo;
-			pi_write(pi, p->lineinfo, len, pi->ud);
-			if (humanReadable) {
-				snprintf(hrBuf, hrBufSize, "persistproto_lineinfo %d\n", len);
-				hrOut(pi);
-			}
-#ifdef TOTEXT
-			printf("persistproto_lineinfo %d\n", len);
-#endif
-		}
-	}
-
-	/* Serialize linedefined and lastlinedefined */
-	pi_write(pi, &p->linedefined, sizeof(int), pi->ud);
-	if (humanReadable) {
-		snprintf(hrBuf, hrBufSize, "persistproto_linedefined %d\n", p->linedefined);
-		hrOut(pi);
-	}
-#ifdef TOTEXT
-	printf("persistproto_linedefined %d\n", p->linedefined);
-#endif
-	pi_write(pi, &p->lastlinedefined, sizeof(int), pi->ud);
-	if (humanReadable) {
-		snprintf(hrBuf, hrBufSize, "persistproto_lastlinedefined %d\n", p->lastlinedefined);
-		hrOut(pi);
-	}
-#ifdef TOTEXT
-	printf("persistproto_lastlinedefined %d\n", p->lastlinedefined);
-#endif
-
-	/* Serialize misc values */
-	{
-		pi_write(pi, &p->nups, sizeof(lu_byte), pi->ud);
-		if (humanReadable) {
-			snprintf(hrBuf, hrBufSize, "persistproto_nups %d\n", (int) p->nups);
-			hrOut(pi);
-		}
-#ifdef TOTEXT
-		printf("persistproto_nups %d\n", (int) p->nups);
-#endif
-		pi_write(pi, &p->numparams, sizeof(lu_byte), pi->ud);
-		if (humanReadable) {
-			snprintf(hrBuf, hrBufSize, "persistproto_numparams %d\n", (int) p->numparams);
-			hrOut(pi);
-		}
-#ifdef TOTEXT
-		printf("persistproto_numparams %d\n", (int) p->numparams);
-#endif
-		pi_write(pi, &p->is_vararg, sizeof(lu_byte), pi->ud);
-		if (humanReadable) {
-			snprintf(hrBuf, hrBufSize, "persistproto_is_vararg %d\n", (int) p->is_vararg);
-			hrOut(pi);
-		}
-#ifdef TOTEXT
-		printf("persistproto_is_vararg %d\n", (int) p->is_vararg);
-#endif
-		pi_write(pi, &p->maxstacksize, sizeof(lu_byte), pi->ud);
-		if (humanReadable) {
-			snprintf(hrBuf, hrBufSize, "persistproto_maxstacksize %d\n", (int) p->maxstacksize);
-			hrOut(pi);
-		}
-#ifdef TOTEXT
-		printf("persistproto_maxstacksize %d\n", (int) p->maxstacksize);
-#endif
-	}
-	/* We do not currently persist upvalue names, local variable names,
-	 * variable lifetimes, line info, or source code. */
-}
-
-/* Copies a stack, but the stack is reversed in the process
- */
-static size_t revappendstack(lua_State *from, lua_State *to)
-{
-	StkId o;
-	for(o=from->top-1; o>=from->stack; o--) {
-		setobj2s(to, to->top, o);
-		to->top++;
-	}
-	return from->top - from->stack;
-}
-
-/* Persist all stack members
- */
-static void persistthread(PersistInfo *pi)
-{
-	size_t posremaining;
-	lua_State *L2;
-					/* perms reftbl ... thr */
-	L2 = lua_tothread(pi->L, -1);
-	lua_checkstack(pi->L, L2->top - L2->stack + 1);
-	if(pi->L == L2) {
-		lua_pushstring(pi->L, "Can't persist currently running thread");
-		lua_error(pi->L);
-		return; /* not reached */
-	}
-
-	/* Persist the stack */
-	posremaining = revappendstack(L2, pi->L);
-					/* perms reftbl ... thr (rev'ed contents of L2) */
-	write_size(pi, &posremaining);
-	for(; posremaining > 0; posremaining--) {
-		persist(pi);
-		lua_pop(pi->L, 1);
-	}
-					/* perms reftbl ... thr */
-	/* Now, persist the CallInfo stack. */
-	{
-		size_t i, numframes = (L2->ci - L2->base_ci) + 1;
-		write_size(pi, &numframes);
-		for(i=0; i<numframes; i++) {
-			CallInfo *ci = L2->base_ci + i;
-			size_t stackbase = ci->base - L2->stack;
-			size_t stackfunc = ci->func - L2->stack;
-			size_t stacktop = ci->top - L2->stack;
-			size_t savedpc = (ci != L2->base_ci) ?
-				ci->savedpc - ci_func(ci)->l.p->code :
-				0;
-			write_size(pi, &stackbase);
-			write_size(pi, &stackfunc);
-			write_size(pi, &stacktop);
-			pi_write(pi, &ci->nresults, sizeof(int), pi->ud);
-			if (humanReadable) {
-				snprintf(hrBuf, hrBufSize, "persistthread %d\n", ci->nresults);
-				hrOut(pi);
-			}
-#ifdef TOTEXT
-			printf("persistthread %d\n", ci->nresults);
-#endif
-			write_size(pi, &savedpc);
-		}
-	}
-
-	/* Serialize the state's other parameters, with the exception of upval stuff */
-	{
-		size_t stackbase = L2->base - L2->stack;
-		size_t stacktop = L2->top - L2->stack;
-		lua_assert(L2->nCcalls <= 1);
-		pi_write(pi, &L2->status, sizeof(lu_byte), pi->ud);
-		if (humanReadable) {
-			snprintf(hrBuf, hrBufSize, "persistthread_status %d\n", (int) L2->status);
-			hrOut(pi);
-		}
-#ifdef TOTEXT
-		printf("persistthread_status %d\n", (int) L2->status);
-#endif
-		write_size(pi, &stackbase);
-		write_size(pi, &stacktop);
-
-		// ptrdiff_t changes sizes based on 32/64 bit
-		// Hard cast to 64 bit size if SIZE64 is defined
-#ifdef SIZES64
-		uint64 ptrIndex = static_cast<uint64>(L2->errfunc);
-		pi_write(pi, &ptrIndex, sizeof(uint64), pi->ud);
-#else
-		pi_write(pi, &L2->errfunc, sizeof(ptrdiff_t), pi->ud);
-#endif
-		//write_size(pi, (size_t *)&L2->errfunc);
-	}
-
-	/* Finally, record upvalues which need to be reopened */
-	/* See the comment above persistupval() for why we do this */
-	{
-		GCObject *gco;
-		UpVal *uv;
-					/* perms reftbl ... thr */
-		for(gco = L2->openupval; gco != NULL; gco = uv->next) {
-			size_t stackpos;
-			uv = gco2uv(gco);
-
-			/* Make sure upvalue is really open */
-			lua_assert(uv->v != &uv->u.value);
-			pushupval(pi->L, uv);
-					/* perms reftbl ... thr uv */
-			persist(pi);
-			lua_pop(pi->L, 1);
-					/* perms reftbl ... thr */
-			stackpos = uv->v - L2->stack;
-			write_size(pi, &stackpos);
-		}
-					/* perms reftbl ... thr */
-		lua_pushnil(pi->L);
-					/* perms reftbl ... thr nil */
-		persist(pi);
-		lua_pop(pi->L, 1);
-					/* perms reftbl ... thr */
-	}
-					/* perms reftbl ... thr */
-}
-
-static void persistboolean(PersistInfo *pi)
-{
-	int b = lua_toboolean(pi->L, -1);
-	pi_write(pi, &b, sizeof(int), pi->ud);
-	if (humanReadable) {
-		snprintf(hrBuf, hrBufSize, "persistboolean %d\n", b);
-		hrOut(pi);
-	}
-#ifdef TOTEXT
-	printf("persistboolean %d\n", b);
-#endif
-}
-
-static void persistlightuserdata(PersistInfo *pi)
-{
-	void *p = lua_touserdata(pi->L, -1);
-	pi_write(pi, &p, sizeof(void *), pi->ud);
-	if (humanReadable) {
-		snprintf(hrBuf, hrBufSize, "persistlightuserdata %p\n", p);
-		hrOut(pi);
-	}
-#ifdef TOTEXT
-	printf("persistlightuserdata %d\n", (int) p);
-#endif
-}
-
-static void persistnumber(PersistInfo *pi)
-{
-	lua_Number n = lua_tonumber(pi->L, -1);
-	pi_write(pi, &n, sizeof(lua_Number), pi->ud);
-	if (humanReadable) {
-		snprintf(hrBuf, hrBufSize, "persistnumber %d (%d)\n", (int) n, (int) sizeof(lua_Number));
-		hrOut(pi);
-	}
-#ifdef TOTEXT
-	printf("persistnumber %d (%d)\n", (int) n, (int) sizeof(lua_Number));
-#endif
-}
-
-static void persiststring(PersistInfo *pi)
-{
-	if (humanReadable) {
-		snprintf(hrBuf, hrBufSize, "persiststring\n");
-		hrOut(pi);
-	}
-#ifdef TOTEXT
-	printf("persiststring\n");
-#endif
-	size_t length = lua_strlen(pi->L, -1);
-	write_size(pi, &length);
-	const char* s = lua_tostring(pi->L, -1);
-	pi_write(pi, s, length, pi->ud);
-	if (humanReadable) {
-		snprintf(hrBuf, hrBufSize, "persiststring %d \"%s\"\n", (int)length, s);
-		hrOut(pi);
-	}
-#ifdef TOTEXT
-	printf("persiststring %d \"%s\"\n", length, s);
-#endif
-}
-
-/* Top-level delegating persist function
- */
-static void persist(PersistInfo *pi)
-{
-					/* perms reftbl ... obj */
-	lua_checkstack(pi->L, 2);
-	/* If the object has already been written, write a reference to it */
-	lua_pushvalue(pi->L, -1);
-					/* perms reftbl ... obj obj */
-	lua_rawget(pi->L, 2);
-					/* perms reftbl ... obj ref? */
-	if(!lua_isnil(pi->L, -1)) {
-					/* perms reftbl ... obj ref */
-		int zero = 0;
-		pi_write(pi, &zero, sizeof(int), pi->ud);
-		if (humanReadable) {
-			snprintf(hrBuf, hrBufSize, "persist_seenobject\n");
-			hrOut(pi);
-		}
-#ifdef TOTEXT
-		printf("persist_seenobject\n");
-#endif
-		int *ref = (int *)lua_touserdata(pi->L, -1);
-		pi_write(pi, ref, sizeof(int), pi->ud);
-		if (humanReadable) {
-			snprintf(hrBuf, hrBufSize, "persist_touserdata_ref %d\n", ref);
-			hrOut(pi);
-		}
-#ifdef TOTEXT
-		printf("persist_touserdata_ref %d\n", ref);
-#endif
-		lua_pop(pi->L, 1);
-					/* perms reftbl ... obj ref */
-#ifdef PLUTO_DEBUG
-		printindent(pi->level);
-		printf("0 %d\n", ref);
-#endif
-		return;
-	}
-					/* perms reftbl ... obj nil */
-	lua_pop(pi->L, 1);
-					/* perms reftbl ... obj */
-	/* If the object is nil, write the pseudoreference 0 */
-	if(lua_isnil(pi->L, -1)) {
-		int zero = 0;
-		/* firsttime */
-		pi_write(pi, &zero, sizeof(int), pi->ud);
-		/* ref */
-		pi_write(pi, &zero, sizeof(int), pi->ud);
-		if (humanReadable) {
-			snprintf(hrBuf, hrBufSize, "persist_nil (last 2 lines)\n");
-			hrOut(pi);
-		}
-#ifdef TOTEXT
-		printf("persist_nil (last 2 lines)\n");
-#endif
-#ifdef PLUTO_DEBUG
-		printindent(pi->level);
-		printf("0 0\n");
-#endif
-		return;
-	}
-	{
-		/* indicate that it's the first time */
-		int one = 1;
-		pi_write(pi, &one, sizeof(int), pi->ud);
-		if (humanReadable) {
-			snprintf(hrBuf, hrBufSize, "persist_newobject\n");
-			hrOut(pi);
-		}
-#ifdef TOTEXT
-		printf("persist_newobject\n");
-#endif
-	}
-	lua_pushvalue(pi->L, -1);
-					/* perms reftbl ... obj obj */
-	int *ref = (int *)lua_newuserdata(pi->L, sizeof(int));
-	*ref = ++(pi->counter);
-					/* perms reftbl ... obj obj ref */
-	lua_rawset(pi->L, 2);
-					/* perms reftbl ... obj */
-
-	pi_write(pi, &pi->counter, sizeof(int), pi->ud);
-	if (humanReadable) {
-		snprintf(hrBuf, hrBufSize, "persist_counter %d\n", pi->counter);
-		hrOut(pi);
-	}
-#ifdef TOTEXT
-	printf("persist_counter %d\n", pi->counter);
-#endif
-
-
-	/* At this point, we'll give the permanents table a chance to play. */
-	{
-		lua_pushvalue(pi->L, -1);
-					/* perms reftbl ... obj obj */
-		lua_gettable(pi->L, 1);
-					/* perms reftbl ... obj permkey? */
-		if(!lua_isnil(pi->L, -1)) {
-					/* perms reftbl ... obj permkey */
-			int type = PLUTO_TPERMANENT;
-#ifdef PLUTO_DEBUG
-			printindent(pi->level);
-			printf("1 %d PERM\n", pi->counter);
-			pi->level++;
-#endif
-			pi_write(pi, &type, sizeof(int), pi->ud);
-			if (humanReadable) {
-				snprintf(hrBuf, hrBufSize, "persist_permtype %d\n", type);
-				hrOut(pi);
-			}
-#ifdef TOTEXT
-			printf("persist_permtype %d\n", type);
-#endif
-			persist(pi);
-			lua_pop(pi->L, 1);
-					/* perms reftbl ... obj */
-#ifdef PLUTO_DEBUG
-			pi->level--;
-#endif
-			return;
-		} else {
-					/* perms reftbl ... obj nil */
-			lua_pop(pi->L, 1);
-					/* perms reftbl ... obj */
-		}
-					/* perms reftbl ... obj */
-	}
-	{
-		int type = lua_type(pi->L, -1);
-		pi_write(pi, &type, sizeof(int), pi->ud);
-		if (humanReadable) {
-			snprintf(hrBuf, hrBufSize, "persist %s\n", type >= 0 && type < NUMTYPES ? typenames[type] : "?");
-			hrOut(pi);
-		}
-#ifdef TOTEXT
-		printf("persist %s\n", type >= 0 && type < NUMTYPES ? typenames[type] : "?");
-#endif
-
-#ifdef PLUTO_DEBUG
-		printindent(pi->level);
-		printf("1 %d %d\n", pi->counter, type);
-		pi->level++;
-#endif
-	}
-
-	switch(lua_type(pi->L, -1)) {
-		case LUA_TBOOLEAN:
-			persistboolean(pi);
-			break;
-		case LUA_TLIGHTUSERDATA:
-			persistlightuserdata(pi);
-			break;
-		case LUA_TNUMBER:
-			persistnumber(pi);
-			break;
-		case LUA_TSTRING:
-			persiststring(pi);
-			break;
-		case LUA_TTABLE:
-			persisttable(pi);
-			break;
-		case LUA_TFUNCTION:
-			persistfunction(pi);
-			break;
-		case LUA_TTHREAD:
-			persistthread(pi);
-			break;
-		case LUA_TPROTO:
-			persistproto(pi);
-			break;
-		case LUA_TUPVAL:
-			persistupval(pi);
-			break;
-		case LUA_TUSERDATA:
-			persistuserdata(pi);
-			break;
-		default:
-			lua_assert(0);
-	}
-#ifdef PLUTO_DEBUG
-	pi->level--;
-#endif
-}
-
-void pluto_persist(lua_State *L, lua_Chunkwriter writer, void *ud)
-{
-	PersistInfo pi;
-
-	pi.counter = 0;
-	pi.L = L;
-	pi.writer = writer;
-	pi.ud = ud;
-#ifdef PLUTO_DEBUG
-	pi.level = 0;
-#endif
-
-	lua_checkstack(L, 4);
-					/* perms? rootobj? ...? */
-	lua_assert(lua_gettop(L) == 2);
-					/* perms rootobj */
-	lua_assert(!lua_isnil(L, 2));
-					/* perms rootobj */
-	lua_newtable(L);
-					/* perms rootobj reftbl */
-
-	/* 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. */
-	lua_newtable(L);
-					/* perms rootobj reftbl mt */
-	lua_pushstring(L, "__mode");
-					/* perms rootobj reftbl mt "__mode" */
-	lua_pushstring(L, "k");
-					/* perms rootobj reftbl mt "__mode" "k" */
-	lua_settable(L, 4);
-					/* perms rootobj reftbl mt */
-	lua_setmetatable(L, 3);
-					/* perms rootobj reftbl */
-	lua_insert(L, 2);
-					/* perms reftbl rootobj */
-	persist(&pi);
-					/* perms reftbl rootobj */
-	lua_remove(L, 2);
-					/* perms rootobj */
-}
-
-typedef struct WriterInfo_t {
-	char* buf;
-	size_t buflen;
-} WriterInfo;
-
-static int bufwriter (lua_State *L, const void *p, size_t sz, void *ud) {
-	const char *cp = (const char *)p;
-	WriterInfo *wi = (WriterInfo *)ud;
-
-	LIF(M,reallocvector)(L, wi->buf, wi->buflen, wi->buflen+sz, char);
-	while(sz)
-	{
-		/* how dearly I love ugly C pointer twiddling */
-		wi->buf[wi->buflen++] = *cp++;
-		sz--;
-	}
-	return 0;
-}
-
-int persist_l(lua_State *L)
-{
-					/* perms? rootobj? ...? */
-	WriterInfo wi;
-
-	wi.buf = NULL;
-	wi.buflen = 0;
-
-	lua_settop(L, 2);
-					/* perms? rootobj? */
-	luaL_checktype(L, 1, LUA_TTABLE);
-					/* perms rootobj? */
-	luaL_checktype(L, 1, LUA_TTABLE);
-					/* perms rootobj */
-
-	pluto_persist(L, bufwriter, &wi);
-
-	lua_settop(L, 0);
-					/* (empty) */
-	lua_pushlstring(L, wi.buf, wi.buflen);
-					/* str */
-	pdep_freearray(L, wi.buf, wi.buflen, char);
-	return 1;
-}
-
-typedef struct UnpersistInfo_t {
-	lua_State *L;
-	ZIO zio;
-#ifdef PLUTO_DEBUG
-	int level;
-#endif
-} UnpersistInfo;
-
-static void unpersist(UnpersistInfo *upi);
-
-/* The object is left on the stack. This is primarily used by unpersist, but
- * may be used by GCed objects that may incur cycles in order to preregister
- * the object. */
-static void registerobject(int ref, UnpersistInfo *upi)
-{
-					/* perms reftbl ... obj */
-	lua_checkstack(upi->L, 2);
-	lua_pushlightuserdata(upi->L, (void *)ref);
-					/* perms reftbl ... obj ref */
-	lua_pushvalue(upi->L, -2);
-					/* perms reftbl ... obj ref obj */
-	lua_settable(upi->L, 2);
-					/* perms reftbl ... obj */
-}
-
-static void unpersistboolean(UnpersistInfo *upi)
-{
-					/* perms reftbl ... */
-	int b;
-	lua_checkstack(upi->L, 1);
-	verify(LIF(Z,read)(&upi->zio, &b, sizeof(int)) == 0);
-	lua_pushboolean(upi->L, b);
-					/* perms reftbl ... bool */
-}
-
-static void unpersistlightuserdata(UnpersistInfo *upi)
-{
-					/* perms reftbl ... */
-	void *p;
-	lua_checkstack(upi->L, 1);
-	verify(LIF(Z,read)(&upi->zio, &p, sizeof(void *)) == 0);
-	lua_pushlightuserdata(upi->L, p);
-					/* perms reftbl ... ludata */
-}
-
-static void unpersistnumber(UnpersistInfo *upi)
-{
-					/* perms reftbl ... */
-	lua_Number n;
-	lua_checkstack(upi->L, 1);
-	verify(LIF(Z,read)(&upi->zio, &n, sizeof(lua_Number)) == 0);
-	lua_pushnumber(upi->L, n);
-					/* perms reftbl ... num */
-}
-
-static void unpersiststring(UnpersistInfo *upi)
-{
-					/* perms reftbl sptbl ref */
-	/*int length;*/
-	size_t length;
-	char* string;
-	lua_checkstack(upi->L, 1);
-	/*verify(LIF(Z,read)(&upi->zio, &length, sizeof(int)) == 0);*/
-	/*verify(LIF(Z,read)(&upi->zio, &length, sizeof(size_t)) == 0);*/
-	read_size(&upi->zio, &length);
-	string = pdep_newvector(upi->L, length, char);
-	verify(LIF(Z,read)(&upi->zio, string, length) == 0);
-	lua_pushlstring(upi->L, string, length);
-					/* perms reftbl sptbl ref str */
-	pdep_freearray(upi->L, string, length, char);
-}
-
-static void unpersistspecialtable(int ref, UnpersistInfo *upi)
-{
-					/* perms reftbl ... */
-	lua_checkstack(upi->L, 1);
-	unpersist(upi);
-					/* perms reftbl ... spfunc? */
-	lua_assert(lua_isfunction(upi->L, -1));
-					/* perms reftbl ... spfunc */
-	lua_call(upi->L, 0, 1);
-					/* perms reftbl ... tbl? */
-	lua_assert(lua_istable(upi->L, -1));
-					/* perms reftbl ... tbl */
-}
-
-static void unpersistliteraltable(int ref, UnpersistInfo *upi)
-{
-					/* perms reftbl ... */
-	lua_checkstack(upi->L, 3);
-	/* Preregister table for handling of cycles */
-	lua_newtable(upi->L);
-					/* perms reftbl ... tbl */
-	registerobject(ref, upi);
-					/* perms reftbl ... tbl */
-	/* Unpersist metatable */
-	{
-		unpersist(upi);
-					/* perms reftbl ... tbl mt/nil? */
-		if(lua_istable(upi->L, -1)) {
-					/* perms reftbl ... tbl mt */
-			lua_setmetatable(upi->L, -2);
-					/* perms reftbl ... tbl */
-		} else {
-					/* perms reftbl ... tbl nil? */
-			lua_assert(lua_isnil(upi->L, -1));
-					/* perms reftbl ... tbl nil */
-			lua_pop(upi->L, 1);
-					/* perms reftbl ... tbl */
-		}
-					/* perms reftbl ... tbl */
-	}
-
-	while(1)
-	{
-					/* perms reftbl ... tbl */
-		unpersist(upi);
-					/* perms reftbl ... tbl key/nil */
-		if(lua_isnil(upi->L, -1)) {
-					/* perms reftbl ... tbl nil */
-			lua_pop(upi->L, 1);
-					/* perms reftbl ... tbl */
-			break;
-		}
-					/* perms reftbl ... tbl key */
-		unpersist(upi);
-					/* perms reftbl ... tbl key value? */
-		lua_assert(!lua_isnil(upi->L, -1));
-					/* perms reftbl ... tbl key value */
-		lua_rawset(upi->L, -3);
-					/* perms reftbl ... tbl */
-	}
-}
-
-static void unpersisttable(int ref, UnpersistInfo *upi)
-{
-					/* perms reftbl ... */
-	lua_checkstack(upi->L, 1);
-	{
-		int isspecial;
-		verify(LIF(Z,read)(&upi->zio, &isspecial, sizeof(int)) == 0);
-		if(isspecial) {
-			unpersistspecialtable(ref, upi);
-					/* perms reftbl ... tbl */
-		} else {
-			unpersistliteraltable(ref, upi);
-					/* perms reftbl ... tbl */
-		}
-					/* perms reftbl ... tbl */
-	}
-}
-
-static UpVal *makeupval(lua_State *L, int stackpos)
-{
-	UpVal *uv = pdep_new(L, UpVal);
-	pdep_link(L, (GCObject *)uv, LUA_TUPVAL);
-	uv->tt = LUA_TUPVAL;
-	uv->v = &uv->u.value;
-	uv->u.l.prev = NULL;
-	uv->u.l.next = NULL;
-	setobj(L, uv->v, getobject(L, stackpos));
-	return uv;
-}
-
-static Proto *makefakeproto(lua_State *L, lu_byte nups)
-{
-	Proto *p = pdep_newproto(L);
-	p->sizelineinfo = 1;
-	p->lineinfo = pdep_newvector(L, 1, int);
-	p->lineinfo[0] = 1;
-	p->sizecode = 1;
-	p->code = pdep_newvector(L, 1, Instruction);
-	p->code[0] = CREATE_ABC(OP_RETURN, 0, 1, 0);
-	p->source = pdep_newlstr(L, "", 0);
-	p->maxstacksize = 2;
-	p->nups = nups;
-	p->sizek = 0;
-	p->sizep = 0;
-
-	return p;
-}
-
-/* The GC is not fond of finding upvalues in tables. We get around this
- * during persistence using a weakly keyed table, so that the GC doesn't
- * bother to mark them. This won't work in unpersisting, however, since
- * if we make the values weak they'll be collected (since nothing else
- * references them). Our solution, during unpersisting, is to represent
- * upvalues as dummy functions, each with one upvalue. */
-static void boxupval_start(lua_State *L)
-{
-	LClosure *lcl;
-	lcl = (LClosure *)pdep_newLclosure(L, 1, hvalue(&L->l_gt));
-	pushclosure(L, (Closure *)lcl);
-					/* ... func */
-	lcl->p = makefakeproto(L, 1);
-
-	/* Temporarily initialize the upvalue to nil */
-
-	lua_pushnil(L);
-	lcl->upvals[0] = makeupval(L, -1);
-	lua_pop(L, 1);
-}
-
-static void boxupval_finish(lua_State *L)
-{
-					/* ... func obj */
-	LClosure *lcl = (LClosure *) clvalue(getobject(L, -2));
-
-	lcl->upvals[0]->u.value = *getobject(L, -1);
-	lua_pop(L, 1);
-}
-
-
-static void unboxupval(lua_State *L)
-{
-					/* ... func */
-	LClosure *lcl;
-	UpVal *uv;
-
-	lcl = (LClosure *)clvalue(getobject(L, -1));
-	uv = lcl->upvals[0];
-	lua_pop(L, 1);
-					/* ... */
-	pushupval(L, uv);
-					/* ... upval */
-}
-
-static void unpersistfunction(int ref, UnpersistInfo *upi)
-{
-					/* perms reftbl ... */
-	LClosure *lcl;
-	int i;
-	lu_byte nupvalues;
-	lua_checkstack(upi->L, 2);
-
-	verify(LIF(Z,read)(&upi->zio, &nupvalues, sizeof(lu_byte)) == 0);
-
-	lcl = (LClosure *)pdep_newLclosure(upi->L, nupvalues, hvalue(&upi->L->l_gt));
-	pushclosure(upi->L, (Closure *)lcl);
-
-					/* perms reftbl ... func */
-	/* Put *some* proto in the closure, before the GC can find it */
-	lcl->p = makefakeproto(upi->L, nupvalues);
-
-	/* Also, we need to temporarily fill the upvalues */
-	lua_pushnil(upi->L);
-					/* perms reftbl ... func nil */
-	for(i=0; i<nupvalues; i++) {
-		lcl->upvals[i] = makeupval(upi->L, -1);
-	}
-	lua_pop(upi->L, 1);
-					/* perms reftbl ... func */
-
-	/* I can't see offhand how a function would ever get to be self-
-	 * referential, but just in case let's register it early */
-	registerobject(ref, upi);
-
-	/* Now that it's safe, we can get the real proto */
-	unpersist(upi);
-					/* perms reftbl ... func proto? */
-	lua_assert(lua_type(upi->L, -1) == LUA_TPROTO);
-					/* perms reftbl ... func proto */
-	lcl->p = toproto(upi->L, -1);
-	lua_pop(upi->L, 1);
-					/* perms reftbl ... func */
-
-	for(i=0; i<nupvalues; i++) {
-					/* perms reftbl ... func */
-		unpersist(upi);
-					/* perms reftbl ... func func2 */
-		unboxupval(upi->L);
-					/* perms reftbl ... func upval */
-		lcl->upvals[i] = toupval(upi->L, -1);
-		lua_pop(upi->L, 1);
-					/* perms reftbl ... func */
-	}
-					/* perms reftbl ... func */
-
-	/* Finally, the fenv */
-	unpersist(upi);
-					/* perms reftbl ... func fenv/nil? */
-	lua_assert(lua_type(upi->L, -1) == LUA_TNIL ||
-		lua_type(upi->L, -1) == LUA_TTABLE);
-					/* perms reftbl ... func fenv/nil */
-	if(!lua_isnil(upi->L, -1)) {
-					/* perms reftbl ... func fenv */
-		lua_setfenv(upi->L, -2);
-					/* perms reftbl ... func */
-	} else {
-					/* perms reftbl ... func nil */
-		lua_pop(upi->L, 1);
-					/* perms reftbl ... func */
-	}
-					/* perms reftbl ... func */
-}
-
-static void unpersistupval(int ref, UnpersistInfo *upi)
-{
-					/* perms reftbl ... */
-	lua_checkstack(upi->L, 2);
-
-	boxupval_start(upi->L);
-					/* perms reftbl ... func */
-	registerobject(ref, upi);
-
-	unpersist(upi);
-					/* perms reftbl ... func obj */
-	boxupval_finish(upi->L);
-					/* perms reftbl ... func */
-}
-
-static void unpersistproto(int ref, UnpersistInfo *upi)
-{
-					/* perms reftbl ... */
-	Proto *p;
-	int i;
-	int sizep, sizek;
-
-	/* We have to be careful. The GC expects a lot out of protos. In
-	 * particular, we need to give the function a valid string for its
-	 * source, and valid code, even before we actually read in the real
-	 * code. */
-	TString *source = pdep_newlstr(upi->L, "", 0);
-	p = pdep_newproto(upi->L);
-	p->source = source;
-	p->sizecode=1;
-	p->code = pdep_newvector(upi->L, 1, Instruction);
-	p->code[0] = CREATE_ABC(OP_RETURN, 0, 1, 0);
-	p->maxstacksize = 2;
-	p->sizek = 0;
-	p->sizep = 0;
-
-	lua_checkstack(upi->L, 2);
-
-	pushproto(upi->L, p);
-					/* perms reftbl ... proto */
-	/* We don't need to register early, since protos can never ever be
-	 * involved in cyclic references */
-
-	/* Read in constant references */
-	{
-		verify(LIF(Z,read)(&upi->zio, &sizek, sizeof(int)) == 0);
-		LIF(M,reallocvector)(upi->L, p->k, 0, sizek, TValue);
-		for(i=0; i<sizek; i++) {
-					/* perms reftbl ... proto */
-			unpersist(upi);
-					/* perms reftbl ... proto k */
-			setobj2s(upi->L, &p->k[i], getobject(upi->L, -1));
-			p->sizek++;
-			lua_pop(upi->L, 1);
-					/* perms reftbl ... proto */
-		}
-					/* perms reftbl ... proto */
-	}
-	/* Read in sub-proto references */
-	{
-		verify(LIF(Z,read)(&upi->zio, &sizep, sizeof(int)) == 0);
-		LIF(M,reallocvector)(upi->L, p->p, 0, sizep, Proto*);
-		for(i=0; i<sizep; i++) {
-					/* perms reftbl ... proto */
-			unpersist(upi);
-					/* perms reftbl ... proto subproto */
-			p->p[i] = toproto(upi->L, -1);
-			p->sizep++;
-			lua_pop(upi->L, 1);
-					/* perms reftbl ... proto */
-		}
-					/* perms reftbl ... proto */
-	}
-
-	/* Read in code */
-	{
-		verify(LIF(Z,read)(&upi->zio, &p->sizecode, sizeof(int)) == 0);
-		LIF(M,reallocvector)(upi->L, p->code, 1, p->sizecode, Instruction);
-		verify(LIF(Z,read)(&upi->zio, p->code,
-			sizeof(Instruction) * p->sizecode) == 0);
-	}
-
-	/* Read in upvalue names */
-	{
-		verify(LIF(Z,read)(&upi->zio, &p->sizeupvalues, sizeof(int)) == 0);
-		if (p->sizeupvalues)
-		{
-			LIF(M,reallocvector)(upi->L, p->upvalues, 0, p->sizeupvalues, TString *);
-			for(i=0; i<p->sizeupvalues; i++)
-			{
-				unpersist(upi);
-				p->upvalues[i] = pdep_newlstr(upi->L, lua_tostring(upi->L, -1), strlen(lua_tostring(upi->L, -1)));
-				lua_pop(upi->L, 1);
-			}
-		}
-	}
-
-	/* Read in local variable infos */
-	{
-		verify(LIF(Z,read)(&upi->zio, &p->sizelocvars, sizeof(int)) == 0);
-		if (p->sizelocvars)
-		{
-			LIF(M,reallocvector)(upi->L, p->locvars, 0, p->sizelocvars, LocVar);
-			for(i=0; i<p->sizelocvars; i++)
-			{
-				unpersist(upi);
-				p->locvars[i].varname = pdep_newlstr(upi->L, lua_tostring(upi->L, -1), strlen(lua_tostring(upi->L, -1)));
-				lua_pop(upi->L, 1);
-
-				verify(LIF(Z,read)(&upi->zio, &p->locvars[i].startpc, sizeof(int)) == 0);
-				verify(LIF(Z,read)(&upi->zio, &p->locvars[i].endpc, sizeof(int)) == 0);
-			}
-		}
-	}
-
-	/* Read in source string*/
-	unpersist(upi);
-	p->source = pdep_newlstr(upi->L, lua_tostring(upi->L, -1), strlen(lua_tostring(upi->L, -1)));
-	lua_pop(upi->L, 1);
-
-	/* Read in line numbers */
-	{
-		verify(LIF(Z,read)(&upi->zio, &p->sizelineinfo, sizeof(int)) == 0);
-		if (p->sizelineinfo)
-		{
-			LIF(M,reallocvector)(upi->L, p->lineinfo, 0, p->sizelineinfo, int);
-			verify(LIF(Z,read)(&upi->zio, p->lineinfo,
-			sizeof(int) * p->sizelineinfo) == 0);
-		}
-	}
-
-	/* Read in linedefined and lastlinedefined */
-	verify(LIF(Z,read)(&upi->zio, &p->linedefined, sizeof(int)) == 0);
-	verify(LIF(Z,read)(&upi->zio, &p->lastlinedefined, sizeof(int)) == 0);
-
-	/* Read in misc values */
-	{
-		verify(LIF(Z,read)(&upi->zio, &p->nups, sizeof(lu_byte)) == 0);
-		verify(LIF(Z,read)(&upi->zio, &p->numparams, sizeof(lu_byte)) == 0);
-		verify(LIF(Z,read)(&upi->zio, &p->is_vararg, sizeof(lu_byte)) == 0);
-		verify(LIF(Z,read)(&upi->zio, &p->maxstacksize, sizeof(lu_byte)) == 0);
-	}
-}
-
-
-/* Does basically the opposite of luaC_link().
- * Right now this function is rather inefficient; it requires traversing the
- * entire root GC set in order to find one object. If the GC list were doubly
- * linked this would be much easier, but there's no reason for Lua to have
- * that. */
-static void gcunlink(lua_State *L, GCObject *gco)
-{
-	GCObject *prevslot;
-	if(G(L)->rootgc == gco) {
-		G(L)->rootgc = G(L)->rootgc->gch.next;
-		return;
-	}
-
-	prevslot = G(L)->rootgc;
-	while(prevslot->gch.next != gco) {
-		lua_assert(prevslot->gch.next != NULL);
-		prevslot = prevslot->gch.next;
-	}
-
-	prevslot->gch.next = prevslot->gch.next->gch.next;
-}
-
-/* FIXME __ALL__ field ordering */
-static void unpersistthread(int ref, UnpersistInfo *upi)
-{
-					/* perms reftbl ... */
-	lua_State *L2;
-	size_t stacklimit = 0;
-	L2 = lua_newthread(upi->L);
-	lua_checkstack(upi->L, 3);
-					/* L1: perms reftbl ... thr */
-					/* L2: (empty) */
-	registerobject(ref, upi);
-
-	/* First, deserialize the object stack. */
-	{
-		size_t i, stacksize;
-		read_size(&upi->zio, &stacksize);
-		LIF(D,growstack)(L2, (int)stacksize);
-		/* Make sure that the first stack element (a nil, representing
-		 * the imaginary top-level C function) is written to the very,
-		 * very bottom of the stack */
-		L2->top--;
-		for(i=0; i<stacksize; i++) {
-			unpersist(upi);
-					/* L1: perms reftbl ... thr obj* */
-		}
-		lua_xmove(upi->L, L2, stacksize);
-					/* L1: perms reftbl ... thr */
-					/* L2: obj* */
-	}
-					/* (hereafter, stacks refer to L1) */
-
-	/* Now, deserialize the CallInfo stack. */
-	{
-		size_t i, numframes;
-		read_size(&upi->zio, &numframes);
-		LIF(D,reallocCI)(L2,numframes*2);
-		for(i=0; i<numframes; i++) {
-			CallInfo *ci = L2->base_ci + i;
-			size_t stackbase, stackfunc, stacktop, savedpc;
-			read_size(&upi->zio, &stackbase);
-			read_size(&upi->zio, &stackfunc);
-			read_size(&upi->zio, &stacktop);
-			verify(LIF(Z,read)(&upi->zio, &ci->nresults, sizeof(int)) == 0);
-			read_size(&upi->zio, &savedpc);
-
-			if(stacklimit < stacktop)
-				stacklimit = stacktop;
-
-			ci->base = L2->stack+stackbase;
-			ci->func = L2->stack+stackfunc;
-			ci->top = L2->stack+stacktop;
-			ci->savedpc = (ci != L2->base_ci) ?
-				ci_func(ci)->l.p->code+savedpc :
-				0;
-			ci->tailcalls = 0;
-			/* Update the pointer each time, to keep the GC
-			 * happy*/
-			L2->ci = ci;
-		}
-	}
-					/* perms reftbl ... thr */
-	/* Deserialize the state's other parameters, with the exception of upval stuff */
-	{
-		size_t stackbase, stacktop;
-		L2->savedpc = L2->ci->savedpc;
-		verify(LIF(Z,read)(&upi->zio, &L2->status, sizeof(lu_byte)) == 0);
-		read_size(&upi->zio, &stackbase);
-		read_size(&upi->zio, &stacktop);
-
-#ifdef SIZES64
-		uint64 value;
-		verify(LIF(Z,read)(&upi->zio, &value, sizeof(uint64)) == 0);
-
-		L2->errfunc = static_cast<ptrdiff_t>(value);
-#else
-		verify(LIF(Z,read)(&upi->zio, &L2->errfunc, sizeof(ptrdiff_t)) == 0);
-#endif
-
-		//read_size(&upi->zio, (size_t *)&L2->errfunc);
-		L2->base = L2->stack + stackbase;
-		L2->top = L2->stack + stacktop;
-	}
-	/* Finally, "reopen" upvalues (see persistupval() for why) */
-	{
-		UpVal* uv;
-		GCObject **nextslot = &L2->openupval;
-		global_State *g = G(L2);
-		while(1) {
-			size_t stackpos;
-			unpersist(upi);
-					/* perms reftbl ... thr uv/nil */
-			if(lua_isnil(upi->L, -1)) {
-					/* perms reftbl ... thr nil */
-				lua_pop(upi->L, 1);
-					/* perms reftbl ... thr */
-				break;
-			}
-					/* perms reftbl ... thr boxeduv */
-			unboxupval(upi->L);
-					/* perms reftbl ... thr uv */
-			uv = toupval(upi->L, -1);
-			lua_pop(upi->L, 1);
-					/* perms reftbl ... thr */
-
-			read_size(&upi->zio, &stackpos);
-			uv->v = L2->stack + stackpos;
-			gcunlink(upi->L, (GCObject *)uv);
-			uv->marked = luaC_white(g);
-			*nextslot = (GCObject *)uv;
-			nextslot = &uv->next;
-			uv->u.l.prev = &G(L2)->uvhead;
-			uv->u.l.next = G(L2)->uvhead.u.l.next;
-			uv->u.l.next->u.l.prev = uv;
-			G(L2)->uvhead.u.l.next = uv;
-			lua_assert(uv->u.l.next->u.l.prev == uv && uv->u.l.prev->u.l.next == uv);
-		}
-		*nextslot = NULL;
-	}
-
-	/* The stack must be valid at least to the highest value among the CallInfos */
-	/* 'top' and the values up to there must be filled with 'nil' */
-	{
-		StkId o;
-		LIF(D,checkstack)(L2, (int)stacklimit);
-		for (o = L2->top; o <= L2->top + stacklimit; o++)
-			setnilvalue(o);
-	}
-}
-
-static void unpersistuserdata(int ref, UnpersistInfo *upi)
-{
-					/* perms reftbl ... */
-	int isspecial;
-	lua_checkstack(upi->L, 2);
-	verify(LIF(Z,read)(&upi->zio, &isspecial, sizeof(int)) == 0);
-	if(isspecial) {
-		unpersist(upi);
-					/* perms reftbl ... spfunc? */
-		lua_assert(lua_isfunction(upi->L, -1));
-					/* perms reftbl ... spfunc */
-#ifdef PLUTO_PASS_USERDATA_TO_PERSIST
-		lua_pushlightuserdata(upi->L, &upi->zio);
-		lua_call(upi->L, 1, 1);
-#else
-		lua_call(upi->L, 0, 1);
-#endif
-					/* perms reftbl ... udata? */
-/* This assertion might not be necessary; it's conceivable, for
- * example, that the SP function might decide to return a table
- * with equivalent functionality. For the time being, we'll
- * ignore this possibility in favor of stricter and more testable
- * requirements. */
-		lua_assert(lua_isuserdata(upi->L, -1));
-					/* perms reftbl ... udata */
-	} else {
-		size_t length;
-		read_size(&upi->zio, &length);
-
-		lua_newuserdata(upi->L, length);
-					/* perms reftbl ... udata */
-		registerobject(ref, upi);
-		verify(LIF(Z,read)(&upi->zio, lua_touserdata(upi->L, -1), length) == 0);
-
-		unpersist(upi);
-					/* perms reftbl ... udata mt/nil? */
-		lua_assert(lua_istable(upi->L, -1) || lua_isnil(upi->L, -1));
-					/* perms reftbl ... udata mt/nil */
-		lua_setmetatable(upi->L, -2);
-					/* perms reftbl ... udata */
-	}
-					/* perms reftbl ... udata */
-}
-
-static void unpersistpermanent(int ref, UnpersistInfo *upi)
-{
-					/* perms reftbl ... */
-	lua_checkstack(upi->L, 2);
-	unpersist(upi);
-					/* perms reftbl permkey */
-	lua_gettable(upi->L, 1);
-					/* perms reftbl perm? */
-	/* We assume currently that the substituted permanent value
-	 * shouldn't be nil. This may be a bad assumption. Real-life
-	 * experience is needed to evaluate this. */
-	lua_assert(!lua_isnil(upi->L, -1));
-					/* perms reftbl perm */
-}
-
-#if 0
-/* For debugging only; not called when lua_assert is empty */
-static int inreftable(lua_State *L, int ref)
-{
-	int res;
-	lua_checkstack(L, 1);
-					/* perms reftbl ... */
-	lua_pushlightuserdata(L, (void *)ref);
-					/* perms reftbl ... ref */
-	lua_gettable(L, 2);
-					/* perms reftbl ... obj? */
-	res = !lua_isnil(L, -1);
-	lua_pop(L, 1);
-					/* perms reftbl ... */
-	return res;
-}
-#endif
-
-static void unpersist(UnpersistInfo *upi)
-{
-					/* perms reftbl ... */
-	int firstTime;
-	int stacksize = lua_gettop(upi->L); stacksize = stacksize; /* DEBUG */
-	lua_checkstack(upi->L, 2);
-	LIF(Z,read)(&upi->zio, &firstTime, sizeof(int));
-	if(firstTime) {
-		int ref;
-		int type;
-		LIF(Z,read)(&upi->zio, &ref, sizeof(int));
-		lua_assert(!inreftable(upi->L, ref));
-		LIF(Z,read)(&upi->zio, &type, sizeof(int));
-#ifdef PLUTO_DEBUG
-		printindent(upi->level);
-		printf("1 %d %d\n", ref, type);
-		upi->level++;
-#endif
-		switch(type) {
-		case LUA_TBOOLEAN:
-			unpersistboolean(upi);
-			break;
-		case LUA_TLIGHTUSERDATA:
-			unpersistlightuserdata(upi);
-			break;
-		case LUA_TNUMBER:
-			unpersistnumber(upi);
-			break;
-		case LUA_TSTRING:
-			unpersiststring(upi);
-			break;
-		case LUA_TTABLE:
-			unpersisttable(ref, upi);
-			break;
-		case LUA_TFUNCTION:
-			unpersistfunction(ref, upi);
-			break;
-		case LUA_TTHREAD:
-			unpersistthread(ref, upi);
-			break;
-		case LUA_TPROTO:
-			unpersistproto(ref, upi);
-			break;
-		case LUA_TUPVAL:
-			unpersistupval(ref, upi);
-			break;
-		case LUA_TUSERDATA:
-			unpersistuserdata(ref, upi);
-			break;
-		case PLUTO_TPERMANENT:
-			unpersistpermanent(ref, upi);
-			break;
-		default:
-			lua_assert(0);
-		}
-					/* perms reftbl ... obj */
-		lua_assert(lua_type(upi->L, -1) == type ||
-			type == PLUTO_TPERMANENT ||
-			/* Remember, upvalues get a special dispensation, as
-			 * described in boxupval */
-			(lua_type(upi->L, -1) == LUA_TFUNCTION &&
-				type == LUA_TUPVAL));
-		registerobject(ref, upi);
-					/* perms reftbl ... obj */
-#ifdef PLUTO_DEBUG
-		upi->level--;
-#endif
-	} else {
-		int ref;
-		LIF(Z,read)(&upi->zio, &ref, sizeof(int));
-#ifdef PLUTO_DEBUG
-		printindent(upi->level);
-		printf("0 %d\n", ref);
-#endif
-		if(ref == 0) {
-			lua_pushnil(upi->L);
-					/* perms reftbl ... nil */
-		} else {
-			lua_pushlightuserdata(upi->L, (void *)ref);
-					/* perms reftbl ... ref */
-			lua_gettable(upi->L, 2);
-					/* perms reftbl ... obj? */
-			lua_assert(!lua_isnil(upi->L, -1));
-		}
-					/* perms reftbl ... obj/nil */
-	}
-					/* perms reftbl ... obj/nil */
-	lua_assert(lua_gettop(upi->L) == stacksize + 1);
-}
-
-void pluto_unpersist(lua_State *L, lua_Chunkreader reader, void *ud)
-{
-	/* We use the graciously provided ZIO (what the heck does the Z stand
-	 * for?) library so that we don't have to deal with the reader directly.
-	 * Letting the reader function decide how much data to return can be
-	 * very unpleasant.
-	 */
-	UnpersistInfo upi;
-	upi.L = L;
-#ifdef PLUTO_DEBUG
-	upi.level = 0;
-#endif
-
-	lua_checkstack(L, 3);
-	LIF(Z,init)(L, &upi.zio, reader, ud);
-
-					/* perms */
-	lua_newtable(L);
-					/* perms reftbl */
-	lua_gc(L, LUA_GCSTOP, 0);
-	unpersist(&upi);
-	lua_gc(L, LUA_GCRESTART, 0);
-					/* perms reftbl rootobj */
-	lua_replace(L, 2);
-					/* perms rootobj  */
-}
-
-typedef struct LoadInfo_t {
-	char *buf;
-	size_t size;
-} LoadInfo;
-
-
-static const char *bufreader(lua_State *L, void *ud, size_t *sz) {
-	LoadInfo *li = (LoadInfo *)ud;
-	if(li->size == 0) {
-		return NULL;
-	}
-	*sz = li->size;
-	li->size = 0;
-	return li->buf;
-}
-
-int unpersist_l(lua_State *L)
-{
-	LoadInfo li;
-	char const *origbuf;
-	char *tempbuf;
-	size_t bufsize;
-					/* perms? str? ...? */
-	lua_settop(L, 2);
-					/* perms? str? */
-	origbuf = luaL_checklstring(L, 2, &bufsize);
-	tempbuf = LIF(M,newvector)(L, bufsize, char);
-	memcpy(tempbuf, origbuf, bufsize);
-
-	li.buf = tempbuf;
-	li.size = bufsize;
-
-					/* perms? str */
-	lua_pop(L, 1);
-					/* perms? */
-	luaL_checktype(L, 1, LUA_TTABLE);
-					/* perms */
-	pluto_unpersist(L, bufreader, &li);
-					/* perms rootobj */
-	LIF(M,freearray)(L, tempbuf, bufsize, char);
-	return 1;
-}
-
-/* Stefan's first C function for Lua! :)
-   Returns a string describing the Pluto version you're using. */
-
-int version_l(lua_State *L)
-{
-	const char *version = VERSION;
-
-	lua_settop(L, 0);
-					/* (empty) */
-	lua_pushlstring(L, version, strlen(version));
-					/* str */
-	return 1;
-}
-
-/* Set human-readable output on or off. */
-int human_l(lua_State *L)
-{
-					/* flag? ...? */
-	lua_settop(L, 1);
-					/* flag? */
-	/*luaL_checktype(L, 1, LUA_TBOOLEAN);*/
-					/* flag */
-
-	humanReadable = lua_toboolean(L, 1);
-
-	lua_settop(L, 0);
-					/* (empty) */
-	return 0;
-}
-
-static luaL_reg pluto_reg[] = {
-	{ "persist", persist_l },
-	{ "unpersist", unpersist_l },
-	{ "version", version_l },
-	{ "human", human_l },
-	{ NULL, NULL }
-};
-
-LUALIB_API int luaopen_pluto(lua_State *L) {
-	luaL_openlib(L, "pluto", pluto_reg, 0);
-	return 1;
-}
diff --git a/engines/sword25/util/pluto/pluto.h b/engines/sword25/util/pluto/pluto.h
deleted file mode 100644
index 3674842..0000000
--- a/engines/sword25/util/pluto/pluto.h
+++ /dev/null
@@ -1,25 +0,0 @@
-/* $Id$ */
-
-/* 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 at 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.
- */
-
-/* lua.h must be included before this file */
-
-void pluto_persist(lua_State *L, lua_Chunkwriter writer, void *ud);
-
-void pluto_unpersist(lua_State *L, lua_Chunkreader reader, void *ud);
-
-LUALIB_API int luaopen_pluto(lua_State *L);
diff --git a/engines/sword25/util/pluto/plzio.cpp b/engines/sword25/util/pluto/plzio.cpp
deleted file mode 100644
index 21f69a9..0000000
--- a/engines/sword25/util/pluto/plzio.cpp
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
-** $Id$
-** a generic input stream interface
-** See Copyright Notice in lua.h
-*/
-
-
-#include <string.h>
-
-#define lzio_c
-#define LUA_CORE
-
-#include "pdep/pdep.h"
-
-int pdep_fill (ZIO *z) {
-  size_t size;
-  lua_State *L = z->L;
-  const char *buff;
-  lua_unlock(L);
-  buff = z->reader(L, z->data, &size);
-  lua_lock(L);
-  if (buff == NULL || size == 0) return EOZ;
-  z->n = size - 1;
-  z->p = buff;
-  return char2int(*(z->p++));
-}
-
-
-int pdep_lookahead (ZIO *z) {
-  if (z->n == 0) {
-    if (pdep_fill(z) == EOZ)
-      return EOZ;
-    else {
-      z->n++;  /* pdep_fill removed first byte; put back it */
-      z->p--;
-    }
-  }
-  return char2int(*z->p);
-}
-
-
-void pdep_init (lua_State *L, ZIO *z, lua_Reader reader, void *data) {
-  z->L = L;
-  z->reader = reader;
-  z->data = data;
-  z->n = 0;
-  z->p = NULL;
-}
-
-
-/* --------------------------------------------------------------- read --- */
-size_t pdep_read (ZIO *z, void *b, size_t n) {
-  while (n) {
-    size_t m;
-    if (pdep_lookahead(z) == EOZ)
-      return n;  /* return number of missing bytes */
-    m = (n <= z->n) ? n : z->n;  /* min. between n and z->n */
-    memcpy(b, z->p, m);
-    z->n -= m;
-    z->p += m;
-    b = (char *)b + m;
-    n -= m;
-  }
-  return 0;
-}
-
-/* ------------------------------------------------------------------------ */
-char *pdep_openspace (lua_State *L, Mbuffer *buff, size_t n) {
-  if (n > buff->buffsize) {
-    if (n < LUA_MINBUFFER) n = LUA_MINBUFFER;
-    pdep_resizebuffer(L, buff, n);
-  }
-  return buff->buffer;
-}


Commit: eaff6a40f6f9cb8a5817c7b90a7e24c8c12da3fe
    https://github.com/scummvm/scummvm/commit/eaff6a40f6f9cb8a5817c7b90a7e24c8c12da3fe
Author: RichieSams (adastley at gmail.com)
Date: 2014-12-30T18:21:43-06:00

Commit Message:
SWORD25: Correct include guards to reflect the changes to the file names

Changed paths:
    engines/sword25/util/lua_persistence.h
    engines/sword25/util/lua_persistence_util.h



diff --git a/engines/sword25/util/lua_persistence.h b/engines/sword25/util/lua_persistence.h
index cf7d7e0..88cbb04 100644
--- a/engines/sword25/util/lua_persistence.h
+++ b/engines/sword25/util/lua_persistence.h
@@ -20,8 +20,8 @@
  *
  */
 
-#ifndef LUA_SERIALIZATION_H
-#define LUA_SERIALIZATION_H
+#ifndef LUA_PERSISTENCE_H
+#define LUA_PERSISTENCE_H
 
 #include "sword25/util/lua/lua.h"
 
diff --git a/engines/sword25/util/lua_persistence_util.h b/engines/sword25/util/lua_persistence_util.h
index 345996f..305eea4 100644
--- a/engines/sword25/util/lua_persistence_util.h
+++ b/engines/sword25/util/lua_persistence_util.h
@@ -20,8 +20,8 @@
  *
  */
 
-#ifndef LUA_SERIALIZATION_UTIL_H
-#define LUA_SERIALIZATION_UTIL_H
+#ifndef LUA_PERISTENCE_UTIL_H
+#define LUA_PERISTENCE_UTIL_H
 
 
 struct lua_State;


Commit: 8ee75e1dc56681337a3ae98c9d207e70e28c5ff5
    https://github.com/scummvm/scummvm/commit/8ee75e1dc56681337a3ae98c9d207e70e28c5ff5
Author: RichieSams (adastley at gmail.com)
Date: 2014-12-30T18:22:15-06:00

Commit Message:
SWORD25: Add Pluto copyright message to new persistence code

Since the code is based off the Pluto code

Changed paths:
    engines/sword25/util/lua_persist.cpp
    engines/sword25/util/lua_persistence.h
    engines/sword25/util/lua_persistence_util.cpp
    engines/sword25/util/lua_persistence_util.h
    engines/sword25/util/lua_unpersist.cpp



diff --git a/engines/sword25/util/lua_persist.cpp b/engines/sword25/util/lua_persist.cpp
index 6d75806..aea4e70 100644
--- a/engines/sword25/util/lua_persist.cpp
+++ b/engines/sword25/util/lua_persist.cpp
@@ -20,6 +20,30 @@
  *
  */
 
+/**
+ * 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 at 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 at luaos.net)
+ * for Mobile Lua (http://luaos.net/pages/mobile-lua.php)
+ */
+
+
 #include "sword25/util/lua_persistence.h"
 
 #include "sword25/util/double_serialization.h"
diff --git a/engines/sword25/util/lua_persistence.h b/engines/sword25/util/lua_persistence.h
index 88cbb04..53e3dee 100644
--- a/engines/sword25/util/lua_persistence.h
+++ b/engines/sword25/util/lua_persistence.h
@@ -20,6 +20,29 @@
  *
  */
 
+/**
+ * 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 at 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 at luaos.net)
+ * for Mobile Lua (http://luaos.net/pages/mobile-lua.php)
+ */
+
 #ifndef LUA_PERSISTENCE_H
 #define LUA_PERSISTENCE_H
 
diff --git a/engines/sword25/util/lua_persistence_util.cpp b/engines/sword25/util/lua_persistence_util.cpp
index 8365f5d..958fb7a 100644
--- a/engines/sword25/util/lua_persistence_util.cpp
+++ b/engines/sword25/util/lua_persistence_util.cpp
@@ -20,6 +20,53 @@
  *
  */
 
+/**
+ * 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 at 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 at luaos.net)
+ * for Mobile Lua (http://luaos.net/pages/mobile-lua.php)
+ */
+
+/**
+ * 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 at 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 at luaos.net)
+ * for Mobile Lua (http://luaos.net/pages/mobile-lua.php)
+ */
+
+
 #include "sword25/util/lua_persistence_util.h"
 
 #include "common/scummsys.h"
diff --git a/engines/sword25/util/lua_persistence_util.h b/engines/sword25/util/lua_persistence_util.h
index 305eea4..4d0085e 100644
--- a/engines/sword25/util/lua_persistence_util.h
+++ b/engines/sword25/util/lua_persistence_util.h
@@ -20,6 +20,30 @@
  *
  */
 
+/**
+ * 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 at 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 at luaos.net)
+ * for Mobile Lua (http://luaos.net/pages/mobile-lua.php)
+ */
+
+
 #ifndef LUA_PERISTENCE_UTIL_H
 #define LUA_PERISTENCE_UTIL_H
 
diff --git a/engines/sword25/util/lua_unpersist.cpp b/engines/sword25/util/lua_unpersist.cpp
index 8d64430..6f32757 100644
--- a/engines/sword25/util/lua_unpersist.cpp
+++ b/engines/sword25/util/lua_unpersist.cpp
@@ -20,6 +20,30 @@
  *
  */
 
+/**
+ * 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 at 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 at luaos.net)
+ * for Mobile Lua (http://luaos.net/pages/mobile-lua.php)
+ */
+
+
 #include "sword25/util/lua_persistence.h"
 
 #include "sword25/util/double_serialization.h"


Commit: 9a4d62e76a29647ed7f2c0b16f009ff143fdf739
    https://github.com/scummvm/scummvm/commit/9a4d62e76a29647ed7f2c0b16f009ff143fdf739
Author: RichieSams (adastley at gmail.com)
Date: 2014-12-30T18:26:59-06:00

Commit Message:
SWORD25: Change function names to use persist instead of serialize

Same argument as in 97c35714ce3986b99848a780f6b195a63f8910b7.
To match the rest of the SWORD25 code base

Changed paths:
    engines/sword25/util/lua_persist.cpp
    engines/sword25/util/lua_unpersist.cpp



diff --git a/engines/sword25/util/lua_persist.cpp b/engines/sword25/util/lua_persist.cpp
index aea4e70..6038111 100644
--- a/engines/sword25/util/lua_persist.cpp
+++ b/engines/sword25/util/lua_persist.cpp
@@ -66,17 +66,17 @@ struct SerializationInfo {
 	uint counter;
 };
 
-static void serialize(SerializationInfo *info);
+static void persist(SerializationInfo *info);
 
-static void serializeBoolean(SerializationInfo *info);
-static void serializeNumber(SerializationInfo *info);
-static void serializeString(SerializationInfo *info);
-static void serializeTable(SerializationInfo *info);
-static void serializeFunction(SerializationInfo *info);
-static void serializeThread(SerializationInfo *info);
-static void serializeProto(SerializationInfo *info);
-static void serializeUpValue(SerializationInfo *info);
-static void serializeUserData(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) {
@@ -127,14 +127,14 @@ void persistLua(lua_State *luaState, Common::WriteStream *writeStream) {
 	// >>>>> permTbl indexTbl rootObj
 
 	// Serialize the root recursively
-	serialize(&info);
+	persist(&info);
 
 	// Return the stack back to the original state
 	lua_remove(luaState, 2);
 	// >>>>> permTbl rootObj
 }
 
-static void serialize(SerializationInfo *info) {
+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
@@ -215,7 +215,7 @@ static void serialize(SerializationInfo *info) {
 		info->writeStream->writeSint32LE(PERMANENT_TYPE);
 
 		// Serialize the key
-		serialize(info);
+		persist(info);
 
 		// Pop the key off the stack
 		lua_pop(info->luaState, 1);
@@ -236,7 +236,7 @@ static void serialize(SerializationInfo *info) {
 
 	switch (objType) {
 	case LUA_TBOOLEAN:
-		serializeBoolean(info);
+		persistBoolean(info);
 		break;
 	case LUA_TLIGHTUSERDATA:
 		// You can't serialize a pointer
@@ -244,41 +244,41 @@ static void serialize(SerializationInfo *info) {
 		assert(0);
 		break;
 	case LUA_TNUMBER:
-		serializeNumber(info);
+		persistNumber(info);
 		break;
 	case LUA_TSTRING:
-		serializeString(info);
+		persistString(info);
 		break;
 	case LUA_TTABLE:
-		serializeTable(info);
+		persistTable(info);
 		break;
 	case LUA_TFUNCTION:
-		serializeFunction(info);
+		persistFunction(info);
 		break;
 	case LUA_TTHREAD:
-		serializeThread(info);
+		persistThread(info);
 		break;
 	case LUA_TPROTO:
-		serializeProto(info);
+		persistProto(info);
 		break;
 	case LUA_TUPVAL:
-		serializeUpValue(info);
+		persistUpValue(info);
 		break;
 	case LUA_TUSERDATA:
-		serializeUserData(info);
+		persistUserData(info);
 		break;
 	default:
 		assert(0);
 	}
 }
 
-static void serializeBoolean(SerializationInfo *info) {
+static void persistBoolean(SerializationInfo *info) {
 	int value = lua_toboolean(info->luaState, -1);
 
 	info->writeStream->writeSint32LE(value);
 }
 
-static void serializeNumber(SerializationInfo *info) {
+static void persistNumber(SerializationInfo *info) {
 	lua_Number value = lua_tonumber(info->luaState, -1);
 
 	#if 1
@@ -298,7 +298,7 @@ static void serializeNumber(SerializationInfo *info) {
 
 }
 
-static void serializeString(SerializationInfo *info) {
+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));
@@ -395,7 +395,7 @@ static bool serializeSpecialObject(SerializationInfo *info, bool defaction) {
 	info->writeStream->writeSint32LE(1);
 
 	// Serialize the function
-	serialize(info);
+	persist(info);
 
 	lua_pop(info->luaState, 2);
 	// >>>>> permTbl indexTbl ...... obj
@@ -403,7 +403,7 @@ static bool serializeSpecialObject(SerializationInfo *info, bool defaction) {
 	return true;
 }
 
-static void serializeTable(SerializationInfo *info) {
+static void persistTable(SerializationInfo *info) {
 	// >>>>> permTbl indexTbl ...... tbl
 
 	// Make sure there is enough room on the stack
@@ -422,7 +422,7 @@ static void serializeTable(SerializationInfo *info) {
 	}
 
 	// >>>>> permTbl indexTbl ...... tbl metaTbl/nil */
-	serialize(info);
+	persist(info);
 
 	lua_pop(info->luaState, 1);
 	// >>>>> permTbl indexTbl ...... tbl
@@ -439,13 +439,13 @@ static void serializeTable(SerializationInfo *info) {
 		// >>>>> permTbl indexTbl ...... tbl k v k */
 
 		// Serialize the key
-		serialize(info);
+		persist(info);
 
 		lua_pop(info->luaState, 1);
 		// >>>>> permTbl indexTbl ...... tbl k v */
 
 		// Serialize the value
-		serialize(info);
+		persist(info);
 
 		lua_pop(info->luaState, 1);
 		// >>>>> permTbl indexTbl ...... tbl k */
@@ -457,13 +457,13 @@ static void serializeTable(SerializationInfo *info) {
 	lua_pushnil(info->luaState);
 	// >>>>> permTbl indexTbl ...... tbl
 
-	serialize(info);
+	persist(info);
 
 	lua_pop(info->luaState, 1);
 	// >>>>> permTbl indexTbl ...... tbl
 }
 
-static void serializeFunction(SerializationInfo *info) {
+static void persistFunction(SerializationInfo *info) {
 	// >>>>> permTbl indexTbl ...... func
 	Closure *cl = clvalue(getObject(info->luaState, -1));
 	lua_checkstack(info->luaState, 2);
@@ -484,7 +484,7 @@ static void serializeFunction(SerializationInfo *info) {
 		pushProto(info->luaState, cl->l.p);
 		// >>>>> permTbl indexTbl ...... func proto */
 
-		serialize(info);
+		persist(info);
 
 		lua_pop(info->luaState, 1);
 		// >>>>> permTbl indexTbl ...... func
@@ -495,7 +495,7 @@ static void serializeFunction(SerializationInfo *info) {
 			pushUpValue(info->luaState, cl->l.upvals[i]);
 			// >>>>> permTbl indexTbl ...... func upval
 
-			serialize(info);
+			persist(info);
 
 			lua_pop(info->luaState, 1);
 			// >>>>> permTbl indexTbl ...... func
@@ -519,14 +519,14 @@ static void serializeFunction(SerializationInfo *info) {
 		}
 
 		// >>>>> permTbl indexTbl ...... func fenv/nil
-		serialize(info);
+		persist(info);
 
 		lua_pop(info->luaState, 1);
 		// >>>>> permTbl indexTbl ...... func
 	}
 }
 
-static void serializeThread(SerializationInfo *info) {
+static void persistThread(SerializationInfo *info) {
 	// >>>>> permTbl indexTbl ...... thread
 	lua_State *threadState = lua_tothread(info->luaState, -1);
 
@@ -547,7 +547,7 @@ static void serializeThread(SerializationInfo *info) {
 
 	// >>>>> permTbl indexTbl ...... thread (reversed contents of thread stack) */
 	for (; stackSize > 0; --stackSize) {
-		serialize(info);
+		persist(info);
 
 		lua_pop(info->luaState, 1);
 	}
@@ -609,7 +609,7 @@ static void serializeThread(SerializationInfo *info) {
 		pushUpValue(info->luaState, upVal);
 		// >>>>> permTbl indexTbl ...... thread upVal
 
-		serialize(info);
+		persist(info);
 
 		lua_pop(info->luaState, 1);
 		// >>>>> permTbl indexTbl ...... thread
@@ -624,13 +624,13 @@ static void serializeThread(SerializationInfo *info) {
 	// >>>>> permTbl indexTbl ...... thread nil
 
 	// Use nil as a terminator
-	serialize(info);
+	persist(info);
 
 	lua_pop(info->luaState, 1);
 	// >>>>> permTbl indexTbl ...... thread
 }
 
-static void serializeProto(SerializationInfo *info) {
+static void persistProto(SerializationInfo *info) {
 	// >>>>> permTbl indexTbl ...... proto
 	Proto *proto = gco2p(getObject(info->luaState, -1)->value.gc);
 
@@ -644,7 +644,7 @@ static void serializeProto(SerializationInfo *info) {
 		pushObject(info->luaState, &proto->k[i]);
 		// >>>>> permTbl indexTbl ...... proto const
 
-		serialize(info);
+		persist(info);
 
 		lua_pop(info->luaState, 1);
 		// >>>>> permTbl indexTbl ...... proto
@@ -660,7 +660,7 @@ static void serializeProto(SerializationInfo *info) {
 		pushProto(info->luaState, proto->p[i]);
 		// >>>>> permTbl indexTbl ...... proto subProto */
 
-		serialize(info);
+		persist(info);
 
 		lua_pop(info->luaState, 1);
 		// >>>>> permTbl indexTbl ...... proto
@@ -683,7 +683,7 @@ static void serializeProto(SerializationInfo *info) {
 		pushString(info->luaState, proto->upvalues[i]);
 		// >>>>> permTbl indexTbl ...... proto str
 
-		serialize(info);
+		persist(info);
 
 		lua_pop(info->luaState, 1);
 		// >>>>> permTbl indexTbl ...... proto
@@ -697,7 +697,7 @@ static void serializeProto(SerializationInfo *info) {
 		pushString(info->luaState, proto->locvars[i].varname);
 		// >>>>> permTbl indexTbl ...... proto str
 
-		serialize(info);
+		persist(info);
 
 		lua_pop(info->luaState, 1);
 		// >>>>> permTbl indexTbl ...... proto
@@ -711,7 +711,7 @@ static void serializeProto(SerializationInfo *info) {
 	pushString(info->luaState, proto->source);
 	// >>>>> permTbl indexTbl ...... proto sourceStr
 
-	serialize(info);
+	persist(info);
 
 	lua_pop(info->luaState, 1);
 	// >>>>> permTbl indexTbl ...... proto
@@ -757,7 +757,7 @@ static void serializeProto(SerializationInfo *info) {
  * (d) When unserializing, "reopen" each of these upvalues as the thread is
  *     unserialized
  */
-static void serializeUpValue(SerializationInfo *info) {
+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);
@@ -774,11 +774,11 @@ static void serializeUpValue(SerializationInfo *info) {
 	pushObject(info->luaState, upValue->v);
 	// >>>>> permTbl indexTbl ...... obj
 
-	serialize(info);
+	persist(info);
 	// >>>>> permTbl indexTbl ...... obj
 }
 
-static void serializeUserData(SerializationInfo *info) {
+static void persistUserData(SerializationInfo *info) {
 	// >>>>> permTbl rootObj ...... udata
 
 	// Make sure there is enough room on the stack
@@ -804,7 +804,7 @@ static void serializeUserData(SerializationInfo *info) {
 	}
 
 	// >>>>> permTbl rootObj ...... udata metaTbl/nil
-	serialize(info);
+	persist(info);
 
 	lua_pop(info->luaState, 1);
 	/* perms reftbl ... udata */
diff --git a/engines/sword25/util/lua_unpersist.cpp b/engines/sword25/util/lua_unpersist.cpp
index 6f32757..ef0ef31 100644
--- a/engines/sword25/util/lua_unpersist.cpp
+++ b/engines/sword25/util/lua_unpersist.cpp
@@ -64,18 +64,18 @@ struct UnSerializationInfo {
 	Common::ReadStream *readStream;
 };
 
-static void unserialize(UnSerializationInfo *info);
+static void unpersist(UnSerializationInfo *info);
 
-static void unserializeBoolean(UnSerializationInfo *info);
-static void unserializeNumber(UnSerializationInfo *info);
-static void unserializeString(UnSerializationInfo *info);
-static void unserializeTable(UnSerializationInfo *info, int index);
-static void unserializeFunction(UnSerializationInfo *info, int index);
-static void unserializeThread(UnSerializationInfo *info, int index);
-static void unserializeProto(UnSerializationInfo *info, int index);
-static void unserializeUpValue(UnSerializationInfo *info, int index);
-static void unserializeUserData(UnSerializationInfo *info, int index);
-static void unserializePermanent(UnSerializationInfo *info, int index);
+static void unpersistBoolean(UnSerializationInfo *info);
+static void unpersistNumber(UnSerializationInfo *info);
+static void unpersistString(UnSerializationInfo *info);
+static void unpersistTable(UnSerializationInfo *info, int index);
+static void unpersistFunction(UnSerializationInfo *info, int index);
+static void unpersistThread(UnSerializationInfo *info, int index);
+static void unpersistProto(UnSerializationInfo *info, int index);
+static void unpersistUpValue(UnSerializationInfo *info, int index);
+static void unpersistUserData(UnSerializationInfo *info, int index);
+static void unpersistPermanent(UnSerializationInfo *info, int index);
 
 
 void unpersistLua(lua_State *luaState, Common::ReadStream *readStream) {
@@ -98,7 +98,7 @@ void unpersistLua(lua_State *luaState, Common::ReadStream *readStream) {
 	lua_gc(luaState, LUA_GCSTOP, 0);
 
 	// Unserialize the root object
-	unserialize(&info);
+	unpersist(&info);
 	// >>>>> permTbl indexTbl rootObj
 
 	// Re-start garbage collection
@@ -129,7 +129,7 @@ static void registerObjectInIndexTable(UnSerializationInfo *info, int index) {
 	// >>>>> permTbl indexTbl ...... obj
 }
 
-static void unserialize(UnSerializationInfo *info) {
+static void unpersist(UnSerializationInfo *info) {
 	// >>>>> permTbl indexTbl ......
 
 	// Make sure there is enough room on the stack
@@ -142,7 +142,7 @@ static void unserialize(UnSerializationInfo *info) {
 
 		switch (type) {
 		case LUA_TBOOLEAN:
-			unserializeBoolean(info);
+			unpersistBoolean(info);
 			break;
 		case LUA_TLIGHTUSERDATA:
 			// You can't serialize a pointer
@@ -150,31 +150,31 @@ static void unserialize(UnSerializationInfo *info) {
 			assert(0);
 			break;
 		case LUA_TNUMBER:
-			unserializeNumber(info);
+			unpersistNumber(info);
 			break;
 		case LUA_TSTRING:
-			unserializeString(info);
+			unpersistString(info);
 			break;
 		case LUA_TTABLE:
-			unserializeTable(info, index);
+			unpersistTable(info, index);
 			break;
 		case LUA_TFUNCTION:
-			unserializeFunction(info, index);
+			unpersistFunction(info, index);
 			break;
 		case LUA_TTHREAD:
-			unserializeThread(info, index);
+			unpersistThread(info, index);
 			break;
 		case LUA_TPROTO:
-			unserializeProto(info, index);
+			unpersistProto(info, index);
 			break;
 		case LUA_TUPVAL:
-			unserializeUpValue(info, index);
+			unpersistUpValue(info, index);
 			break;
 		case LUA_TUSERDATA:
-			unserializeUserData(info, index);
+			unpersistUserData(info, index);
 			break;
 		case PERMANENT_TYPE:
-			unserializePermanent(info, index);
+			unpersistPermanent(info, index);
 			break;
 		default:
 			assert(0);
@@ -212,7 +212,7 @@ static void unserialize(UnSerializationInfo *info) {
 	// >>>>> permTbl indexTbl ...... obj/nil
 }
 
-static void unserializeBoolean(UnSerializationInfo *info) {
+static void unpersistBoolean(UnSerializationInfo *info) {
 	// >>>>> permTbl indexTbl ......
 
 	// Make sure there is enough room on the stack
@@ -224,7 +224,7 @@ static void unserializeBoolean(UnSerializationInfo *info) {
 	// >>>>> permTbl indexTbl ...... bool
 }
 
-static void unserializeNumber(UnSerializationInfo *info) {
+static void unpersistNumber(UnSerializationInfo *info) {
 	// >>>>> permTbl indexTbl ......
 
 	// Make sure there is enough room on the stack
@@ -242,7 +242,7 @@ static void unserializeNumber(UnSerializationInfo *info) {
 	// >>>>> permTbl indexTbl ...... num
 }
 
-static void unserializeString(UnSerializationInfo *info) {
+static void unpersistString(UnSerializationInfo *info) {
 	// >>>>> permTbl indexTbl ......
 
 	// Make sure there is enough room on the stack
@@ -265,7 +265,7 @@ static void unserializeSpecialTable(UnSerializationInfo *info, int index) {
 	// Make sure there is enough room on the stack
 	lua_checkstack(info->luaState, 1);
 
-	unserialize(info);
+	unpersist(info);
 
 	// >>>>> permTbl indexTbl ...... spfunc
 	lua_call(info->luaState, 0, 1);
@@ -286,7 +286,7 @@ static void unserializeLiteralTable(UnSerializationInfo *info, int index) {
 	// >>>>> permTbl indexTbl ...... tbl
 
 	// Unserialize metatable
-	unserialize(info);
+	unpersist(info);
 	// >>>>> permTbl indexTbl ...... tbl ?metaTbl/nil?
 
 	if (lua_istable(info->luaState, -1)) {
@@ -303,7 +303,7 @@ static void unserializeLiteralTable(UnSerializationInfo *info, int index) {
 
 	while (1) {
 		// >>>>> permTbl indexTbl ...... tbl
-		unserialize(info);
+		unpersist(info);
 		// >>>>> permTbl indexTbl ...... tbl key/nil
 
 		// The table serialization is nil terminated
@@ -316,7 +316,7 @@ static void unserializeLiteralTable(UnSerializationInfo *info, int index) {
 		}
 
 		// >>>>> permTbl indexTbl ...... tbl key
-		unserialize(info);
+		unpersist(info);
 		// >>>>> permTbl indexTbl ...... tbl value
 
 		lua_rawset(info->luaState, -3);
@@ -324,7 +324,7 @@ static void unserializeLiteralTable(UnSerializationInfo *info, int index) {
 	}
 }
 
-void unserializeTable(UnSerializationInfo *info, int index) {
+void unpersistTable(UnSerializationInfo *info, int index) {
 	// >>>>> permTbl indexTbl ......
 
 	// Make sure there is enough room on the stack
@@ -341,7 +341,7 @@ void unserializeTable(UnSerializationInfo *info, int index) {
 	}
 }
 
-void unserializeFunction(UnSerializationInfo *info, int index) {
+void unpersistFunction(UnSerializationInfo *info, int index) {
 	// >>>>> permTbl indexTbl ......
 
 	// Make sure there is enough room on the stack
@@ -372,7 +372,7 @@ void unserializeFunction(UnSerializationInfo *info, int index) {
 	registerObjectInIndexTable(info, index);
 
 	// Now that it's safe, we can get the real proto
-	unserialize(info);
+	unpersist(info);
 	// >>>>> permTbl indexTbl ...... func proto
 
 	lclosure->p = gco2p(getObject(info->luaState, -1)->value.gc);
@@ -382,7 +382,7 @@ void unserializeFunction(UnSerializationInfo *info, int index) {
 
 	for (byte i = 0; i < numUpValues; ++i) {
 		// >>>>> permTbl indexTbl ...... func
-		unserialize(info);
+		unpersist(info);
 		// >>>>> permTbl indexTbl ...... func func2
 
 		unboxUpValue(info->luaState);
@@ -394,7 +394,7 @@ void unserializeFunction(UnSerializationInfo *info, int index) {
 	}
 
 	// Finally, the fenv
-	unserialize(info);
+	unpersist(info);
 
 	// >>>>> permTbl indexTbl ...... func ?fenv/nil?
 	if (!lua_isnil(info->luaState, -1)) {
@@ -410,7 +410,7 @@ void unserializeFunction(UnSerializationInfo *info, int index) {
 	// >>>>> permTbl indexTbl ...... func
 }
 
-void unserializeThread(UnSerializationInfo *info, int index) {
+void unpersistThread(UnSerializationInfo *info, int index) {
 	// >>>>> permTbl indexTbl ......
 
 	lua_State *L2;
@@ -432,7 +432,7 @@ void unserializeThread(UnSerializationInfo *info, int index) {
 	// very bottom of the stack
 	L2->top--;
 	for (uint32 i = 0; i < stackSize; ++i) {
-		unserialize(info);
+		unpersist(info);
 		// L1: permTbl indexTbl ...... thread obj*
 	}
 
@@ -492,7 +492,7 @@ void unserializeThread(UnSerializationInfo *info, int index) {
 	global_State *g = G(L2);
 
 	while (true) {
-		unserialize(info);
+		unpersist(info);
 		// >>>>> permTbl indexTbl ...... thread upVal/nil
 
 		// The list is terminated by a nil
@@ -535,7 +535,7 @@ void unserializeThread(UnSerializationInfo *info, int index) {
 	}
 }
 
-void unserializeProto(UnSerializationInfo *info, int index) {
+void unpersistProto(UnSerializationInfo *info, int index) {
 	// >>>>> permTbl indexTbl ......
 
 	// We have to be careful. The GC expects a lot out of protos. In particular, we need
@@ -564,7 +564,7 @@ void unserializeProto(UnSerializationInfo *info, int index) {
 	lua_reallocvector(info->luaState, p->k, 0, sizek, TValue);
 	for (int i = 0; i < sizek; ++i) {
 		// >>>>> permTbl indexTbl ...... proto
-		unserialize(info);
+		unpersist(info);
 		// >>>>> permTbl indexTbl ...... proto  k
 
 		setobj2s(info->luaState, &p->k[i], getObject(info->luaState, -1));
@@ -581,7 +581,7 @@ void unserializeProto(UnSerializationInfo *info, int index) {
 	lua_reallocvector(info->luaState, p->p, 0, sizep, Proto *);
 	for (int i = 0; i < sizep; ++i) {
 		// >>>>> permTbl indexTbl ...... proto
-		unserialize(info);
+		unpersist(info);
 		// >>>>> permTbl indexTbl ...... proto  subproto
 
 		p->p[i] = (Proto *)getObject(info->luaState, -1)->value.gc;
@@ -605,7 +605,7 @@ void unserializeProto(UnSerializationInfo *info, int index) {
 		lua_reallocvector(info->luaState, p->upvalues, 0, p->sizeupvalues, TString *);
 		for (int i = 0; i < p->sizeupvalues; ++i) {
 			// >>>>> permTbl indexTbl ...... proto
-			unserialize(info);
+			unpersist(info);
 			// >>>>> permTbl indexTbl ...... proto str
 
 			p->upvalues[i] = lua_newlstr(info->luaState, lua_tostring(info->luaState, -1), strlen(lua_tostring(info->luaState, -1)));
@@ -621,7 +621,7 @@ void unserializeProto(UnSerializationInfo *info, int index) {
 		lua_reallocvector(info->luaState, p->locvars, 0, p->sizelocvars, LocVar);
 		for (int i = 0; i < p->sizelocvars; ++i) {
 			// >>>>> permTbl indexTbl ...... proto
-			unserialize(info);
+			unpersist(info);
 			// >>>>> permTbl indexTbl ...... proto str
 
 			p->locvars[i].varname = lua_newlstr(info->luaState, lua_tostring(info->luaState, -1), strlen(lua_tostring(info->luaState, -1)));
@@ -635,7 +635,7 @@ void unserializeProto(UnSerializationInfo *info, int index) {
 	// >>>>> permTbl indexTbl ...... proto
 
 	// Read in source string
-	unserialize(info);
+	unpersist(info);
 	// >>>>> permTbl indexTbl ...... proto sourceStr
 
 	p->source = lua_newlstr(info->luaState, lua_tostring(info->luaState, -1), strlen(lua_tostring(info->luaState, -1)));
@@ -661,7 +661,7 @@ void unserializeProto(UnSerializationInfo *info, int index) {
 	p->maxstacksize = info->readStream->readByte();
 }
 
-void unserializeUpValue(UnSerializationInfo *info, int index) {
+void unpersistUpValue(UnSerializationInfo *info, int index) {
 	// >>>>> permTbl indexTbl ......
 	lua_checkstack(info->luaState, 2);
 
@@ -669,14 +669,14 @@ void unserializeUpValue(UnSerializationInfo *info, int index) {
 	// >>>>> permTbl indexTbl ...... func
 	registerObjectInIndexTable(info, index);
 
-	unserialize(info);
+	unpersist(info);
 	// >>>>> permTbl indexTbl ...... func obj
 
 	boxUpValue_finish(info->luaState);
 	// >>>>> permTbl indexTbl ...... func
 }
 
-void unserializeUserData(UnSerializationInfo *info, int index) {
+void unpersistUserData(UnSerializationInfo *info, int index) {
 	// >>>>> permTbl indexTbl ......
 
 	// Make sure there is enough room on the stack
@@ -684,7 +684,7 @@ void unserializeUserData(UnSerializationInfo *info, int index) {
 
 	int isspecial = info->readStream->readSint32LE();
 	if (isspecial) {
-		unserialize(info);
+		unpersist(info);
 		// >>>>> permTbl indexTbl ...... specialFunc
 
 		lua_call(info->luaState, 0, 1);
@@ -697,7 +697,7 @@ void unserializeUserData(UnSerializationInfo *info, int index) {
 
 		info->readStream->read(lua_touserdata(info->luaState, -1), length);
 
-		unserialize(info);
+		unpersist(info);
 		// >>>>> permTbl indexTbl ...... udata metaTable/nil
 
 		lua_setmetatable(info->luaState, -2);
@@ -706,13 +706,13 @@ void unserializeUserData(UnSerializationInfo *info, int index) {
 	// >>>>> permTbl indexTbl ...... udata
 }
 
-void unserializePermanent(UnSerializationInfo *info, int index) {
+void unpersistPermanent(UnSerializationInfo *info, int index) {
 	// >>>>> permTbl indexTbl ......
 
 	// Make sure there is enough room on the stack
 	lua_checkstack(info->luaState, 2);
 
-	unserialize(info);
+	unpersist(info);
 	// >>>>> permTbl indexTbl ...... permKey
 
 	lua_gettable(info->luaState, 1);


Commit: e4f74b6c346023608841d9f871b16069e5b54194
    https://github.com/scummvm/scummvm/commit/e4f74b6c346023608841d9f871b16069e5b54194
Author: RichieSams (adastley at gmail.com)
Date: 2014-12-30T18:28:14-06:00

Commit Message:
SWORD25: Remove the option to persist a double as a string

Since the current method *should* be more accurate

Changed paths:
    engines/sword25/util/lua_persist.cpp



diff --git a/engines/sword25/util/lua_persist.cpp b/engines/sword25/util/lua_persist.cpp
index 6038111..6fe88fe 100644
--- a/engines/sword25/util/lua_persist.cpp
+++ b/engines/sword25/util/lua_persist.cpp
@@ -281,21 +281,11 @@ static void persistBoolean(SerializationInfo *info) {
 static void persistNumber(SerializationInfo *info) {
 	lua_Number value = lua_tonumber(info->luaState, -1);
 
-	#if 1
-		Util::SerializedDouble serializedValue(Util::encodeDouble(value));
-
-		info->writeStream->writeUint32LE(serializedValue.significandOne);
-		info->writeStream->writeUint32LE(serializedValue.signAndSignificandTwo);
-		info->writeStream->writeSint16LE(serializedValue.exponent);
-	#else
-		// NOTE: We need to store a double. Unfortunately, we have to accommodate endianness.
-		// Also, I don't know if we can assume all compilers use IEEE double
-		// Therefore, I have chosen to store the double as a string.
-		Common::String buffer = Common::String::format("%f", value);
-
-		info->writeStream->write(buffer.c_str(), buffer.size());
-	#endif
+	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) {


Commit: 2587852c88e2fbc52bf702f71738e80628eb43fe
    https://github.com/scummvm/scummvm/commit/2587852c88e2fbc52bf702f71738e80628eb43fe
Author: Eugene Sandulenko (sev at scummvm.org)
Date: 2015-01-04T19:47:17+01:00

Commit Message:
Merge pull request #557 from RichieSams/replace_pluto

SWORD25: Replace 'Pluto' lua persistance code with re-written, platform-agnostic code

Changed paths:
  A engines/sword25/util/double_serialization.cpp
  A engines/sword25/util/double_serialization.h
  A engines/sword25/util/lua_persist.cpp
  A engines/sword25/util/lua_persistence.h
  A engines/sword25/util/lua_persistence_util.cpp
  A engines/sword25/util/lua_persistence_util.h
  A engines/sword25/util/lua_unpersist.cpp
  R engines/sword25/util/pluto/CHANGELOG
  R engines/sword25/util/pluto/FILEFORMAT
  R engines/sword25/util/pluto/README
  R engines/sword25/util/pluto/THANKS
  R engines/sword25/util/pluto/pdep.cpp
  R engines/sword25/util/pluto/pdep/README
  R engines/sword25/util/pluto/pdep/lzio.h
  R engines/sword25/util/pluto/pdep/pdep.h
  R engines/sword25/util/pluto/pluto.cpp
  R engines/sword25/util/pluto/pluto.h
  R engines/sword25/util/pluto/plzio.cpp
    engines/sword25/kernel/outputpersistenceblock.cpp
    engines/sword25/kernel/outputpersistenceblock.h
    engines/sword25/module.mk
    engines/sword25/script/luascript.cpp









More information about the Scummvm-git-logs mailing list