From 165d287d59f2d7d59e31a8322677fe967c748b1c Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Tue, 3 Nov 2015 22:47:21 +0100 Subject: [PATCH 01/17] fixing CID 22537, leak in cb_insert --- critbit | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/critbit b/critbit index e538739b3..77130e660 160000 --- a/critbit +++ b/critbit @@ -1 +1 @@ -Subproject commit e538739b38593b90312831a5e52d2e3bd731069b +Subproject commit 77130e660e2227ae740e06f38e85cd18ff728599 From 0c5ef21c10861a2ebd1f4ca49c1f872f390245e8 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Tue, 3 Nov 2015 22:53:19 +0100 Subject: [PATCH 02/17] CID 22434 Ignoring number of bytes read also potential missing null-termination --- src/kernel/jsonconf.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/kernel/jsonconf.c b/src/kernel/jsonconf.c index 9e23c3360..4602008f5 100644 --- a/src/kernel/jsonconf.c +++ b/src/kernel/jsonconf.c @@ -839,8 +839,9 @@ static void json_include(cJSON *json) { fseek(F, 0, SEEK_END); sz = ftell(F); rewind(F); - data = malloc(sz); - fread(data, 1, sz, F); + data = malloc(sz+1); + sz = fread(data, 1, sz, F); + data[sz] = 0; fclose(F); config = cJSON_Parse(data); free(data); From 307c5ec85bfec4561e104f9e36920cb7d793ffbd Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Tue, 3 Nov 2015 22:56:05 +0100 Subject: [PATCH 03/17] CID 22435 Unchecked return value from library --- src/kernel/save.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/kernel/save.c b/src/kernel/save.c index 45e9902ca..505120e32 100644 --- a/src/kernel/save.c +++ b/src/kernel/save.c @@ -1428,9 +1428,14 @@ int readgame(const char *filename, bool backup) READ_INT(&store, &gameid); if (gameid != game_id()) { - log_warning("game mismatch: datafile contains game %d, but config is for %d\n", gameid, game_id()); + int c; + log_warning("game mismatch: datafile contains game %d, but config is for %d", gameid, game_id()); printf("WARNING: invalid game id. any key to continue, Ctrl-C to stop\n"); - getchar(); + c = getchar(); + if (c == EOF) { + log_error("aborting."); + abort(); + } } } else { From 870d42ccfea7bb05bc9344118891df7631a08f9b Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Tue, 3 Nov 2015 23:01:09 +0100 Subject: [PATCH 04/17] CID 22442 Unchecked return value from library --- src/bind_storage.c | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/src/bind_storage.c b/src/bind_storage.c index dd67d93a8..b531b4c0f 100644 --- a/src/bind_storage.c +++ b/src/bind_storage.c @@ -34,6 +34,7 @@ static int tolua_storage_create(lua_State * L) const char *filename = tolua_tostring(L, 1, 0); const char *type = tolua_tostring(L, 2, "rb"); FILE * F; + int err = 0; F = fopen(filename, type); if (F) { @@ -42,7 +43,7 @@ static int tolua_storage_create(lua_State * L) data->store = store; if (strchr(type, 'r')) { fread(&data->version, sizeof(int), 1, F); - fseek(F, sizeof(int), SEEK_CUR); + err = fseek(F, sizeof(int), SEEK_CUR); } else if (strchr(type, 'w')) { int n = STREAM_VERSION; @@ -50,10 +51,16 @@ static int tolua_storage_create(lua_State * L) fwrite(&data->version, sizeof(int), 1, F); fwrite(&n, sizeof(int), 1, F); } - fstream_init(&data->strm, F); - binstore_init(store, &data->strm); - tolua_pushusertype(L, (void *)data, TOLUA_CAST "storage"); - return 1; + if (err) { + fclose(F); + free(data); + free(store); + } else { + fstream_init(&data->strm, F); + binstore_init(store, &data->strm); + tolua_pushusertype(L, (void *)data, TOLUA_CAST "storage"); + return 1; + } } return 0; } From f78fe8421657218d7b6f14b41a9ddf8e909e93b7 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Tue, 3 Nov 2015 23:03:40 +0100 Subject: [PATCH 05/17] CID 22443 Ignoring number of bytes read --- src/bind_storage.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/bind_storage.c b/src/bind_storage.c index b531b4c0f..ba96791af 100644 --- a/src/bind_storage.c +++ b/src/bind_storage.c @@ -35,6 +35,7 @@ static int tolua_storage_create(lua_State * L) const char *type = tolua_tostring(L, 2, "rb"); FILE * F; int err = 0; + size_t sz; F = fopen(filename, type); if (F) { @@ -42,8 +43,13 @@ static int tolua_storage_create(lua_State * L) storage *store = (storage *)calloc(1, sizeof(storage)); data->store = store; if (strchr(type, 'r')) { - fread(&data->version, sizeof(int), 1, F); - err = fseek(F, sizeof(int), SEEK_CUR); + sz = fread(&data->version, sizeof(int), 1, F); + if (sz != sizeof(int)) { + err = ferror(F); + } + else { + err = fseek(F, sizeof(int), SEEK_CUR); + } } else if (strchr(type, 'w')) { int n = STREAM_VERSION; From e6973ff3945b5a515f7faf3b527e4caa81da64b5 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Tue, 3 Nov 2015 23:05:44 +0100 Subject: [PATCH 06/17] CID 22445 Unchecked return value --- src/util/umlaut.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/util/umlaut.c b/src/util/umlaut.c index f20045b2c..73a4195c2 100644 --- a/src/util/umlaut.c +++ b/src/util/umlaut.c @@ -97,7 +97,12 @@ char * transliterate(char * out, size_t size, const char * in) } else { ucs4_t ucs; - unicode_utf8_to_ucs4(&ucs, src, &len); + int ret = unicode_utf8_to_ucs4(&ucs, src, &len); + if (ret != 0) { + /* encoding is broken. yikes */ + log_error("transliterate | encoding error in '%s'\n", src); + return NULL; + } src += len; *dst++ = '?'; --size; From fff40f048ba162b1796f6807e8c579353c0a8a3f Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Tue, 3 Nov 2015 23:11:34 +0100 Subject: [PATCH 07/17] CID 22462 Division or modulo by zero --- src/modules/autoseed.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/modules/autoseed.c b/src/modules/autoseed.c index 4ba679439..bf56bcda9 100644 --- a/src/modules/autoseed.c +++ b/src/modules/autoseed.c @@ -54,6 +54,7 @@ const terrain_type *random_terrain(const terrain_type * terrains[], const terrain_type *terrain; int n; + assert(size > 0); if (distribution) { ndistribution = 0; for (n = 0; n != size; ++n) { From 876e4122b1dbe0fdda4153394383963859f182fd Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Tue, 3 Nov 2015 23:13:04 +0100 Subject: [PATCH 08/17] CID 22463 Division or modulo by zero --- src/kernel/faction.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/kernel/faction.c b/src/kernel/faction.c index 636619310..f43539362 100755 --- a/src/kernel/faction.c +++ b/src/kernel/faction.c @@ -593,10 +593,12 @@ int skill_limit(faction * f, skill_t sk) if (sk != SK_ALCHEMY && sk != SK_MAGIC) return INT_MAX; if (f_get_alliance(f)) { - int ac = listlen(f->alliance->members); /* number of factions */ - int fl = (al + ac - 1) / ac; /* faction limit, rounded up */ + int sc, fl, ac = listlen(f->alliance->members); /* number of factions */ + + assert(ac > 0); + fl = (al + ac - 1) / ac; /* faction limit, rounded up */ /* the faction limit may not be achievable because it would break the alliance-limit */ - int sc = al - allied_skillcount(f, sk); + sc = al - allied_skillcount(f, sk); if (sc <= 0) return 0; return fl; From 1093a23d5a3cfc5e82fc53b8a0c3dd09153ef9ed Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Tue, 3 Nov 2015 23:14:06 +0100 Subject: [PATCH 09/17] CID 22464 Division or modulo by zero --- src/kernel/faction.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/kernel/faction.c b/src/kernel/faction.c index f43539362..fe4a7ad38 100755 --- a/src/kernel/faction.c +++ b/src/kernel/faction.c @@ -160,6 +160,9 @@ const unit *random_unit_in_faction(const faction * f) unit *u; int c = 0, u_nr; + if (!f->units) { + return NULL; + } for (u = f->units; u; u = u->next) c++; From 103c480c91f340aee222e216479817a6d155fd44 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Tue, 3 Nov 2015 23:15:26 +0100 Subject: [PATCH 10/17] CID 22465 Division or modulo by zero --- src/battle.c | 33 +++++++++++++++++---------------- 1 file changed, 17 insertions(+), 16 deletions(-) diff --git a/src/battle.c b/src/battle.c index f4d3bc5a7..08a170e42 100644 --- a/src/battle.c +++ b/src/battle.c @@ -300,9 +300,8 @@ fighter *select_corpse(battle * b, fighter * af) * * Untote werden nicht ausgewählt (casualties, not dead) */ { - int si, di, maxcasualties = 0; + int si, maxcasualties = 0; fighter *df; - side *s; for (si = 0; si != b->nsides; ++si) { side *s = b->sides + si; @@ -310,24 +309,26 @@ fighter *select_corpse(battle * b, fighter * af) maxcasualties += s->casualties; } } - di = (int)(rng_int() % maxcasualties); - for (s = b->sides; s != b->sides + b->nsides; ++s) { - for (df = s->fighters; df; df = df->next) { - /* Geflohene haben auch 0 hp, dürfen hier aber nicht ausgewählt - * werden! */ - int dead = dead_fighters(df); - if (!playerrace(u_race(df->unit))) - continue; + if (maxcasualties > 0) { + int di = (int)(rng_int() % maxcasualties); + side *s; + for (s = b->sides; s != b->sides + b->nsides; ++s) { + for (df = s->fighters; df; df = df->next) { + /* Geflohene haben auch 0 hp, dürfen hier aber nicht ausgewählt + * werden! */ + int dead = dead_fighters(df); + if (!playerrace(u_race(df->unit))) + continue; - if (af && !helping(af->side, df->side)) - continue; - if (di < dead) { - return df; + if (af && !helping(af->side, df->side)) + continue; + if (di < dead) { + return df; + } + di -= dead; } - di -= dead; } } - return NULL; } From 1f055b31753d7a438b233c1492cb461b19143025 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Tue, 3 Nov 2015 23:17:11 +0100 Subject: [PATCH 11/17] CID 22466 Division or modulo by zero --- src/names.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/names.c b/src/names.c index e32d553d7..eb70fa5f4 100644 --- a/src/names.c +++ b/src/names.c @@ -421,8 +421,7 @@ const char *abkz(const char *s, char *buf, size_t buflen, size_t maxchars) } /* Buchstaben pro Teilkürzel = _max(1,max/AnzWort) */ - - bpt = _max(1, maxchars / c); + bpt = (c > 0) ? _max(1, maxchars / c) : 1; /* Einzelne Wörter anspringen und jeweils die ersten BpT kopieren */ From 7efda5f967fcd7ea27059c35017cc9599ca543b6 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Tue, 3 Nov 2015 23:18:56 +0100 Subject: [PATCH 12/17] CID 22468 Division or modulo by zero --- src/names.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/names.c b/src/names.c index eb70fa5f4..71c4c6504 100644 --- a/src/names.c +++ b/src/names.c @@ -91,7 +91,7 @@ static const char *make_names(const char *monster, int *num_postfix, uu = rng_int() % *num_name; /* nur 50% aller Namen haben "Nach-Teil", wenn kein Vor-Teil */ - if (uv >= *num_prefix) { + if (*num_postfix > 0 && uv >= *num_prefix) { un = rng_int() % *num_postfix; } else { From 04b5bc0c601bc0092d11a326bde2920b0f9c9e10 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Tue, 3 Nov 2015 23:19:35 +0100 Subject: [PATCH 13/17] CID 22474 Evaluation order violation --- src/kernel/race.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/kernel/race.c b/src/kernel/race.c index 0339a1b49..191c4f27d 100644 --- a/src/kernel/race.c +++ b/src/kernel/race.c @@ -244,7 +244,7 @@ const char *raceprefix(const unit * u) const attrib *asource = u->faction->attribs; if (fval(u, UFL_GROUP)) { - const attrib *agroup = agroup = a_findc(u->attribs, &at_group); + const attrib *agroup = a_findc(u->attribs, &at_group); if (agroup != NULL) asource = ((const group *)(agroup->data.v))->attribs; } From 0be8724093429d4a9207878c9f899c28dc99cd56 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Wed, 4 Nov 2015 07:56:19 +0100 Subject: [PATCH 14/17] CID 22475 Dereference after null check --- src/bindings.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/src/bindings.c b/src/bindings.c index c2f18d8d5..a684f4e20 100755 --- a/src/bindings.c +++ b/src/bindings.c @@ -1,4 +1,4 @@ -/* +/* +-------------------+ | | Enno Rehling | Eressea PBEM host | Christian Schlittchen @@ -250,11 +250,15 @@ static int tolua_message_faction(lua_State * L) unit *sender = (unit *)tolua_tousertype(L, 1, 0); faction *target = (faction *)tolua_tousertype(L, 2, 0); const char *str = tolua_tostring(L, 3, 0); - if (!target) + if (!target) { tolua_error(L, TOLUA_CAST "target is nil", NULL); - if (!sender) + } + else if (!sender) { tolua_error(L, TOLUA_CAST "sender is nil", NULL); - deliverMail(target, sender->region, sender, str, NULL); + } + else { + deliverMail(target, sender->region, sender, str, NULL); + } return 0; } @@ -1172,7 +1176,7 @@ int eressea_run(lua_State *L, const char *luafile) if (err != 0) { log_lua_error(L); } - else { + else { if (lua_isnumber(L, -1)) { err = (int)lua_tonumber(L, -1); } From dedbd67d071c42c06387d4872c806e4462a25019 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Wed, 4 Nov 2015 09:36:09 +0100 Subject: [PATCH 15/17] re-apply fix for CID 22551: dereference before null check (merge conflict) --- src/spells/flyingship.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/spells/flyingship.c b/src/spells/flyingship.c index 7751451ed..da57ddd93 100644 --- a/src/spells/flyingship.c +++ b/src/spells/flyingship.c @@ -154,9 +154,11 @@ static curse *shipcurse_flyingship(ship * sh, unit * mage, double power, int dur /* mit C_SHIP_NODRIFT haben wir kein Problem */ curse *c = create_curse(mage, &sh->attribs, ct_flyingship, power, duration, 0.0, 0); - c->data.v = sh; - if (c && c->duration > 0) { - sh->flags |= SF_FLYING; + if (c) { + c->data.v = sh; + if (c->duration > 0) { + sh->flags |= SF_FLYING; + } } return c; } From c57668e6ee97fc2f0afd40a71dca3d622baf9bfb Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Wed, 4 Nov 2015 09:48:51 +0100 Subject: [PATCH 16/17] failing test for newly discovered storage problems --- scripts/tests/storage.lua | 3 +++ src/kernel/save.c | 3 +-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/scripts/tests/storage.lua b/scripts/tests/storage.lua index 065cca57c..0aa0b45f7 100644 --- a/scripts/tests/storage.lua +++ b/scripts/tests/storage.lua @@ -25,6 +25,9 @@ function test_store_unit() store = storage.create(filename, "rb") assert_not_nil(store) u = store:read_unit() + assert_not_nil(u) + assert_equal(r, u.region) + assert_equal(f, u.faction) store:close() os.remove(filename) assert_not_nil(u) diff --git a/src/kernel/save.c b/src/kernel/save.c index 505120e32..3111c09e5 100644 --- a/src/kernel/save.c +++ b/src/kernel/save.c @@ -613,8 +613,7 @@ unit *read_unit(struct gamedata *data) ++u->faction->no_units; } else { - log_error("unit %s has faction == NULL\n", unitname(u)); - assert(u->faction); + log_error("unit %s has faction == NULL\n", itoa36(u->no)); return 0; } From 024e4c45ca03097f9186cfd8e742d2d383aa317c Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Wed, 4 Nov 2015 10:38:12 +0100 Subject: [PATCH 17/17] fix a bug introduced by f78fe842 (CID 22443) --- scripts/tests/storage.lua | 2 +- src/bind_storage.c | 41 +++++----------------------- src/kernel/save.c | 44 ++++++++++++++++++++++++++++++ src/kernel/save.h | 56 ++++++++++++++++++++------------------- src/kernel/save.test.c | 38 ++++++++++++++++++++++++++ storage | 2 +- 6 files changed, 119 insertions(+), 64 deletions(-) diff --git a/scripts/tests/storage.lua b/scripts/tests/storage.lua index 0aa0b45f7..c262652db 100644 --- a/scripts/tests/storage.lua +++ b/scripts/tests/storage.lua @@ -26,8 +26,8 @@ function test_store_unit() assert_not_nil(store) u = store:read_unit() assert_not_nil(u) - assert_equal(r, u.region) assert_equal(f, u.faction) + assert_equal(nil, u.region) store:close() os.remove(filename) assert_not_nil(u) diff --git a/src/bind_storage.c b/src/bind_storage.c index ba96791af..ca83f199a 100644 --- a/src/bind_storage.c +++ b/src/bind_storage.c @@ -33,40 +33,12 @@ static int tolua_storage_create(lua_State * L) { const char *filename = tolua_tostring(L, 1, 0); const char *type = tolua_tostring(L, 2, "rb"); - FILE * F; - int err = 0; - size_t sz; + gamedata *data; - F = fopen(filename, type); - if (F) { - gamedata *data = (gamedata *)calloc(1, sizeof(gamedata)); - storage *store = (storage *)calloc(1, sizeof(storage)); - data->store = store; - if (strchr(type, 'r')) { - sz = fread(&data->version, sizeof(int), 1, F); - if (sz != sizeof(int)) { - err = ferror(F); - } - else { - err = fseek(F, sizeof(int), SEEK_CUR); - } - } - else if (strchr(type, '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); - tolua_pushusertype(L, (void *)data, TOLUA_CAST "storage"); - return 1; - } + data = gamedata_open(filename, type); + if (data) { + tolua_pushusertype(L, (void *)data, TOLUA_CAST "storage"); + return 1; } return 0; } @@ -134,8 +106,7 @@ static int tolua_storage_tostring(lua_State * L) static int tolua_storage_close(lua_State * L) { gamedata *data = (gamedata *)tolua_tousertype(L, 1, 0); - binstore_done(data->store); - fstream_done(&data->strm); + gamedata_close(data); return 0; } diff --git a/src/kernel/save.c b/src/kernel/save.c index 3111c09e5..cb942c83f 100644 --- a/src/kernel/save.c +++ b/src/kernel/save.c @@ -1887,6 +1887,50 @@ 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; + } + } + 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 11b53d620..ca364fc9c 100644 --- a/src/kernel/save.h +++ b/src/kernel/save.h @@ -42,44 +42,46 @@ extern "C" { /* Nach MAX_INPUT_SIZE brechen wir das Einlesen der Zeile ab und nehmen an, * dass hier ein Fehler (fehlende ") vorliegt */ + extern int data_version; + extern int enc_gamedata; + int readorders(const char *filename); int creategame(void); int readgame(const char *filename, bool backup); int writegame(const char *filename); - /* Versionsänderungen: */ - extern int data_version; - extern int enc_gamedata; + int current_turn(void); - extern int current_turn(void); + void read_items(struct storage *store, struct item **it); + void write_items(struct storage *store, struct item *it); - extern void read_items(struct storage *store, struct item **it); - extern void write_items(struct storage *store, struct item *it); + void read_spellbook(struct spellbook **bookp, struct storage *store, int(*get_level)(const struct spell * sp, void *), void * cbdata); + void write_spellbook(const struct spellbook *book, struct storage *store); - extern void read_spellbook(struct spellbook **bookp, struct storage *store, int(*get_level)(const struct spell * sp, void *), void * cbdata); - extern void write_spellbook(const struct spellbook *book, struct storage *store); + void write_unit(struct gamedata *data, const struct unit *u); + struct unit *read_unit(struct gamedata *data); - extern void write_unit(struct gamedata *data, const struct unit *u); - extern struct unit *read_unit(struct gamedata *data); + int a_readint(struct attrib *a, void *owner, struct storage *store); + void a_writeint(const struct attrib *a, const void *owner, + struct storage *store); + int a_readshorts(struct attrib *a, void *owner, struct storage *store); + void a_writeshorts(const struct attrib *a, const void *owner, + struct storage *store); + int a_readchars(struct attrib *a, void *owner, struct storage *store); + void a_writechars(const struct attrib *a, const void *owner, + struct storage *store); + int a_readvoid(struct attrib *a, void *owner, struct storage *store); + void a_writevoid(const struct attrib *a, const void *owner, + struct storage *store); + int a_readstring(struct attrib *a, void *owner, struct storage *store); + void a_writestring(const struct attrib *a, const void *owner, + struct storage *store); + void a_finalizestring(struct attrib *a); - extern int a_readint(struct attrib *a, void *owner, struct storage *store); - extern void a_writeint(const struct attrib *a, const void *owner, - struct storage *store); - extern int a_readshorts(struct attrib *a, void *owner, struct storage *store); - extern void a_writeshorts(const struct attrib *a, const void *owner, - struct storage *store); - extern int a_readchars(struct attrib *a, void *owner, struct storage *store); - extern void a_writechars(const struct attrib *a, const void *owner, - struct storage *store); - extern int a_readvoid(struct attrib *a, void *owner, struct storage *store); - extern void a_writevoid(const struct attrib *a, const void *owner, - struct storage *store); - extern int a_readstring(struct attrib *a, void *owner, struct storage *store); - extern void a_writestring(const struct attrib *a, const void *owner, - struct storage *store); - extern void a_finalizestring(struct attrib *a); + void create_backup(char *file); - extern void create_backup(char *file); + struct gamedata *gamedata_open(const char *filename, const char *mode); + void gamedata_close(struct gamedata *data); #ifdef __cplusplus } diff --git a/src/kernel/save.test.c b/src/kernel/save.test.c index 26f48a07f..fd8ff48ea 100644 --- a/src/kernel/save.test.c +++ b/src/kernel/save.test.c @@ -2,6 +2,8 @@ #include #include "save.h" +#include "unit.h" +#include "faction.h" #include "version.h" #include #include @@ -21,9 +23,45 @@ static void test_readwrite_data(CuTest * tc) test_cleanup(); } +static void test_readwrite_unit(CuTest * tc) +{ + const char *filename = "test.dat"; + char path[MAX_PATH]; + gamedata *data; + struct unit *u; + struct region *r; + struct faction *f; + int fno; + + test_cleanup(); + r = test_create_region(0, 0, 0); + f = test_create_faction(0); + fno = f->no; + u = test_create_unit(f, r); + sprintf(path, "%s/%s", datapath(), filename); + + data = gamedata_open(path, "wb"); + write_unit(data, u); + gamedata_close(data); + + free_gamedata(); + f = test_create_faction(0); + renumber_faction(f, fno); + data = gamedata_open(path, "rb"); + u = read_unit(data); + gamedata_close(data); + + CuAssertPtrNotNull(tc, u); + CuAssertPtrEquals(tc, f, u->faction); + CuAssertPtrEquals(tc, 0, u->region); + CuAssertIntEquals(tc, 0, remove(path)); + test_cleanup(); +} + CuSuite *get_save_suite(void) { CuSuite *suite = CuSuiteNew(); SUITE_ADD_TEST(suite, test_readwrite_data); + SUITE_ADD_TEST(suite, test_readwrite_unit); return suite; } diff --git a/storage b/storage index 86b967441..1d92cb36d 160000 --- a/storage +++ b/storage @@ -1 +1 @@ -Subproject commit 86b96744157eb08c55998df4c12fa2e073005b49 +Subproject commit 1d92cb36df41c183c378aad17cbbfc0eddbb5c84