mirror of
https://github.com/libretro/scummvm.git
synced 2025-01-27 05:32:45 +00:00
387 lines
11 KiB
C++
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
|