From 17edaae02b663b1da5db7d39e491bb1bb1b8f45e Mon Sep 17 00:00:00 2001 From: Ted John Date: Sun, 29 Nov 2020 00:40:17 +0000 Subject: [PATCH] Improve banner formatting fix --- src/openrct2/core/String.cpp | 17 +++++++++ src/openrct2/core/String.hpp | 6 ++++ src/openrct2/localisation/FormatCodes.cpp | 43 +++++++++++++++++++---- src/openrct2/localisation/FormatCodes.h | 2 +- src/openrct2/rct1/S4Importer.cpp | 2 +- src/openrct2/rct2/S6Importer.cpp | 2 +- src/openrct2/world/Banner.cpp | 11 ++---- 7 files changed, 64 insertions(+), 19 deletions(-) diff --git a/src/openrct2/core/String.cpp b/src/openrct2/core/String.cpp index 1ac4e7aa09..32b4ff76fa 100644 --- a/src/openrct2/core/String.cpp +++ b/src/openrct2/core/String.cpp @@ -126,6 +126,23 @@ namespace String #endif } + std::string_view ToStringView(const char* ch, size_t maxLen) + { + size_t len{}; + for (size_t i = 0; i < maxLen; i++) + { + if (ch[i] == '\0') + { + break; + } + else + { + len++; + } + } + return std::string_view(ch, len); + } + bool IsNullOrEmpty(const utf8* str) { return str == nullptr || str[0] == '\0'; diff --git a/src/openrct2/core/String.hpp b/src/openrct2/core/String.hpp index 62fbadb9a6..1fe7c29d41 100644 --- a/src/openrct2/core/String.hpp +++ b/src/openrct2/core/String.hpp @@ -39,6 +39,12 @@ namespace String std::string ToUtf8(const std::wstring_view& src); std::wstring ToWideChar(const std::string_view& src); + /** + * Creates a string_view from a char pointer with a length up to either the + * first null terminator or a given maximum length, whatever is smallest. + */ + std::string_view ToStringView(const char* ch, size_t maxLen); + bool IsNullOrEmpty(const utf8* str); int32_t Compare(const std::string& a, const std::string& b, bool ignoreCase = false); int32_t Compare(const utf8* a, const utf8* b, bool ignoreCase = false); diff --git a/src/openrct2/localisation/FormatCodes.cpp b/src/openrct2/localisation/FormatCodes.cpp index 5ea08f8620..f30950982f 100644 --- a/src/openrct2/localisation/FormatCodes.cpp +++ b/src/openrct2/localisation/FormatCodes.cpp @@ -9,7 +9,10 @@ #include "FormatCodes.h" +#include +#include #include +#include // clang-format off static const std::unordered_map FormatTokenMap = { @@ -62,22 +65,48 @@ static const std::unordered_map FormatTokenMap = }; // clang-format on +static std::string_view GetFormatTokenStringWithBraces(FormatToken token) +{ + // Ensure cache is thread safe + static std::mutex mutex; + std::lock_guard guard(mutex); + + static std::vector cache; + auto index = static_cast(token); + if (cache.size() <= index) + { + cache.resize(index + 1); + } + if (cache[index].empty()) + { + cache[index] = "{" + std::string(FormatTokenToString(token)) + "}"; + } + return cache[index]; +} + FormatToken FormatTokenFromString(std::string_view token) { auto result = FormatTokenMap.find(token); return result != std::end(FormatTokenMap) ? result->second : FormatToken::Unknown; } -std::string_view FormatTokenToString(FormatToken token) +std::string_view FormatTokenToString(FormatToken token, bool withBraces) { - for (const auto& t : FormatTokenMap) + if (withBraces) { - if (t.second == token) - { - return t.first; - } + return GetFormatTokenStringWithBraces(token); + } + else + { + for (const auto& t : FormatTokenMap) + { + if (t.second == token) + { + return t.first; + } + } + return {}; } - return {}; } bool FormatTokenTakesArgument(FormatToken token) diff --git a/src/openrct2/localisation/FormatCodes.h b/src/openrct2/localisation/FormatCodes.h index 49eae6cb48..c805f85854 100644 --- a/src/openrct2/localisation/FormatCodes.h +++ b/src/openrct2/localisation/FormatCodes.h @@ -77,7 +77,7 @@ enum class FormatToken }; FormatToken FormatTokenFromString(std::string_view token); -std::string_view FormatTokenToString(FormatToken token); +std::string_view FormatTokenToString(FormatToken token, bool withBraces = false); bool FormatTokenTakesArgument(FormatToken token); bool FormatTokenIsColour(FormatToken token); size_t FormatTokenGetTextColourIndex(FormatToken token); diff --git a/src/openrct2/rct1/S4Importer.cpp b/src/openrct2/rct1/S4Importer.cpp index 2fb3a72d84..ca08d52370 100644 --- a/src/openrct2/rct1/S4Importer.cpp +++ b/src/openrct2/rct1/S4Importer.cpp @@ -3004,7 +3004,7 @@ private: std::string GetUserString(rct_string_id stringId) { const auto originalString = _s4.string_table[(stringId - USER_STRING_START) % 1024]; - std::string_view originalStringView(originalString, USER_STRING_MAX_LENGTH); + auto originalStringView = String::ToStringView(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/S6Importer.cpp b/src/openrct2/rct2/S6Importer.cpp index 2002d85c70..a7153fd27c 100644 --- a/src/openrct2/rct2/S6Importer.cpp +++ b/src/openrct2/rct2/S6Importer.cpp @@ -1659,7 +1659,7 @@ public: std::string GetUserString(rct_string_id stringId) { const auto originalString = _s6.custom_strings[(stringId - USER_STRING_START) % 1024]; - std::string_view originalStringView(originalString, USER_STRING_MAX_LENGTH); + auto originalStringView = String::ToStringView(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/world/Banner.cpp b/src/openrct2/world/Banner.cpp index 008ff53a63..af09e64db2 100644 --- a/src/openrct2/world/Banner.cpp +++ b/src/openrct2/world/Banner.cpp @@ -45,16 +45,9 @@ void Banner::FormatTextTo(Formatter& ft, bool addColour) const if (addColour) { auto formatToken = FormatTokenFromTextColour(text_colour); - auto tokenText = FormatTokenToString(formatToken); - - thread_local std::string tokenTextColourBuffer; - tokenTextColourBuffer.clear(); - tokenTextColourBuffer.push_back('{'); - tokenTextColourBuffer.append(tokenText); - tokenTextColourBuffer.push_back('}'); - + auto tokenText = FormatTokenToString(formatToken, true); ft.Add(STR_STRING_STRINGID); - ft.Add(tokenTextColourBuffer.c_str()); + ft.Add(tokenText.data()); } FormatTextTo(ft);