1
0
mirror of https://github.com/OpenRCT2/OpenRCT2 synced 2026-01-21 05:53:02 +01:00

Implement C++ solution to truncate UTF8 strings

This commit is contained in:
Duncanspumpkin
2021-03-18 21:56:51 +01:00
committed by Gymnasiast
parent 645685de18
commit 0957542503
3 changed files with 48 additions and 5 deletions

View File

@@ -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);
}

View File

@@ -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)

View File

@@ -147,6 +147,37 @@ namespace String
}
return result;
}
/**
* Returns codepoint size or no value if not valid
*/
constexpr std::optional<int> 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