Improved save file format inspired by IFF.
Savefile is built of chunks that include their length. The only two right now are Summ (the summary, must be first) and OmnZ (the omnibus compressed data). Padding that was originally used for alignment purposes has been removed from the format, unless is it is part of the compressed data.
This commit is contained in:
+82
-17
@@ -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);
|
||||
|
||||
+12
-8
@@ -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;
|
||||
|
||||
|
||||
+4
-2
@@ -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
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user