/src/FreeRDP/winpr/libwinpr/crt/unicode_icu.c
Line | Count | Source (jump to first uncovered line) |
1 | | /** |
2 | | * WinPR: Windows Portable Runtime |
3 | | * Unicode Conversion (CRT) |
4 | | * |
5 | | * Copyright 2012 Marc-Andre Moreau <marcandre.moreau@gmail.com> |
6 | | * Copyright 2022 Armin Novak <anovak@thincast.com> |
7 | | * Copyright 2022 Thincast Technologies GmbH |
8 | | * |
9 | | * Licensed under the Apache License, Version 2.0 (the "License"); |
10 | | * you may not use this file except in compliance with the License. |
11 | | * You may obtain a copy of the License at |
12 | | * |
13 | | * http://www.apache.org/licenses/LICENSE-2.0 |
14 | | * |
15 | | * Unless required by applicable law or agreed to in writing, software |
16 | | * distributed under the License is distributed on an "AS IS" BASIS, |
17 | | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
18 | | * See the License for the specific language governing permissions and |
19 | | * limitations under the License. |
20 | | */ |
21 | | |
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 | | #ifndef MIN |
33 | | #define MIN(a, b) (a) < (b) ? (a) : (b) |
34 | | #endif |
35 | | |
36 | | #include <unicode/ucnv.h> |
37 | | #include <unicode/ustring.h> |
38 | | |
39 | | #include "unicode.h" |
40 | | |
41 | | #include "../log.h" |
42 | | #define TAG WINPR_TAG("unicode") |
43 | | |
44 | | int int_MultiByteToWideChar(UINT CodePage, DWORD dwFlags, LPCSTR lpMultiByteStr, int cbMultiByte, |
45 | | LPWSTR lpWideCharStr, int cchWideChar) |
46 | 0 | { |
47 | 0 | const BOOL isNullTerminated = cbMultiByte < 0; |
48 | 0 | LPWSTR targetStart = NULL; |
49 | |
|
50 | 0 | WINPR_UNUSED(dwFlags); |
51 | | |
52 | | /* If cbMultiByte is 0, the function fails */ |
53 | |
|
54 | 0 | if ((cbMultiByte == 0) || (cbMultiByte < -1)) |
55 | 0 | { |
56 | 0 | SetLastError(ERROR_INVALID_PARAMETER); |
57 | 0 | return 0; |
58 | 0 | } |
59 | | |
60 | 0 | size_t len = 0; |
61 | 0 | if (isNullTerminated) |
62 | 0 | len = strlen(lpMultiByteStr) + 1; |
63 | 0 | else |
64 | 0 | len = cbMultiByte; |
65 | |
|
66 | 0 | if (len >= INT_MAX) |
67 | 0 | { |
68 | 0 | SetLastError(ERROR_INVALID_PARAMETER); |
69 | 0 | return 0; |
70 | 0 | } |
71 | 0 | cbMultiByte = (int)len; |
72 | | |
73 | | /* |
74 | | * if cchWideChar is 0, the function returns the required buffer size |
75 | | * in characters for lpWideCharStr and makes no use of the output parameter itself. |
76 | | */ |
77 | 0 | { |
78 | 0 | UErrorCode error = U_ZERO_ERROR; |
79 | 0 | int32_t targetLength = -1; |
80 | 0 | int32_t targetCapacity = -1; |
81 | |
|
82 | 0 | switch (CodePage) |
83 | 0 | { |
84 | 0 | case CP_ACP: |
85 | 0 | case CP_UTF8: |
86 | 0 | break; |
87 | | |
88 | 0 | default: |
89 | 0 | WLog_ERR(TAG, "Unsupported encoding %u", CodePage); |
90 | 0 | SetLastError(ERROR_INVALID_PARAMETER); |
91 | 0 | return 0; |
92 | 0 | } |
93 | | |
94 | 0 | targetStart = lpWideCharStr; |
95 | 0 | targetCapacity = cchWideChar; |
96 | |
|
97 | 0 | u_strFromUTF8(targetStart, targetCapacity, &targetLength, lpMultiByteStr, cbMultiByte, |
98 | 0 | &error); |
99 | |
|
100 | 0 | switch (error) |
101 | 0 | { |
102 | 0 | case U_BUFFER_OVERFLOW_ERROR: |
103 | 0 | if (targetCapacity > 0) |
104 | 0 | { |
105 | 0 | cchWideChar = 0; |
106 | 0 | WLog_ERR(TAG, "insufficient buffer supplied, got %d, required %d", |
107 | 0 | targetCapacity, targetLength); |
108 | 0 | SetLastError(ERROR_INSUFFICIENT_BUFFER); |
109 | 0 | } |
110 | 0 | else |
111 | 0 | cchWideChar = targetLength; |
112 | 0 | break; |
113 | 0 | case U_STRING_NOT_TERMINATED_WARNING: |
114 | 0 | cchWideChar = targetLength; |
115 | 0 | break; |
116 | 0 | case U_ZERO_ERROR: |
117 | 0 | cchWideChar = targetLength; |
118 | 0 | break; |
119 | 0 | default: |
120 | 0 | WLog_WARN(TAG, "unexpected ICU error code %s [0x%08" PRIx32 "]", u_errorName(error), |
121 | 0 | error); |
122 | 0 | if (U_FAILURE(error)) |
123 | 0 | { |
124 | 0 | WLog_ERR(TAG, "unexpected ICU error code %s [0x%08" PRIx32 "] is fatal", |
125 | 0 | u_errorName(error), error); |
126 | 0 | cchWideChar = 0; |
127 | 0 | SetLastError(ERROR_NO_UNICODE_TRANSLATION); |
128 | 0 | } |
129 | 0 | else |
130 | 0 | cchWideChar = targetLength; |
131 | 0 | break; |
132 | 0 | } |
133 | 0 | } |
134 | | |
135 | 0 | return cchWideChar; |
136 | 0 | } |
137 | | |
138 | | int int_WideCharToMultiByte(UINT CodePage, DWORD dwFlags, LPCWSTR lpWideCharStr, int cchWideChar, |
139 | | LPSTR lpMultiByteStr, int cbMultiByte, LPCSTR lpDefaultChar, |
140 | | LPBOOL lpUsedDefaultChar) |
141 | 0 | { |
142 | 0 | char* targetStart = NULL; |
143 | | |
144 | | /* If cchWideChar is 0, the function fails */ |
145 | |
|
146 | 0 | if ((cchWideChar == 0) || (cchWideChar < -1)) |
147 | 0 | { |
148 | 0 | SetLastError(ERROR_INVALID_PARAMETER); |
149 | 0 | return 0; |
150 | 0 | } |
151 | | |
152 | | /* If cchWideChar is -1, the string is null-terminated */ |
153 | | |
154 | 0 | size_t len = 0; |
155 | 0 | if (cchWideChar == -1) |
156 | 0 | len = _wcslen(lpWideCharStr) + 1; |
157 | 0 | else |
158 | 0 | len = cchWideChar; |
159 | |
|
160 | 0 | if (len >= INT32_MAX) |
161 | 0 | { |
162 | 0 | SetLastError(ERROR_INVALID_PARAMETER); |
163 | 0 | return 0; |
164 | 0 | } |
165 | 0 | cchWideChar = (int)len; |
166 | | |
167 | | /* |
168 | | * if cbMultiByte is 0, the function returns the required buffer size |
169 | | * in bytes for lpMultiByteStr and makes no use of the output parameter itself. |
170 | | */ |
171 | 0 | { |
172 | 0 | UErrorCode error = U_ZERO_ERROR; |
173 | 0 | int32_t targetLength = -1; |
174 | 0 | int32_t targetCapacity = -1; |
175 | |
|
176 | 0 | switch (CodePage) |
177 | 0 | { |
178 | 0 | case CP_ACP: |
179 | 0 | case CP_UTF8: |
180 | 0 | break; |
181 | | |
182 | 0 | default: |
183 | 0 | WLog_ERR(TAG, "Unsupported encoding %u", CodePage); |
184 | 0 | SetLastError(ERROR_INVALID_PARAMETER); |
185 | 0 | return 0; |
186 | 0 | } |
187 | | |
188 | 0 | targetStart = lpMultiByteStr; |
189 | 0 | targetCapacity = cbMultiByte; |
190 | |
|
191 | 0 | u_strToUTF8(targetStart, targetCapacity, &targetLength, lpWideCharStr, cchWideChar, &error); |
192 | 0 | switch (error) |
193 | 0 | { |
194 | 0 | case U_BUFFER_OVERFLOW_ERROR: |
195 | 0 | if (targetCapacity > 0) |
196 | 0 | { |
197 | 0 | WLog_ERR(TAG, "insufficient buffer supplied, got %d, required %d", |
198 | 0 | targetCapacity, targetLength); |
199 | 0 | cbMultiByte = 0; |
200 | 0 | SetLastError(ERROR_INSUFFICIENT_BUFFER); |
201 | 0 | } |
202 | 0 | else |
203 | 0 | cbMultiByte = targetLength; |
204 | 0 | break; |
205 | 0 | case U_STRING_NOT_TERMINATED_WARNING: |
206 | 0 | cbMultiByte = targetLength; |
207 | 0 | break; |
208 | 0 | case U_ZERO_ERROR: |
209 | 0 | cbMultiByte = targetLength; |
210 | 0 | break; |
211 | 0 | default: |
212 | 0 | WLog_WARN(TAG, "unexpected ICU error code %s [0x%08" PRIx32 "]", u_errorName(error), |
213 | 0 | error); |
214 | 0 | if (U_FAILURE(error)) |
215 | 0 | { |
216 | 0 | WLog_ERR(TAG, "unexpected ICU error code %s [0x%08" PRIx32 "] is fatal", |
217 | 0 | u_errorName(error), error); |
218 | 0 | cbMultiByte = 0; |
219 | 0 | SetLastError(ERROR_NO_UNICODE_TRANSLATION); |
220 | 0 | } |
221 | 0 | else |
222 | 0 | cbMultiByte = targetLength; |
223 | 0 | break; |
224 | 0 | } |
225 | 0 | } |
226 | 0 | return cbMultiByte; |
227 | 0 | } |