diff --git a/sc2/src/uqm/load.c b/sc2/src/uqm/load.c index e115273b6..b4da899ec 100644 --- a/sc2/src/uqm/load.c +++ b/sc2/src/uqm/load.c @@ -160,6 +160,18 @@ read_a8 (void *fp, BYTE *ar, COUNT count) return ReadResFile (ar, 1, count, fp) == count; } +static inline size_t +skip_8 (void *fp, COUNT count) +{ + int i; + for (i = 0; i < count; ++i) + { + if (read_8(fp, NULL) != 1) + return 0; + } + return 1; +} + static inline size_t read_str (void *fp, char *str, COUNT count) { @@ -478,7 +490,7 @@ LoadGameState (GAME_STATE *GSPtr, DECODE_REF fh) } static BOOLEAN -LoadSisState (SIS_STATE *SSPtr, void *fp, SDWORD first) +LoadSisState (SIS_STATE *SSPtr, void *fp, SDWORD first, BOOLEAN legacy) { SSPtr->log_x = first; if ( @@ -496,26 +508,31 @@ LoadSisState (SIS_STATE *SSPtr, void *fp, SDWORD first) read_str (fp, SSPtr->ShipName, SIS_NAME_SIZE) != 1 || read_str (fp, SSPtr->CommanderName, SIS_NAME_SIZE) != 1 || - read_str (fp, SSPtr->PlanetName, SIS_NAME_SIZE) != 1 || - - read_16 (fp, NULL) != 1 /* padding */ + read_str (fp, SSPtr->PlanetName, SIS_NAME_SIZE) != 1 ) return FALSE; - else - return TRUE; + if (legacy && (read_16 (fp, NULL) != 1)) + return FALSE; + return TRUE; } static BOOLEAN -LoadSummary (SUMMARY_DESC *SummPtr, void *fp) +LoadSummary (SUMMARY_DESC *SummPtr, void *fp, BOOLEAN *legacy_ptr) { SDWORD magic; + DWORD nameSize = 0; BOOLEAN legacy; - SummPtr->SaveName[0] = 0; if (!read_32s (fp, &magic)) return FALSE; if (magic == SAVE_MAGIC) { legacy = FALSE; + *legacy_ptr = FALSE; + if (read_32 (fp, &magic) != 1 || magic != SUMMARY_MAGIC) + return FALSE; + if (read_32 (fp, &magic) != 1 || magic < 161) + return FALSE; + nameSize = magic - 160; // Read in the real first value for LoadSisState if (read_32 (fp, &magic) != 1) return FALSE; @@ -525,9 +542,10 @@ LoadSummary (SUMMARY_DESC *SummPtr, void *fp) // Otherwise, we're legacy and the "magic" number was // really LoadSisState's first value legacy = TRUE; + *legacy_ptr = TRUE; } - if (!LoadSisState (&SummPtr->SS, fp, magic)) + if (!LoadSisState (&SummPtr->SS, fp, magic, legacy)) return FALSE; if ( @@ -544,14 +562,32 @@ LoadSummary (SUMMARY_DESC *SummPtr, void *fp) read_a8 (fp, SummPtr->DeviceList, MAX_EXCLUSIVE_DEVICES) != 1 ) return FALSE; - if (!legacy && (read_a8 (fp, SummPtr->SaveName, SAVE_NAME_SIZE) != 1)) - return FALSE; - // Don't trust the savefile to properly null-terminate! - SummPtr->SaveName[SAVE_NAME_SIZE-1] = 0; - if (read_16 (fp, NULL) != 1) /* padding */ - return FALSE; + + if (!legacy) + { + if (nameSize < SAVE_NAME_SIZE) + { + if (read_a8 (fp, SummPtr->SaveName, nameSize) != 1) + return FALSE; + SummPtr->SaveName[nameSize] = 0; + } + else + { + DWORD remaining = nameSize - SAVE_NAME_SIZE + 1; + if (read_a8 (fp, SummPtr->SaveName, SAVE_NAME_SIZE-1) != 1) + return FALSE; + SummPtr->SaveName[SAVE_NAME_SIZE-1] = 0; + if (skip_8 (fp, remaining) != 1) + return FALSE; + } + } else - return TRUE; + { + SummPtr->SaveName[0] = 0; + if (read_16 (fp, NULL) != 1) /* padding */ + return FALSE; + } + return TRUE; } static void @@ -577,13 +613,15 @@ LoadGame (COUNT which_game, SUMMARY_DESC *SummPtr) COUNT num_links; STAR_DESC SD; ACTIVITY Activity; + BOOLEAN legacy; + DWORD chunk, chunkSize; sprintf (file, "starcon2.%02u", which_game); in_fp = res_OpenResFile (saveDir, file, "rb"); if (!in_fp) return FALSE; - if (!LoadSummary (&loc_sd, in_fp)) + if (!LoadSummary (&loc_sd, in_fp, &legacy)) { log_add (log_Error, "Warning: Savegame is corrupt"); res_CloseResFile (in_fp); @@ -618,6 +656,33 @@ LoadGame (COUNT which_game, SUMMARY_DESC *SummPtr) GlobData.SIS_state = SummPtr->SS; + if (!legacy) + { + chunk = 0; + while (chunk != OMNIZIP_MAGIC) + { + if (read_32(in_fp, &chunk) != 1) + { + res_CloseResFile (in_fp); + return FALSE; + } + if (read_32(in_fp, &chunkSize) != 1) + { + res_CloseResFile (in_fp); + return FALSE; + } + if (chunk == OMNIZIP_MAGIC) + break; + + log_add (log_Debug, "Skipping chunk of tag %08X (size %u)", chunk, chunkSize); + if (skip_8(in_fp, chunkSize) != 1) + return FALSE; + } + /* Fortunately for us, the OmnZ chunk is internally + * self-sizing, so we can ignore the chunk size as long as we + * aren't skipping it. */ + } + if ((fh = copen (in_fp, FILE_STREAM, STREAM_READ)) == 0) { res_CloseResFile (in_fp); diff --git a/sc2/src/uqm/save.c b/sc2/src/uqm/save.c index 9c3e389d8..509515c15 100644 --- a/sc2/src/uqm/save.c +++ b/sc2/src/uqm/save.c @@ -431,9 +431,7 @@ SaveSisState (const SIS_STATE *SSPtr, void *fp) write_str (fp, SSPtr->ShipName, SIS_NAME_SIZE) != 1 || write_str (fp, SSPtr->CommanderName, SIS_NAME_SIZE) != 1 || - write_str (fp, SSPtr->PlanetName, SIS_NAME_SIZE) != 1 || - - write_16 (fp, 0) != 1 /* padding */ + write_str (fp, SSPtr->PlanetName, SIS_NAME_SIZE) != 1 ) return FALSE; else @@ -443,7 +441,11 @@ SaveSisState (const SIS_STATE *SSPtr, void *fp) static BOOLEAN SaveSummary (const SUMMARY_DESC *SummPtr, void *fp) { - if (write_32 (fp, SAVE_MAGIC) != 1) + if ( + write_32 (fp, SAVE_MAGIC) != 1 || + write_32 (fp, SUMMARY_MAGIC) != 1 || + write_32 (fp, 161 + strlen(SummPtr->SaveName)) != 1 + ) return FALSE; if (!SaveSisState (&SummPtr->SS, fp)) return FALSE; @@ -460,9 +462,7 @@ SaveSummary (const SUMMARY_DESC *SummPtr, void *fp) write_8 (fp, SummPtr->NumDevices) != 1 || write_a8 (fp, SummPtr->ShipList, MAX_BUILT_SHIPS) != 1 || write_a8 (fp, SummPtr->DeviceList, MAX_EXCLUSIVE_DEVICES) != 1 || - write_a8 (fp, SummPtr->SaveName, SAVE_NAME_SIZE) != 1 || - - write_16 (fp, 0) != 1 /* padding */ + write_a8 (fp, SummPtr->SaveName, strlen(SummPtr->SaveName)+1) != 1 ) return FALSE; else @@ -835,13 +835,17 @@ RetrySave: // Write the memory file to the actual savegame file. sprintf (file, "starcon2.%02u", which_game); log_add (log_Debug, "'%s' is %u bytes long", file, - flen + sizeof (*SummPtr)); + flen + 181 + strlen(SummPtr->SaveName)); if (flen && (out_fp = res_OpenResFile (saveDir, file, "wb"))) { PrepareSummary (SummPtr, name); success = SaveSummary (SummPtr, out_fp); // Then write the rest of the data. + if (success && write_32 (out_fp, OMNIZIP_MAGIC) != 1) + success = FALSE; + if (success && write_32 (out_fp, flen) != 1) + success = FALSE; if (success && WriteResFile (h, flen, 1, out_fp) != 1) success = FALSE; diff --git a/sc2/src/uqm/save.h b/sc2/src/uqm/save.h index 6f37f01ff..f06c4a051 100644 --- a/sc2/src/uqm/save.h +++ b/sc2/src/uqm/save.h @@ -31,8 +31,10 @@ extern "C" { // is only used for displaying savegame summaries. There is also // room for only 16 devices on screen. #define MAX_EXCLUSIVE_DEVICES 16 -#define SAVE_MAGIC 0x01534d55 -#define SAVE_NAME_SIZE 24 +#define SAVE_MAGIC 0x01534d55 // "UMS\x01": UQM Save version 1 +#define SUMMARY_MAGIC 0x6d6d7553 // "Summ": Summary. Must be first! +#define OMNIZIP_MAGIC 0x5a6e6d4f // "OmnZ": All data compressed. +#define SAVE_NAME_SIZE 64 typedef struct {