mirror of
https://github.com/kichikuou/xsystem35-sdl2.git
synced 2026-10-05 13:18:08 +03:00
Compare commits
1
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
64edcfda29 |
+208
-12
@@ -23,6 +23,7 @@
|
|||||||
|
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
@@ -44,6 +45,7 @@ typedef int emscripten_align1_int;
|
|||||||
#include "message.h"
|
#include "message.h"
|
||||||
|
|
||||||
const char *save_signature[] = {
|
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_XSYS35] = "System3.5 SavaData(c)ALICE-SOFT",
|
||||||
[SAVEFMT_SYS36] = "System3.5 SaveData(c)ALICE-SOFT",
|
[SAVEFMT_SYS36] = "System3.5 SaveData(c)ALICE-SOFT",
|
||||||
[SAVEFMT_SYS38] = "System3.8 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;
|
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) {
|
int save_loadPartial(int no, struct VarRef *vref, int cnt) {
|
||||||
if (no >= SAVE_MAXNUMBER)
|
if (no >= SAVE_MAXNUMBER)
|
||||||
return SAVE_SAVEERR;
|
return SAVE_SAVEERR;
|
||||||
|
|
||||||
cnt = min(cnt, v_sliceSize(vref));
|
|
||||||
int *var = v_resolveRef(vref);
|
|
||||||
|
|
||||||
int status, filesize;
|
int status, filesize;
|
||||||
char *saveTop = loadGameData(no, &status, &filesize);
|
char *saveTop = loadGameData(no, &status, &filesize);
|
||||||
if (!saveTop)
|
if (!saveTop)
|
||||||
return status;
|
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))
|
if (filesize <= sizeof(asd_baseHdr))
|
||||||
goto errexit;
|
goto errexit;
|
||||||
|
|
||||||
@@ -495,6 +561,8 @@ int save_loadPartial(int no, struct VarRef *vref, int cnt) {
|
|||||||
goto errexit;
|
goto errexit;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
cnt = min(cnt, v_sliceSize(vref));
|
||||||
|
int *var = v_resolveRef(vref);
|
||||||
if (save_base->varSys[vref->page] == 0)
|
if (save_base->varSys[vref->page] == 0)
|
||||||
goto errexit;
|
goto errexit;
|
||||||
|
|
||||||
@@ -551,6 +619,125 @@ int save_savePartial(int no, struct VarRef *vref, int cnt) {
|
|||||||
return SAVE_SAVEERR;
|
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) {
|
int save_loadAll(int no) {
|
||||||
@@ -561,17 +748,11 @@ int save_loadAll(int no) {
|
|||||||
char *saveTop = loadGameData(no, &status, &filesize);
|
char *saveTop = loadGameData(no, &status, &filesize);
|
||||||
if (!saveTop)
|
if (!saveTop)
|
||||||
return status;
|
return status;
|
||||||
if (filesize <= sizeof(asd_baseHdr))
|
if (filesize < 0x60)
|
||||||
goto errexit;
|
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;
|
enum save_format format = (enum save_format)-1;
|
||||||
for (int i = 0; i < sizeof(save_signature) / sizeof(save_signature[0]); i++) {
|
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;
|
format = i;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -581,6 +762,21 @@ int save_loadAll(int no) {
|
|||||||
goto errexit;
|
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.MsgFontSize = save_base->selMsgSize;
|
||||||
nact->sel.MsgFontColor = save_base->selMsgColor;
|
nact->sel.MsgFontColor = save_base->selMsgColor;
|
||||||
nact->sel.WinBackgroundColor = save_base->selBackColor;
|
nact->sel.WinBackgroundColor = save_base->selBackColor;
|
||||||
|
|||||||
@@ -38,6 +38,7 @@
|
|||||||
|
|
||||||
enum save_format {
|
enum save_format {
|
||||||
SAVEFMT_XSYS35,
|
SAVEFMT_XSYS35,
|
||||||
|
SAVEFMT_SYS35, // System3.5 v1.x
|
||||||
SAVEFMT_SYS36, // System3.5 v2.x - System3.6
|
SAVEFMT_SYS36, // System3.5 v2.x - System3.6
|
||||||
SAVEFMT_SYS38, // System3.8 - System3.9
|
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_NEARJMP = 1,
|
||||||
SAVE_FARJMP = 2,
|
SAVE_FARJMP = 2,
|
||||||
SAVE_VARIABLE = 3,
|
SAVE_VARIABLE = 3,
|
||||||
@@ -367,15 +367,15 @@ enum txx_type {
|
|||||||
TxxTEXTLOC = 3
|
TxxTEXTLOC = 3
|
||||||
};
|
};
|
||||||
|
|
||||||
struct save_stack_frame {
|
struct xsys35_stack_frame {
|
||||||
struct save_stack_frame *next;
|
struct xsys35_stack_frame *next;
|
||||||
int len;
|
int len;
|
||||||
int buf[];
|
int buf[];
|
||||||
};
|
};
|
||||||
|
|
||||||
struct save_stack_frame *push_save_stack_frame(int size, struct save_stack_frame *next) {
|
struct xsys35_stack_frame *push_xsys35_stack_frame(int size, struct xsys35_stack_frame *next) {
|
||||||
struct save_stack_frame *f =
|
struct xsys35_stack_frame *f =
|
||||||
malloc(sizeof(struct save_stack_frame) + sizeof(int) * size);
|
malloc(sizeof(struct xsys35_stack_frame) + sizeof(int) * size);
|
||||||
f->next = next;
|
f->next = next;
|
||||||
f->len = size;
|
f->len = size;
|
||||||
return f;
|
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.
|
// 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;
|
uint8_t *sp = stack_top;
|
||||||
while (sp > stack_buf) {
|
while (sp > stack_buf) {
|
||||||
switch (sp[-1]) {
|
switch (sp[-1]) {
|
||||||
case STACK_FARCALL:
|
case STACK_FARCALL:
|
||||||
sp -= 7;
|
sp -= 7;
|
||||||
frame = push_save_stack_frame(4, frame);
|
frame = push_xsys35_stack_frame(4, frame);
|
||||||
frame->buf[3] = SAVE_FARJMP;
|
frame->buf[3] = SAVE_FARJMP;
|
||||||
frame->buf[2] = 2;
|
frame->buf[2] = 2;
|
||||||
frame->buf[1] = LittleEndian_getW(sp, 0) - 1; // page
|
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;
|
break;
|
||||||
case STACK_NEARCALL:
|
case STACK_NEARCALL:
|
||||||
sp -= 5;
|
sp -= 5;
|
||||||
frame = push_save_stack_frame(3, frame);
|
frame = push_xsys35_stack_frame(3, frame);
|
||||||
frame->buf[2] = SAVE_NEARJMP;
|
frame->buf[2] = SAVE_NEARJMP;
|
||||||
frame->buf[1] = 1;
|
frame->buf[1] = 1;
|
||||||
frame->buf[0] = LittleEndian_getDW(sp, 0); // addr
|
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];
|
int base = frame->buf[frame->len - 4];
|
||||||
// Merge into existing SAVE_VARIABLE frame.
|
// Merge into existing SAVE_VARIABLE frame.
|
||||||
if (page == fpage && index == base - 1) {
|
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->len++;
|
||||||
frame->buf[frame->len - 1] = SAVE_VARIABLE;
|
frame->buf[frame->len - 1] = SAVE_VARIABLE;
|
||||||
frame->buf[frame->len - 2] = count + 1;
|
frame->buf[frame->len - 2] = count + 1;
|
||||||
@@ -432,7 +432,7 @@ uint8_t *sl_saveStack(enum save_format format, int *size_out) {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
frame = push_save_stack_frame(5, frame);
|
frame = push_xsys35_stack_frame(5, frame);
|
||||||
frame->buf[4] = SAVE_VARIABLE;
|
frame->buf[4] = SAVE_VARIABLE;
|
||||||
frame->buf[3] = 3;
|
frame->buf[3] = 3;
|
||||||
frame->buf[2] = page;
|
frame->buf[2] = page;
|
||||||
@@ -442,7 +442,7 @@ uint8_t *sl_saveStack(enum save_format format, int *size_out) {
|
|||||||
break;
|
break;
|
||||||
case STACK_TEXTCOLOR:
|
case STACK_TEXTCOLOR:
|
||||||
sp -= 3;
|
sp -= 3;
|
||||||
frame = push_save_stack_frame(5, frame);
|
frame = push_xsys35_stack_frame(5, frame);
|
||||||
frame->buf[4] = SAVE_TXXSTATE;
|
frame->buf[4] = SAVE_TXXSTATE;
|
||||||
frame->buf[3] = 3;
|
frame->buf[3] = 3;
|
||||||
frame->buf[2] = TxxTEXTCOLOR;
|
frame->buf[2] = TxxTEXTCOLOR;
|
||||||
@@ -451,7 +451,7 @@ uint8_t *sl_saveStack(enum save_format format, int *size_out) {
|
|||||||
break;
|
break;
|
||||||
case STACK_TEXTSIZE:
|
case STACK_TEXTSIZE:
|
||||||
sp -= 6;
|
sp -= 6;
|
||||||
frame = push_save_stack_frame(5, frame);
|
frame = push_xsys35_stack_frame(5, frame);
|
||||||
frame->buf[4] = SAVE_TXXSTATE;
|
frame->buf[4] = SAVE_TXXSTATE;
|
||||||
frame->buf[3] = 3;
|
frame->buf[3] = 3;
|
||||||
frame->buf[2] = TxxTEXTSIZE;
|
frame->buf[2] = TxxTEXTSIZE;
|
||||||
@@ -460,7 +460,7 @@ uint8_t *sl_saveStack(enum save_format format, int *size_out) {
|
|||||||
break;
|
break;
|
||||||
case STACK_TEXTLOC:
|
case STACK_TEXTLOC:
|
||||||
sp -= 9;
|
sp -= 9;
|
||||||
frame = push_save_stack_frame(5, frame);
|
frame = push_xsys35_stack_frame(5, frame);
|
||||||
frame->buf[4] = SAVE_TXXSTATE;
|
frame->buf[4] = SAVE_TXXSTATE;
|
||||||
frame->buf[3] = 3;
|
frame->buf[3] = 3;
|
||||||
frame->buf[2] = TxxTEXTLOC;
|
frame->buf[2] = TxxTEXTLOC;
|
||||||
@@ -472,15 +472,15 @@ uint8_t *sl_saveStack(enum save_format format, int *size_out) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
int total_len = 0;
|
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;
|
total_len += f->len;
|
||||||
|
|
||||||
int *buf = malloc(total_len * sizeof(int));
|
int *buf = malloc(total_len * sizeof(int));
|
||||||
int *p = buf;
|
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));
|
memcpy(p, f->buf, f->len * sizeof(int));
|
||||||
p += f->len;
|
p += f->len;
|
||||||
struct save_stack_frame *next = f->next;
|
struct xsys35_stack_frame *next = f->next;
|
||||||
free(f);
|
free(f);
|
||||||
f = next;
|
f = next;
|
||||||
}
|
}
|
||||||
@@ -510,36 +510,22 @@ uint8_t *sl_saveStack(enum save_format format, int *size_out) {
|
|||||||
return (uint8_t *)buf;
|
return (uint8_t *)buf;
|
||||||
}
|
}
|
||||||
|
|
||||||
void sl_loadStack(enum save_format format, uint8_t *unaligned_data, int size) {
|
static void load_stack_xsys35(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;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Deserialize from the stack format used in old versions of xsystem35.
|
// Deserialize from the stack format used in old versions of xsystem35.
|
||||||
int *data = malloc(size);
|
int *data = malloc(size);
|
||||||
memcpy(data, unaligned_data, 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;) {
|
for (int *p = data + size / sizeof(int); p > data;) {
|
||||||
int len = p[-2] + 2;
|
int len = p[-2] + 2;
|
||||||
p -= len;
|
p -= len;
|
||||||
frame = push_save_stack_frame(len, frame);
|
frame = push_xsys35_stack_frame(len, frame);
|
||||||
memcpy(frame->buf, p, len * sizeof(int));
|
memcpy(frame->buf, p, len * sizeof(int));
|
||||||
}
|
}
|
||||||
free(data);
|
free(data);
|
||||||
|
|
||||||
stack_top = stack_buf;
|
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]) {
|
switch (f->buf[f->len - 1]) {
|
||||||
case SAVE_NEARJMP:
|
case SAVE_NEARJMP:
|
||||||
if (f->len != 3)
|
if (f->len != 3)
|
||||||
@@ -601,12 +587,111 @@ void sl_loadStack(enum save_format format, uint8_t *unaligned_data, int size) {
|
|||||||
default:
|
default:
|
||||||
SYSERROR("broken stack data");
|
SYSERROR("broken stack data");
|
||||||
}
|
}
|
||||||
struct save_stack_frame *next = f->next;
|
struct xsys35_stack_frame *next = f->next;
|
||||||
free(f);
|
free(f);
|
||||||
f = next;
|
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) {
|
void sl_getStackInfo(struct stack_info *info) {
|
||||||
memset(info, 0, sizeof(struct stack_info));
|
memset(info, 0, sizeof(struct stack_info));
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user