scummvm/engines/grim/lua/lsave.cpp
2022-01-14 09:01:44 +01:00

387 lines
11 KiB
C++

#define FORBIDDEN_SYMBOL_EXCEPTION_setjmp
#define FORBIDDEN_SYMBOL_EXCEPTION_longjmp
#include "common/endian.h"
#include "common/debug.h"
#include "engines/grim/savegame.h"
#include "engines/grim/lua/ltask.h"
#include "engines/grim/lua/lauxlib.h"
#include "engines/grim/lua/lmem.h"
#include "engines/grim/lua/ldo.h"
#include "engines/grim/lua/ltm.h"
#include "engines/grim/lua/ltable.h"
#include "engines/grim/lua/lvm.h"
#include "engines/grim/lua/lopcodes.h"
#include "engines/grim/lua/lstring.h"
#include "engines/grim/lua/lua.h"
namespace Grim {
PointerId makeIdFromPointer(void *ptr) {
PointerId pointer;
pointer.id = (uintptr)ptr;
return pointer;
}
void *makePointerFromId(PointerId ptr) {
return (void *)ptr.id;
}
static void saveObjectValue(TObject *object, SaveGame *savedState) {
savedState->writeLESint32(object->ttype);
switch (object->ttype) {
case LUA_T_CPROTO:
case LUA_T_CMARK:
{
luaL_libList *list = list_of_libs;
int32 idObj = 0;
while (list) {
for (int32 l = 0; l < list->number; l++) {
if (list->list[l].func == object->value.f) {
idObj = (idObj << 16) | l;
savedState->writeLESint32(idObj);
savedState->writeLESint32(0);
return;
}
}
list = list->next;
idObj++;
}
assert(0);
break;
}
case LUA_T_NUMBER:
case LUA_T_TASK:
{
savedState->writeFloat(object->value.n);
}
break;
case LUA_T_NIL:
break;
case LUA_T_ARRAY:
{
savedState->writeLEUint64(makeIdFromPointer(object->value.a).id);
}
break;
case LUA_T_USERDATA:
{
savedState->writeLESint32(object->value.ud.id);
savedState->writeLESint32(object->value.ud.tag);
}
break;
case LUA_T_STRING:
{
savedState->writeLEUint64(makeIdFromPointer(object->value.ts).id);
}
break;
case LUA_T_PROTO:
case LUA_T_PMARK:
{
savedState->writeLEUint64(makeIdFromPointer(object->value.tf).id);
}
break;
case LUA_T_CLOSURE:
case LUA_T_CLMARK:
{
savedState->writeLEUint64(makeIdFromPointer(object->value.cl).id);
}
break;
case LUA_T_LINE:
{
savedState->writeLESint32(object->value.i);
}
break;
default:
savedState->writeLEUint64(makeIdFromPointer(object->value.ts).id);
}
}
static int32 opcodeSizeTable[] = {
1, 2, 1, 2, 1, 1, 1, 3, 2, 1, 1, 1, 1, 1, 1, 1, 1, 3, 2, 1,
1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 3,
1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 3, 2, 1, 1, 1, 1, 1, 1, 1, 1,
3, 2, 1, 1, 3, 2, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1,
1, 1, 1, 3, 1, 2, 3, 2, 4, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 1, 1,
3, 2, 2, 2, 2, 3, 2, 1, 1, 1, 2, 1, 2, 1, 1, 1, 3, 2, 1, 1,
1, 1, 1, 1, 1, 1, 3, 2, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 2,
1, 1, 1, 1, 1, 1, 1, 1, 3, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 3,
2, 1, 1, 1, 1, 1, 1, 1, 1, 3, 2, 1, 1, 3, 2, 1, 1, 1, 1, 1,
1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 3, 1, 2, 3, 2, 4, 2, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 3, 2, 3, 2, 3,
2, 3, 2, 3, 2, 3, 2, 1, 1, 3, 2, 2, 2, 2, 3, 2, 1, 1
};
void lua_Save(SaveGame *savedState) {
savedState->beginSection('LUAS');
lua_collectgarbage(0);
int32 i, l;
int32 countElements = 0;
int32 maxStringLength = 0;
// Check for max length for strings and count them
for (i = 0; i < NUM_HASHS; i++) {
stringtable *tempStringTable = &string_root[i];
for (l = 0; l < tempStringTable->size; l++) {
if (tempStringTable->hash[l] && tempStringTable->hash[l] != &EMPTY) {
countElements++;
if (tempStringTable->hash[l]->constindex != -1) {
int len = strlen(tempStringTable->hash[l]->str);
if (maxStringLength < len) {
maxStringLength = len;
}
}
}
}
}
// save number of strings
savedState->writeLESint32(countElements);
// save number of closures
countElements = 0;
GCnode *tempNode;
tempNode = rootcl.next;
while (tempNode) {
countElements++;
tempNode = tempNode->next;
}
savedState->writeLESint32(countElements);
// save number of tables
countElements = 0;
tempNode = roottable.next;
while (tempNode) {
countElements++;
tempNode = tempNode->next;
}
savedState->writeLESint32(countElements);
// save number of prototypes
countElements = 0;
tempNode = rootproto.next;
while (tempNode) {
countElements++;
tempNode = tempNode->next;
}
savedState->writeLESint32(countElements);
// save number of global strings
countElements = 0;
tempNode = rootglobal.next;
while (tempNode) {
countElements++;
tempNode = tempNode->next;
}
savedState->writeLESint32(countElements);
// save maximum length for string
savedState->writeLESint32(maxStringLength);
//printf("1: %d\n", g_grim->_savedState->getBufferPos());
// save hash tables for strings and user data
TaggedString *tempString;
for (i = 0; i < NUM_HASHS; i++) {
stringtable *tempStringTable = &string_root[i];
for (l = 0; l < tempStringTable->size; l++) {
if (tempStringTable->hash[l] && tempStringTable->hash[l] != &EMPTY) {
tempString = tempStringTable->hash[l];
savedState->writeLEUint64(makeIdFromPointer(tempString).id);
savedState->writeLESint32(tempString->constindex);
if (tempString->constindex != -1) {
saveObjectValue(&tempString->globalval, savedState);
int len = strlen(tempString->str);
savedState->writeLESint32(len);
savedState->write(tempString->str, len);
}
}
}
}
//printf("2: %d\n", g_grim->_savedState->getBufferPos());
Closure *tempClosure = (Closure *)rootcl.next;
while (tempClosure) {
savedState->writeLEUint64(makeIdFromPointer(tempClosure).id);
savedState->writeLESint32(tempClosure->nelems);
for (i = 0; i <= tempClosure->nelems; i++) {
saveObjectValue(&tempClosure->consts[i], savedState);
}
tempClosure = (Closure *)tempClosure->head.next;
}
Hash *tempHash = (Hash *)roottable.next;
while (tempHash) {
savedState->writeLEUint64(makeIdFromPointer(tempHash).id);
savedState->writeLESint32(tempHash->nhash);
int32 countUsedHash = 0;
for (i = 0; i < tempHash->nhash; i++) {
Node *newNode = &tempHash->node[i];
if (newNode->ref.ttype != LUA_T_NIL && newNode->val.ttype != LUA_T_NIL) {
countUsedHash++;
}
}
savedState->writeLESint32(countUsedHash);
savedState->writeLESint32(tempHash->htag);
for (i = 0; i < tempHash->nhash; i++) {
Node *newNode = &tempHash->node[i];
if (newNode->ref.ttype != LUA_T_NIL && newNode->val.ttype != LUA_T_NIL) {
saveObjectValue(&tempHash->node[i].ref, savedState);
saveObjectValue(&tempHash->node[i].val, savedState);
}
}
tempHash = (Hash *)tempHash->head.next;
}
TProtoFunc *tempProtoFunc = (TProtoFunc *)rootproto.next;
while (tempProtoFunc) {
savedState->writeLEUint64(makeIdFromPointer(tempProtoFunc).id);
savedState->writeLEUint64(makeIdFromPointer(tempProtoFunc->fileName).id);
savedState->writeLESint32(tempProtoFunc->lineDefined);
savedState->writeLESint32(tempProtoFunc->nconsts);
for (i = 0; i < tempProtoFunc->nconsts; i++) {
saveObjectValue(&tempProtoFunc->consts[i], savedState);
}
int32 countVariables = 0;
if (tempProtoFunc->locvars) {
for (; tempProtoFunc->locvars[countVariables++].line != -1;) { }
}
savedState->writeLESint32(countVariables);
for (i = 0; i < countVariables; i++) {
savedState->writeLEUint64(makeIdFromPointer(tempProtoFunc->locvars[i].varname).id);
savedState->writeLESint32(tempProtoFunc->locvars[i].line);
}
byte *codePtr = tempProtoFunc->code + 2;
byte *tmpPtr = codePtr;
int32 opcodeId;
do {
opcodeId = *tmpPtr;
tmpPtr += opcodeSizeTable[opcodeId];
} while (opcodeId != ENDCODE);
int32 codeSize = (tmpPtr - codePtr) + 2;
savedState->writeLESint32(codeSize);
savedState->write(tempProtoFunc->code, codeSize);
tempProtoFunc = (TProtoFunc *)tempProtoFunc->head.next;
}
tempString = (TaggedString *)rootglobal.next;
while (tempString) {
savedState->writeLEUint64(makeIdFromPointer(tempString).id);
tempString = (TaggedString *)tempString->head.next;
}
saveObjectValue(&errorim, savedState);
IM *tempIm = IMtable;
savedState->writeLESint32(IMtable_size);
for (i = 0; i < IMtable_size; i++) {
for (l = 0; l < IM_N; l++) {
saveObjectValue(&tempIm->int_method[l], savedState);
}
tempIm++;
}
savedState->writeLESint32(last_tag);
savedState->writeLESint32(refSize);
for (i = 0 ; i < refSize; i++) {
saveObjectValue(&refArray[i].o, savedState);
savedState->writeLESint32(refArray[i].status);
}
savedState->writeLESint32(GCthreshold);
savedState->writeLESint32(nblocks);
savedState->writeLESint32(Mbuffsize);
savedState->write(Mbuffer, Mbuffsize);
int32 MbaseOffset = Mbuffbase - Mbuffer;
savedState->writeLESint32(MbaseOffset);
savedState->writeLESint32(Mbuffnext);
savedState->writeLESint32(globalTaskSerialId);
int32 countStates = 0, currentState = 0;
LState *state = lua_rootState;
while (state) {
if (lua_state == state)
currentState = countStates;
countStates++;
state = state->next;
}
savedState->writeLESint32(countStates);
savedState->writeLESint32(currentState);
state = lua_rootState;
while (state) {
lua_Task *task = state->task;
int32 countTasks = 0, n = -1;
while (task) {
if (state->prevTask && state->prevTask == task)
n = countTasks;
countTasks++;
task = task->next;
}
savedState->writeLESint32(countTasks);
task = state->task;
while (task) {
savedState->writeLEUint64(makeIdFromPointer(task->cl).id);
savedState->writeLEUint64(makeIdFromPointer(task->tf).id);
savedState->writeLESint32(task->base);
savedState->writeLESint32(task->initBase);
savedState->writeLESint32(task->initResults);
savedState->writeBool(task->executed);
int32 pcOffset = task->pc - task->tf->code;
savedState->writeLESint32(pcOffset);
savedState->writeLESint32(task->aux);
task = task->next;
}
savedState->writeLESint32(n);
savedState->writeBool(state->updated);
byte pauseState = 0;
pauseState = state->all_paused & LUA_SG_ALL_PAUSED;
pauseState |= state->paused ? LUA_SG_PAUSED : 0;
savedState->writeByte(pauseState);
savedState->writeLESint32(state->preventBreakCounter);
savedState->writeLESint32(state->callLevelCounter);
int32 stackLastSize = (state->stack.last - state->stack.stack) + 1;
savedState->writeLESint32(stackLastSize);
int32 stackTopSize = state->stack.top - state->stack.stack;
savedState->writeLESint32(stackTopSize);
for (i = 0; i < stackTopSize; i++) {
saveObjectValue(&state->stack.stack[i], savedState);
}
savedState->writeLESint32(state->Cstack.base);
savedState->writeLESint32(state->Cstack.lua2C);
savedState->writeLESint32(state->Cstack.num);
savedState->writeLESint32(state->numCblocks);
for (i = 0; i < state->numCblocks; i++) {
savedState->writeLESint32(state->Cblocks[i].base);
savedState->writeLESint32(state->Cblocks[i].lua2C);
savedState->writeLESint32(state->Cblocks[i].num);
}
savedState->writeLEUint32(state->sleepFor);
savedState->writeLEUint32(state->id);
saveObjectValue(&state->taskFunc, savedState);
state = state->next;
}
savedState->endSection();
}
} // end of namespace Grim