mirror of
https://github.com/nunuhara/xsystem4.git
synced 2026-09-30 02:48:14 +03:00
BanMisc: Use the same save format as AliceSoft's implementation
BanMisc.{Save,Load}Struct now serializes structs in the same format as
AliceSoft's implementation, rather than in JSON format. The old JSON
format can also be loaded for backwards compatibility.
This commit is contained in:
@@ -314,7 +314,7 @@ bool ADVSceneKeeper_AddADVScene(struct page **page)
|
||||
// serialize
|
||||
struct iarray_writer out;
|
||||
iarray_init_writer(&out, "SCN");
|
||||
iarray_write_struct(&out, *page);
|
||||
iarray_write_struct(&out, *page, false);
|
||||
scenes.data[scenes.n++] = iarray_to_page(&out);
|
||||
iarray_free_writer(&out);
|
||||
|
||||
@@ -341,7 +341,7 @@ bool ADVSceneKeeper_GetADVScene(int index, struct page **page)
|
||||
free_page(*page);
|
||||
}
|
||||
|
||||
*page = iarray_read_struct(&in, scene_struct_no());
|
||||
*page = iarray_read_struct(&in, scene_struct_no(), false);
|
||||
return !in.error;
|
||||
}
|
||||
|
||||
|
||||
+98
-37
@@ -17,39 +17,101 @@
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <zlib.h>
|
||||
|
||||
#include "system4/file.h"
|
||||
#include "system4/string.h"
|
||||
#include "system4/mt19937int.h"
|
||||
|
||||
#include "hll.h"
|
||||
#include "audio.h"
|
||||
#include "iarray.h"
|
||||
#include "little_endian.h"
|
||||
#include "savedata.h"
|
||||
#include "vm/page.h"
|
||||
#include "xsystem4.h"
|
||||
|
||||
#define MD11_ENCRYPT_KEY 0x18ec03
|
||||
#define MD11_HEADER_SIZE 8
|
||||
|
||||
static const uint8_t md11_signature[] = { 'M', 'D', 0x01, 0x01 };
|
||||
|
||||
static int BanMisc_SaveStruct(struct page *page, struct string *file_name)
|
||||
{
|
||||
// serialize
|
||||
struct iarray_writer out;
|
||||
iarray_init_writer(&out, NULL);
|
||||
iarray_write_struct(&out, page, true);
|
||||
size_t raw_size;
|
||||
uint8_t *raw_buf = iarray_to_buffer(&out, &raw_size);
|
||||
iarray_free_writer(&out);
|
||||
|
||||
// compress
|
||||
unsigned long compressed_size = compressBound(raw_size);
|
||||
uint8_t *buf = xmalloc(MD11_HEADER_SIZE + compressed_size);
|
||||
memcpy(buf, md11_signature, sizeof(md11_signature));
|
||||
LittleEndian_putDW(buf, 4, raw_size);
|
||||
uint8_t *compressed = buf + MD11_HEADER_SIZE;
|
||||
int r = compress2(compressed, &compressed_size, raw_buf, raw_size, Z_DEFAULT_COMPRESSION);
|
||||
free(raw_buf);
|
||||
if (r != Z_OK) {
|
||||
free(buf);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// encrypt
|
||||
mt19937_xorcode(compressed, compressed_size, MD11_ENCRYPT_KEY);
|
||||
|
||||
// write
|
||||
char *path = unix_path(file_name->text);
|
||||
FILE *fp = file_open_utf8(path, "w");
|
||||
if (!fp) {
|
||||
WARNING("Failed to open file '%s': %s", display_utf0(path), strerror(errno));
|
||||
free(path);
|
||||
return 0;
|
||||
}
|
||||
free(path);
|
||||
|
||||
cJSON *json = page_to_json(page);
|
||||
char *str = cJSON_Print(json);
|
||||
cJSON_Delete(json);
|
||||
|
||||
bool ok = fputs(str, fp) != EOF;
|
||||
free(str);
|
||||
fclose(fp);
|
||||
bool ok = file_write(path, buf, MD11_HEADER_SIZE + compressed_size);
|
||||
if (!ok) {
|
||||
WARNING("BanMisc.SaveStruct failed (fputs): %s", strerror(errno));
|
||||
return 0;
|
||||
WARNING("Failed to write file '%s': %s", display_utf0(path), strerror(errno));
|
||||
}
|
||||
return 1;
|
||||
free(buf);
|
||||
free(path);
|
||||
return ok;
|
||||
}
|
||||
|
||||
static struct page *load_md11(int struct_type, uint8_t *buf, size_t len)
|
||||
{
|
||||
if (len < MD11_HEADER_SIZE) {
|
||||
WARNING("BanMisc.LoadStruct file too short");
|
||||
return NULL;
|
||||
}
|
||||
unsigned long raw_size = LittleEndian_getDW(buf, 4);
|
||||
if (raw_size % 4 != 0) {
|
||||
WARNING("BanMisc.LoadStruct invalid file format");
|
||||
return NULL;
|
||||
}
|
||||
buf += MD11_HEADER_SIZE;
|
||||
len -= MD11_HEADER_SIZE;
|
||||
|
||||
// decrypt
|
||||
mt19937_xorcode(buf, len, MD11_ENCRYPT_KEY);
|
||||
|
||||
// decompress
|
||||
uint8_t *raw_buf = xmalloc(raw_size);
|
||||
int r = uncompress(raw_buf, &raw_size, buf, len);
|
||||
if (r != Z_OK) {
|
||||
WARNING("BanMisc.LoadStruct uncompress failed: %d", r);
|
||||
free(raw_buf);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// deserialize
|
||||
int nr_vars = raw_size / 4;
|
||||
struct page *tmp_page = alloc_page(ARRAY_PAGE, AIN_ARRAY_INT, nr_vars);
|
||||
tmp_page->array.rank = 1;
|
||||
for (int i = 0; i < nr_vars; i++) {
|
||||
tmp_page->values[i].i = LittleEndian_getDW(raw_buf, i * 4);
|
||||
}
|
||||
struct iarray_reader in;
|
||||
iarray_init_reader(&in, tmp_page, NULL);
|
||||
struct page *page = iarray_read_struct(&in, struct_type, true);
|
||||
free_page(tmp_page);
|
||||
free(raw_buf);
|
||||
return page;
|
||||
}
|
||||
|
||||
static int BanMisc_LoadStruct(struct page **_page, struct string *file_name)
|
||||
@@ -60,31 +122,30 @@ static int BanMisc_LoadStruct(struct page **_page, struct string *file_name)
|
||||
}
|
||||
|
||||
char *path = unix_path(file_name->text);
|
||||
FILE *fp = file_open_utf8(path, "r");
|
||||
if (!fp) {
|
||||
WARNING("Failed to open file '%s': %s", display_utf0(path), strerror(errno));
|
||||
free(path);
|
||||
return 0;
|
||||
}
|
||||
size_t len;
|
||||
uint8_t *buf = file_read(path, &len);
|
||||
free(path);
|
||||
|
||||
fseek(fp, 0, SEEK_END);
|
||||
long len = ftell(fp);
|
||||
fseek(fp, 0, SEEK_SET);
|
||||
|
||||
char *buf = xmalloc(len + 1);
|
||||
buf[len] = '\0';
|
||||
if (fread(buf, len, 1, fp) != 1) {
|
||||
WARNING("BanMisc.LoadStruct failed (fread): %s", strerror(errno));
|
||||
free(buf);
|
||||
if (!buf) {
|
||||
return 0;
|
||||
}
|
||||
fclose(fp);
|
||||
|
||||
cJSON *json = cJSON_Parse(buf);
|
||||
if (!memcmp(buf, md11_signature, sizeof(md11_signature))) {
|
||||
page = load_md11(page->index, buf, len);
|
||||
free(buf);
|
||||
if (!page)
|
||||
return 0;
|
||||
if (*_page) {
|
||||
delete_page_vars(*_page);
|
||||
free_page(*_page);
|
||||
}
|
||||
*_page = page;
|
||||
return 1;
|
||||
}
|
||||
// load from JSON (for backward compatibility)
|
||||
cJSON *json = cJSON_Parse((char *)buf);
|
||||
free(buf);
|
||||
if (!json) {
|
||||
WARNING("BanMisc.LoadStruct failed to parse JSON");
|
||||
WARNING("BanMisc.LoadStruct invalid file format");
|
||||
return 0;
|
||||
}
|
||||
if (!cJSON_IsArray(json)) {
|
||||
|
||||
+22
-4
@@ -16,6 +16,7 @@
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
#include "little_endian.h"
|
||||
#include "system4.h"
|
||||
#include "system4/string.h"
|
||||
#include "system4/utfsjis.h"
|
||||
@@ -108,7 +109,7 @@ static void iarray_write_value(struct iarray_writer *w, struct ain_type *t, int
|
||||
iarray_write_string(w, heap_get_string(value));
|
||||
break;
|
||||
case AIN_STRUCT:
|
||||
iarray_write_struct(w, heap_get_page(value));
|
||||
iarray_write_struct(w, heap_get_page(value), false);
|
||||
break;
|
||||
case AIN_ARRAY_INT:
|
||||
case AIN_ARRAY_FLOAT:
|
||||
@@ -122,12 +123,14 @@ static void iarray_write_value(struct iarray_writer *w, struct ain_type *t, int
|
||||
}
|
||||
}
|
||||
|
||||
void iarray_write_struct(struct iarray_writer *w, struct page *page)
|
||||
void iarray_write_struct(struct iarray_writer *w, struct page *page, bool with_type)
|
||||
{
|
||||
assert(page->type == STRUCT_PAGE);
|
||||
struct ain_struct *s = &ain->structures[page->index];
|
||||
assert(s->nr_members == page->nr_vars);
|
||||
for (int i = 0; i < s->nr_members; i++) {
|
||||
if (with_type)
|
||||
iarray_write(w, s->members[i].type.data);
|
||||
iarray_write_value(w, &s->members[i].type, page->values[i].i);
|
||||
}
|
||||
}
|
||||
@@ -202,6 +205,16 @@ struct page *iarray_to_page(struct iarray_writer *w)
|
||||
return page;
|
||||
}
|
||||
|
||||
uint8_t *iarray_to_buffer(struct iarray_writer *w, size_t *size_out)
|
||||
{
|
||||
*size_out = w->size * 4;
|
||||
uint8_t *buf = xmalloc(*size_out);
|
||||
for (unsigned i = 0; i < w->size; i++) {
|
||||
LittleEndian_putDW(buf, i * 4, w->data[i]);
|
||||
}
|
||||
return buf;
|
||||
}
|
||||
|
||||
bool iarray_init_reader(struct iarray_reader *r, struct page *a, const char *header)
|
||||
{
|
||||
r->data = a->values;
|
||||
@@ -267,7 +280,7 @@ static int32_t iarray_read_member(struct iarray_reader *r, struct ain_type *t)
|
||||
case AIN_STRING:
|
||||
return heap_alloc_string(iarray_read_string(r));
|
||||
case AIN_STRUCT:
|
||||
return heap_alloc_page(iarray_read_struct(r, t->struc));
|
||||
return heap_alloc_page(iarray_read_struct(r, t->struc, false));
|
||||
case AIN_ARRAY_INT:
|
||||
case AIN_ARRAY_FLOAT:
|
||||
case AIN_ARRAY_STRING:
|
||||
@@ -279,11 +292,16 @@ static int32_t iarray_read_member(struct iarray_reader *r, struct ain_type *t)
|
||||
}
|
||||
}
|
||||
|
||||
struct page *iarray_read_struct(struct iarray_reader *r, int struct_type)
|
||||
struct page *iarray_read_struct(struct iarray_reader *r, int struct_type, bool with_type)
|
||||
{
|
||||
struct ain_struct *s = &ain->structures[struct_type];
|
||||
struct page *page = alloc_page(STRUCT_PAGE, struct_type, s->nr_members);
|
||||
for (int i = 0; i < s->nr_members; i++) {
|
||||
if (with_type) {
|
||||
int type = iarray_read(r);
|
||||
if (type != s->members[i].type.data)
|
||||
VM_ERROR("iarray_read_struct: type mismatch");
|
||||
}
|
||||
page->values[i].i = iarray_read_member(r, &s->members[i].type);
|
||||
}
|
||||
return page;
|
||||
|
||||
+3
-2
@@ -40,7 +40,7 @@ void iarray_write_at(struct iarray_writer *w, unsigned pos, int data);
|
||||
void iarray_write_float(struct iarray_writer *w, float data);
|
||||
void iarray_write_string(struct iarray_writer *w, struct string *s);
|
||||
void iarray_write_string_or_null(struct iarray_writer *w, struct string *s);
|
||||
void iarray_write_struct(struct iarray_writer *w, struct page *page);
|
||||
void iarray_write_struct(struct iarray_writer *w, struct page *page, bool with_type);
|
||||
void iarray_write_array(struct iarray_writer *w, struct page *page);
|
||||
void iarray_write_point(struct iarray_writer *w, Point *p);
|
||||
void iarray_write_rectangle(struct iarray_writer *w, Rectangle *r);
|
||||
@@ -53,6 +53,7 @@ static inline unsigned iarray_writer_pos(struct iarray_writer *w)
|
||||
}
|
||||
|
||||
struct page *iarray_to_page(struct iarray_writer *w);
|
||||
uint8_t *iarray_to_buffer(struct iarray_writer *w, size_t *size_out);
|
||||
|
||||
struct iarray_reader {
|
||||
union vm_value *data;
|
||||
@@ -71,7 +72,7 @@ int iarray_read(struct iarray_reader *r);
|
||||
float iarray_read_float(struct iarray_reader *r);
|
||||
struct string *iarray_read_string(struct iarray_reader *r);
|
||||
struct string *iarray_read_string_or_null(struct iarray_reader *r);
|
||||
struct page *iarray_read_struct(struct iarray_reader *r, int struct_type);
|
||||
struct page *iarray_read_struct(struct iarray_reader *r, int struct_type, bool with_type);
|
||||
struct page *iarray_read_array(struct iarray_reader *r, struct ain_type *t);
|
||||
void iarray_read_point(struct iarray_reader *r, Point *p);
|
||||
void iarray_read_rectangle(struct iarray_reader *r, Rectangle *rect);
|
||||
|
||||
Reference in New Issue
Block a user