From bfb7bd05a404d43985502282ce9cccbcae0c832d Mon Sep 17 00:00:00 2001 From: Katayama Hirofumi MZ Date: Thu, 14 Oct 2021 08:07:06 +0900 Subject: [PATCH] [IMM32] Re-implement ImmGetCompositionStringA/W (#4026) - Re-implement ImmGetCompositionStringA and ImmGetCompositionStringW functions. - Add Imm32CompStrAnsiToWide, Imm32CompStrWideToAnsi, Imm32CompAttrWideToAnsi, Imm32CompAttrAnsiToWide, Imm32CompClauseAnsiToWide, and Imm32CompClauseWideToAnsi helper functions. CORE-11700 --- dll/win32/imm32/compstr.c | 403 ++++++++++++++++++++++++++++++++++++-- 1 file changed, 390 insertions(+), 13 deletions(-) diff --git a/dll/win32/imm32/compstr.c b/dll/win32/imm32/compstr.c index 4ce157356e3..df0726c2fa2 100644 --- a/dll/win32/imm32/compstr.c +++ b/dll/win32/imm32/compstr.c @@ -2,38 +2,251 @@ * PROJECT: ReactOS IMM32 * LICENSE: LGPL-2.1-or-later (https://spdx.org/licenses/LGPL-2.1-or-later) * PURPOSE: Implementing composition strings of IMM32 - * COPYRIGHT: Copyright 2020-2021 Katayama Hirofumi MZ + * COPYRIGHT: Copyright 1998 Patrik Stridvall + * Copyright 2002, 2003, 2007 CodeWeavers, Aric Stewart + * Copyright 2017 James Tabor + * Copyright 2018 Amine Khaldi + * Copyright 2020 Oleg Dubinskiy + * Copyright 2020-2021 Katayama Hirofumi MZ */ #include "precomp.h" WINE_DEFAULT_DEBUG_CHANNEL(imm); +static inline LONG APIENTRY +Imm32CompStrAnsiToWide(LPCSTR psz, DWORD cb, LPWSTR lpBuf, DWORD dwBufLen, UINT uCodePage) +{ + DWORD ret = MultiByteToWideChar(uCodePage, MB_PRECOMPOSED, psz, cb / sizeof(CHAR), + lpBuf, dwBufLen / sizeof(WCHAR)); + if ((ret + 1) * sizeof(WCHAR) <= dwBufLen) + lpBuf[ret] = 0; + return ret * sizeof(WCHAR); +} + +static inline LONG APIENTRY +Imm32CompStrWideToAnsi(LPCWSTR psz, DWORD cb, LPSTR lpBuf, DWORD dwBufLen, UINT uCodePage) +{ + DWORD ret = WideCharToMultiByte(uCodePage, 0, psz, cb / sizeof(WCHAR), + lpBuf, dwBufLen / sizeof(CHAR), NULL, NULL); + if ((ret + 1) * sizeof(CHAR) <= dwBufLen) + lpBuf[ret] = 0; + return ret * sizeof(CHAR); +} + +static INT APIENTRY +Imm32CompAttrWideToAnsi(const BYTE *src, INT src_len, LPCWSTR text, + INT str_len, LPBYTE dst, INT dst_len, UINT uCodePage) +{ + INT rc; + INT i, j = 0, k = 0, len; + + if (!src_len) + return 0; + + rc = WideCharToMultiByte(uCodePage, 0, text, str_len, NULL, 0, NULL, NULL); + + if (dst_len) + { + if (dst_len > rc) + dst_len = rc; + + for (i = 0; i < str_len; ++i, ++k) + { + len = WideCharToMultiByte(uCodePage, 0, &text[i], 1, NULL, 0, NULL, NULL); + for (; len > 0; --len) + { + dst[j++] = src[k]; + + if (dst_len <= j) + goto end; + } + } +end: + rc = j; + } + + return rc; +} + +static INT APIENTRY +Imm32CompAttrAnsiToWide(const BYTE *src, INT src_len, LPCSTR text, + INT str_len, LPBYTE dst, INT dst_len, UINT uCodePage) +{ + INT rc; + INT i, j = 0; + + if (!src_len) + return 0; + + rc = MultiByteToWideChar(uCodePage, MB_PRECOMPOSED, text, str_len, NULL, 0); + + if (dst_len) + { + if (dst_len > rc) + dst_len = rc; + + for (i = 0; i < str_len; ++i) + { + if (IsDBCSLeadByteEx(uCodePage, text[i]) && text[i + 1]) + continue; + + dst[j++] = src[i]; + + if (dst_len <= j) + break; + } + + rc = j; + } + + return rc; +} + +static INT APIENTRY +Imm32CompClauseAnsiToWide(const DWORD *source, INT slen, LPCSTR text, + LPDWORD target, INT tlen, UINT uCodePage) +{ + INT rc, i; + + if (!slen) + return 0; + + if (tlen) + { + if (tlen > slen) + tlen = slen; + + tlen /= sizeof(DWORD); + + for (i = 0; i < tlen; ++i) + { + target[i] = MultiByteToWideChar(uCodePage, MB_PRECOMPOSED, text, source[i], NULL, 0); + } + + rc = sizeof(DWORD) * i; + } + else + { + rc = slen; + } + + return rc; +} + +static INT APIENTRY +Imm32CompClauseWideToAnsi(const DWORD *source, INT slen, LPCWSTR text, + LPDWORD target, INT tlen, UINT uCodePage) +{ + INT rc, i; + + if (!slen) + return 0; + + if (tlen) + { + if (tlen > slen) + tlen = slen; + + tlen /= sizeof(DWORD); + + for (i = 0; i < tlen; ++i) + { + target[i] = WideCharToMultiByte(uCodePage, 0, text, source[i], NULL, 0, NULL, NULL); + } + + rc = sizeof(DWORD) * i; + } + else + { + rc = slen; + } + + return rc; +} + +#define CS_StrA(pCS, Name) ((LPCSTR)(pCS) + (pCS)->dw##Name##Offset) +#define CS_StrW(pCS, Name) ((LPCWSTR)CS_StrA(pCS, Name)) +#define CS_Attr(pCS, Name) ((const BYTE *)CS_StrA(pCS, Name)) +#define CS_Clause(pCS, Name) ((const DWORD *)CS_StrA(pCS, Name)) +#define CS_Size(pCS, Name) ((pCS)->dw##Name##Len) +#define CS_SizeA(pCS, Name) (CS_Size(pCS, Name) * sizeof(CHAR)) +#define CS_SizeW(pCS, Name) (CS_Size(pCS, Name) * sizeof(WCHAR)) + +#define CS_DoStr(pCS, Name, AorW) do { \ + if (dwBufLen == 0) { \ + dwBufLen = CS_Size##AorW((pCS), Name); \ + } else { \ + if (dwBufLen > CS_Size##AorW((pCS), Name)) \ + dwBufLen = CS_Size##AorW((pCS), Name); \ + RtlCopyMemory(lpBuf, CS_Str##AorW((pCS), Name), dwBufLen); \ + } \ +} while (0) + +#define CS_DoStrA(pCS, Name) CS_DoStr(pCS, Name, A) +#define CS_DoStrW(pCS, Name) CS_DoStr(pCS, Name, W) +#define CS_DoAttr CS_DoStrA +#define CS_DoClause CS_DoStrA + LONG APIENTRY Imm32GetCompStrA(HIMC hIMC, const COMPOSITIONSTRING *pCS, DWORD dwIndex, LPVOID lpBuf, DWORD dwBufLen, BOOL bAnsiClient, UINT uCodePage) { - LONG ret = IMM_ERROR_GENERAL; - if (bAnsiClient) { switch (dwIndex) { case GCS_COMPREADSTR: + CS_DoStrA(pCS, CompReadStr); + break; + case GCS_COMPREADATTR: + CS_DoAttr(pCS, CompReadAttr); + break; + case GCS_COMPREADCLAUSE: + CS_DoClause(pCS, CompReadClause); + break; + case GCS_COMPSTR: + CS_DoStrA(pCS, CompStr); + break; + case GCS_COMPATTR: + CS_DoAttr(pCS, CompAttr); + break; + case GCS_COMPCLAUSE: + CS_DoClause(pCS, CompClause); + break; + case GCS_CURSORPOS: + dwBufLen = pCS->dwCursorPos; + break; + case GCS_DELTASTART: + dwBufLen = pCS->dwDeltaStart; + break; + case GCS_RESULTREADSTR: + CS_DoStrA(pCS, ResultReadStr); + break; + case GCS_RESULTREADCLAUSE: + CS_DoClause(pCS, ResultReadClause); + break; + case GCS_RESULTSTR: + CS_DoStrA(pCS, ResultStr); + break; + case GCS_RESULTCLAUSE: + CS_DoClause(pCS, ResultClause); + break; + default: FIXME("TODO:\n"); - break; + return IMM_ERROR_GENERAL; } } else /* !bAnsiClient */ @@ -41,51 +254,175 @@ Imm32GetCompStrA(HIMC hIMC, const COMPOSITIONSTRING *pCS, DWORD dwIndex, switch (dwIndex) { case GCS_COMPREADSTR: + dwBufLen = Imm32CompStrWideToAnsi(CS_StrW(pCS, CompReadStr), + CS_SizeW(pCS, CompReadStr), + lpBuf, dwBufLen, uCodePage); + break; + case GCS_COMPREADATTR: + dwBufLen = Imm32CompAttrWideToAnsi(CS_Attr(pCS, CompReadAttr), + CS_Size(pCS, CompReadAttr), + CS_StrW(pCS, CompStr), + CS_SizeW(pCS, CompStr), + lpBuf, dwBufLen, uCodePage); + break; + case GCS_COMPREADCLAUSE: + dwBufLen = Imm32CompClauseWideToAnsi(CS_Clause(pCS, CompReadClause), + CS_Size(pCS, CompReadClause), + CS_StrW(pCS, CompStr), + lpBuf, dwBufLen, uCodePage); + break; + case GCS_COMPSTR: + dwBufLen = Imm32CompStrWideToAnsi(CS_StrW(pCS, CompStr), + CS_SizeW(pCS, CompStr), + lpBuf, dwBufLen, uCodePage); + break; + case GCS_COMPATTR: + dwBufLen = Imm32CompAttrWideToAnsi(CS_Attr(pCS, CompAttr), + CS_Size(pCS, CompAttr), + CS_StrW(pCS, CompStr), + CS_SizeW(pCS, CompStr), + lpBuf, dwBufLen, uCodePage); + break; + case GCS_COMPCLAUSE: + dwBufLen = Imm32CompClauseWideToAnsi(CS_Clause(pCS, CompClause), + CS_Size(pCS, CompClause), + CS_StrW(pCS, CompStr), + lpBuf, dwBufLen, uCodePage); + break; + case GCS_CURSORPOS: + dwBufLen = IchAnsiFromWide(pCS->dwCursorPos, CS_StrW(pCS, CompStr), uCodePage); + break; + case GCS_DELTASTART: + dwBufLen = IchAnsiFromWide(pCS->dwDeltaStart, CS_StrW(pCS, CompStr), uCodePage); + break; + case GCS_RESULTREADSTR: + dwBufLen = Imm32CompStrWideToAnsi(CS_StrW(pCS, ResultReadStr), + CS_SizeW(pCS, ResultReadStr), + lpBuf, dwBufLen, uCodePage); + break; + case GCS_RESULTREADCLAUSE: + dwBufLen = Imm32CompClauseWideToAnsi(CS_Clause(pCS, ResultReadClause), + CS_Size(pCS, ResultReadClause), + CS_StrW(pCS, CompStr), + lpBuf, dwBufLen, uCodePage); + break; + case GCS_RESULTSTR: + dwBufLen = Imm32CompStrWideToAnsi(CS_StrW(pCS, ResultStr), + CS_SizeW(pCS, ResultStr), + lpBuf, dwBufLen, uCodePage); + break; + case GCS_RESULTCLAUSE: + dwBufLen = Imm32CompClauseWideToAnsi(CS_Clause(pCS, ResultClause), + CS_Size(pCS, ResultClause), + CS_StrW(pCS, CompStr), + lpBuf, dwBufLen, uCodePage); + break; + default: FIXME("TODO:\n"); - break; + return IMM_ERROR_GENERAL; } } - return ret; + return dwBufLen; } LONG APIENTRY Imm32GetCompStrW(HIMC hIMC, const COMPOSITIONSTRING *pCS, DWORD dwIndex, LPVOID lpBuf, DWORD dwBufLen, BOOL bAnsiClient, UINT uCodePage) { - LONG ret = IMM_ERROR_GENERAL; - if (bAnsiClient) { switch (dwIndex) { case GCS_COMPREADSTR: + dwBufLen = Imm32CompStrAnsiToWide(CS_StrA(pCS, CompReadStr), + CS_SizeA(pCS, CompReadStr), + lpBuf, dwBufLen, uCodePage); + break; + case GCS_COMPREADATTR: + dwBufLen = Imm32CompAttrAnsiToWide(CS_Attr(pCS, CompReadAttr), + CS_Size(pCS, CompReadAttr), + CS_StrA(pCS, CompStr), CS_SizeA(pCS, CompStr), + lpBuf, dwBufLen, uCodePage); + break; + case GCS_COMPREADCLAUSE: + dwBufLen = Imm32CompClauseAnsiToWide(CS_Clause(pCS, CompReadClause), + CS_Size(pCS, CompReadClause), + CS_StrA(pCS, CompStr), + lpBuf, dwBufLen, uCodePage); + break; + case GCS_COMPSTR: + dwBufLen = Imm32CompStrAnsiToWide(CS_StrA(pCS, CompStr), + CS_SizeA(pCS, CompStr), + lpBuf, dwBufLen, uCodePage); + break; + case GCS_COMPATTR: + dwBufLen = Imm32CompAttrAnsiToWide(CS_Attr(pCS, CompAttr), + CS_Size(pCS, CompAttr), + CS_StrA(pCS, CompStr), CS_SizeA(pCS, CompStr), + lpBuf, dwBufLen, uCodePage); + break; + case GCS_COMPCLAUSE: + dwBufLen = Imm32CompClauseAnsiToWide(CS_Clause(pCS, CompClause), + CS_Size(pCS, CompClause), + CS_StrA(pCS, CompStr), + lpBuf, dwBufLen, uCodePage); + break; + case GCS_CURSORPOS: + dwBufLen = IchWideFromAnsi(pCS->dwCursorPos, CS_StrA(pCS, CompStr), uCodePage); + break; + case GCS_DELTASTART: + dwBufLen = IchWideFromAnsi(pCS->dwDeltaStart, CS_StrA(pCS, CompStr), uCodePage); + break; + case GCS_RESULTREADSTR: + dwBufLen = Imm32CompStrAnsiToWide(CS_StrA(pCS, ResultReadStr), + CS_SizeA(pCS, ResultReadStr), + lpBuf, dwBufLen, uCodePage); + break; + case GCS_RESULTREADCLAUSE: + dwBufLen = Imm32CompClauseAnsiToWide(CS_Clause(pCS, ResultReadClause), + CS_Size(pCS, ResultReadClause), + CS_StrA(pCS, CompStr), + lpBuf, dwBufLen, uCodePage); + break; + case GCS_RESULTSTR: + dwBufLen = Imm32CompStrAnsiToWide(CS_StrA(pCS, ResultStr), + CS_SizeA(pCS, ResultStr), + lpBuf, dwBufLen, uCodePage); + break; + case GCS_RESULTCLAUSE: + dwBufLen = Imm32CompClauseAnsiToWide(CS_Clause(pCS, ResultClause), + CS_Size(pCS, ResultClause), + CS_StrA(pCS, CompStr), + lpBuf, dwBufLen, uCodePage); + break; + default: FIXME("TODO:\n"); - break; + return IMM_ERROR_GENERAL; } } else /* !bAnsiClient */ @@ -93,24 +430,60 @@ Imm32GetCompStrW(HIMC hIMC, const COMPOSITIONSTRING *pCS, DWORD dwIndex, switch (dwIndex) { case GCS_COMPREADSTR: + CS_DoStrW(pCS, CompReadStr); + break; + case GCS_COMPREADATTR: + CS_DoAttr(pCS, CompReadAttr); + break; + case GCS_COMPREADCLAUSE: + CS_DoClause(pCS, CompReadClause); + break; + case GCS_COMPSTR: + CS_DoStrW(pCS, CompStr); + break; + case GCS_COMPATTR: + CS_DoAttr(pCS, CompAttr); + break; + case GCS_COMPCLAUSE: + CS_DoClause(pCS, CompClause); + break; + case GCS_CURSORPOS: + dwBufLen = pCS->dwCursorPos; + break; + case GCS_DELTASTART: + dwBufLen = pCS->dwDeltaStart; + break; + case GCS_RESULTREADSTR: + CS_DoStrW(pCS, ResultReadStr); + break; + case GCS_RESULTREADCLAUSE: + CS_DoClause(pCS, ResultReadClause); + break; + case GCS_RESULTSTR: + CS_DoStrW(pCS, ResultStr); + break; + case GCS_RESULTCLAUSE: + CS_DoClause(pCS, ResultClause); + break; + default: FIXME("TODO:\n"); - break; + return IMM_ERROR_GENERAL; } } - return ret; + return dwBufLen; } BOOL APIENTRY @@ -131,6 +504,7 @@ LONG WINAPI ImmGetCompositionStringA(HIMC hIMC, DWORD dwIndex, LPVOID lpBuf, DWO PCLIENTIMC pClientImc; LPCOMPOSITIONSTRING pCS; BOOL bAnsiClient; + UINT uCodePage; TRACE("(%p, %lu, %p, %lu)\n", hIMC, dwIndex, lpBuf, dwBufLen); @@ -142,6 +516,7 @@ LONG WINAPI ImmGetCompositionStringA(HIMC hIMC, DWORD dwIndex, LPVOID lpBuf, DWO return 0; bAnsiClient = !(pClientImc->dwFlags & CLIENTIMC_WIDE); + uCodePage = pClientImc->uCodePage; ImmUnlockClientImc(pClientImc); pIC = ImmLockIMC(hIMC); @@ -155,7 +530,7 @@ LONG WINAPI ImmGetCompositionStringA(HIMC hIMC, DWORD dwIndex, LPVOID lpBuf, DWO return 0; } - ret = Imm32GetCompStrA(hIMC, pCS, dwIndex, lpBuf, dwBufLen, bAnsiClient, CP_ACP); + ret = Imm32GetCompStrA(hIMC, pCS, dwIndex, lpBuf, dwBufLen, bAnsiClient, uCodePage); ImmUnlockIMCC(pIC->hCompStr); ImmUnlockIMC(hIMC); return ret; @@ -171,6 +546,7 @@ LONG WINAPI ImmGetCompositionStringW(HIMC hIMC, DWORD dwIndex, LPVOID lpBuf, DWO PCLIENTIMC pClientImc; LPCOMPOSITIONSTRING pCS; BOOL bAnsiClient; + UINT uCodePage; TRACE("(%p, %lu, %p, %lu)\n", hIMC, dwIndex, lpBuf, dwBufLen); @@ -182,6 +558,7 @@ LONG WINAPI ImmGetCompositionStringW(HIMC hIMC, DWORD dwIndex, LPVOID lpBuf, DWO return 0; bAnsiClient = !(pClientImc->dwFlags & CLIENTIMC_WIDE); + uCodePage = pClientImc->uCodePage; ImmUnlockClientImc(pClientImc); pIC = ImmLockIMC(hIMC); @@ -195,7 +572,7 @@ LONG WINAPI ImmGetCompositionStringW(HIMC hIMC, DWORD dwIndex, LPVOID lpBuf, DWO return 0; } - ret = Imm32GetCompStrW(hIMC, pCS, dwIndex, lpBuf, dwBufLen, bAnsiClient, CP_ACP); + ret = Imm32GetCompStrW(hIMC, pCS, dwIndex, lpBuf, dwBufLen, bAnsiClient, uCodePage); ImmUnlockIMCC(pIC->hCompStr); ImmUnlockIMC(hIMC); return ret;