SDL: adjustments to ime_candidates

From 97269e143d06d75415d7d501f3ecc278608d677e Mon Sep 17 00:00:00 2001
From: pionere <[EMAIL REDACTED]>
Date: Tue, 18 Jan 2022 17:51:17 +0100
Subject: [PATCH] adjustments to ime_candidates - allocate ime_candidates on
 demand - allow write to the whole allocated memory of ime_candidates - ensure
 ime_candcount is set to zero in case the candidates can not be queried for
 any reason

---
 src/video/windows/SDL_windowskeyboard.c | 43 +++++++++++++++++--------
 src/video/windows/SDL_windowsvideo.h    |  3 +-
 2 files changed, 31 insertions(+), 15 deletions(-)

diff --git a/src/video/windows/SDL_windowskeyboard.c b/src/video/windows/SDL_windowskeyboard.c
index bdf431f1756..6ab440dddfc 100644
--- a/src/video/windows/SDL_windowskeyboard.c
+++ b/src/video/windows/SDL_windowskeyboard.c
@@ -67,7 +67,7 @@ WIN_InitKeyboard(_THIS)
     data->ime_cursor = 0;
 
     data->ime_candlist = SDL_FALSE;
-    SDL_memset(data->ime_candidates, 0, sizeof(data->ime_candidates));
+    data->ime_candidates = NULL;
     data->ime_candcount = 0;
     data->ime_candref = 0;
     data->ime_candsel = 0;
