diff --git a/src/bind_storage.c b/src/bind_storage.c index ca83f199a..70ae1736b 100644 --- a/src/bind_storage.c +++ b/src/bind_storage.c @@ -35,7 +35,7 @@ static int tolua_storage_create(lua_State * L) const char *type = tolua_tostring(L, 2, "rb"); gamedata *data; - data = gamedata_open(filename, type); + data = gamedata_open(filename, type, RELEASE_VERSION); if (data) { tolua_pushusertype(L, (void *)data, TOLUA_CAST "storage"); return 1; diff --git a/src/kernel/save.c b/src/kernel/save.c index ec16f8517..10dea2736 100644 --- a/src/kernel/save.c +++ b/src/kernel/save.c @@ -60,6 +60,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include #include #include +#include #include #include #include @@ -1954,51 +1955,6 @@ int writegame(const char *filename) return 0; } -void gamedata_close(gamedata *data) { - binstore_done(data->store); - fstream_done(&data->strm); -} - -gamedata *gamedata_open(const char *filename, const char *mode) { - FILE *F = fopen(filename, mode); - - if (F) { - gamedata *data = (gamedata *)calloc(1, sizeof(gamedata)); - storage *store = (storage *)calloc(1, sizeof(storage)); - int err = 0; - size_t sz; - - data->store = store; - if (strchr(mode, 'r')) { - sz = fread(&data->version, 1, sizeof(int), F); - if (sz != sizeof(int)) { - err = ferror(F); - } - else { - err = fseek(F, sizeof(int), SEEK_CUR); - } - } - else if (strchr(mode, 'w')) { - int n = STREAM_VERSION; - data->version = RELEASE_VERSION; - fwrite(&data->version, sizeof(int), 1, F); - fwrite(&n, sizeof(int), 1, F); - } - if (err) { - fclose(F); - free(data); - free(store); - } - else { - fstream_init(&data->strm, F); - binstore_init(store, &data->strm); - return data; - } - } - log_error("could not open %s: %s", filename, strerror(errno)); - return 0; -} - int a_readint(attrib * a, void *owner, struct storage *store) { /* assert(sizeof(int)==sizeof(a->data)); */ diff --git a/src/kernel/save.h b/src/kernel/save.h index 01773f5f7..6c641719e 100644 --- a/src/kernel/save.h +++ b/src/kernel/save.h @@ -20,6 +20,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #define H_KRNL_SAVE #include +#include // FIXME: eliminate include dependency from this file #ifdef __cplusplus extern "C" { #endif @@ -31,13 +32,6 @@ extern "C" { struct spellbook; struct unit; - typedef struct gamedata { - struct storage *store; - stream strm; - int version; - int encoding; - } gamedata; - #define MAX_INPUT_SIZE DISPLAYSIZE*2 /* Nach MAX_INPUT_SIZE brechen wir das Einlesen der Zeile ab und nehmen an, * dass hier ein Fehler (fehlende ") vorliegt */ @@ -83,9 +77,6 @@ extern "C" { void create_backup(char *file); - struct gamedata *gamedata_open(const char *filename, const char *mode); - void gamedata_close(struct gamedata *data); - /* test-only functions that give access to internal implementation details (BAD) */ void _test_write_password(struct gamedata *data, const struct faction *f); void _test_read_password(struct gamedata *data, struct faction *f); diff --git a/src/kernel/save.test.c b/src/kernel/save.test.c index b7af173ef..b89a82c32 100644 --- a/src/kernel/save.test.c +++ b/src/kernel/save.test.c @@ -1,6 +1,7 @@ #include #include #include +#include #include #include "save.h" @@ -43,7 +44,7 @@ static void test_readwrite_unit(CuTest * tc) { const char *filename = "test.dat"; char path[MAX_PATH]; - gamedata *data; + gamedata data; struct unit *u; struct region *r; struct faction *f; @@ -58,20 +59,16 @@ static void test_readwrite_unit(CuTest * tc) u = test_create_unit(f, r); join_path(datapath(), filename, path, sizeof(path)); - data = gamedata_open(path, "wb"); - CuAssertPtrNotNull(tc, data); // TODO: intermittent test (even after the 'b' fix!) - - write_unit(data, u); - gamedata_close(data); - + CuAssertIntEquals(tc, 0, gamedata_openfile(&data, path, "wb", RELEASE_VERSION)); // TODO: intermittent test (even after the 'b' fix!) + write_unit(&data, u); + gamedata_close(&data); + free_gamedata(); f = test_create_faction(0); renumber_faction(f, fno); - data = gamedata_open(path, "rb"); - CuAssertPtrNotNull(tc, data); - - u = read_unit(data); - gamedata_close(data); + CuAssertIntEquals(tc, 0, gamedata_openfile(&data, path, "rb", RELEASE_VERSION)); // TODO: intermittent test (even after the 'b' fix!) + u = read_unit(&data); + gamedata_close(&data); CuAssertPtrNotNull(tc, u); CuAssertPtrEquals(tc, f, u->faction); @@ -86,7 +83,7 @@ static void test_readwrite_attrib(CuTest *tc) { const char *path = "attrib.dat"; test_cleanup(); global.data_version = RELEASE_VERSION; // FIXME: hack! - data = gamedata_open(path, "wb"); + data = gamedata_open(path, "wb", RELEASE_VERSION); CuAssertPtrNotNull(tc, data); key_set(&a, 41); key_set(&a, 42); @@ -95,7 +92,7 @@ static void test_readwrite_attrib(CuTest *tc) { a_removeall(&a, NULL); CuAssertPtrEquals(tc, 0, a); - data = gamedata_open(path, "rb"); + data = gamedata_open(path, "rb", RELEASE_VERSION); CuAssertPtrNotNull(tc, data); read_attribs(data->store, &a, NULL); gamedata_close(data); @@ -237,11 +234,11 @@ static void test_read_password(CuTest *tc) { faction *f; f = test_create_faction(0); faction_setpassword(f, password_encode("secret", PASSWORD_DEFAULT)); - data = gamedata_open(path, "wb"); + data = gamedata_open(path, "wb", RELEASE_VERSION); CuAssertPtrNotNull(tc, data); _test_write_password(data, f); gamedata_close(data); - data = gamedata_open(path, "rb"); + data = gamedata_open(path, "rb", RELEASE_VERSION); CuAssertPtrNotNull(tc, data); _test_read_password(data, f); gamedata_close(data); @@ -259,12 +256,12 @@ static void test_read_password_external(CuTest *tc) { f = test_create_faction(0); faction_setpassword(f, password_encode("secret", PASSWORD_DEFAULT)); CuAssertPtrNotNull(tc, f->_password); - data = gamedata_open(path, "wb"); + data = gamedata_open(path, "wb", RELEASE_VERSION); CuAssertPtrNotNull(tc, data); WRITE_TOK(data->store, (const char *)f->_password); WRITE_TOK(data->store, (const char *)f->_password); gamedata_close(data); - data = gamedata_open(path, "rb"); + data = gamedata_open(path, "rb", RELEASE_VERSION); CuAssertPtrNotNull(tc, data); data->version = BADCRYPT_VERSION; _test_read_password(data, f); diff --git a/src/util/CMakeLists.txt b/src/util/CMakeLists.txt index a441bcfe7..f844cc490 100644 --- a/src/util/CMakeLists.txt +++ b/src/util/CMakeLists.txt @@ -23,6 +23,7 @@ event.c filereader.c functions.c goodies.c +gamedata.c language.c lists.c log.c diff --git a/src/util/gamedata.c b/src/util/gamedata.c new file mode 100644 index 000000000..8b2de60d0 --- /dev/null +++ b/src/util/gamedata.c @@ -0,0 +1,98 @@ +#include + +#include "gamedata.h" +#include "log.h" + +#include +#include +#include +#include + +#include +#include +#include + +void gamedata_close(gamedata *data) { + binstore_done(data->store); + fstream_done(&data->strm); +} + +void gamedata_init(gamedata *data, storage *store, int version) { + data->version = version; + data->store = store; + binstore_init(data->store, &data->strm); +} + +int gamedata_openfile(gamedata *data, const char *filename, const char *mode, int version) { + FILE *F = fopen(filename, mode); + if (F) { + int err = 0; + + if (strchr(mode, 'r')) { + size_t sz; + sz = fread(&version, 1, sizeof(int), F); + if (sz != sizeof(int)) { + err = ferror(F); + } + else { + err = fseek(F, sizeof(int), SEEK_CUR); + } + } + else if (strchr(mode, 'w')) { + int n = STREAM_VERSION; + fwrite(&version, sizeof(int), 1, F); + fwrite(&n, sizeof(int), 1, F); + } + if (err) { + fclose(F); + free(data); + } + else { + storage *store = malloc(sizeof(storage)); + fstream_init(&data->strm, F); + gamedata_init(data, store, version); + } + return err; + } + return errno; +} + +gamedata *gamedata_open(const char *filename, const char *mode, int version) { + FILE *F = fopen(filename, mode); + + if (F) { + gamedata *data = (gamedata *)calloc(1, sizeof(gamedata)); + storage *store = (storage *)calloc(1, sizeof(storage)); + int err = 0; + size_t sz; + + data->store = store; + if (strchr(mode, 'r')) { + sz = fread(&data->version, 1, sizeof(int), F); + if (sz != sizeof(int)) { + err = ferror(F); + } + else { + err = fseek(F, sizeof(int), SEEK_CUR); + } + } + else if (strchr(mode, 'w')) { + int n = STREAM_VERSION; + data->version = version; + fwrite(&data->version, sizeof(int), 1, F); + fwrite(&n, sizeof(int), 1, F); + } + if (err) { + fclose(F); + free(data); + free(store); + } + else { + fstream_init(&data->strm, F); + binstore_init(store, &data->strm); + return data; + } + } + log_error("could not open %s: %s", filename, strerror(errno)); + return 0; +} diff --git a/src/util/gamedata.h b/src/util/gamedata.h new file mode 100644 index 000000000..e0ac54c30 --- /dev/null +++ b/src/util/gamedata.h @@ -0,0 +1,23 @@ +#pragma once + +#ifndef _GAMEDATA_H +#define _GAMEDATA_H + +#include + +struct storage; + +typedef struct gamedata { + struct storage *store; + stream strm; + int version; + int encoding; +} gamedata; + +void gamedata_close(struct gamedata *data); +struct gamedata *gamedata_open(const char *filename, const char *mode, int version); +int gamedata_openfile(gamedata *data, const char *filename, const char *mode, int version); + +#define STREAM_VERSION 2 /* internal encoding of binary files */ + +#endif