mirror of
https://github.com/kichikuou/xsystem35-sdl2.git
synced 2026-09-22 22:48:08 +03:00
Support loading system3.5 v1 save files
This commit is contained in:
+208
-12
@@ -23,6 +23,7 @@
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
@@ -44,6 +45,7 @@ typedef int emscripten_align1_int;
|
||||
#include "message.h"
|
||||
|
||||
const char *save_signature[] = {
|
||||
[SAVEFMT_SYS35] = "This is save data for System3.5 Win95 For NACT/ADV system (C) 1996 ALICE-SOFT",
|
||||
[SAVEFMT_XSYS35] = "System3.5 SavaData(c)ALICE-SOFT",
|
||||
[SAVEFMT_SYS36] = "System3.5 SaveData(c)ALICE-SOFT",
|
||||
[SAVEFMT_SYS38] = "System3.8 SaveData(c)ALICE-SOFT",
|
||||
@@ -473,19 +475,83 @@ int save_copyAll(int dstno, int srcno) {
|
||||
return status;
|
||||
}
|
||||
|
||||
static int loadpartial_sys35(char *saveTop, int filesize, struct VarRef *vref, int cnt) {
|
||||
if (filesize < 0xb0)
|
||||
return SAVE_LOADERR;
|
||||
cnt = min(cnt, v_sliceSize(vref));
|
||||
int *var = v_resolveRef(vref);
|
||||
|
||||
if (vref->page == 0) {
|
||||
// SysVar section
|
||||
int section_offset = LittleEndian_getDW(saveTop, 0x90);
|
||||
int section_length = LittleEndian_getDW(saveTop, 0x94);
|
||||
if (section_offset + 16 + section_length > filesize)
|
||||
return SAVE_LOADERR;
|
||||
|
||||
int sysvar_count = LittleEndian_getDW(saveTop, section_offset);
|
||||
if (sysvar_count > varPage[0].size)
|
||||
return SAVE_LOADERR; // resizing system page is not supported in sys3.5
|
||||
int offset = section_offset + 16 + vref->index * 2;
|
||||
for (int i = 0; i < cnt; i++) {
|
||||
var[i] = LittleEndian_getW(saveTop, offset);
|
||||
offset += 2;
|
||||
}
|
||||
return SAVE_LOADOK;
|
||||
}
|
||||
// Arrays section
|
||||
int section_offset = LittleEndian_getDW(saveTop, 0xa0);
|
||||
int section_length = LittleEndian_getDW(saveTop, 0xa4);
|
||||
if (section_offset + 16 + section_length > filesize)
|
||||
return SAVE_LOADERR;
|
||||
int page_count = LittleEndian_getDW(saveTop, section_offset + 4);
|
||||
int offset = section_offset + 16;
|
||||
// TODO: section size check
|
||||
for (int i = 0; i < page_count; i++) {
|
||||
int page = LittleEndian_getDW(saveTop, offset); offset += 4;
|
||||
int count = LittleEndian_getDW(saveTop, offset); offset += 4;
|
||||
int content_offset = LittleEndian_getDW(saveTop, offset); offset += 4;
|
||||
offset += 4;
|
||||
if (page != vref->page)
|
||||
continue;
|
||||
// TODO page resize
|
||||
// TODO: section size check
|
||||
content_offset += vref->index * 2;
|
||||
for (int j = 0; j < cnt; j++) {
|
||||
var[j] = LittleEndian_getW(saveTop, content_offset + j * 2);
|
||||
}
|
||||
return SAVE_LOADOK;
|
||||
}
|
||||
return SAVE_LOADERR;
|
||||
}
|
||||
|
||||
/* データの一部ロード */
|
||||
int save_loadPartial(int no, struct VarRef *vref, int cnt) {
|
||||
if (no >= SAVE_MAXNUMBER)
|
||||
return SAVE_SAVEERR;
|
||||
|
||||
cnt = min(cnt, v_sliceSize(vref));
|
||||
int *var = v_resolveRef(vref);
|
||||
|
||||
int status, filesize;
|
||||
char *saveTop = loadGameData(no, &status, &filesize);
|
||||
if (!saveTop)
|
||||
return status;
|
||||
|
||||
if (filesize < 0x60)
|
||||
goto errexit;
|
||||
enum save_format format = (enum save_format)-1;
|
||||
for (int i = 0; i < sizeof(save_signature) / sizeof(save_signature[0]); i++) {
|
||||
if (!strcmp(save_signature[i], saveTop)) {
|
||||
format = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (format < 0) {
|
||||
WARNING("unrecognized save format");
|
||||
goto errexit;
|
||||
}
|
||||
|
||||
if (format == SAVEFMT_SYS35) {
|
||||
int result = loadpartial_sys35(saveTop, filesize, vref, cnt);
|
||||
free(saveTop);
|
||||
return result;
|
||||
}
|
||||
if (filesize <= sizeof(asd_baseHdr))
|
||||
goto errexit;
|
||||
|
||||
@@ -495,6 +561,8 @@ int save_loadPartial(int no, struct VarRef *vref, int cnt) {
|
||||
goto errexit;
|
||||
}
|
||||
|
||||
cnt = min(cnt, v_sliceSize(vref));
|
||||
int *var = v_resolveRef(vref);
|
||||
if (save_base->varSys[vref->page] == 0)
|
||||
goto errexit;
|
||||
|
||||
@@ -551,6 +619,125 @@ int save_savePartial(int no, struct VarRef *vref, int cnt) {
|
||||
return SAVE_SAVEERR;
|
||||
}
|
||||
|
||||
static int loadall_sys35(char *saveTop, int filesize) {
|
||||
if (filesize < 0xb0)
|
||||
return SAVE_LOADERR;
|
||||
|
||||
int page = LittleEndian_getDW(saveTop, 0x80);
|
||||
int addr = LittleEndian_getDW(saveTop, 0x84);
|
||||
sl_jmpFar2(page - 1, addr);
|
||||
|
||||
// SysVar section
|
||||
int section_offset = LittleEndian_getDW(saveTop, 0x90);
|
||||
int section_length = LittleEndian_getDW(saveTop, 0x94);
|
||||
if (section_offset + 16 + section_length > filesize)
|
||||
return SAVE_LOADERR;
|
||||
|
||||
int sysvar_count = LittleEndian_getDW(saveTop, section_offset);
|
||||
if (sysvar_count > varPage[0].size)
|
||||
return SAVE_LOADERR; // resizing system page is not supported in sys3.5
|
||||
int offset = section_offset + 16;
|
||||
for (int i = 0; i < sysvar_count; i++) {
|
||||
varPage[0].value[i] = LittleEndian_getW(saveTop, offset);
|
||||
offset += 2;
|
||||
}
|
||||
nact->sel.MsgFontSize = LittleEndian_getW(saveTop, offset); offset += 2;
|
||||
nact->msg.MsgFontSize = LittleEndian_getW(saveTop, offset); offset += 2;
|
||||
cg_vspPB = LittleEndian_getW(saveTop, offset); offset += 2;
|
||||
nact->msg.MsgFontColor = LittleEndian_getW(saveTop, offset); offset += 2;
|
||||
nact->sel.MsgFontColor = LittleEndian_getW(saveTop, offset); offset += 2;
|
||||
nact->sel.WinFrameColor = LittleEndian_getW(saveTop, offset); offset += 2;
|
||||
nact->sel.WinBackgroundColor = LittleEndian_getW(saveTop, offset); offset += 2;
|
||||
nact->msg.WinFrameColor = LittleEndian_getW(saveTop, offset); offset += 2;
|
||||
nact->msg.WinBackgroundColor = LittleEndian_getW(saveTop, offset); offset += 2;
|
||||
int left = section_offset + 16 + section_length - offset;
|
||||
WARNING("0x%x bytes for window info", left);
|
||||
if (left < 0)
|
||||
return SAVE_LOADERR;
|
||||
int win_info_count = left / 32;
|
||||
if (win_info_count >= SELWINMAX)
|
||||
return SAVE_LOADERR;
|
||||
for (int i = 1; i <= win_info_count; i++) {
|
||||
offset += 2;
|
||||
nact->sel.wininfo[i].x = LittleEndian_getW(saveTop, offset); offset += 2;
|
||||
nact->sel.wininfo[i].y = LittleEndian_getW(saveTop, offset); offset += 2;
|
||||
int ex = LittleEndian_getW(saveTop, offset); offset += 2;
|
||||
int ey = LittleEndian_getW(saveTop, offset); offset += 2;
|
||||
nact->sel.wininfo[i].width = ex + 1 - nact->sel.wininfo[i].x;
|
||||
nact->sel.wininfo[i].height = ey + 1 - nact->sel.wininfo[i].y;
|
||||
offset += 6;
|
||||
}
|
||||
for (int i = 1; i <= win_info_count; i++) {
|
||||
offset += 2;
|
||||
nact->msg.wininfo[i].x = LittleEndian_getW(saveTop, offset); offset += 2;
|
||||
nact->msg.wininfo[i].y = LittleEndian_getW(saveTop, offset); offset += 2;
|
||||
int ex = LittleEndian_getW(saveTop, offset); offset += 2;
|
||||
int ey = LittleEndian_getW(saveTop, offset); offset += 2;
|
||||
nact->msg.wininfo[i].width = ex + 1 - nact->msg.wininfo[i].x;
|
||||
nact->msg.wininfo[i].height = ey + 1 - nact->msg.wininfo[i].y;
|
||||
offset += 6;
|
||||
}
|
||||
//assert(offset == section_offset + 16 + section_length);
|
||||
|
||||
// Strings section
|
||||
section_offset = LittleEndian_getDW(saveTop, 0x98);
|
||||
section_length = LittleEndian_getDW(saveTop, 0x9c);
|
||||
if (section_offset + 16 + section_length > filesize)
|
||||
return SAVE_LOADERR;
|
||||
|
||||
int strvar_count = LittleEndian_getDW(saveTop, section_offset);
|
||||
int strvar_length = LittleEndian_getDW(saveTop, section_offset + 4);
|
||||
offset = section_offset + 16;
|
||||
if (section_length != strvar_count * strvar_length)
|
||||
return SAVE_LOADERR;
|
||||
if (strvar_count > svar_maxindex())
|
||||
strvar_count = svar_maxindex();
|
||||
char *buf = malloc(strvar_length + 1);
|
||||
buf[strvar_length] = '\0';
|
||||
for (int i = 1; i <= strvar_count; i++) {
|
||||
memcpy(buf, saveTop + offset, strvar_length);
|
||||
svar_set(i, buf);
|
||||
offset += strvar_length;
|
||||
}
|
||||
|
||||
// Arrays section
|
||||
section_offset = LittleEndian_getDW(saveTop, 0xa0);
|
||||
section_length = LittleEndian_getDW(saveTop, 0xa4);
|
||||
if (section_offset + 16 + section_length > filesize)
|
||||
return SAVE_LOADERR;
|
||||
|
||||
int array_total_size = LittleEndian_getDW(saveTop, section_offset);
|
||||
int page_count = LittleEndian_getDW(saveTop, section_offset + 4);
|
||||
offset = section_offset + 16;
|
||||
// TODO: section size check
|
||||
int total = 0;
|
||||
for (int i = 0; i < page_count; i++) {
|
||||
int page = LittleEndian_getDW(saveTop, offset); offset += 4;
|
||||
int count = LittleEndian_getDW(saveTop, offset); offset += 4;
|
||||
int content_offset = LittleEndian_getDW(saveTop, offset); offset += 4;
|
||||
offset += 4;
|
||||
total += count;
|
||||
// TODO page resize
|
||||
// TODO: section size check
|
||||
for (int j = 0; j < count; j++) {
|
||||
varPage[page].value[j] = LittleEndian_getW(saveTop, content_offset + j * 2);
|
||||
}
|
||||
}
|
||||
if (total != array_total_size) {
|
||||
WARNING("wrong array total size");
|
||||
} else {
|
||||
WARNING("correct array total size");
|
||||
}
|
||||
|
||||
// Stack section
|
||||
section_offset = LittleEndian_getDW(saveTop, 0xa8);
|
||||
section_length = LittleEndian_getDW(saveTop, 0xac);
|
||||
if (section_offset + section_length > filesize)
|
||||
return SAVE_LOADERR;
|
||||
|
||||
sl_loadStack(SAVEFMT_SYS35, saveTop + section_offset, section_length);
|
||||
return SAVE_LOADOK;
|
||||
}
|
||||
|
||||
/* データのロード */
|
||||
int save_loadAll(int no) {
|
||||
@@ -561,17 +748,11 @@ int save_loadAll(int no) {
|
||||
char *saveTop = loadGameData(no, &status, &filesize);
|
||||
if (!saveTop)
|
||||
return status;
|
||||
if (filesize <= sizeof(asd_baseHdr))
|
||||
if (filesize < 0x60)
|
||||
goto errexit;
|
||||
/* 各種データの反映 */
|
||||
asd_baseHdr *save_base = (asd_baseHdr *)saveTop;
|
||||
if (save_base->version != SAVE_DATAVERSION) {
|
||||
WARNING("endian mismatch");
|
||||
goto errexit;
|
||||
}
|
||||
enum save_format format = (enum save_format)-1;
|
||||
for (int i = 0; i < sizeof(save_signature) / sizeof(save_signature[0]); i++) {
|
||||
if (!strcmp(save_signature[i], save_base->ID)) {
|
||||
if (!strcmp(save_signature[i], saveTop)) {
|
||||
format = i;
|
||||
break;
|
||||
}
|
||||
@@ -581,6 +762,21 @@ int save_loadAll(int no) {
|
||||
goto errexit;
|
||||
}
|
||||
|
||||
if (format == SAVEFMT_SYS35) {
|
||||
int result = loadall_sys35(saveTop, filesize);
|
||||
free(saveTop);
|
||||
return result;
|
||||
}
|
||||
|
||||
if (filesize <= sizeof(asd_baseHdr))
|
||||
goto errexit;
|
||||
/* 各種データの反映 */
|
||||
asd_baseHdr *save_base = (asd_baseHdr *)saveTop;
|
||||
if (save_base->version != SAVE_DATAVERSION) {
|
||||
WARNING("endian mismatch");
|
||||
goto errexit;
|
||||
}
|
||||
|
||||
nact->sel.MsgFontSize = save_base->selMsgSize;
|
||||
nact->sel.MsgFontColor = save_base->selMsgColor;
|
||||
nact->sel.WinBackgroundColor = save_base->selBackColor;
|
||||
|
||||
@@ -38,6 +38,7 @@
|
||||
|
||||
enum save_format {
|
||||
SAVEFMT_XSYS35,
|
||||
SAVEFMT_SYS35, // System3.5 v1.x
|
||||
SAVEFMT_SYS36, // System3.5 v2.x - System3.6
|
||||
SAVEFMT_SYS38, // System3.8 - System3.9
|
||||
};
|
||||
|
||||
+121
-36
@@ -354,7 +354,7 @@ void sl_popVar(struct VarRef *vref, int cnt) {
|
||||
}
|
||||
}
|
||||
|
||||
enum save_stack_frame_type {
|
||||
enum xsys35_stack_frame_type {
|
||||
SAVE_NEARJMP = 1,
|
||||
SAVE_FARJMP = 2,
|
||||
SAVE_VARIABLE = 3,
|
||||
@@ -367,15 +367,15 @@ enum txx_type {
|
||||
TxxTEXTLOC = 3
|
||||
};
|
||||
|
||||
struct save_stack_frame {
|
||||
struct save_stack_frame *next;
|
||||
struct xsys35_stack_frame {
|
||||
struct xsys35_stack_frame *next;
|
||||
int len;
|
||||
int buf[];
|
||||
};
|
||||
|
||||
struct save_stack_frame *push_save_stack_frame(int size, struct save_stack_frame *next) {
|
||||
struct save_stack_frame *f =
|
||||
malloc(sizeof(struct save_stack_frame) + sizeof(int) * size);
|
||||
struct xsys35_stack_frame *push_xsys35_stack_frame(int size, struct xsys35_stack_frame *next) {
|
||||
struct xsys35_stack_frame *f =
|
||||
malloc(sizeof(struct xsys35_stack_frame) + sizeof(int) * size);
|
||||
f->next = next;
|
||||
f->len = size;
|
||||
return f;
|
||||
@@ -391,13 +391,13 @@ uint8_t *sl_saveStack(enum save_format format, int *size_out) {
|
||||
}
|
||||
|
||||
// Serialize to the stack format used in old versions of xsystem35.
|
||||
struct save_stack_frame *frame = NULL;
|
||||
struct xsys35_stack_frame *frame = NULL;
|
||||
uint8_t *sp = stack_top;
|
||||
while (sp > stack_buf) {
|
||||
switch (sp[-1]) {
|
||||
case STACK_FARCALL:
|
||||
sp -= 7;
|
||||
frame = push_save_stack_frame(4, frame);
|
||||
frame = push_xsys35_stack_frame(4, frame);
|
||||
frame->buf[3] = SAVE_FARJMP;
|
||||
frame->buf[2] = 2;
|
||||
frame->buf[1] = LittleEndian_getW(sp, 0) - 1; // page
|
||||
@@ -405,7 +405,7 @@ uint8_t *sl_saveStack(enum save_format format, int *size_out) {
|
||||
break;
|
||||
case STACK_NEARCALL:
|
||||
sp -= 5;
|
||||
frame = push_save_stack_frame(3, frame);
|
||||
frame = push_xsys35_stack_frame(3, frame);
|
||||
frame->buf[2] = SAVE_NEARJMP;
|
||||
frame->buf[1] = 1;
|
||||
frame->buf[0] = LittleEndian_getDW(sp, 0); // addr
|
||||
@@ -422,7 +422,7 @@ uint8_t *sl_saveStack(enum save_format format, int *size_out) {
|
||||
int base = frame->buf[frame->len - 4];
|
||||
// Merge into existing SAVE_VARIABLE frame.
|
||||
if (page == fpage && index == base - 1) {
|
||||
frame = realloc(frame, sizeof(struct save_stack_frame) + sizeof(int) * (frame->len + 1));
|
||||
frame = realloc(frame, sizeof(struct xsys35_stack_frame) + sizeof(int) * (frame->len + 1));
|
||||
frame->len++;
|
||||
frame->buf[frame->len - 1] = SAVE_VARIABLE;
|
||||
frame->buf[frame->len - 2] = count + 1;
|
||||
@@ -432,7 +432,7 @@ uint8_t *sl_saveStack(enum save_format format, int *size_out) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
frame = push_save_stack_frame(5, frame);
|
||||
frame = push_xsys35_stack_frame(5, frame);
|
||||
frame->buf[4] = SAVE_VARIABLE;
|
||||
frame->buf[3] = 3;
|
||||
frame->buf[2] = page;
|
||||
@@ -442,7 +442,7 @@ uint8_t *sl_saveStack(enum save_format format, int *size_out) {
|
||||
break;
|
||||
case STACK_TEXTCOLOR:
|
||||
sp -= 3;
|
||||
frame = push_save_stack_frame(5, frame);
|
||||
frame = push_xsys35_stack_frame(5, frame);
|
||||
frame->buf[4] = SAVE_TXXSTATE;
|
||||
frame->buf[3] = 3;
|
||||
frame->buf[2] = TxxTEXTCOLOR;
|
||||
@@ -451,7 +451,7 @@ uint8_t *sl_saveStack(enum save_format format, int *size_out) {
|
||||
break;
|
||||
case STACK_TEXTSIZE:
|
||||
sp -= 6;
|
||||
frame = push_save_stack_frame(5, frame);
|
||||
frame = push_xsys35_stack_frame(5, frame);
|
||||
frame->buf[4] = SAVE_TXXSTATE;
|
||||
frame->buf[3] = 3;
|
||||
frame->buf[2] = TxxTEXTSIZE;
|
||||
@@ -460,7 +460,7 @@ uint8_t *sl_saveStack(enum save_format format, int *size_out) {
|
||||
break;
|
||||
case STACK_TEXTLOC:
|
||||
sp -= 9;
|
||||
frame = push_save_stack_frame(5, frame);
|
||||
frame = push_xsys35_stack_frame(5, frame);
|
||||
frame->buf[4] = SAVE_TXXSTATE;
|
||||
frame->buf[3] = 3;
|
||||
frame->buf[2] = TxxTEXTLOC;
|
||||
@@ -472,15 +472,15 @@ uint8_t *sl_saveStack(enum save_format format, int *size_out) {
|
||||
}
|
||||
}
|
||||
int total_len = 0;
|
||||
for (struct save_stack_frame *f = frame; f; f = f->next)
|
||||
for (struct xsys35_stack_frame *f = frame; f; f = f->next)
|
||||
total_len += f->len;
|
||||
|
||||
int *buf = malloc(total_len * sizeof(int));
|
||||
int *p = buf;
|
||||
for (struct save_stack_frame *f = frame; f;) {
|
||||
for (struct xsys35_stack_frame *f = frame; f;) {
|
||||
memcpy(p, f->buf, f->len * sizeof(int));
|
||||
p += f->len;
|
||||
struct save_stack_frame *next = f->next;
|
||||
struct xsys35_stack_frame *next = f->next;
|
||||
free(f);
|
||||
f = next;
|
||||
}
|
||||
@@ -510,36 +510,22 @@ uint8_t *sl_saveStack(enum save_format format, int *size_out) {
|
||||
return (uint8_t *)buf;
|
||||
}
|
||||
|
||||
void sl_loadStack(enum save_format format, uint8_t *unaligned_data, int size) {
|
||||
if (format != SAVEFMT_XSYS35) {
|
||||
if (size > stack_size) {
|
||||
while (size > stack_size)
|
||||
stack_size *= 2;
|
||||
free(stack_buf);
|
||||
stack_buf = malloc(stack_size);
|
||||
if (!stack_buf)
|
||||
NOMEMERR();
|
||||
}
|
||||
memcpy(stack_buf, unaligned_data, size);
|
||||
stack_top = stack_buf + size;
|
||||
return;
|
||||
}
|
||||
|
||||
static void load_stack_xsys35(uint8_t *unaligned_data, int size) {
|
||||
// Deserialize from the stack format used in old versions of xsystem35.
|
||||
int *data = malloc(size);
|
||||
memcpy(data, unaligned_data, size);
|
||||
struct save_stack_frame *frame = NULL;
|
||||
struct xsys35_stack_frame *frame = NULL;
|
||||
|
||||
for (int *p = data + size / sizeof(int); p > data;) {
|
||||
int len = p[-2] + 2;
|
||||
p -= len;
|
||||
frame = push_save_stack_frame(len, frame);
|
||||
frame = push_xsys35_stack_frame(len, frame);
|
||||
memcpy(frame->buf, p, len * sizeof(int));
|
||||
}
|
||||
free(data);
|
||||
|
||||
stack_top = stack_buf;
|
||||
for (struct save_stack_frame *f = frame; f;) {
|
||||
for (struct xsys35_stack_frame *f = frame; f;) {
|
||||
switch (f->buf[f->len - 1]) {
|
||||
case SAVE_NEARJMP:
|
||||
if (f->len != 3)
|
||||
@@ -601,12 +587,111 @@ void sl_loadStack(enum save_format format, uint8_t *unaligned_data, int size) {
|
||||
default:
|
||||
SYSERROR("broken stack data");
|
||||
}
|
||||
struct save_stack_frame *next = f->next;
|
||||
struct xsys35_stack_frame *next = f->next;
|
||||
free(f);
|
||||
f = next;
|
||||
}
|
||||
}
|
||||
|
||||
struct asdv1_stack_frame {
|
||||
struct asdv1_stack_frame *next;
|
||||
int len;
|
||||
uint8_t buf[];
|
||||
};
|
||||
|
||||
struct asdv1_stack_frame *push_asdv1_stack_frame(int size, struct asdv1_stack_frame *next) {
|
||||
struct asdv1_stack_frame *f =
|
||||
malloc(sizeof(struct asdv1_stack_frame) + size);
|
||||
f->next = next;
|
||||
f->len = size;
|
||||
return f;
|
||||
}
|
||||
|
||||
static void load_stack_sys35(uint8_t *data, int size) {
|
||||
struct asdv1_stack_frame *frame = NULL;
|
||||
for (uint8_t *p = data + size; p > data;) {
|
||||
int frame_size = 0;
|
||||
switch (p[-1]) {
|
||||
case STACK_FARCALL:
|
||||
frame_size = 13;
|
||||
break;
|
||||
case 0xee:
|
||||
frame_size = 5;
|
||||
break;
|
||||
case 0xdd:
|
||||
frame_size = LittleEndian_getW(p, -3) * 2 + 5;
|
||||
break;
|
||||
}
|
||||
if (!frame_size)
|
||||
break; // System3.5 save files has some junk data at the stack bottom.
|
||||
p -= frame_size;
|
||||
frame = push_asdv1_stack_frame(frame_size, frame);
|
||||
memcpy(frame->buf, p, frame_size);
|
||||
}
|
||||
|
||||
stack_top = stack_buf;
|
||||
for (struct asdv1_stack_frame *f = frame; f;) {
|
||||
switch (f->buf[f->len - 1]) {
|
||||
case STACK_FARCALL:
|
||||
stack_reserve(2 + 4 + 1);
|
||||
if (LittleEndian_getDW(f->buf, 0) != 0)
|
||||
WARNING("unexpected stack structure");
|
||||
stack_push_word(LittleEndian_getDW(f->buf, 4));
|
||||
stack_push_dword(LittleEndian_getDW(f->buf, 8));
|
||||
stack_push_byte(STACK_FARCALL);
|
||||
break;
|
||||
case STACK_NEARCALL:
|
||||
stack_reserve(4 + 1);
|
||||
stack_push_dword(LittleEndian_getDW(f->buf, 0));
|
||||
stack_push_byte(STACK_NEARCALL);
|
||||
break;
|
||||
case STACK_VARIABLE:
|
||||
{
|
||||
int count = LittleEndian_getW(f->buf, f->len - 3);
|
||||
int base = LittleEndian_getW(f->buf, f->len - 5);
|
||||
stack_reserve((2 + 2 + 2 + 1) * count);
|
||||
for (int i = 0; i < count; i++) {
|
||||
stack_push_word(base + 1);
|
||||
stack_push_word(0); // page
|
||||
stack_push_word(LittleEndian_getW(f->buf, i * 2));
|
||||
stack_push_byte(STACK_VARIABLE);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
struct asdv1_stack_frame *next = f->next;
|
||||
free(f);
|
||||
f = next;
|
||||
}
|
||||
}
|
||||
|
||||
static void load_stack_sys39(uint8_t *data, int size) {
|
||||
if (size > stack_size) {
|
||||
while (size > stack_size)
|
||||
stack_size *= 2;
|
||||
free(stack_buf);
|
||||
stack_buf = malloc(stack_size);
|
||||
if (!stack_buf)
|
||||
NOMEMERR();
|
||||
}
|
||||
memcpy(stack_buf, data, size);
|
||||
stack_top = stack_buf + size;
|
||||
}
|
||||
|
||||
void sl_loadStack(enum save_format format, uint8_t *unaligned_data, int size) {
|
||||
switch (format) {
|
||||
case SAVEFMT_XSYS35:
|
||||
load_stack_xsys35(unaligned_data, size);
|
||||
break;
|
||||
case SAVEFMT_SYS35:
|
||||
load_stack_sys35(unaligned_data, size);
|
||||
break;
|
||||
default:
|
||||
load_stack_sys39(unaligned_data, size);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void sl_getStackInfo(struct stack_info *info) {
|
||||
memset(info, 0, sizeof(struct stack_info));
|
||||
|
||||
|
||||
Reference in New Issue
Block a user