scummvm/engine/lua/lrestore.cpp
2008-08-03 13:02:45 +00:00

583 lines
17 KiB
C++

#include "common/endian.h"
#include "common/debug.h"
#include "engine/engine.h"
#include "engine/savegame.h"
#include "engine/lua/ltask.h"
#include "engine/lua/lauxlib.h"
#include "engine/lua/lmem.h"
#include "engine/lua/ldo.h"
#include "engine/lua/ltm.h"
#include "engine/lua/ltable.h"
#include "engine/lua/lvm.h"
#include "engine/lua/lopcodes.h"
#include "engine/lua/lstring.h"
#include "engine/lua/lua.h"
RestoreCallback restoreCallbackPtr = NULL;
static void restoreObjectValue(TObject *object, RestoreSint32 restoreSint32, RestoreUint32 restoreUint32) {
object->ttype = (lua_Type)restoreSint32();
switch (object->ttype) {
case LUA_T_NUMBER:
case LUA_T_TASK:
{
byte *udata = (byte *)(&object->value.n);
uint32 v = restoreUint32();
restoreUint32();
#if defined(SYSTEM_LITTLE_ENDIAN)
byte b[4];
*(uint32 *)&b = v;
udata[0] = b[3];
udata[1] = b[2];
udata[2] = b[1];
udata[3] = b[0];
#else
memcpy(&udata, &v, 4);
#endif
}
break;
case LUA_T_NIL:
{
restoreUint32();
restoreUint32();
object->value.ts = NULL;
}
break;
case LUA_T_ARRAY:
{
PointerId ptr;
ptr.low = restoreUint32();
ptr.hi = restoreUint32();
object->value.a = (Hash *)makePointerFromId(ptr);
}
break;
case LUA_T_USERDATA:
case LUA_T_STRING:
{
PointerId ptr;
ptr.low = restoreUint32();
ptr.hi = restoreUint32();
object->value.ts = (TaggedString *)makePointerFromId(ptr);
}
break;
case LUA_T_PROTO:
case LUA_T_PMARK:
{
PointerId ptr;
ptr.low = restoreUint32();
ptr.hi = restoreUint32();
object->value.tf = (TProtoFunc *)makePointerFromId(ptr);
}
break;
case LUA_T_CPROTO:
case LUA_T_CMARK:
{
PointerId ptr;
ptr.low = restoreUint32();
ptr.hi = restoreUint32();
object->value.f = (lua_CFunction)makePointerFromId(ptr);
}
break;
case LUA_T_CLOSURE:
case LUA_T_CLMARK:
{
PointerId ptr;
ptr.low = restoreUint32();
ptr.hi = restoreUint32();
object->value.cl = (Closure *)makePointerFromId(ptr);
}
break;
case LUA_T_LINE:
{
object->value.i = restoreSint32();
restoreSint32();
}
break;
default:
if (object->ttype == MKID_BE('ACTR') || object->ttype == MKID_BE('COLR') || object->ttype == MKID_BE('STAT') || object->ttype == MKID_BE('FONT')
|| object->ttype == MKID_BE('VBUF') || object->ttype == MKID_BE('PRIM') || object->ttype == MKID_BE('TEXT')) {
PointerId ptr;
ptr.low = restoreUint32();
ptr.hi = restoreUint32();
object->value.ts = (TaggedString *)makePointerFromId(ptr);
} else {
error("restoreObjectValue: Unsupported object type");
}
}
}
struct ArrayIDObj {
void *object;
PointerId idObj;
};
static int sortCallback(const void *id1, const void *id2) {
#ifdef TARGET_64BITS
uint64 p1 = ((ArrayIDObj *)id1)->idObj.low | ((uint64)(((ArrayIDObj *)id1)->idObj.hi)) << 32;
uint64 p2 = ((ArrayIDObj *)id2)->idObj.low | ((uint64)(((ArrayIDObj *)id2)->idObj.hi)) << 32;
if (p1 > p2) {
return 1;
} else if (p1 < p2) {
return -1;
} else {
return 0;
}
#else
if (((ArrayIDObj *)id1)->idObj.low > ((ArrayIDObj *)id2)->idObj.low) {
return 1;
} else if (((ArrayIDObj *)id1)->idObj.low < ((ArrayIDObj *)id2)->idObj.low) {
return -1;
} else {
return 0;
}
#endif
}
int32 arrayHashTablesCount = 0;
int32 arrayProtoFuncsCount = 0;
int32 arrayClosuresCount = 0;
int32 arrayStringsCount = 0;
ArrayIDObj *arrayStrings = NULL;
ArrayIDObj *arrayHashTables = NULL;
ArrayIDObj *arrayClosures = NULL;
ArrayIDObj *arrayProtoFuncs = NULL;
static bool arraysAllreadySort = false;
static void recreateObj(TObject *obj) {
if (obj->ttype == LUA_T_CPROTO) {
#ifdef TARGET_64BITS
uint64 id = ((uint64)(obj->value.f)) >> 16;
#else
uint32 id = ((uint32)(obj->value.f)) >> 16;
#endif
luaL_libList *list = list_of_libs;
while (list) {
if (id == 0)
break;
id--;
list = list->next;
}
#ifdef TARGET_64BITS
int32 numberFunc = (uint64)(obj->value.f) & 0xffff;
#else
int32 numberFunc = (uint32)(obj->value.f) & 0xffff;
#endif
if (list && id == 0 && numberFunc < list->number) {
obj->value.f = list->list[numberFunc].func;
} else {
obj->value.f = NULL;
assert(obj->value.f);
}
} else if (obj->ttype == LUA_T_NIL || obj->ttype == LUA_T_LINE || obj->ttype == LUA_T_NUMBER) {
return;
} else {
if (obj->value.i == 0)
return;
if (!arraysAllreadySort) {
arraysAllreadySort = true;
qsort(arrayHashTables, arrayHashTablesCount, sizeof(ArrayIDObj), sortCallback);
qsort(arrayProtoFuncs, arrayProtoFuncsCount, sizeof(ArrayIDObj), sortCallback);
qsort(arrayClosures, arrayClosuresCount, sizeof(ArrayIDObj), sortCallback);
qsort(arrayStrings, arrayStringsCount, sizeof(ArrayIDObj), sortCallback);
}
ArrayIDObj *found;
ArrayIDObj tmpId;
tmpId.object = NULL;
switch (obj->ttype) {
case LUA_T_PMARK:
tmpId.idObj = makeIdFromPointer(obj->value.tf);
found = (ArrayIDObj *)bsearch(&tmpId, arrayProtoFuncs, arrayProtoFuncsCount, sizeof(ArrayIDObj), sortCallback);
assert(found);
obj->value.tf = (TProtoFunc *)found->object;
break;
case LUA_T_USERDATA:
tmpId.idObj = makeIdFromPointer(obj->value.ts);
found = (ArrayIDObj *)bsearch(&tmpId, arrayStrings, arrayStringsCount, sizeof(ArrayIDObj), sortCallback);
assert(found);
obj->value.ts = (TaggedString *)found->object;
break;
case LUA_T_PROTO:
tmpId.idObj = makeIdFromPointer(obj->value.tf);
found = (ArrayIDObj *)bsearch(&tmpId, arrayProtoFuncs, arrayProtoFuncsCount, sizeof(ArrayIDObj), sortCallback);
assert(found);
obj->value.tf = (TProtoFunc *)found->object;
break;
case LUA_T_CLOSURE:
tmpId.idObj = makeIdFromPointer(obj->value.cl);
found = (ArrayIDObj *)bsearch(&tmpId, arrayClosures, arrayClosuresCount, sizeof(ArrayIDObj), sortCallback);
assert(found);
obj->value.cl = (Closure *)found->object;
break;
case LUA_T_ARRAY:
tmpId.idObj = makeIdFromPointer(obj->value.a);
found = (ArrayIDObj *)bsearch(&tmpId, arrayHashTables, arrayHashTablesCount, sizeof(ArrayIDObj), sortCallback);
assert(found);
obj->value.a = (Hash *)found->object;
break;
case LUA_T_STRING:
tmpId.idObj = makeIdFromPointer(obj->value.ts);
found = (ArrayIDObj *)bsearch(&tmpId, arrayStrings, arrayStringsCount, sizeof(ArrayIDObj), sortCallback);
assert(found);
obj->value.ts = (TaggedString *)found->object;
break;
default:
obj->value.i = 0;
obj->value.ts = 0;
return;
}
}
}
void lua_Restore(RestoreStream restoreStream, RestoreSint32 restoreSint32, RestoreUint32 restoreUint32) {
printf("lua_Restore() started.\n");
lua_close();
L = luaM_new(lua_State);
lua_resetglobals();
arrayStringsCount = restoreSint32();
arrayClosuresCount = restoreSint32();
arrayHashTablesCount = restoreSint32();
arrayProtoFuncsCount = restoreSint32();
int32 rootGlobalCount = restoreSint32();
arrayStrings = (ArrayIDObj *)luaM_malloc(sizeof(ArrayIDObj) * arrayStringsCount);
ArrayIDObj *arraysObj = arrayStrings;
int32 maxStringsLength;
maxStringsLength = restoreSint32();
char *tempStringBuffer = (char *)luaM_malloc(maxStringsLength);
//printf("1: %d\n", g_engine->_savedState->getBufferPos());
int32 i;
for (i = 0; i < arrayStringsCount; i++) {
arraysObj->idObj.low = restoreSint32();
arraysObj->idObj.hi = restoreSint32();
int32 constIndex = restoreSint32();
TaggedString *tempString;
if (constIndex != -1) {
TObject obj;
restoreObjectValue(&obj, restoreSint32, restoreUint32);
int32 length = restoreSint32();
restoreStream(tempStringBuffer, length);
tempString = luaS_newlstr(tempStringBuffer, length);
tempString->u.s.globalval = obj;
} else {
PointerId ptr;
lua_Type tag = (lua_Type)restoreSint32();
ptr.low = restoreUint32();
ptr.hi = restoreUint32();
if (tag == 0)
tempString = luaS_createudata((void *)makePointerFromId(ptr), LUA_ANYTAG);
else
tempString = luaS_createudata((void *)makePointerFromId(ptr), tag);
if (restoreCallbackPtr) {
PointerId ptr = makeIdFromPointer(tempString->u.d.v);
ptr = restoreCallbackPtr(tempString->u.d.tag, ptr, restoreSint32);
tempString->u.d.v = makePointerFromId(ptr);
}
}
tempString->constindex = constIndex;
arraysObj->object = tempString;
arraysObj++;
}
luaM_free(tempStringBuffer);
//printf("2: %d\n", g_engine->_savedState->getBufferPos());
int32 l;
Closure *tempClosure;
arraysObj = (ArrayIDObj *)luaM_malloc(sizeof(ArrayIDObj) * arrayClosuresCount);
arrayClosures = arraysObj;
for (i = 0; i < arrayClosuresCount; i++) {
arraysObj->idObj.low = restoreSint32();
arraysObj->idObj.hi = restoreSint32();
int32 countElements = restoreSint32();
tempClosure = (Closure *)luaM_malloc((countElements * sizeof(TObject)) + sizeof(Closure));
luaO_insertlist(&L->rootcl, (GCnode *)tempClosure);
tempClosure->nelems = countElements;
for (l = 0; l <= tempClosure->nelems; l++) {
restoreObjectValue(&tempClosure->consts[l], restoreSint32, restoreUint32);
}
arraysObj->object = tempClosure;
arraysObj++;
}
Hash *tempHash;
arraysObj = (ArrayIDObj *)luaM_malloc(sizeof(ArrayIDObj) * arrayHashTablesCount);
arrayHashTables = arraysObj;
for (i = 0; i < arrayHashTablesCount; i++) {
arraysObj->idObj.low = restoreSint32();
arraysObj->idObj.hi = restoreSint32();
tempHash = luaM_new(Hash);
tempHash->nhash = restoreSint32();
tempHash->nuse = restoreSint32();
tempHash->htag = restoreSint32();
tempHash->node = hashnodecreate(tempHash->nhash);
luaO_insertlist(&L->roottable, (GCnode *)tempHash);
for (l = 0; l < tempHash->nuse; l++) {
restoreObjectValue(&tempHash->node[l].ref, restoreSint32, restoreUint32);
restoreObjectValue(&tempHash->node[l].val, restoreSint32, restoreUint32);
}
arraysObj->object = tempHash;
arraysObj++;
}
TProtoFunc *tempProtoFunc;
arrayProtoFuncs = (ArrayIDObj *)luaM_malloc(sizeof(ArrayIDObj) * arrayProtoFuncsCount);
arraysObj = arrayProtoFuncs;
for (i = 0; i < arrayProtoFuncsCount; i++) {
arraysObj->idObj.low = restoreSint32();
arraysObj->idObj.hi = restoreSint32();
tempProtoFunc = luaM_new(TProtoFunc);
luaO_insertlist(&L->rootproto, (GCnode *)tempProtoFunc);
PointerId ptr;
ptr.low = restoreSint32();
ptr.hi = restoreSint32();
tempProtoFunc->fileName = (TaggedString *)makePointerFromId(ptr);
tempProtoFunc->lineDefined = restoreSint32();
tempProtoFunc->nconsts = restoreSint32();
tempProtoFunc->consts = (TObject *)luaM_malloc(tempProtoFunc->nconsts * sizeof(TObject));
for (l = 0; l < tempProtoFunc->nconsts; l++) {
restoreObjectValue(&tempProtoFunc->consts[l], restoreSint32, restoreUint32);
}
int32 countVariables = restoreSint32();
if (countVariables) {
tempProtoFunc->locvars = (LocVar *)luaM_malloc(countVariables * sizeof(LocVar));
} else {
tempProtoFunc->locvars = NULL;
}
for (l = 0; l < countVariables; l++) {
PointerId ptr;
ptr.low = restoreSint32();
ptr.hi = restoreSint32();
tempProtoFunc->locvars[l].varname = (TaggedString *)makePointerFromId(ptr);
tempProtoFunc->locvars[l].line = restoreSint32();
}
int32 codeSize = restoreSint32();
tempProtoFunc->code = (byte *)luaM_malloc(codeSize);
restoreStream(tempProtoFunc->code, codeSize);
arraysObj->object = tempProtoFunc;
arraysObj++;
}
for (i = 0; i < NUM_HASHS; i++) {
stringtable *tempStringTable = &L->string_root[i];
for (l = 0; l < tempStringTable->size; l++) {
TaggedString *tempString = tempStringTable->hash[l];
if (tempString && tempString->constindex != -1 && tempString != &EMPTY) {
recreateObj(&tempString->u.s.globalval);
}
}
}
tempProtoFunc = (TProtoFunc *)L->rootproto.next;
while (tempProtoFunc) {
TObject tempObj;
tempObj.value.ts = (TaggedString *)tempProtoFunc->fileName;
tempObj.ttype = LUA_T_STRING;
recreateObj(&tempObj);
tempProtoFunc->fileName = (TaggedString *)tempObj.value.ts;
for (i = 0; i < tempProtoFunc->nconsts; i++) {
recreateObj(&tempProtoFunc->consts[i]);
}
if (tempProtoFunc->locvars) {
i = 0;
for (i = 0; tempProtoFunc->locvars[i].line != -1; i++) {
TObject tempObj2;
tempObj2.value.ts = tempProtoFunc->locvars[i].varname;
tempObj2.ttype = LUA_T_STRING;
recreateObj(&tempObj2);
tempProtoFunc->locvars[i].varname = (TaggedString *)tempObj2.value.ts;
}
}
tempProtoFunc = (TProtoFunc *)tempProtoFunc->head.next;
}
tempHash = (Hash *)L->roottable.next;
while (tempHash) {
for (i = 0; i < tempHash->nuse; i++) {
recreateObj(&tempHash->node[i].ref);
recreateObj(&tempHash->node[i].val);
}
Node *oldNode = tempHash->node;
tempHash->node = hashnodecreate(tempHash->nhash);
for (i = 0; i < tempHash->nuse; i++) {
Node *newNode = oldNode + i;
if (newNode->ref.ttype != LUA_T_NIL && newNode->val.ttype != LUA_T_NIL) {
*node(tempHash, present(tempHash, &newNode->ref)) = *newNode;
}
}
luaM_free(oldNode);
tempHash = (Hash *)tempHash->head.next;
}
tempClosure = (Closure *)L->rootcl.next;
while (tempClosure) {
for (i = 0; i <= tempClosure->nelems; i++) {
recreateObj(&tempClosure->consts[i]);
}
tempClosure = (Closure *)tempClosure->head.next;
}
TaggedString *tempListString = (TaggedString *)&(L->rootglobal);
for (i = 0; i < rootGlobalCount; i++) {
TObject tempObj;
TaggedString *tempString = NULL;
tempObj.ttype = LUA_T_STRING;
PointerId ptr;
ptr.low = restoreSint32();
ptr.hi = restoreSint32();
tempObj.value.ts = (TaggedString *)makePointerFromId(ptr);
recreateObj(&tempObj);
tempString = (TaggedString *)tempObj.value.ts;
assert(tempString);
tempListString->head.next = (GCnode *)tempString;
tempListString = tempString;
}
tempListString->head.next = NULL;
restoreObjectValue(&L->errorim, restoreSint32, restoreUint32);
recreateObj(&L->errorim);
L->IMtable_size = restoreSint32();
L->IMtable = (IM *)luaM_malloc(L->IMtable_size * sizeof(IM));
for (i = 0; i < L->IMtable_size; i++) {
IM *im = &L->IMtable[i];
for (l = 0; l < IM_N; l++) {
restoreObjectValue(&im->int_method[l], restoreSint32, restoreUint32);
recreateObj(&im->int_method[l]);
}
}
L->last_tag = restoreSint32();
L->refSize = restoreSint32();
L->refArray = (ref *)luaM_malloc(L->refSize * sizeof(ref));
for (i = 0; i < L->refSize; i++) {
restoreObjectValue(&L->refArray[i].o, restoreSint32, restoreUint32);
recreateObj(&L->refArray[i].o);
L->refArray[i].status = (Status)restoreSint32();
}
L->GCthreshold = restoreSint32();
L->nblocks = restoreSint32();
L->Mbuffsize = restoreSint32();
L->Mbuffer = (char *)luaM_malloc(L->Mbuffsize);
restoreStream(L->Mbuffer, L->Mbuffsize);
int32 MbaseOffset;
MbaseOffset = restoreSint32();
L->Mbuffbase = MbaseOffset + L->Mbuffer;
L->Mbuffnext = restoreSint32();
globalTaskSerialId = restoreSint32();
lua_Task *tempTask = NULL;
lua_Task *prevTask = L->root_task;
int32 countTasks = restoreSint32();
for (l = 0; l < countTasks; l++) {
tempTask = luaM_new(lua_Task);
memset(tempTask, 0, sizeof(lua_Task));
prevTask->next = tempTask;
prevTask = tempTask;
int32 stackLastSize = restoreSint32();
tempTask->stack.stack = (TObject *)luaM_malloc(stackLastSize * sizeof(TObject));
tempTask->stack.last = tempTask->stack.stack + stackLastSize - 1;
int32 stackTopSize = restoreSint32();
tempTask->stack.top = tempTask->stack.stack + stackTopSize;
for (i = 0; i < stackTopSize; i++) {
restoreObjectValue(&tempTask->stack.stack[i], restoreSint32, restoreUint32);
recreateObj(&tempTask->stack.stack[i]);
}
tempTask->Cstack.base = restoreSint32();
tempTask->Cstack.lua2C = restoreSint32();
tempTask->Cstack.num = restoreSint32();
tempTask->numCblocks = restoreSint32();
for (i = 0; i < tempTask->numCblocks; i++) {
tempTask->Cblocks[i].base = restoreSint32();
tempTask->Cblocks[i].lua2C = restoreSint32();
tempTask->Cblocks[i].num = restoreSint32();
}
int32 pcOffset, taskCi;
tempTask->base_ci_size = restoreSint32();
tempTask->base_ci = (CallInfo *)luaM_malloc(tempTask->base_ci_size * sizeof(CallInfo));
memset(tempTask->base_ci, 0, sizeof(CallInfo) * tempTask->base_ci_size);
CallInfo *tempCi = tempTask->base_ci;
int32 countCi = tempTask->base_ci_size / sizeof(CallInfo);
for (i = 0; i < countCi; i++) {
TObject tempObj;
tempObj.ttype = LUA_T_CLOSURE;
PointerId ptr;
ptr.low = restoreUint32();
ptr.hi = restoreUint32();
tempObj.value.cl = (Closure *)makePointerFromId(ptr);
recreateObj(&tempObj);
tempCi->c = (Closure *)tempObj.value.cl;
tempObj.ttype = LUA_T_PROTO;
ptr.low = restoreUint32();
ptr.hi = restoreUint32();
tempObj.value.tf = (TProtoFunc *)makePointerFromId(ptr);
recreateObj(&tempObj);
tempCi->tf = (TProtoFunc *)tempObj.value.tf;
pcOffset = restoreSint32();
if (pcOffset)
tempCi->pc = tempCi->tf->code + pcOffset;
else
tempCi->pc = NULL;
tempCi->base = restoreSint32();
tempCi->nResults = restoreSint32();
tempCi++;
}
taskCi = restoreSint32();
tempTask->ci = tempTask->base_ci + taskCi;
tempTask->end_ci = tempTask->base_ci + countCi;
int32 Mbasepos = restoreSint32();
tempTask->Mbuffbase = Mbasepos + tempTask->Mbuffer;
tempTask->Mbuffnext = restoreSint32();
tempTask->Tstate = (TaskState)restoreSint32();
tempTask->id = restoreSint32();
}
L->last_task = tempTask;
arraysAllreadySort = false;
arrayStringsCount = 0;
arrayHashTablesCount = 0;
arrayClosuresCount = 0;
arrayProtoFuncsCount = 0;
luaM_free(arrayClosures);
luaM_free(arrayStrings);
luaM_free(arrayHashTables);
luaM_free(arrayProtoFuncs);
arrayHashTables = NULL;
arrayClosures = NULL;
arrayProtoFuncs = NULL;
arrayStrings = NULL;
printf("lua_Restore() finished.\n");
}