From 4afd54bb897988eae902bfc3924e8c31bb4d6e1e Mon Sep 17 00:00:00 2001 From: Nunuhara Cabbage Date: Sun, 2 Aug 2020 14:28:23 -0700 Subject: [PATCH] ACXLoader: implement GetDataString Strings are embedded in the rows, making them variable length. So we now deserialize the whole ACX file in ACXLoader.Load and store them such that they can be indexed by row/col in constant time. --- src/hll/ACXLoader.c | 85 +++++++++++++++++++++++++++++++++++---------- src/hll/Confirm2.c | 12 ++++++- 2 files changed, 77 insertions(+), 20 deletions(-) diff --git a/src/hll/ACXLoader.c b/src/hll/ACXLoader.c index c2203fe..8983225 100644 --- a/src/hll/ACXLoader.c +++ b/src/hll/ACXLoader.c @@ -26,17 +26,50 @@ #include "vm/page.h" #include "xsystem4.h" +union acx_value { + int32_t i; + struct string *s; +}; + struct acx_file { int compressed_size; - int size; int nr_columns; int nr_lines; - uint8_t *data_raw; - uint8_t *data; + int32_t *column_types; + union acx_value *lines; }; static struct acx_file acx; +static void acx_read(uint8_t *data_raw) +{ + acx.nr_columns = LittleEndian_getDW(data_raw, 0); + acx.nr_lines = LittleEndian_getDW(data_raw, 4 + acx.nr_columns * 4); + uint8_t *data = data_raw + (8 + acx.nr_columns * 4); + + acx.column_types = xcalloc(acx.nr_columns, sizeof(int32_t)); + for (int i = 0; i < acx.nr_columns; i++) { + acx.column_types[i] = LittleEndian_getDW(data_raw, 4 + 4*i); + } + + int ptr = 0; + acx.lines = xcalloc(acx.nr_lines * acx.nr_columns, sizeof(union acx_value)); + for (int line = 0; line < acx.nr_lines; line++) { + for (int col = 0; col < acx.nr_columns; col++) { + if (acx.column_types[col] == 2) { + int old_ptr = ptr; + while (data[ptr]) + ptr++; + acx.lines[line*acx.nr_columns + col].s = make_string((char*)data+old_ptr, ptr-old_ptr); + ptr++; + } else { + acx.lines[line*acx.nr_columns + col].i = LittleEndian_getDW(data, ptr); + ptr += 4; + } + } + } +} + //bool Load(string pIFileName) bool ACXLoader_Load(struct string *filename) { @@ -68,28 +101,35 @@ bool ACXLoader_Load(struct string *filename) return false; } - acx.compressed_size = LittleEndian_getDW(buf, 8); - acx.size = LittleEndian_getDW(buf, 12); - acx.data_raw = xmalloc(acx.size); + int compressed_size = LittleEndian_getDW(buf, 8); + unsigned long size = LittleEndian_getDW(buf, 12); + uint8_t *data_raw = xmalloc(size); - unsigned long size = acx.size; - if (Z_OK != uncompress(acx.data_raw, &size, buf+16, len-16)) { + if (Z_OK != uncompress(data_raw, &size, buf+16, compressed_size)) { WARNING("ACXLoader.Load: uncompress failed"); free(buf); + free(data_raw); return false; } - acx.nr_columns = LittleEndian_getDW(acx.data_raw, 0); - acx.nr_lines = LittleEndian_getDW(acx.data_raw, 4 + acx.nr_columns * 4); - acx.data = acx.data_raw + (8 + acx.nr_columns * 4); + acx_read(data_raw); free(buf); + free(data_raw); return true; } void ACXLoader_Release(void) { - free(acx.data_raw); + for (int col = 0; col < acx.nr_columns; col++) { + if (acx.column_types[col] != 2) + continue; + for (int line = 0; line < acx.nr_lines; line++) { + free_string(acx.lines[line*acx.nr_columns+col].s); + } + } + free(acx.lines); + free(acx.column_types); memset(&acx, 0, sizeof(struct acx_file)); } @@ -105,17 +145,21 @@ int ACXLoader_GetNumofColumn(void) bool ACXLoader_GetDataInt(int line, int col, int *ptr) { - if (line < 0 || line >= acx.nr_lines || col < 0 || col >= acx.nr_columns) return false; - uint8_t *data = acx.data + (line * acx.nr_columns * 4) + (col * 4); - *ptr = LittleEndian_getDW(data, 0); - + *ptr = acx.lines[line*acx.nr_columns + col].i; return true; } -HLL_UNIMPLEMENTED(bool, ACXLoader, GetDataString, int line, int col, struct string *data); +bool ACXLoader_GetDataString(int line, int col, struct string **ptr) +{ + if (line < 0 || line >= acx.nr_lines || col < 0 || col >= acx.nr_columns) + return false; + + *ptr = string_ref(acx.lines[line*acx.nr_columns + col].s); + return true; +} bool ACXLoader_GetDataStruct(int line, struct page **page) { @@ -124,9 +168,12 @@ bool ACXLoader_GetDataStruct(int line, struct page **page) if (line >= acx.nr_lines) return false; - uint8_t *data = acx.data + (line * acx.nr_columns * 4); for (int i = 0; i < acx.nr_columns; i++) { - s[i].i = LittleEndian_getDW(data, i*4); + if (acx.column_types[i] == 2) { + s[i].i = vm_string_ref(acx.lines[line*acx.nr_columns + i].s); + } else { + s[i].i = acx.lines[line*acx.nr_columns + i].i; + } } return true; diff --git a/src/hll/Confirm2.c b/src/hll/Confirm2.c index 7ff24c6..3d0614a 100644 --- a/src/hll/Confirm2.c +++ b/src/hll/Confirm2.c @@ -14,6 +14,7 @@ * along with this program; if not, see . */ +#include "system4/string.h" #include "hll.h" HLL_WARN_UNIMPLEMENTED( , void, Confirm2, Init, void *imainsystem); @@ -21,8 +22,17 @@ HLL_WARN_UNIMPLEMENTED(1, int, Confirm2, ExistKeyFile, struct string *filename, HLL_UNIMPLEMENTED(int, Confirm2, CheckProtectFile, struct string *filename, int keynum); HLL_UNIMPLEMENTED(int, Confirm2, CreateKeyFile, struct string *filename, int keynum); + +void Confirm2_ExistKeyFile2(possibly_unused struct string *pIFileName, possibly_unused int nKeyNum, struct string **pIResult) +{ + // XXX: this is the magic value for Yokubori Saboten + // need to check if this works for other games + *pIResult = make_string("moke-", 5); +} + HLL_LIBRARY(Confirm2, HLL_EXPORT(Init, Confirm2_Init), HLL_EXPORT(ExistKeyFile, Confirm2_ExistKeyFile), HLL_EXPORT(CheckProtectFile, Confirm2_CheckProtectFile), - HLL_EXPORT(CreateKeyFile, Confirm2_CreateKeyFile)); + HLL_EXPORT(CreateKeyFile, Confirm2_CreateKeyFile), + HLL_EXPORT(ExistKeyFile2, Confirm2_ExistKeyFile2));