diff --git a/src/openrct2-ui/windows/TextInput.cpp b/src/openrct2-ui/windows/TextInput.cpp index bdeb2555ad..fa401ad79b 100644 --- a/src/openrct2-ui/windows/TextInput.cpp +++ b/src/openrct2-ui/windows/TextInput.cpp @@ -105,11 +105,7 @@ public: void SetText(std::string_view text, size_t maxLength) { - char* tmp = new char[maxLength]; - safe_strcpy(tmp, std::string(text).c_str(), maxLength); - _buffer = tmp; - delete[] tmp; - _buffer.resize(maxLength); + _buffer = String::UTF8Truncate(text, maxLength); _maxInputLength = maxLength; gTextInput = context_start_text_input(_buffer.data(), maxLength); } diff --git a/src/openrct2/core/String.cpp b/src/openrct2/core/String.cpp index 9f394be4f1..bb773e5df9 100644 --- a/src/openrct2/core/String.cpp +++ b/src/openrct2/core/String.cpp @@ -807,6 +807,22 @@ namespace String return res; #endif } + + std::string_view UTF8Truncate(std::string_view v, size_t size) + { + auto trunc = v.substr(0, size); + for (size_t i = 0; i < trunc.size();) + { + auto length = UTF8GetCodePointSize(trunc.substr(i, trunc.size())); + if (!length.has_value()) + { + return trunc.substr(0, i); + } + i += *length; + } + + return trunc; + } } // namespace String char32_t CodepointView::iterator::GetNextCodepoint(const char* ch, const char** next) diff --git a/src/openrct2/core/String.hpp b/src/openrct2/core/String.hpp index 0849571353..d4ce69210e 100644 --- a/src/openrct2/core/String.hpp +++ b/src/openrct2/core/String.hpp @@ -147,6 +147,37 @@ namespace String } return result; } + + /** + * Returns codepoint size or no value if not valid + */ + constexpr std::optional UTF8GetCodePointSize(std::string_view v) + { + if (v.size() >= 1 && !(v[0] & 0x80)) + { + return { 1 }; + } + else if (v.size() >= 2 && ((v[0] & 0xE0) == 0xC0)) + { + return { 2 }; + } + else if (v.size() >= 3 && ((v[0] & 0xF0) == 0xE0)) + { + return { 3 }; + } + else if (v.size() >= 4 && ((v[0] & 0xF8) == 0xF0)) + { + return { 4 }; + } + return {}; + } + + /** + * Truncates a string to at most `size` bytes, + * making sure not to cut in the middle of a sequence. + */ + std::string_view UTF8Truncate(std::string_view v, size_t size); + } // namespace String class CodepointView