@@ -349,7 +349,7 @@ DEFINE_GUID(IID_ITfThreadMgrEx,                                0x3E90ADE3,0x7594
 #define SUBLANG() SUBLANGID(LANG())
 
 static void IME_UpdateInputLocale(SDL_VideoData *videodata);
-static void IME_ShowCandidateList(SDL_VideoData *videodata);
+static int IME_ShowCandidateList(SDL_VideoData *videodata);
 static void IME_ClearComposition(SDL_VideoData *videodata);
 static void IME_SetWindow(SDL_VideoData* videodata, HWND hwnd);
 static void IME_SetupAPI(SDL_VideoData *videodata);
@@ -801,12 +801,14 @@ IME_SendEditingEvent(SDL_VideoData *videodata)
 static void
 IME_AddCandidate(SDL_VideoData *videodata, UINT i, LPCWSTR candidate)
 {
-    LPWSTR dst = videodata->ime_candidates[i];
+    LPWSTR dst = &videodata->ime_candidates[i * MAX_CANDLENGTH];
+    LPWSTR end = &dst[MAX_CANDLENGTH - 1];
+    SDL_COMPILE_TIME_ASSERT(IME_CANDIDATE_INDEXING_REQUIRES, MAX_CANDLIST == 10);
     *dst++ = (WCHAR)(TEXT('0') + ((i + videodata->ime_candlistindexbase) % 10));
     if (videodata->ime_candvertical)
         *dst++ = TEXT(' ');
 
-    while (*candidate && (SDL_arraysize(videodata->ime_candidates[i]) > (dst - videodata->ime_candidates[i])))
+    while (*candidate && dst < end)
         *dst++ = *candidate++;
 
     *dst = (WCHAR)'\0';
@@ -819,8 +821,8 @@ IME_GetCandidateList(HWND hwnd, SDL_VideoData *videodata)
     DWORD size;
     LPCANDIDATELIST cand_list;
 
-    IME_ShowCandidateList(videodata);
-
+    if (IME_ShowCandidateList(videodata) < 0)
+        return;
     himc = ImmGetContext(hwnd);
     if (!himc)
         return;
@@ -857,7 +859,6 @@ IME_GetCandidateList(HWND hwnd, SDL_VideoData *videodata)
                     videodata->ime_candpgsize = SDL_min(cand_list->dwPageSize == 0 ? MAX_CANDLIST : cand_list->dwPageSize, MAX_CANDLIST);
                     page_start = (cand_list->dwSelection / videodata->ime_candpgsize) * videodata->ime_candpgsize;
                 }
-                SDL_memset(&videodata->ime_candidates, 0, sizeof(videodata->ime_candidates));
                 for (i = page_start, j = 0; (DWORD)i < cand_list->dwCount && j < videodata->ime_candpgsize; i++, j++) {
                     LPCWSTR candidate = (LPCWSTR)((DWORD_PTR)cand_list + cand_list->dwOffset[i]);
                     IME_AddCandidate(videodata, j, candidate);
@@ -873,13 +874,26 @@ IME_GetCandidateList(HWND hwnd, SDL_VideoData *videodata)
     ImmReleaseContext(hwnd, himc);
 }
 
-static void
+static int
 IME_ShowCandidateList(SDL_VideoData *videodata)
 {
+    void *candidates;
+
+    videodata->ime_candcount = 0;
+    candidates = SDL_realloc(videodata->ime_candidates, MAX_CANDSIZE);
+    if (candidates != NULL)
+        videodata->ime_candidates = (WCHAR *)candidates;
+
+    if (videodata->ime_candidates == NULL)
+        return -1;
+
+    SDL_memset(videodata->ime_candidates, 0, MAX_CANDSIZE);
+
     videodata->ime_dirty = SDL_TRUE;
     videodata->ime_candlist = SDL_TRUE;
     IME_DestroyTextures(videodata);
     IME_SendEditingEvent(videodata);
+    return 0;
 }
 
 static void
@@ -995,7 +1009,8 @@ IME_CloseCandidateList(SDL_VideoData *videodata)
 {
     IME_HideCandidateList(videodata);
     videodata->ime_candcount = 0;
-    SDL_memset(videodata->ime_candidates, 0, sizeof(videodata->ime_candidates));
+    SDL_free(videodata->ime_candidates);
+    videodata->ime_candidates = NULL;
 }
 
 static void
@@ -1008,13 +1023,15 @@ UILess_GetCandidateList(SDL_VideoData *videodata, ITfCandidateListUIElement *pca
     DWORD pgstart = 0;
     DWORD pgsize = 0;
     UINT i, j;
+    if (IME_ShowCandidateList(videodata) < 0)
+        return;
+
     pcandlist->lpVtbl->GetSelection(pcandlist, &selection);
     pcandlist->lpVtbl->GetCount(pcandlist, &count);
     pcandlist->lpVtbl->GetCurrentPage(pcandlist, &page);
 
     videodata->ime_candsel = selection;
     videodata->ime_candcount = count;
-    IME_ShowCandidateList(videodata);
 
     pcandlist->lpVtbl->GetPageIndex(pcandlist, 0, 0, &pgcount);
     if (pgcount > 0) {
@@ -1032,8 +1049,6 @@ UILess_GetCandidateList(SDL_VideoData *videodata, ITfCandidateListUIElement *pca
     }
     videodata->ime_candpgsize = SDL_min(pgsize, MAX_CANDLIST);
     videodata->ime_candsel = videodata->ime_candsel - pgstart;
-
-    SDL_memset(videodata->ime_candidates, 0, sizeof(videodata->ime_candidates));
     for (i = pgstart, j = 0; (DWORD)i < count && j < videodata->ime_candpgsize; i++, j++) {
         BSTR bstr;
         if (SUCCEEDED(pcandlist->lpVtbl->GetString(pcandlist, i, &bstr))) {
@@ -1462,7 +1477,7 @@ IME_RenderCandidateList(SDL_VideoData *videodata, HDC hdc)
     SelectObject(hdc, font);
 
     for (i = 0; i < candcount; ++i) {
-        const WCHAR *s = videodata->ime_candidates[i];
+        const WCHAR *s = &videodata->ime_candidates[i * MAX_CANDLENGTH];
         if (!*s)
             break;
 
@@ -1524,7 +1539,7 @@ IME_RenderCandidateList(SDL_VideoData *videodata, HDC hdc)
     SetBkMode(hdc, TRANSPARENT);
 
     for (i = 0; i < candcount; ++i) {
-        const WCHAR *s = videodata->ime_candidates[i];
+        const WCHAR *s = &videodata->ime_candidates[i * MAX_CANDLENGTH];
         int left, top, right, bottom;
         if (!*s)
             break;
diff --git a/src/video/windows/SDL_windowsvideo.h b/src/video/windows/SDL_windowsvideo.h
index 7dae16a4ac8..daf68e6c2d6 100644
--- a/src/video/windows/SDL_windowsvideo.h
+++ b/src/video/windows/SDL_windowsvideo.h
@@ -37,6 +37,7 @@
 
 #define MAX_CANDLIST    10
 #define MAX_CANDLENGTH  256
+#define MAX_CANDSIZE    (sizeof(WCHAR) * MAX_CANDLIST * MAX_CANDLENGTH)
 
 #include "SDL_windowsclipboard.h"
 #include "SDL_windowsevents.h"
@@ -157,7 +158,7 @@ typedef struct SDL_VideoData
     int ime_cursor;
 
     SDL_bool ime_candlist;
-    WCHAR ime_candidates[MAX_CANDLIST][MAX_CANDLENGTH];
+    WCHAR* ime_candidates;
     DWORD ime_candcount;
     DWORD ime_candref;
     DWORD ime_candsel;