scummvm/lua/lrestore.cpp

445 lines
14 KiB
C++

#include <stdlib.h>
#include <stdio.h>
#include <search.h>
#include <assert.h>
#include "ltask.h"
#include "lauxlib.h"
#include "lmem.h"
#include "ldo.h"
#include "ltm.h"
#include "ltable.h"
#include "lvm.h"
#include "lopcodes.h"
#include "lstring.h"
#include "lua.h"
SaveRestoreCallback restoreCallback = NULL;
struct ArrayIDObj {
void *object;
unsigned int idObj;
};
static int sortCallback(const void *id1, const void *id2) {
if (((ArrayIDObj *)id1)->idObj > ((ArrayIDObj *)id2)->idObj) {
return 1;
} else if (((ArrayIDObj *)id1)->idObj < ((ArrayIDObj *)id2)->idObj) {
return -1;
} else {
return 0;
}
}
int arrayHashTablesCount = 0;
int arrayProtoFuncsCount = 0;
int arrayClosuresCount = 0;
int 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) {
int some = ((int)(obj->value.f)) >> 16;
luaL_libList *list = list_of_libs;
while (list != NULL) {
if (some == 0)
break;
some--;
list = list->next;
}
int numberFunc = (int)(obj->value.f) & 0xffff;
if ((list != NULL) && (some == 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.idObj = obj->value.i;
tmpId.object = NULL;
obj->value.i = 0;
switch (obj->ttype) {
case LUA_T_PMARK:
found = (ArrayIDObj *)bsearch(&tmpId, arrayProtoFuncs, arrayProtoFuncsCount, sizeof(ArrayIDObj), sortCallback);
break;
case LUA_T_USERDATA:
found = (ArrayIDObj *)bsearch(&tmpId, arrayStrings, arrayStringsCount, sizeof(ArrayIDObj), sortCallback);
break;
case LUA_T_PROTO:
found = (ArrayIDObj *)bsearch(&tmpId, arrayProtoFuncs, arrayProtoFuncsCount, sizeof(ArrayIDObj), sortCallback);
break;
case LUA_T_CLOSURE:
found = (ArrayIDObj *)bsearch(&tmpId, arrayClosures, arrayClosuresCount, sizeof(ArrayIDObj), sortCallback);
break;
case LUA_T_ARRAY:
found = (ArrayIDObj *)bsearch(&tmpId, arrayHashTables, arrayHashTablesCount, sizeof(ArrayIDObj), sortCallback);
break;
case LUA_T_STRING:
found = (ArrayIDObj *)bsearch(&tmpId, arrayStrings, arrayStringsCount, sizeof(ArrayIDObj), sortCallback);
break;
default:
return;
}
obj->value.i = (unsigned int)found->object;
}
}
void lua_Restore(SaveRestoreFunc restoreFunc) {
printf("lua_Restore() start.\n");
lua_close();
L = luaM_new(lua_State);
lua_resetglobals();
restoreFunc(&arrayStringsCount, sizeof(int));
restoreFunc(&arrayClosuresCount, sizeof(int));
restoreFunc(&arrayHashTablesCount, sizeof(int));
restoreFunc(&arrayProtoFuncsCount, sizeof(int));
int rootGlobalCount;
restoreFunc(&rootGlobalCount, sizeof(int));
arrayStrings = (ArrayIDObj *)luaM_malloc(sizeof(ArrayIDObj) * arrayStringsCount);
ArrayIDObj *arraysObj = arrayStrings;
int maxStringsLength;
restoreFunc(&maxStringsLength, sizeof(int));
char *tempStringBuffer = (char *)luaM_malloc(maxStringsLength);
int i;
for (i = 0; i < arrayStringsCount; i++) {
restoreFunc(&arraysObj->idObj, sizeof(unsigned int));
int constIndex;
restoreFunc(&constIndex, sizeof(int));
lua_Type tag;
restoreFunc(&tag, sizeof(int));
void *value;
restoreFunc(&value, sizeof(void *));
TaggedString *tempString;
if (constIndex != -1) {
long length;
restoreFunc(&length, sizeof(long));
restoreFunc(tempStringBuffer, length);
tempString = luaS_newlstr(tempStringBuffer, length);
tempString->u.s.globalval.ttype = tag;
tempString->u.s.globalval.value.ts = (TaggedString *)value;
} else {
if (tag == 0)
tempString = luaS_createudata(value, LUA_ANYTAG);
else
tempString = luaS_createudata(value, tag);
if (restoreCallback != NULL) {
tempString->u.s.globalval.value.ts = (TaggedString *)restoreCallback(tempString->u.s.globalval.ttype, (int)tempString->u.s.globalval.value.ts, restoreFunc);
}
}
tempString->constindex = constIndex;
arraysObj->object = tempString;
arraysObj++;
}
luaM_free(tempStringBuffer);
int l;
Closure *tempClosure;
arraysObj = (ArrayIDObj *)luaM_malloc(sizeof(ArrayIDObj) * arrayClosuresCount);
arrayClosures = arraysObj;
for (i = 0; i < arrayClosuresCount; i++) {
restoreFunc(&arraysObj->idObj, sizeof(unsigned int));
int countElements;
restoreFunc(&countElements, sizeof(int));
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++) {
restoreFunc(&tempClosure->consts[l].ttype, sizeof(lua_Type));
restoreFunc(&tempClosure->consts[l].value, sizeof(Value));
}
arraysObj->object = tempClosure;
arraysObj++;
}
Hash *tempHash;
arraysObj = (ArrayIDObj *)luaM_malloc(sizeof(ArrayIDObj) * arrayHashTablesCount);
arrayHashTables = arraysObj;
for (i = 0; i < arrayHashTablesCount; i++) {
restoreFunc(&arraysObj->idObj, sizeof(unsigned int));
tempHash = luaM_new(Hash);
restoreFunc(&tempHash->nhash, sizeof(int));
restoreFunc(&tempHash->nuse, sizeof(int));
restoreFunc(&tempHash->htag, sizeof(int));
tempHash->node = hashnodecreate(tempHash->nhash);
luaO_insertlist(&L->roottable, (GCnode *)tempHash);
for (l = 0; l < tempHash->nuse; l++) {
restoreFunc(&tempHash->node[l].ref.ttype, sizeof(lua_Type));
restoreFunc(&tempHash->node[l].ref.value, sizeof(Value));
restoreFunc(&tempHash->node[l].val.ttype, sizeof(lua_Type));
restoreFunc(&tempHash->node[l].val.value, sizeof(Value));
}
arraysObj->object = tempHash;
arraysObj++;
}
TProtoFunc *tempProtoFunc;
arrayProtoFuncs = (ArrayIDObj *)luaM_malloc(sizeof(ArrayIDObj) * arrayProtoFuncsCount);
arraysObj = arrayProtoFuncs;
for (i = 0; i < arrayProtoFuncsCount; i++) {
restoreFunc(&arraysObj->idObj, sizeof(unsigned int));
tempProtoFunc = luaM_new(TProtoFunc);
luaO_insertlist(&L->rootproto, (GCnode *)tempProtoFunc);
restoreFunc(&tempProtoFunc->fileName, sizeof(TaggedString *));
restoreFunc(&tempProtoFunc->lineDefined, sizeof(int));
restoreFunc(&tempProtoFunc->nconsts, sizeof(int));
tempProtoFunc->consts = (TObject *)luaM_malloc(tempProtoFunc->nconsts * sizeof(TObject));
for (l = 0; l < tempProtoFunc->nconsts; l++) {
restoreFunc(&tempProtoFunc->consts[l].ttype, sizeof(lua_Type));
restoreFunc(&tempProtoFunc->consts[l].value, sizeof(Value));
}
int countVariables;
restoreFunc(&countVariables, sizeof(int));
if (countVariables != 0) {
tempProtoFunc->locvars = (LocVar *)luaM_malloc(countVariables * sizeof(LocVar));
} else {
tempProtoFunc->locvars = NULL;
}
for (l = 0; l < countVariables; l++) {
restoreFunc(&tempProtoFunc->locvars[l].varname, sizeof(TaggedString *));
restoreFunc(&tempProtoFunc->locvars[l].line, sizeof(int));
}
int codeSize;
restoreFunc(&codeSize, sizeof(int));
tempProtoFunc->code = (lua_Byte *)luaM_malloc(codeSize);
restoreFunc(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 != NULL) && (tempString->constindex != -1) && (tempString != &EMPTY)) {
recreateObj(&tempString->u.s.globalval);
}
}
}
tempProtoFunc = (TProtoFunc *)L->rootproto.next;
while (tempProtoFunc != NULL) {
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 != NULL) {
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->val.ttype != LUA_T_NIL) && (newNode->ref.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 != NULL) {
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;
restoreFunc(&tempObj.value, sizeof(TaggedString *));
recreateObj(&tempObj);
tempString = (TaggedString *)tempObj.value.ts;
assert(tempString);
tempListString->head.next = (GCnode *)tempString;
tempListString = tempString;
}
tempListString->head.next = NULL;
restoreFunc(&L->errorim.ttype, sizeof(lua_Type));
restoreFunc(&L->errorim.value, sizeof(Value));
recreateObj(&L->errorim);
restoreFunc(&L->IMtable_size, sizeof(int));
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++) {
restoreFunc(&im->int_method[l].ttype, sizeof(lua_Type));
restoreFunc(&im->int_method[l].value, sizeof(Value));
recreateObj(&im->int_method[l]);
}
}
restoreFunc(&L->last_tag, sizeof(int));
restoreFunc(&L->refSize, sizeof(int));
L->refArray = (ref *)luaM_malloc(L->refSize * sizeof(ref));
for (i = 0; i < L->refSize; i++) {
restoreFunc(&L->refArray[i].o.ttype, sizeof(lua_Type));
restoreFunc(&L->refArray[i].o.value, sizeof(Value));
recreateObj(&L->refArray[i].o);
restoreFunc(&L->refArray[i].status, sizeof(Status));
}
restoreFunc(&L->GCthreshold, sizeof(unsigned long));
restoreFunc(&L->nblocks, sizeof(unsigned long));
restoreFunc(&L->Mbuffsize, sizeof(int));
L->Mbuffer = (char *)luaM_malloc(L->Mbuffsize);
restoreFunc(L->Mbuffer, L->Mbuffsize);
int MbaseOffset;
restoreFunc(&MbaseOffset, sizeof(int));
L->Mbuffbase = MbaseOffset + L->Mbuffer;
restoreFunc(&L->Mbuffnext, sizeof(int));
int countTasks;
lua_Task *tempTask = NULL;
restoreFunc(&countTasks, sizeof(int));
lua_Task *prevTask = L->root_task;
for (l = 0; l < countTasks; l++) {
tempTask = luaM_new(lua_Task);
memset(tempTask, 0, sizeof(lua_Task));
prevTask->next = tempTask;
prevTask = tempTask;
int stackLastSize;
restoreFunc(&stackLastSize, sizeof(int));
tempTask->stack.stack = (TObject *)luaM_malloc(stackLastSize * sizeof(TObject));
tempTask->stack.last = tempTask->stack.stack + stackLastSize - 1;
int stackTopSize;
restoreFunc(&stackTopSize, sizeof(int));
tempTask->stack.top = tempTask->stack.stack + stackTopSize;
for (i = 0; i < stackTopSize; i++) {
restoreFunc(&tempTask->stack.stack[i].ttype, sizeof(lua_Type));
restoreFunc(&tempTask->stack.stack[i].value, sizeof(Value));
recreateObj(&tempTask->stack.stack[i]);
}
restoreFunc(&tempTask->Cstack.base, sizeof(StkId));
restoreFunc(&tempTask->Cstack.lua2C, sizeof(StkId));
restoreFunc(&tempTask->Cstack.num, sizeof(int));
restoreFunc(&tempTask->numCblocks, sizeof(int));
for (i = 0; i < tempTask->numCblocks; i++) {
restoreFunc(&tempTask->Cblocks[i].base, sizeof(StkId));
restoreFunc(&tempTask->Cblocks[i].lua2C, sizeof(StkId));
restoreFunc(&tempTask->Cblocks[i].num, sizeof(int));
}
int pcOffset, taskCi;
restoreFunc(&tempTask->base_ci_size, sizeof(int));
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;
int countCi = tempTask->base_ci_size / sizeof(CallInfo);
for (i = 0; i < countCi; i++) {
TObject tempObj;
tempObj.ttype = LUA_T_CLOSURE;
restoreFunc(&tempObj.value, sizeof(Closure *));
recreateObj(&tempObj);
tempCi->c = (Closure *)tempObj.value.cl;
tempObj.ttype = LUA_T_PROTO;
restoreFunc(&tempObj.value, sizeof(TProtoFunc *));
recreateObj(&tempObj);
tempCi->tf = (TProtoFunc *)tempObj.value.tf;
restoreFunc(&pcOffset, sizeof(int));
if (pcOffset != 0)
tempCi->pc = tempCi->tf->code + pcOffset;
else
tempCi->pc = NULL;
restoreFunc(&tempCi->base, sizeof(StkId));
restoreFunc(&tempCi->nResults, sizeof(int));
tempCi++;
}
restoreFunc(&taskCi, sizeof(int));
tempTask->ci = tempTask->base_ci + taskCi;
tempTask->end_ci = tempTask->base_ci + countCi;
int Mbasepos;
restoreFunc(&Mbasepos, sizeof(int));
tempTask->Mbuffbase = Mbasepos + tempTask->Mbuffer;
restoreFunc(&tempTask->Mbuffnext, sizeof(int));
restoreFunc(&tempTask->Tstate, sizeof(TaskState));
restoreFunc(&tempTask->auto_delete, sizeof(int));
}
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() end.\n");
}