[IMM32] Re-implement ImmGetCompositionStringA/W (#4026)
[reactos.git] / dll / win32 / imm32 / compstr.c
1 /*
2 * PROJECT: ReactOS IMM32
3 * LICENSE: LGPL-2.1-or-later (https://spdx.org/licenses/LGPL-2.1-or-later)
4 * PURPOSE: Implementing composition strings of IMM32
5 * COPYRIGHT: Copyright 1998 Patrik Stridvall
6 * Copyright 2002, 2003, 2007 CodeWeavers, Aric Stewart
7 * Copyright 2017 James Tabor <james.tabor@reactos.org>
8 * Copyright 2018 Amine Khaldi <amine.khaldi@reactos.org>
9 * Copyright 2020 Oleg Dubinskiy <oleg.dubinskij2013@yandex.ua>
10 * Copyright 2020-2021 Katayama Hirofumi MZ <katayama.hirofumi.mz@gmail.com>
11 */
12
13 #include "precomp.h"
14
15 WINE_DEFAULT_DEBUG_CHANNEL(imm);
16
17 static inline LONG APIENTRY
18 Imm32CompStrAnsiToWide(LPCSTR psz, DWORD cb, LPWSTR lpBuf, DWORD dwBufLen, UINT uCodePage)
19 {
20 DWORD ret = MultiByteToWideChar(uCodePage, MB_PRECOMPOSED, psz, cb / sizeof(CHAR),
21 lpBuf, dwBufLen / sizeof(WCHAR));
22 if ((ret + 1) * sizeof(WCHAR) <= dwBufLen)
23 lpBuf[ret] = 0;
24 return ret * sizeof(WCHAR);
25 }
26
27 static inline LONG APIENTRY
28 Imm32CompStrWideToAnsi(LPCWSTR psz, DWORD cb, LPSTR lpBuf, DWORD dwBufLen, UINT uCodePage)
29 {
30 DWORD ret = WideCharToMultiByte(uCodePage, 0, psz, cb / sizeof(WCHAR),
31 lpBuf, dwBufLen / sizeof(CHAR), NULL, NULL);
32 if ((ret + 1) * sizeof(CHAR) <= dwBufLen)
33 lpBuf[ret] = 0;
34 return ret * sizeof(CHAR);
35 }
36
37 static INT APIENTRY
38 Imm32CompAttrWideToAnsi(const BYTE *src, INT src_len, LPCWSTR text,
39 INT str_len, LPBYTE dst, INT dst_len, UINT uCodePage)
40 {
41 INT rc;
42 INT i, j = 0, k = 0, len;
43
44 if (!src_len)
45 return 0;
46
47 rc = WideCharToMultiByte(uCodePage, 0, text, str_len, NULL, 0, NULL, NULL);
48
49 if (dst_len)
50 {
51 if (dst_len > rc)
52 dst_len = rc;
53
54 for (i = 0; i < str_len; ++i, ++k)
55 {
56 len = WideCharToMultiByte(uCodePage, 0, &text[i], 1, NULL, 0, NULL, NULL);
57 for (; len > 0; --len)
58 {
59 dst[j++] = src[k];
60
61 if (dst_len <= j)
62 goto end;
63 }
64 }
65 end:
66 rc = j;
67 }
68
69 return rc;
70 }
71
72 static INT APIENTRY
73 Imm32CompAttrAnsiToWide(const BYTE *src, INT src_len, LPCSTR text,
74 INT str_len, LPBYTE dst, INT dst_len, UINT uCodePage)
75 {
76 INT rc;
77 INT i, j = 0;
78
79 if (!src_len)
80 return 0;
81
82 rc = MultiByteToWideChar(uCodePage, MB_PRECOMPOSED, text, str_len, NULL, 0);
83
84 if (dst_len)
85 {
86 if (dst_len > rc)
87 dst_len = rc;
88
89 for (i = 0; i < str_len; ++i)
90 {
91 if (IsDBCSLeadByteEx(uCodePage, text[i]) && text[i + 1])
92 continue;
93
94 dst[j++] = src[i];
95
96 if (dst_len <= j)
97 break;
98 }
99
100 rc = j;
101 }
102
103 return rc;
104 }
105
106 static INT APIENTRY
107 Imm32CompClauseAnsiToWide(const DWORD *source, INT slen, LPCSTR text,
108 LPDWORD target, INT tlen, UINT uCodePage)
109 {
110 INT rc, i;
111
112 if (!slen)
113 return 0;
114
115 if (tlen)
116 {
117 if (tlen > slen)
118 tlen = slen;
119
120 tlen /= sizeof(DWORD);
121
122 for (i = 0; i < tlen; ++i)
123 {
124 target[i] = MultiByteToWideChar(uCodePage, MB_PRECOMPOSED, text, source[i], NULL, 0);
125 }
126
127 rc = sizeof(DWORD) * i;
128 }
129 else
130 {
131 rc = slen;
132 }
133
134 return rc;
135 }
136
137 static INT APIENTRY
138 Imm32CompClauseWideToAnsi(const DWORD *source, INT slen, LPCWSTR text,
139 LPDWORD target, INT tlen, UINT uCodePage)
140 {
141 INT rc, i;
142
143 if (!slen)
144 return 0;
145
146 if (tlen)
147 {
148 if (tlen > slen)
149 tlen = slen;
150
151 tlen /= sizeof(DWORD);
152
153 for (i = 0; i < tlen; ++i)
154 {
155 target[i] = WideCharToMultiByte(uCodePage, 0, text, source[i], NULL, 0, NULL, NULL);
156 }
157
158 rc = sizeof(DWORD) * i;
159 }
160 else
161 {
162 rc = slen;
163 }
164
165 return rc;
166 }
167
168 #define CS_StrA(pCS, Name) ((LPCSTR)(pCS) + (pCS)->dw##Name##Offset)
169 #define CS_StrW(pCS, Name) ((LPCWSTR)CS_StrA(pCS, Name))
170 #define CS_Attr(pCS, Name) ((const BYTE *)CS_StrA(pCS, Name))
171 #define CS_Clause(pCS, Name) ((const DWORD *)CS_StrA(pCS, Name))
172 #define CS_Size(pCS, Name) ((pCS)->dw##Name##Len)
173 #define CS_SizeA(pCS, Name) (CS_Size(pCS, Name) * sizeof(CHAR))
174 #define CS_SizeW(pCS, Name) (CS_Size(pCS, Name) * sizeof(WCHAR))
175
176 #define CS_DoStr(pCS, Name, AorW) do { \
177 if (dwBufLen == 0) { \
178 dwBufLen = CS_Size##AorW((pCS), Name); \
179 } else { \
180 if (dwBufLen > CS_Size##AorW((pCS), Name)) \
181 dwBufLen = CS_Size##AorW((pCS), Name); \
182 RtlCopyMemory(lpBuf, CS_Str##AorW((pCS), Name), dwBufLen); \
183 } \
184 } while (0)
185
186 #define CS_DoStrA(pCS, Name) CS_DoStr(pCS, Name, A)
187 #define CS_DoStrW(pCS, Name) CS_DoStr(pCS, Name, W)
188 #define CS_DoAttr CS_DoStrA
189 #define CS_DoClause CS_DoStrA
190
191 LONG APIENTRY
192 Imm32GetCompStrA(HIMC hIMC, const COMPOSITIONSTRING *pCS, DWORD dwIndex,
193 LPVOID lpBuf, DWORD dwBufLen, BOOL bAnsiClient, UINT uCodePage)
194 {
195 if (bAnsiClient)
196 {
197 switch (dwIndex)
198 {
199 case GCS_COMPREADSTR:
200 CS_DoStrA(pCS, CompReadStr);
201 break;
202
203 case GCS_COMPREADATTR:
204 CS_DoAttr(pCS, CompReadAttr);
205 break;
206
207 case GCS_COMPREADCLAUSE:
208 CS_DoClause(pCS, CompReadClause);
209 break;
210
211 case GCS_COMPSTR:
212 CS_DoStrA(pCS, CompStr);
213 break;
214
215 case GCS_COMPATTR:
216 CS_DoAttr(pCS, CompAttr);
217 break;
218
219 case GCS_COMPCLAUSE:
220 CS_DoClause(pCS, CompClause);
221 break;
222
223 case GCS_CURSORPOS:
224 dwBufLen = pCS->dwCursorPos;
225 break;
226
227 case GCS_DELTASTART:
228 dwBufLen = pCS->dwDeltaStart;
229 break;
230
231 case GCS_RESULTREADSTR:
232 CS_DoStrA(pCS, ResultReadStr);
233 break;
234
235 case GCS_RESULTREADCLAUSE:
236 CS_DoClause(pCS, ResultReadClause);
237 break;
238
239 case GCS_RESULTSTR:
240 CS_DoStrA(pCS, ResultStr);
241 break;
242
243 case GCS_RESULTCLAUSE:
244 CS_DoClause(pCS, ResultClause);
245 break;
246
247 default:
248 FIXME("TODO:\n");
249 return IMM_ERROR_GENERAL;
250 }
251 }
252 else /* !bAnsiClient */
253 {
254 switch (dwIndex)
255 {
256 case GCS_COMPREADSTR:
257 dwBufLen = Imm32CompStrWideToAnsi(CS_StrW(pCS, CompReadStr),
258 CS_SizeW(pCS, CompReadStr),
259 lpBuf, dwBufLen, uCodePage);
260 break;
261
262 case GCS_COMPREADATTR:
263 dwBufLen = Imm32CompAttrWideToAnsi(CS_Attr(pCS, CompReadAttr),
264 CS_Size(pCS, CompReadAttr),
265 CS_StrW(pCS, CompStr),
266 CS_SizeW(pCS, CompStr),
267 lpBuf, dwBufLen, uCodePage);
268 break;
269
270 case GCS_COMPREADCLAUSE:
271 dwBufLen = Imm32CompClauseWideToAnsi(CS_Clause(pCS, CompReadClause),
272 CS_Size(pCS, CompReadClause),
273 CS_StrW(pCS, CompStr),
274 lpBuf, dwBufLen, uCodePage);
275 break;
276
277 case GCS_COMPSTR:
278 dwBufLen = Imm32CompStrWideToAnsi(CS_StrW(pCS, CompStr),
279 CS_SizeW(pCS, CompStr),
280 lpBuf, dwBufLen, uCodePage);
281 break;
282
283 case GCS_COMPATTR:
284 dwBufLen = Imm32CompAttrWideToAnsi(CS_Attr(pCS, CompAttr),
285 CS_Size(pCS, CompAttr),
286 CS_StrW(pCS, CompStr),
287 CS_SizeW(pCS, CompStr),
288 lpBuf, dwBufLen, uCodePage);
289 break;
290
291 case GCS_COMPCLAUSE:
292 dwBufLen = Imm32CompClauseWideToAnsi(CS_Clause(pCS, CompClause),
293 CS_Size(pCS, CompClause),
294 CS_StrW(pCS, CompStr),
295 lpBuf, dwBufLen, uCodePage);
296 break;
297
298 case GCS_CURSORPOS:
299 dwBufLen = IchAnsiFromWide(pCS->dwCursorPos, CS_StrW(pCS, CompStr), uCodePage);
300 break;
301
302 case GCS_DELTASTART:
303 dwBufLen = IchAnsiFromWide(pCS->dwDeltaStart, CS_StrW(pCS, CompStr), uCodePage);
304 break;
305
306 case GCS_RESULTREADSTR:
307 dwBufLen = Imm32CompStrWideToAnsi(CS_StrW(pCS, ResultReadStr),
308 CS_SizeW(pCS, ResultReadStr),
309 lpBuf, dwBufLen, uCodePage);
310 break;
311
312 case GCS_RESULTREADCLAUSE:
313 dwBufLen = Imm32CompClauseWideToAnsi(CS_Clause(pCS, ResultReadClause),
314 CS_Size(pCS, ResultReadClause),
315 CS_StrW(pCS, CompStr),
316 lpBuf, dwBufLen, uCodePage);
317 break;
318
319 case GCS_RESULTSTR:
320 dwBufLen = Imm32CompStrWideToAnsi(CS_StrW(pCS, ResultStr),
321 CS_SizeW(pCS, ResultStr),
322 lpBuf, dwBufLen, uCodePage);
323 break;
324
325 case GCS_RESULTCLAUSE:
326 dwBufLen = Imm32CompClauseWideToAnsi(CS_Clause(pCS, ResultClause),
327 CS_Size(pCS, ResultClause),
328 CS_StrW(pCS, CompStr),
329 lpBuf, dwBufLen, uCodePage);
330 break;
331
332 default:
333 FIXME("TODO:\n");
334 return IMM_ERROR_GENERAL;
335 }
336 }
337
338 return dwBufLen;
339 }
340
341 LONG APIENTRY
342 Imm32GetCompStrW(HIMC hIMC, const COMPOSITIONSTRING *pCS, DWORD dwIndex,
343 LPVOID lpBuf, DWORD dwBufLen, BOOL bAnsiClient, UINT uCodePage)
344 {
345 if (bAnsiClient)
346 {
347 switch (dwIndex)
348 {
349 case GCS_COMPREADSTR:
350 dwBufLen = Imm32CompStrAnsiToWide(CS_StrA(pCS, CompReadStr),
351 CS_SizeA(pCS, CompReadStr),
352 lpBuf, dwBufLen, uCodePage);
353 break;
354
355 case GCS_COMPREADATTR:
356 dwBufLen = Imm32CompAttrAnsiToWide(CS_Attr(pCS, CompReadAttr),
357 CS_Size(pCS, CompReadAttr),
358 CS_StrA(pCS, CompStr), CS_SizeA(pCS, CompStr),
359 lpBuf, dwBufLen, uCodePage);
360 break;
361
362 case GCS_COMPREADCLAUSE:
363 dwBufLen = Imm32CompClauseAnsiToWide(CS_Clause(pCS, CompReadClause),
364 CS_Size(pCS, CompReadClause),
365 CS_StrA(pCS, CompStr),
366 lpBuf, dwBufLen, uCodePage);
367 break;
368
369 case GCS_COMPSTR:
370 dwBufLen = Imm32CompStrAnsiToWide(CS_StrA(pCS, CompStr),
371 CS_SizeA(pCS, CompStr),
372 lpBuf, dwBufLen, uCodePage);
373 break;
374
375 case GCS_COMPATTR:
376 dwBufLen = Imm32CompAttrAnsiToWide(CS_Attr(pCS, CompAttr),
377 CS_Size(pCS, CompAttr),
378 CS_StrA(pCS, CompStr), CS_SizeA(pCS, CompStr),
379 lpBuf, dwBufLen, uCodePage);
380 break;
381
382 case GCS_COMPCLAUSE:
383 dwBufLen = Imm32CompClauseAnsiToWide(CS_Clause(pCS, CompClause),
384 CS_Size(pCS, CompClause),
385 CS_StrA(pCS, CompStr),
386 lpBuf, dwBufLen, uCodePage);
387 break;
388
389 case GCS_CURSORPOS:
390 dwBufLen = IchWideFromAnsi(pCS->dwCursorPos, CS_StrA(pCS, CompStr), uCodePage);
391 break;
392
393 case GCS_DELTASTART:
394 dwBufLen = IchWideFromAnsi(pCS->dwDeltaStart, CS_StrA(pCS, CompStr), uCodePage);
395 break;
396
397 case GCS_RESULTREADSTR:
398 dwBufLen = Imm32CompStrAnsiToWide(CS_StrA(pCS, ResultReadStr),
399 CS_SizeA(pCS, ResultReadStr),
400 lpBuf, dwBufLen, uCodePage);
401 break;
402
403 case GCS_RESULTREADCLAUSE:
404 dwBufLen = Imm32CompClauseAnsiToWide(CS_Clause(pCS, ResultReadClause),
405 CS_Size(pCS, ResultReadClause),
406 CS_StrA(pCS, CompStr),
407 lpBuf, dwBufLen, uCodePage);
408 break;
409
410 case GCS_RESULTSTR:
411 dwBufLen = Imm32CompStrAnsiToWide(CS_StrA(pCS, ResultStr),
412 CS_SizeA(pCS, ResultStr),
413 lpBuf, dwBufLen, uCodePage);
414 break;
415
416 case GCS_RESULTCLAUSE:
417 dwBufLen = Imm32CompClauseAnsiToWide(CS_Clause(pCS, ResultClause),
418 CS_Size(pCS, ResultClause),
419 CS_StrA(pCS, CompStr),
420 lpBuf, dwBufLen, uCodePage);
421 break;
422
423 default:
424 FIXME("TODO:\n");
425 return IMM_ERROR_GENERAL;
426 }
427 }
428 else /* !bAnsiClient */
429 {
430 switch (dwIndex)
431 {
432 case GCS_COMPREADSTR:
433 CS_DoStrW(pCS, CompReadStr);
434 break;
435
436 case GCS_COMPREADATTR:
437 CS_DoAttr(pCS, CompReadAttr);
438 break;
439
440 case GCS_COMPREADCLAUSE:
441 CS_DoClause(pCS, CompReadClause);
442 break;
443
444 case GCS_COMPSTR:
445 CS_DoStrW(pCS, CompStr);
446 break;
447
448 case GCS_COMPATTR:
449 CS_DoAttr(pCS, CompAttr);
450 break;
451
452 case GCS_COMPCLAUSE:
453 CS_DoClause(pCS, CompClause);
454 break;
455
456 case GCS_CURSORPOS:
457 dwBufLen = pCS->dwCursorPos;
458 break;
459
460 case GCS_DELTASTART:
461 dwBufLen = pCS->dwDeltaStart;
462 break;
463
464 case GCS_RESULTREADSTR:
465 CS_DoStrW(pCS, ResultReadStr);
466 break;
467
468 case GCS_RESULTREADCLAUSE:
469 CS_DoClause(pCS, ResultReadClause);
470 break;
471
472 case GCS_RESULTSTR:
473 CS_DoStrW(pCS, ResultStr);
474 break;
475
476 case GCS_RESULTCLAUSE:
477 CS_DoClause(pCS, ResultClause);
478 break;
479
480 default:
481 FIXME("TODO:\n");
482 return IMM_ERROR_GENERAL;
483 }
484 }
485
486 return dwBufLen;
487 }
488
489 BOOL APIENTRY
490 Imm32SetCompositionStringAW(HIMC hIMC, DWORD dwIndex, LPCVOID lpComp, DWORD dwCompLen,
491 LPCVOID lpRead, DWORD dwReadLen, BOOL bAnsi)
492 {
493 FIXME("TODO:\n");
494 return FALSE;
495 }
496
497 /***********************************************************************
498 * ImmGetCompositionStringA (IMM32.@)
499 */
500 LONG WINAPI ImmGetCompositionStringA(HIMC hIMC, DWORD dwIndex, LPVOID lpBuf, DWORD dwBufLen)
501 {
502 LONG ret = 0;
503 LPINPUTCONTEXT pIC;
504 PCLIENTIMC pClientImc;
505 LPCOMPOSITIONSTRING pCS;
506 BOOL bAnsiClient;
507 UINT uCodePage;
508
509 TRACE("(%p, %lu, %p, %lu)\n", hIMC, dwIndex, lpBuf, dwBufLen);
510
511 if (dwBufLen && !lpBuf)
512 return 0;
513
514 pClientImc = ImmLockClientImc(hIMC);
515 if (!pClientImc)
516 return 0;
517
518 bAnsiClient = !(pClientImc->dwFlags & CLIENTIMC_WIDE);
519 uCodePage = pClientImc->uCodePage;
520 ImmUnlockClientImc(pClientImc);
521
522 pIC = ImmLockIMC(hIMC);
523 if (!pIC)
524 return 0;
525
526 pCS = ImmLockIMCC(pIC->hCompStr);
527 if (!pCS)
528 {
529 ImmUnlockIMC(hIMC);
530 return 0;
531 }
532
533 ret = Imm32GetCompStrA(hIMC, pCS, dwIndex, lpBuf, dwBufLen, bAnsiClient, uCodePage);
534 ImmUnlockIMCC(pIC->hCompStr);
535 ImmUnlockIMC(hIMC);
536 return ret;
537 }
538
539 /***********************************************************************
540 * ImmGetCompositionStringW (IMM32.@)
541 */
542 LONG WINAPI ImmGetCompositionStringW(HIMC hIMC, DWORD dwIndex, LPVOID lpBuf, DWORD dwBufLen)
543 {
544 LONG ret = 0;
545 LPINPUTCONTEXT pIC;
546 PCLIENTIMC pClientImc;
547 LPCOMPOSITIONSTRING pCS;
548 BOOL bAnsiClient;
549 UINT uCodePage;
550
551 TRACE("(%p, %lu, %p, %lu)\n", hIMC, dwIndex, lpBuf, dwBufLen);
552
553 if (dwBufLen && !lpBuf)
554 return 0;
555
556 pClientImc = ImmLockClientImc(hIMC);
557 if (!pClientImc)
558 return 0;
559
560 bAnsiClient = !(pClientImc->dwFlags & CLIENTIMC_WIDE);
561 uCodePage = pClientImc->uCodePage;
562 ImmUnlockClientImc(pClientImc);
563
564 pIC = ImmLockIMC(hIMC);
565 if (!pIC)
566 return 0;
567
568 pCS = ImmLockIMCC(pIC->hCompStr);
569 if (!pCS)
570 {
571 ImmUnlockIMC(hIMC);
572 return 0;
573 }
574
575 ret = Imm32GetCompStrW(hIMC, pCS, dwIndex, lpBuf, dwBufLen, bAnsiClient, uCodePage);
576 ImmUnlockIMCC(pIC->hCompStr);
577 ImmUnlockIMC(hIMC);
578 return ret;
579 }
580
581 /***********************************************************************
582 * ImmSetCompositionStringA (IMM32.@)
583 */
584 BOOL WINAPI
585 ImmSetCompositionStringA(HIMC hIMC, DWORD dwIndex, LPCVOID lpComp, DWORD dwCompLen,
586 LPCVOID lpRead, DWORD dwReadLen)
587 {
588 TRACE("(%p, %lu, %p, %lu, %p, %lu)\n",
589 hIMC, dwIndex, lpComp, dwCompLen, lpRead, dwReadLen);
590 return Imm32SetCompositionStringAW(hIMC, dwIndex, lpComp, dwCompLen,
591 lpRead, dwReadLen, TRUE);
592 }
593
594 /***********************************************************************
595 * ImmSetCompositionStringW (IMM32.@)
596 */
597 BOOL WINAPI
598 ImmSetCompositionStringW(HIMC hIMC, DWORD dwIndex, LPCVOID lpComp, DWORD dwCompLen,
599 LPCVOID lpRead, DWORD dwReadLen)
600 {
601 TRACE("(%p, %lu, %p, %lu, %p, %lu)\n",
602 hIMC, dwIndex, lpComp, dwCompLen, lpRead, dwReadLen);
603 return Imm32SetCompositionStringAW(hIMC, dwIndex, lpComp, dwCompLen,
604 lpRead, dwReadLen, FALSE);
605 }