From 9809df8de63fe4c6d1f53606fce65ae5a669b1fb Mon Sep 17 00:00:00 2001 From: Ted John Date: Wed, 23 Dec 2020 19:19:25 +0000 Subject: [PATCH] Fix #13549: Ride name is truncated/resetted in Korean Handle multi-byte RCT2 strings when converting to string_view. --- src/openrct2/rct1/S4Importer.cpp | 3 ++- src/openrct2/rct2/RCT2.cpp | 29 +++++++++++++++++++++++++++++ src/openrct2/rct2/RCT2.h | 6 ++++++ src/openrct2/rct2/S6Importer.cpp | 3 ++- 4 files changed, 39 insertions(+), 2 deletions(-) diff --git a/src/openrct2/rct1/S4Importer.cpp b/src/openrct2/rct1/S4Importer.cpp index 5dc0635b6c..4e509e22cb 100644 --- a/src/openrct2/rct1/S4Importer.cpp +++ b/src/openrct2/rct1/S4Importer.cpp @@ -3004,7 +3004,8 @@ private: std::string GetUserString(rct_string_id stringId) { const auto originalString = _s4.string_table[(stringId - USER_STRING_START) % 1024]; - auto originalStringView = String::ToStringView(originalString, USER_STRING_MAX_LENGTH); + auto originalStringView = std::string_view( + originalString, GetRCT2StringBufferLen(originalString, USER_STRING_MAX_LENGTH)); auto asUtf8 = rct2_to_utf8(originalStringView, RCT2_LANGUAGE_ID_ENGLISH_UK); auto justText = RCT12RemoveFormattingUTF8(asUtf8); return justText.data(); diff --git a/src/openrct2/rct2/RCT2.cpp b/src/openrct2/rct2/RCT2.cpp index 698c3421b4..a6a88e9974 100644 --- a/src/openrct2/rct2/RCT2.cpp +++ b/src/openrct2/rct2/RCT2.cpp @@ -84,6 +84,35 @@ uint8_t OpenRCT2RideTypeToRCT2RideType(ObjectEntryIndex openrct2Type) } } +size_t GetRCT2StringBufferLen(const char* buffer, size_t maxBufferLen) +{ + constexpr char MULTIBYTE = static_cast(255); + size_t len = 0; + for (size_t i = 0; i < maxBufferLen; i++) + { + auto ch = buffer[i]; + if (ch == MULTIBYTE) + { + i += 2; + + // Check if reading two more bytes exceeds max buffer len + if (i < maxBufferLen) + { + len += 3; + } + } + else if (ch == '\0') + { + break; + } + else + { + len++; + } + } + return len; +} + uint8_t rct2_ride::GetMinCarsPerTrain() const { return min_max_cars_per_train >> 4; diff --git a/src/openrct2/rct2/RCT2.h b/src/openrct2/rct2/RCT2.h index 1017e5a3b1..55d385d0b3 100644 --- a/src/openrct2/rct2/RCT2.h +++ b/src/openrct2/rct2/RCT2.h @@ -779,3 +779,9 @@ std::vector DecryptSea(const fs::path& path); ObjectEntryIndex RCT2RideTypeToOpenRCT2RideType(uint8_t rct2RideType, const rct_ride_entry* rideEntry); bool RCT2RideTypeNeedsConversion(uint8_t rct2RideType); uint8_t OpenRCT2RideTypeToRCT2RideType(ObjectEntryIndex openrct2Type); + +/** + * Iterates an RCT2 string buffer and returns the length of the string in bytes. + * Handles single and multi-byte strings. + */ +size_t GetRCT2StringBufferLen(const char* buffer, size_t maxBufferLen); diff --git a/src/openrct2/rct2/S6Importer.cpp b/src/openrct2/rct2/S6Importer.cpp index ff7ff5310c..13e33efd4e 100644 --- a/src/openrct2/rct2/S6Importer.cpp +++ b/src/openrct2/rct2/S6Importer.cpp @@ -1658,7 +1658,8 @@ public: std::string GetUserString(rct_string_id stringId) { const auto originalString = _s6.custom_strings[(stringId - USER_STRING_START) % 1024]; - auto originalStringView = String::ToStringView(originalString, USER_STRING_MAX_LENGTH); + auto originalStringView = std::string_view( + originalString, GetRCT2StringBufferLen(originalString, USER_STRING_MAX_LENGTH)); auto asUtf8 = rct2_to_utf8(originalStringView, RCT2_LANGUAGE_ID_ENGLISH_UK); auto justText = RCT12RemoveFormattingUTF8(asUtf8); return justText.data();