GB: fix 32/64 bit save/state incompatibility

The MBC3 and TAMA5 battery formats save the RTC data including a
`time_t` field which is the last field.

Since `time_t` is 32 bits for 32 bit builds and 64 bits for 64 bit
builds, pad it in the two battery structs with a `uint64_t` and detect
the 4 byte shorter saves made by older 32 bit builds.

Also remove some pointless code in save state reading that also uses
`sizeof(time_t)`.

Add two new constants for RTC data size in gbMemory.h and use them.

Signed-off-by: Rafael Kitover <rkitover@gmail.com>
This commit is contained in:
Rafael Kitover 2019-02-23 13:40:25 -08:00
parent b9d6f35f8f
commit 98cb298efc
No known key found for this signature in database
GPG Key ID: 08AB596679D86240
4 changed files with 25 additions and 28 deletions

View File

@ -2847,7 +2847,7 @@ void gbWriteSaveMBC3(const char* name, bool extendedSave)
if (extendedSave) if (extendedSave)
fwrite(&gbDataMBC3.mapperSeconds, fwrite(&gbDataMBC3.mapperSeconds,
1, 1,
10 * sizeof(int) + sizeof(time_t), MBC3_RTC_DATA_SIZE,
gzFile); gzFile);
fclose(gzFile); fclose(gzFile);
@ -2914,7 +2914,7 @@ void gbWriteSaveTAMA5(const char* name, bool extendedSave)
if (extendedSave) if (extendedSave)
fwrite(&gbDataTAMA5.mapperSeconds, fwrite(&gbDataTAMA5.mapperSeconds,
1, 1,
14 * sizeof(int) + sizeof(time_t), TAMA5_RTC_DATA_SIZE,
gzFile); gzFile);
fclose(gzFile); fclose(gzFile);
@ -3049,20 +3049,17 @@ bool gbReadSaveMBC3(const char* name)
N_("Battery file's size incompatible with the rom settings %s (%d).\nWarning : save of the battery file is now disabled !"), name, read); N_("Battery file's size incompatible with the rom settings %s (%d).\nWarning : save of the battery file is now disabled !"), name, read);
gbBatteryError = true; gbBatteryError = true;
res = false; res = false;
} else if ((gbRomType == 0xf) || (gbRomType == 0x10)) { } else if ((gbRomType == 0xf) || (gbRomType == 0x10)) { // read RTC data
read = gzread(gzFile, read = gzread(gzFile,
&gbDataMBC3.mapperSeconds, &gbDataMBC3.mapperSeconds,
sizeof(int) * 10 + sizeof(time_t)); MBC3_RTC_DATA_SIZE);
if (read != (sizeof(int) * 10 + sizeof(time_t)) && read != 0) { if (!read || (read != MBC3_RTC_DATA_SIZE && read != MBC3_RTC_DATA_SIZE - 4)) { // detect old 32 bit saves
systemMessage(MSG_FAILED_TO_READ_RTC, N_("Failed to read RTC from save game %s (continuing)"), systemMessage(MSG_FAILED_TO_READ_RTC, N_("Failed to read RTC from save game %s (continuing)"),
name); name);
res = false; res = false;
} else if (read == 0) { }
systemMessage(MSG_FAILED_TO_READ_RTC, N_("Failed to read RTC from save game %s (continuing)"), else {
name);
res = false;
} else {
// Also checks if the battery file it bigger than gbRamSizeMask+1+RTC ! // Also checks if the battery file it bigger than gbRamSizeMask+1+RTC !
uint8_t data[1]; uint8_t data[1];
data[0] = 0; data[0] = 0;
@ -3200,13 +3197,9 @@ bool gbReadSaveTAMA5(const char* name)
} else { } else {
read = gzread(gzFile, read = gzread(gzFile,
&gbDataTAMA5.mapperSeconds, &gbDataTAMA5.mapperSeconds,
sizeof(int) * 14 + sizeof(time_t)); TAMA5_RTC_DATA_SIZE);
if (read != (sizeof(int) * 14 + sizeof(time_t)) && read != 0) { if (!read || (read != TAMA5_RTC_DATA_SIZE && read != TAMA5_RTC_DATA_SIZE - 4)) { // detect old 32 bit saves
systemMessage(MSG_FAILED_TO_READ_RTC, N_("Failed to read RTC from save game %s (continuing)"),
name);
res = false;
} else if (read == 0) {
systemMessage(MSG_FAILED_TO_READ_RTC, N_("Failed to read RTC from save game %s (continuing)"), systemMessage(MSG_FAILED_TO_READ_RTC, N_("Failed to read RTC from save game %s (continuing)"),
name); name);
res = false; res = false;
@ -3736,13 +3729,7 @@ static bool gbReadSaveState(gzFile gzFile)
else else
utilGzRead(gzFile, &gbDataMBC1, sizeof(gbDataMBC1)); utilGzRead(gzFile, &gbDataMBC1, sizeof(gbDataMBC1));
utilGzRead(gzFile, &gbDataMBC2, sizeof(gbDataMBC2)); utilGzRead(gzFile, &gbDataMBC2, sizeof(gbDataMBC2));
if (version < GBSAVE_GAME_VERSION_4) utilGzRead(gzFile, &gbDataMBC3, sizeof(gbDataMBC3));
// prior to version 4, there was no adjustment for the time the game
// was last played, so we have less to read. This needs update if the
// structure changes again.
utilGzRead(gzFile, &gbDataMBC3, sizeof(gbDataMBC3) - sizeof(time_t));
else
utilGzRead(gzFile, &gbDataMBC3, sizeof(gbDataMBC3));
utilGzRead(gzFile, &gbDataMBC5, sizeof(gbDataMBC5)); utilGzRead(gzFile, &gbDataMBC5, sizeof(gbDataMBC5));
utilGzRead(gzFile, &gbDataHuC1, sizeof(gbDataHuC1)); utilGzRead(gzFile, &gbDataHuC1, sizeof(gbDataHuC1));
utilGzRead(gzFile, &gbDataHuC3, sizeof(gbDataHuC3)); utilGzRead(gzFile, &gbDataHuC3, sizeof(gbDataHuC3));

View File

@ -308,7 +308,7 @@ mapperMBC3 gbDataMBC3 = {
0, // timer latched hours 0, // timer latched hours
0, // timer latched days 0, // timer latched days
0, // timer latched control 0, // timer latched control
(time_t)-1 // last time 0 // last time
}; };
void memoryUpdateMBC3Clock() void memoryUpdateMBC3Clock()

View File

@ -36,7 +36,10 @@ struct mapperMBC3 {
int mapperLHours; int mapperLHours;
int mapperLDays; int mapperLDays;
int mapperLControl; int mapperLControl;
time_t mapperLastTime; union {
time_t mapperLastTime;
uint64_t _time_pad; /* so that 32bit and 64bit saves are compatible */
};
}; };
struct mapperMBC5 { struct mapperMBC5 {
@ -118,7 +121,10 @@ struct mapperTAMA5 {
int mapperLMonths; int mapperLMonths;
int mapperLYears; int mapperLYears;
int mapperLControl; int mapperLControl;
time_t mapperLastTime; union {
time_t mapperLastTime;
uint64_t _time_pad; /* so that 32bit and 64bit saves are compatible */
};
}; };
struct mapperMMM01 { struct mapperMMM01 {
@ -186,4 +192,8 @@ extern void memoryUpdateMapTAMA5();
extern void memoryUpdateMapMMM01(); extern void memoryUpdateMapMMM01();
extern void memoryUpdateMapGS3(); extern void memoryUpdateMapGS3();
#define MBC3_RTC_DATA_SIZE sizeof(int) * 10 + sizeof(uint64_t)
#define TAMA5_RTC_DATA_SIZE sizeof(int) * 14 + sizeof(uint64_t)
#endif // GBMEMORY_H #endif // GBMEMORY_H

View File

@ -220,11 +220,11 @@ static size_t gb_rtcdata_size(void)
switch (gbRomType) { switch (gbRomType) {
case 0x0f: case 0x0f:
case 0x10: // MBC3 + extended case 0x10: // MBC3 + extended
return (10 * sizeof(int) + sizeof(time_t)); return MBC3_RTC_DATA_SIZE;
break; break;
case 0x13: case 0x13:
case 0xfd: // TAMA5 + extended case 0xfd: // TAMA5 + extended
return (14 * sizeof(int) + sizeof(time_t)); return TAMA5_RTC_DATA_SIZE;
break; break;
} }
} }