FreeRDP
Loading...
Searching...
No Matches
unicode_icu.c
1
22#include <winpr/config.h>
23#include <winpr/assert.h>
24
25#include <errno.h>
26#include <wctype.h>
27
28#include <winpr/crt.h>
29#include <winpr/error.h>
30#include <winpr/print.h>
31
32#include <unicode/ucnv.h>
33#include <unicode/ustring.h>
34
35#include "unicode.h"
36
37#include "../log.h"
38#define TAG WINPR_TAG("unicode")
39
40#define UCNV_CONVERT 1
41
42int int_MultiByteToWideChar(UINT CodePage, DWORD dwFlags, LPCSTR lpMultiByteStr, int cbMultiByte,
43 LPWSTR lpWideCharStr, int cchWideChar)
44{
45 const BOOL isNullTerminated = cbMultiByte < 0;
46
47 WINPR_UNUSED(dwFlags);
48
49 /* If cbMultiByte is 0, the function fails */
50
51 if ((cbMultiByte == 0) || (cbMultiByte < -1))
52 {
53 SetLastError(ERROR_INVALID_PARAMETER);
54 return 0;
55 }
56
57 size_t len = 0;
58 if (isNullTerminated)
59 len = strlen(lpMultiByteStr) + 1;
60 else
61 len = WINPR_ASSERTING_INT_CAST(size_t, cbMultiByte);
62
63 if (len >= INT_MAX)
64 {
65 SetLastError(ERROR_INVALID_PARAMETER);
66 return 0;
67 }
68 cbMultiByte = WINPR_ASSERTING_INT_CAST(int, len);
69
70 /*
71 * if cchWideChar is 0, the function returns the required buffer size
72 * in characters for lpWideCharStr and makes no use of the output parameter itself.
73 */
74 {
75 UErrorCode error = U_ZERO_ERROR;
76 int32_t targetLength = -1;
77
78 switch (CodePage)
79 {
80 case CP_ACP:
81 case CP_UTF8:
82 break;
83
84 default:
85 WLog_ERR(TAG, "Unsupported encoding %u", CodePage);
86 SetLastError(ERROR_INVALID_PARAMETER);
87 return 0;
88 }
89
90 const int32_t targetCapacity = cchWideChar;
91#if defined(UCNV_CONVERT)
92 char* targetStart = (char*)lpWideCharStr;
93 targetLength =
94 ucnv_convert("UTF-16LE", "UTF-8", targetStart, targetCapacity * (int32_t)sizeof(WCHAR),
95 lpMultiByteStr, cbMultiByte, &error);
96 if (targetLength > 0)
97 targetLength /= sizeof(WCHAR);
98#else
99 WCHAR* targetStart = lpWideCharStr;
100 u_strFromUTF8(targetStart, targetCapacity, &targetLength, lpMultiByteStr, cbMultiByte,
101 &error);
102#endif
103
104 switch (error)
105 {
106 case U_BUFFER_OVERFLOW_ERROR:
107 if (targetCapacity > 0)
108 {
109 cchWideChar = 0;
110 WLog_ERR(TAG, "insufficient buffer supplied, got %d, required %d",
111 targetCapacity, targetLength);
112 SetLastError(ERROR_INSUFFICIENT_BUFFER);
113 }
114 else
115 cchWideChar = targetLength;
116 break;
117 case U_STRING_NOT_TERMINATED_WARNING:
118 cchWideChar = targetLength;
119 break;
120 case U_ZERO_ERROR:
121 cchWideChar = targetLength;
122 break;
123 default:
124 WLog_WARN(TAG, "unexpected ICU error code %s [0x%08" PRIx32 "]", u_errorName(error),
125 error);
126 if (U_FAILURE(error))
127 {
128 WLog_ERR(TAG, "unexpected ICU error code %s [0x%08" PRIx32 "] is fatal",
129 u_errorName(error), error);
130 cchWideChar = 0;
131 SetLastError(ERROR_NO_UNICODE_TRANSLATION);
132 }
133 else
134 cchWideChar = targetLength;
135 break;
136 }
137 }
138
139 return cchWideChar;
140}
141
142int int_WideCharToMultiByte(UINT CodePage, WINPR_ATTR_UNUSED DWORD dwFlags, LPCWSTR lpWideCharStr,
143 int cchWideChar, LPSTR lpMultiByteStr, int cbMultiByte,
144 WINPR_ATTR_UNUSED LPCSTR lpDefaultChar,
145 WINPR_ATTR_UNUSED LPBOOL lpUsedDefaultChar)
146{
147 /* If cchWideChar is 0, the function fails */
148
149 if ((cchWideChar == 0) || (cchWideChar < -1))
150 {
151 SetLastError(ERROR_INVALID_PARAMETER);
152 return 0;
153 }
154
155 /* If cchWideChar is -1, the string is null-terminated */
156
157 size_t len = 0;
158 if (cchWideChar == -1)
159 len = _wcslen(lpWideCharStr) + 1;
160 else
161 len = WINPR_ASSERTING_INT_CAST(size_t, cchWideChar);
162
163 if (len >= INT32_MAX)
164 {
165 SetLastError(ERROR_INVALID_PARAMETER);
166 return 0;
167 }
168 cchWideChar = WINPR_ASSERTING_INT_CAST(int, len);
169
170 /*
171 * if cbMultiByte is 0, the function returns the required buffer size
172 * in bytes for lpMultiByteStr and makes no use of the output parameter itself.
173 */
174 {
175 UErrorCode error = U_ZERO_ERROR;
176 int32_t targetLength = -1;
177
178 switch (CodePage)
179 {
180 case CP_ACP:
181 case CP_UTF8:
182 break;
183
184 default:
185 WLog_ERR(TAG, "Unsupported encoding %u", CodePage);
186 SetLastError(ERROR_INVALID_PARAMETER);
187 return 0;
188 }
189
190 char* targetStart = lpMultiByteStr;
191 const int32_t targetCapacity = cbMultiByte;
192#if defined(UCNV_CONVERT)
193 const char* str = (const char*)lpWideCharStr;
194 targetLength = ucnv_convert("UTF-8", "UTF-16LE", targetStart, targetCapacity, str,
195 cchWideChar * (int32_t)sizeof(WCHAR), &error);
196#else
197 u_strToUTF8(targetStart, targetCapacity, &targetLength, lpWideCharStr, cchWideChar, &error);
198#endif
199 switch (error)
200 {
201 case U_BUFFER_OVERFLOW_ERROR:
202 if (targetCapacity > 0)
203 {
204 WLog_ERR(TAG, "insufficient buffer supplied, got %d, required %d",
205 targetCapacity, targetLength);
206 cbMultiByte = 0;
207 SetLastError(ERROR_INSUFFICIENT_BUFFER);
208 }
209 else
210 cbMultiByte = targetLength;
211 break;
212 case U_STRING_NOT_TERMINATED_WARNING:
213 cbMultiByte = targetLength;
214 break;
215 case U_ZERO_ERROR:
216 cbMultiByte = targetLength;
217 break;
218 default:
219 WLog_WARN(TAG, "unexpected ICU error code %s [0x%08" PRIx32 "]", u_errorName(error),
220 error);
221 if (U_FAILURE(error))
222 {
223 WLog_ERR(TAG, "unexpected ICU error code %s [0x%08" PRIx32 "] is fatal",
224 u_errorName(error), error);
225 cbMultiByte = 0;
226 SetLastError(ERROR_NO_UNICODE_TRANSLATION);
227 }
228 else
229 cbMultiByte = targetLength;
230 break;
231 }
232 }
233 return cbMultiByte;
234}