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)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93
diff --git a/src/SDL_utils_c.h b/src/SDL_utils_c.h
index baa552f..7fbd07b 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 4a01703..eb7d2e3 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 ded4f16..a2268a2 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);