diff --git a/src/saveload/oldloader_sl.cpp b/src/saveload/oldloader_sl.cpp index b73ccb86e0..89cc1357c0 100644 --- a/src/saveload/oldloader_sl.cpp +++ b/src/saveload/oldloader_sl.cpp @@ -483,7 +483,7 @@ static inline uint RemapOrderIndex(uint x) extern std::vector _animated_tiles; extern TimeoutTimer _new_competitor_timeout; -extern char *_old_name_array; +extern std::unique_ptr _old_name_array; static uint32_t _old_town_index; static uint16_t _old_string_id; @@ -1384,6 +1384,25 @@ bool LoadOldVehicle(LoadgameState *ls, int num) return true; } +/** + * Read a single string from the savegame. + * @param ls The state for loading this save game. + * @param index The index of the loaded custom string. + * @return Always true. + */ +bool LoadOldCustomString(LoadgameState *ls, int index) +{ + /* + * Data is stored in fixed size "cells"; read these completely. + * Validation and conversion to UTF-8 are happening at a later stage. + */ + std::string &str = _old_name_array[index]; + str.resize(_savegame_type == SGT_TTO ? 24 : 32); + for (auto &c : str) c = ReadByte(ls); + + return true; +} + static const OldChunks sign_chunk[] = { OCL_VAR ( OC_UINT16, 1, &_old_string_id ), OCL_SVAR( OC_FILE_U16 | OC_VAR_I32, Sign, x ), @@ -1680,8 +1699,8 @@ static const OldChunks main_chunk[] = { OCL_ASSERT( OC_TTD, 0x6F0F2 ), OCL_ASSERT( OC_TTO, 0x45746 ), - OCL_VAR ( OC_TTD | OC_UINT8 | OC_DEREFERENCE_POINTER, 32 * 500, &_old_name_array ), - OCL_VAR ( OC_TTO | OC_UINT8 | OC_DEREFERENCE_POINTER, 24 * 200, &_old_name_array ), + OCL_CCHUNK( OC_TTD, 500, LoadOldCustomString ), + OCL_CCHUNK( OC_TTO, 200, LoadOldCustomString ), OCL_ASSERT( OC_TTO, 0x46A06 ), diff --git a/src/saveload/strings_sl.cpp b/src/saveload/strings_sl.cpp index 88f9ffd1cd..f638ef7c8c 100644 --- a/src/saveload/strings_sl.cpp +++ b/src/saveload/strings_sl.cpp @@ -18,9 +18,8 @@ #include "../safeguards.h" -static const int NUM_OLD_STRINGS = 512; ///< The number of custom strings stored in old savegames. -static const int LEN_OLD_STRINGS = 32; ///< The number of characters per string. -static const int LEN_OLD_STRINGS_TTO = 24; ///< The number of characters per string in TTO savegames. +static const int NUM_OLD_STRINGS = 512; ///< The number of custom strings stored in old savegames. +static const size_t LEN_OLD_STRINGS = 32; ///< The number of characters per string. /** * Remap a string ID from the old format to the new format @@ -49,7 +48,7 @@ StringID RemapOldStringID(StringID s) } /** Location to load the old names to. */ -char *_old_name_array = nullptr; +std::unique_ptr _old_name_array; /** * Copy and convert old custom names to UTF-8. @@ -64,13 +63,12 @@ std::string CopyFromOldName(StringID id) if (GetStringTab(id) != TEXT_TAB_OLD_CUSTOM) return std::string(); if (IsSavegameVersionBefore(SLV_37)) { - uint offs = _savegame_type == SGT_TTO ? LEN_OLD_STRINGS_TTO * GB(id, 0, 8) : LEN_OLD_STRINGS * GB(id, 0, 9); - const char *strfrom = &_old_name_array[offs]; + const std::string &strfrom = _old_name_array[GB(id, 0, 9)]; std::ostringstream tmp; std::ostreambuf_iterator strto(tmp); - for (; *strfrom != '\0'; strfrom++) { - char32_t c = (uint8_t)*strfrom; + for (char32_t c : strfrom) { + if (c == '\0') break; /* Map from non-ISO8859-15 characters to UTF-8. */ switch (c) { @@ -85,13 +83,13 @@ std::string CopyFromOldName(StringID id) default: break; } - Utf8Encode(strto, c); + if (IsPrintable(c)) Utf8Encode(strto, c); } return tmp.str(); } else { /* Name will already be in UTF-8. */ - return std::string(&_old_name_array[LEN_OLD_STRINGS * GB(id, 0, 9)]); + return StrMakeValid(_old_name_array[GB(id, 0, 9)]); } } @@ -101,7 +99,6 @@ std::string CopyFromOldName(StringID id) */ void ResetOldNames() { - free(_old_name_array); _old_name_array = nullptr; } @@ -110,8 +107,7 @@ void ResetOldNames() */ void InitializeOldNames() { - free(_old_name_array); - _old_name_array = CallocT(NUM_OLD_STRINGS * LEN_OLD_STRINGS); // 200 * 24 would be enough for TTO savegames + _old_name_array = std::make_unique(NUM_OLD_STRINGS); // 200 would be enough for TTO savegames } struct NAMEChunkHandler : ChunkHandler { @@ -123,11 +119,10 @@ struct NAMEChunkHandler : ChunkHandler { while ((index = SlIterateArray()) != -1) { if (index >= NUM_OLD_STRINGS) SlErrorCorrupt("Invalid old name index"); - if (SlGetFieldLength() > (uint)LEN_OLD_STRINGS) SlErrorCorrupt("Invalid old name length"); + size_t length = SlGetFieldLength(); + if (length > LEN_OLD_STRINGS) SlErrorCorrupt("Invalid old name length"); - SlCopy(&_old_name_array[LEN_OLD_STRINGS * index], SlGetFieldLength(), SLE_UINT8); - /* Make sure the old name is null terminated */ - _old_name_array[LEN_OLD_STRINGS * index + LEN_OLD_STRINGS - 1] = '\0'; + SlReadString(_old_name_array[index], length); } } };