mirror of
https://github.com/libretro/scummvm.git
synced 2025-02-23 04:33:09 +00:00
426 lines
12 KiB
C++
426 lines
12 KiB
C++
#include "engine/savegame.h"
|
|
#include "engine/engine.h"
|
|
|
|
#include "common/endian.h"
|
|
#include "common/debug.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"
|
|
|
|
PointerId makeIdFromPointer(void *ptr) {
|
|
PointerId pointer;
|
|
|
|
#ifdef TARGET_64BITS
|
|
uint64 v = (uint64)ptr;
|
|
pointer.low = v & 0xffffffff;
|
|
pointer.hi = v >> 32;
|
|
#else
|
|
pointer.low = (uint32)ptr;
|
|
pointer.hi = 0;
|
|
#endif
|
|
|
|
return pointer;
|
|
}
|
|
|
|
void *makePointerFromId(PointerId ptr) {
|
|
void *pointer;
|
|
|
|
#ifdef TARGET_64BITS
|
|
uint64 v = ptr.low | ((uint64)ptr.hi << 32);
|
|
pointer = (void *)v;
|
|
#else
|
|
pointer = (void *)ptr.low;
|
|
#endif
|
|
|
|
return pointer;
|
|
}
|
|
|
|
SaveCallback saveCallbackPtr = NULL;
|
|
|
|
static void saveObjectValue(TObject *object, SaveSint32 saveSint32, SaveUint32 saveUint32) {
|
|
saveSint32(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;
|
|
saveSint32(idObj);
|
|
saveSint32(0);
|
|
return;
|
|
}
|
|
}
|
|
list = list->next;
|
|
idObj++;
|
|
}
|
|
assert(0);
|
|
break;
|
|
}
|
|
case LUA_T_NUMBER:
|
|
case LUA_T_TASK:
|
|
{
|
|
byte *udata = (byte *)(&object->value.n);
|
|
uint32 v;
|
|
#if defined(SYSTEM_LITTLE_ENDIAN)
|
|
byte b[4];
|
|
b[0] = udata[3];
|
|
b[1] = udata[2];
|
|
b[2] = udata[1];
|
|
b[3] = udata[0];
|
|
v = *(uint32 *)b;
|
|
#else
|
|
memcpy(&v, udata, 4);
|
|
#endif
|
|
saveUint32(v);
|
|
saveUint32(0);
|
|
}
|
|
break;
|
|
case LUA_T_NIL:
|
|
{
|
|
saveUint32(0);
|
|
saveUint32(0);
|
|
}
|
|
break;
|
|
case LUA_T_ARRAY:
|
|
{
|
|
saveUint32(makeIdFromPointer(object->value.a).low);
|
|
saveUint32(makeIdFromPointer(object->value.a).hi);
|
|
}
|
|
break;
|
|
case LUA_T_USERDATA:
|
|
case LUA_T_STRING:
|
|
{
|
|
saveUint32(makeIdFromPointer(object->value.ts).low);
|
|
saveUint32(makeIdFromPointer(object->value.ts).hi);
|
|
}
|
|
break;
|
|
case LUA_T_PROTO:
|
|
case LUA_T_PMARK:
|
|
{
|
|
saveUint32(makeIdFromPointer(object->value.tf).low);
|
|
saveUint32(makeIdFromPointer(object->value.tf).hi);
|
|
}
|
|
break;
|
|
case LUA_T_CLOSURE:
|
|
case LUA_T_CLMARK:
|
|
{
|
|
saveUint32(makeIdFromPointer(object->value.cl).low);
|
|
saveUint32(makeIdFromPointer(object->value.cl).hi);
|
|
}
|
|
break;
|
|
case LUA_T_LINE:
|
|
{
|
|
saveSint32(object->value.i);
|
|
saveSint32(0);
|
|
}
|
|
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')) {
|
|
saveUint32(makeIdFromPointer(object->value.ts).low);
|
|
saveUint32(makeIdFromPointer(object->value.ts).hi);
|
|
} else {
|
|
error("saveObjectValue: Unsupported object type");
|
|
}
|
|
}
|
|
}
|
|
|
|
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(SaveStream saveStream, SaveSint32 saveSint32, SaveUint32 saveUint32) {
|
|
printf("lua_Save() started.\n");
|
|
|
|
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 = &L->string_root[i];
|
|
for (int32 l = 0; l < tempStringTable->size; l++) {
|
|
if (tempStringTable->hash[l] && tempStringTable->hash[l] != &EMPTY) {
|
|
countElements++;
|
|
if (tempStringTable->hash[l]->constindex != -1) {
|
|
if (maxStringLength < tempStringTable->hash[l]->u.s.len) {
|
|
maxStringLength = tempStringTable->hash[l]->u.s.len;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
// save number of strings
|
|
saveSint32(countElements);
|
|
|
|
|
|
// save number of closures
|
|
countElements = 0;
|
|
GCnode *tempNode;
|
|
tempNode = L->rootcl.next;
|
|
while (tempNode) {
|
|
countElements++;
|
|
tempNode = tempNode->next;
|
|
}
|
|
saveSint32(countElements);
|
|
|
|
// save number of tables
|
|
countElements = 0;
|
|
tempNode = L->roottable.next;
|
|
while (tempNode) {
|
|
countElements++;
|
|
tempNode = tempNode->next;
|
|
}
|
|
saveSint32(countElements);
|
|
|
|
// save number of prototypes
|
|
countElements = 0;
|
|
tempNode = L->rootproto.next;
|
|
while (tempNode) {
|
|
countElements++;
|
|
tempNode = tempNode->next;
|
|
}
|
|
saveSint32(countElements);
|
|
|
|
// save number of global strings
|
|
countElements = 0;
|
|
tempNode = L->rootglobal.next;
|
|
while (tempNode) {
|
|
countElements++;
|
|
tempNode = tempNode->next;
|
|
}
|
|
saveSint32(countElements);
|
|
|
|
// save maximum length for string
|
|
saveSint32(maxStringLength);
|
|
|
|
//printf("1: %d\n", g_engine->_savedState->getBufferPos());
|
|
|
|
// save hash tables for strings and user data
|
|
TaggedString *tempString;
|
|
for (i = 0; i < NUM_HASHS; i++) {
|
|
stringtable *tempStringTable = &L->string_root[i];
|
|
for (l = 0; l < tempStringTable->size; l++) {
|
|
if (tempStringTable->hash[l] && tempStringTable->hash[l] != &EMPTY) {
|
|
tempString = tempStringTable->hash[l];
|
|
saveUint32(makeIdFromPointer(tempString).low);
|
|
saveUint32(makeIdFromPointer(tempString).hi);
|
|
saveSint32(tempString->constindex);
|
|
if (tempString->constindex != -1) {
|
|
saveObjectValue(&tempString->u.s.globalval, saveSint32, saveUint32);
|
|
saveSint32(tempString->u.s.len);
|
|
saveStream(tempString->str, tempString->u.s.len);
|
|
} else {
|
|
if (saveCallbackPtr) {
|
|
PointerId ptr = makeIdFromPointer(tempString->u.d.v);
|
|
ptr = saveCallbackPtr(tempString->u.d.tag, ptr, saveSint32);
|
|
tempString->u.d.v = makePointerFromId(ptr);
|
|
}
|
|
saveObjectValue((TObject *)&tempString->u.d, saveSint32, saveUint32);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//printf("2: %d\n", g_engine->_savedState->getBufferPos());
|
|
|
|
Closure *tempClosure = (Closure *)L->rootcl.next;
|
|
while (tempClosure) {
|
|
saveUint32(makeIdFromPointer(tempClosure).low);
|
|
saveUint32(makeIdFromPointer(tempClosure).hi);
|
|
saveSint32(tempClosure->nelems);
|
|
for (i = 0; i <= tempClosure->nelems; i++) {
|
|
saveObjectValue(&tempClosure->consts[i], saveSint32, saveUint32);
|
|
}
|
|
tempClosure = (Closure *)tempClosure->head.next;
|
|
}
|
|
|
|
Hash *tempHash = (Hash *)L->roottable.next;
|
|
while (tempHash) {
|
|
saveUint32(makeIdFromPointer(tempHash).low);
|
|
saveUint32(makeIdFromPointer(tempHash).hi);
|
|
saveSint32(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++;
|
|
}
|
|
}
|
|
saveSint32(countUsedHash);
|
|
saveSint32(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, saveSint32, saveUint32);
|
|
saveObjectValue(&tempHash->node[i].val, saveSint32, saveUint32);
|
|
}
|
|
}
|
|
tempHash = (Hash *)tempHash->head.next;
|
|
}
|
|
|
|
TProtoFunc *tempProtoFunc = (TProtoFunc *)L->rootproto.next;
|
|
while (tempProtoFunc) {
|
|
saveUint32(makeIdFromPointer(tempProtoFunc).low);
|
|
saveUint32(makeIdFromPointer(tempProtoFunc).hi);
|
|
saveUint32(makeIdFromPointer(tempProtoFunc->fileName).low);
|
|
saveUint32(makeIdFromPointer(tempProtoFunc->fileName).hi);
|
|
saveSint32(tempProtoFunc->lineDefined);
|
|
saveSint32(tempProtoFunc->nconsts);
|
|
for (i = 0; i < tempProtoFunc->nconsts; i++) {
|
|
saveObjectValue(&tempProtoFunc->consts[i], saveSint32, saveUint32);
|
|
}
|
|
int32 countVariables = 0;
|
|
if (tempProtoFunc->locvars) {
|
|
for (; tempProtoFunc->locvars[countVariables++].line != -1;) { }
|
|
}
|
|
|
|
saveSint32(countVariables);
|
|
for (i = 0; i < countVariables; i++) {
|
|
saveUint32(makeIdFromPointer(tempProtoFunc->locvars[i].varname).low);
|
|
saveUint32(makeIdFromPointer(tempProtoFunc->locvars[i].varname).hi);
|
|
saveSint32(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;
|
|
saveSint32(codeSize);
|
|
saveStream(tempProtoFunc->code, codeSize);
|
|
tempProtoFunc = (TProtoFunc *)tempProtoFunc->head.next;
|
|
}
|
|
|
|
tempString = (TaggedString *)L->rootglobal.next;
|
|
while (tempString) {
|
|
saveUint32(makeIdFromPointer(tempString).low);
|
|
saveUint32(makeIdFromPointer(tempString).hi);
|
|
tempString = (TaggedString *)tempString->head.next;
|
|
}
|
|
|
|
saveObjectValue(&L->errorim, saveSint32, saveUint32);
|
|
|
|
IM *tempIm = L->IMtable;
|
|
saveSint32(L->IMtable_size);
|
|
for (i = 0; i < L->IMtable_size; i++) {
|
|
for (l = 0; l < IM_N; l++) {
|
|
saveObjectValue(&tempIm->int_method[l], saveSint32, saveUint32);
|
|
}
|
|
tempIm++;
|
|
}
|
|
|
|
saveSint32(L->last_tag);
|
|
saveSint32(L->refSize);
|
|
for (i = 0 ; i < L->refSize; i++) {
|
|
saveObjectValue(&L->refArray[i].o, saveSint32, saveUint32);
|
|
saveSint32(L->refArray[i].status);
|
|
}
|
|
|
|
saveSint32(L->GCthreshold);
|
|
saveSint32(L->nblocks);
|
|
|
|
saveSint32(L->Mbuffsize);
|
|
saveStream(L->Mbuffer, L->Mbuffsize);
|
|
int32 MbaseOffset = L->Mbuffbase - L->Mbuffer;
|
|
saveSint32(MbaseOffset);
|
|
saveSint32(L->Mbuffnext);
|
|
|
|
saveSint32(globalTaskSerialId);
|
|
|
|
int32 countTasks = 0;
|
|
lua_Task *tempTask = L->root_task->next;
|
|
while (tempTask) {
|
|
countTasks++;
|
|
tempTask = tempTask->next;
|
|
}
|
|
saveSint32(countTasks);
|
|
|
|
tempTask = L->root_task->next;
|
|
while (tempTask) {
|
|
int32 stackLastSize = (tempTask->stack.last - tempTask->stack.stack) + 1;
|
|
saveSint32(stackLastSize);
|
|
int32 stackTopSize = tempTask->stack.top - tempTask->stack.stack;
|
|
saveSint32(stackTopSize);
|
|
for (i = 0; i < stackTopSize; i++) {
|
|
saveObjectValue(&tempTask->stack.stack[i], saveSint32, saveUint32);
|
|
}
|
|
|
|
saveSint32(tempTask->Cstack.base);
|
|
saveSint32(tempTask->Cstack.lua2C);
|
|
saveSint32(tempTask->Cstack.num);
|
|
|
|
saveSint32(tempTask->numCblocks);
|
|
for (i = 0; i < tempTask->numCblocks; i++) {
|
|
saveSint32(tempTask->Cblocks[i].base);
|
|
saveSint32(tempTask->Cblocks[i].lua2C);
|
|
saveSint32(tempTask->Cblocks[i].num);
|
|
}
|
|
|
|
int32 pcOffset, taskCi = -1;
|
|
saveSint32(tempTask->base_ci_size);
|
|
assert(tempTask->base_ci);
|
|
CallInfo *tempCi = tempTask->base_ci;
|
|
int32 countCi = tempTask->base_ci_size / sizeof(CallInfo);
|
|
for (i = 0; i < countCi; i++) {
|
|
saveUint32(makeIdFromPointer(tempCi->c).low);
|
|
saveUint32(makeIdFromPointer(tempCi->c).hi);
|
|
saveUint32(makeIdFromPointer(tempCi->tf).low);
|
|
saveUint32(makeIdFromPointer(tempCi->tf).hi);
|
|
if (tempCi->pc && tempTask->ci->tf)
|
|
pcOffset = tempCi->pc - tempCi->tf->code;
|
|
else
|
|
pcOffset = 0;
|
|
saveSint32(pcOffset);
|
|
saveSint32(tempCi->base);
|
|
saveSint32(tempCi->nResults);
|
|
if (tempCi == tempTask->ci)
|
|
taskCi = i;
|
|
tempCi++;
|
|
}
|
|
assert(taskCi != -1);
|
|
saveSint32(taskCi);
|
|
|
|
MbaseOffset = tempTask->Mbuffbase - tempTask->Mbuffer;
|
|
saveSint32(MbaseOffset);
|
|
saveSint32(tempTask->Mbuffnext);
|
|
|
|
saveSint32(tempTask->Tstate);
|
|
saveSint32(tempTask->id);
|
|
|
|
tempTask = tempTask->next;
|
|
}
|
|
|
|
printf("lua_Save() finished.\n");
|
|
}
|