summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/lang/english.txt1
-rw-r--r--src/saveload/oldloader.cpp51
2 files changed, 37 insertions, 15 deletions
diff --git a/src/lang/english.txt b/src/lang/english.txt
index e85163834..01729fa0c 100644
--- a/src/lang/english.txt
+++ b/src/lang/english.txt
@@ -2028,6 +2028,7 @@ STR_GAME_SAVELOAD_ERROR_BROKEN_SAVEGAME :Broken savegame
STR_GAME_SAVELOAD_ERROR_TOO_NEW_SAVEGAME :Savegame is made with newer version
STR_GAME_SAVELOAD_ERROR_FILE_NOT_READABLE :File not readable
STR_GAME_SAVELOAD_ERROR_FILE_NOT_WRITEABLE :File not writeable
+STR_GAME_SAVELOAD_ERROR_DATA_INTEGRITY_CHECK_FAILED :Data integrity check failed
STR_400A_LIST_OF_DRIVES_DIRECTORIES :{BLACK}List of drives, directories and saved-game files
STR_400B_CURRENTLY_SELECTED_NAME :{BLACK}Currently selected name for saved-game
STR_400C_DELETE_THE_CURRENTLY_SELECTED :{BLACK}Delete the currently selected saved-game
diff --git a/src/saveload/oldloader.cpp b/src/saveload/oldloader.cpp
index d8009878a..73aaa440b 100644
--- a/src/saveload/oldloader.cpp
+++ b/src/saveload/oldloader.cpp
@@ -1452,9 +1452,6 @@ static bool LoadOldMain(LoadgameState *ls)
{
int i;
- /* The first 49 is the name of the game + checksum, skip it */
- fseek(ls->file, HEADER_SIZE, SEEK_SET);
-
DEBUG(oldloader, 3, "Reading main chunk...");
/* Load the biggest chunk */
_old_map3 = MallocT<byte>(OLD_MAP_SIZE * 2);
@@ -1540,6 +1537,28 @@ static bool LoadOldMain(LoadgameState *ls)
return true;
}
+/**
+ * Verifies the title has a valid checksum
+ * @param title title and checksum
+ * @return true iff the title is valid
+ * @note the title (incl. checksum) has to be at least 49 (HEADER_SIZE) bytes long!
+ */
+static bool VerifyOldNameChecksum(char *title)
+{
+ uint16 sum = 0;
+ for (uint i = 0; i < HEADER_SIZE - 2; i++) {
+ sum += title[i];
+ sum = ROL(sum, 1);
+ }
+
+ sum ^= 0xAAAA; // computed checksum
+
+ uint16 sum2 = title[HEADER_SIZE - 2]; // checksum in file
+ SB(sum2, 8, 8, title[HEADER_SIZE - 1]);
+
+ return sum == sum2;
+}
+
bool LoadOldSaveGame(const char *file)
{
LoadgameState ls;
@@ -1556,10 +1575,12 @@ bool LoadOldSaveGame(const char *file)
return false;
}
- /* Load the main chunk */
- if (!LoadOldMain(&ls)) return false;
-
- fclose(ls.file);
+ char temp[HEADER_SIZE];
+ if (fread(temp, 1, HEADER_SIZE, ls.file) != HEADER_SIZE || !VerifyOldNameChecksum(temp) || !LoadOldMain(&ls)) {
+ SetSaveLoadError(STR_GAME_SAVELOAD_ERROR_DATA_INTEGRITY_CHECK_FAILED);
+ fclose(ls.file);
+ return false;
+ }
/* Some old TTD(Patch) savegames could have buoys at tile 0
* (without assigned station struct)
@@ -1575,20 +1596,20 @@ bool LoadOldSaveGame(const char *file)
void GetOldSaveGameName(const char *path, const char *file, char *title, const char *last)
{
char filename[MAX_PATH];
- char temp[HEADER_SIZE - 1];
+ char temp[HEADER_SIZE];
snprintf(filename, lengthof(filename), "%s" PATHSEP "%s", path, file);
FILE *f = fopen(filename, "rb");
- temp[0] = '\0';
- temp[HEADER_SIZE - 2] = '\0';
+ temp[0] = '\0'; // name is nul-terminated in savegame ...
if (f == NULL) return;
- if (fread(temp, 1, HEADER_SIZE - 2, f) != HEADER_SIZE - 2) {
- seprintf(title, last, "Corrupt file");
- } else {
- seprintf(title, last, temp);
- }
+ bool broken = (fread(temp, 1, HEADER_SIZE, f) != HEADER_SIZE || !VerifyOldNameChecksum(temp));
+
+ temp[HEADER_SIZE - 2] = '\0'; // ... but it's better to be sure
+
+ if (broken) title = strecpy(title, "(broken) ", last);
+ title = strecpy(title, temp, last);
fclose(f);
}