From bfef7c302cd277904ab62bd40fabc1af1a9b3bc7 Mon Sep 17 00:00:00 2001 From: Sam Lantinga Date: Sun, 4 Jun 2023 02:06:52 -0700 Subject: [PATCH] Only convert the result of XLookupString() if it's not already UTF-8 Fixes https://github.com/libsdl-org/SDL/issues/7766 (cherry picked from commit 491ae20d963cff397b5980b31d142d576e74becb) --- src/SDL_utils_c.h | 5 ++++- src/stdlib/SDL_string.c | 38 ++++++++++++++++++++++++++++++++++- src/video/x11/SDL_x11events.c | 3 ++- 3 files changed, 43 insertions(+), 3 deletions(-) diff --git a/src/SDL_utils_c.h b/src/SDL_utils_c.h index baa552ff3..7fbd07b92 100644 --- a/src/SDL_utils_c.h +++ b/src/SDL_utils_c.h @@ -25,7 +25,10 @@ /* Common utility functions that aren't in the public API */ /* Return the smallest power of 2 greater than or equal to 'x' */ -int SDL_powerof2(int x); +extern int SDL_powerof2(int x); + +/* Return whether the string is valid UTF8 */ +extern SDL_bool SDL_utf8valid(const char *str, size_t bytes); #endif /* SDL_utils_h_ */ diff --git a/src/stdlib/SDL_string.c b/src/stdlib/SDL_string.c index 4a0170345..eb7d2e3f3 100644 --- a/src/stdlib/SDL_string.c +++ b/src/stdlib/SDL_string.c @@ -41,7 +41,7 @@ #define UTF8_IsLeadByte(c) ((c) >= 0xC0 && (c) <= 0xF4) #define UTF8_IsTrailingByte(c) ((c) >= 0x80 && (c) <= 0xBF) -static unsigned UTF8_TrailingBytes(unsigned char c) +static size_t UTF8_TrailingBytes(unsigned char c) { if (c >= 0xC0 && c <= 0xDF) { return 1; @@ -621,6 +621,42 @@ SDL_utf8strnlen(const char *str, size_t bytes) return retval; } +SDL_bool SDL_utf8valid(const char *str, size_t bytes) +{ + while (*str && bytes > 0) { + Uint8 ch = (Uint8)*str; + + if (ch <= 0x7F) { + ++str; + --bytes; + continue; + } + + if (UTF8_IsLeadByte(ch)) { + size_t left = UTF8_TrailingBytes(ch); + if (bytes < left) { + return SDL_FALSE; + } + + ++str; + --bytes; + + while (left-- > 0) { + ch = (Uint8)*str; + if (!UTF8_IsTrailingByte(ch)) { + return SDL_FALSE; + } + + ++str; + --bytes; + } + } else { + return SDL_FALSE; + } + } + return SDL_TRUE; +} + size_t SDL_strlcat(SDL_INOUT_Z_CAP(maxlen) char *dst, const char *src, size_t maxlen) { diff --git a/src/video/x11/SDL_x11events.c b/src/video/x11/SDL_x11events.c index ded4f1684..a2268a2d6 100644 --- a/src/video/x11/SDL_x11events.c +++ b/src/video/x11/SDL_x11events.c @@ -36,6 +36,7 @@ #include "../../events/SDL_events_c.h" #include "../../events/SDL_mouse_c.h" #include "../../events/SDL_touch_c.h" +#include "../../SDL_utils_c.h" #include "SDL_hints.h" #include "SDL_timer.h" @@ -742,7 +743,7 @@ static Bool isReparentNotify(Display *display, XEvent *ev, XPointer arg) static int XLookupStringAsUTF8(XKeyEvent *event_struct, char *buffer_return, int bytes_buffer, KeySym *keysym_return, XComposeStatus *status_in_out) { int result = X11_XLookupString(event_struct, buffer_return, bytes_buffer, keysym_return, status_in_out); - if (result > 0) { + if (result > 0 && !SDL_utf8valid(buffer_return, (size_t)result)) { char *utf8_text = SDL_iconv_string("UTF-8", "ISO-8859-1", buffer_return, result); if (utf8_text) { SDL_strlcpy(buffer_return, utf8_text, bytes_buffer);