ReactOS 0.4.15-dev-7674-gc0b4db1
codepage.c
Go to the documentation of this file.
1/*
2 * Unit tests for code page to/from unicode translations
3 *
4 * Copyright (c) 2002 Dmitry Timoshkov
5 * Copyright (c) 2008 Colin Finck
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20 */
21
22#include <stdarg.h>
23#include <stdio.h>
24#include <limits.h>
25
26#include "wine/test.h"
27#include "windef.h"
28#include "winbase.h"
29#include "winnls.h"
30
31static const char foobarA[] = "foobar";
32static const WCHAR foobarW[] = {'f','o','o','b','a','r',0};
33
34static void test_destination_buffer(void)
35{
37 INT maxsize;
38 INT needed;
39 INT len;
40
41 SetLastError(0xdeadbeef);
42 needed = WideCharToMultiByte(CP_ACP, 0, foobarW, -1, NULL, 0, NULL, NULL);
43 ok( (needed > 0), "returned %d with %u (expected '> 0')\n",
44 needed, GetLastError());
45
46 maxsize = needed*2;
47 buffer = HeapAlloc(GetProcessHeap(), 0, maxsize);
48 if (buffer == NULL) return;
49
50 maxsize--;
51 memset(buffer, 'x', maxsize);
52 buffer[maxsize] = '\0';
53 SetLastError(0xdeadbeef);
54 len = WideCharToMultiByte(CP_ACP, 0, foobarW, -1, buffer, needed+1, NULL, NULL);
55 ok( (len > 0), "returned %d with %u and '%s' (expected '> 0')\n",
57
58 memset(buffer, 'x', maxsize);
59 buffer[maxsize] = '\0';
60 SetLastError(0xdeadbeef);
61 len = WideCharToMultiByte(CP_ACP, 0, foobarW, -1, buffer, needed, NULL, NULL);
62 ok( (len > 0), "returned %d with %u and '%s' (expected '> 0')\n",
64
65 memset(buffer, 'x', maxsize);
66 buffer[maxsize] = '\0';
67 SetLastError(0xdeadbeef);
68 len = WideCharToMultiByte(CP_ACP, 0, foobarW, -1, buffer, needed-1, NULL, NULL);
70 "returned %d with %u and '%s' (expected '0' with "
71 "ERROR_INSUFFICIENT_BUFFER)\n", len, GetLastError(), buffer);
72
73 memset(buffer, 'x', maxsize);
74 buffer[maxsize] = '\0';
75 SetLastError(0xdeadbeef);
78 "returned %d with %u and '%s' (expected '0' with "
79 "ERROR_INSUFFICIENT_BUFFER)\n", len, GetLastError(), buffer);
80
81 SetLastError(0xdeadbeef);
83 ok( (len > 0), "returned %d with %u (expected '> 0')\n",
84 len, GetLastError());
85
86 SetLastError(0xdeadbeef);
87 len = WideCharToMultiByte(CP_ACP, 0, foobarW, -1, NULL, needed, NULL, NULL);
89 "returned %d with %u (expected '0' with "
90 "ERROR_INVALID_PARAMETER)\n", len, GetLastError());
91
93}
94
95
96static void test_null_source(void)
97{
98 int len;
99 DWORD GLE;
100
101 SetLastError(0);
103 GLE = GetLastError();
105 "WideCharToMultiByte returned %d with GLE=%u (expected 0 with ERROR_INVALID_PARAMETER)\n",
106 len, GLE);
107
108 SetLastError(0);
110 GLE = GetLastError();
112 "WideCharToMultiByte returned %d with GLE=%u (expected 0 with ERROR_INVALID_PARAMETER)\n",
113 len, GLE);
114}
115
117{
118 int len;
119 char buf[10];
120 WCHAR bufW[10];
121
122 /* Test, whether any negative source length works as strlen() + 1 */
123 SetLastError( 0xdeadbeef );
124 memset(buf,'x',sizeof(buf));
125 len = WideCharToMultiByte(CP_ACP, 0, foobarW, -2002, buf, 10, NULL, NULL);
126 ok(len == 7 && GetLastError() == 0xdeadbeef,
127 "WideCharToMultiByte(-2002): len=%d error=%u\n", len, GetLastError());
128 ok(!lstrcmpA(buf, "foobar"),
129 "WideCharToMultiByte(-2002): expected \"foobar\" got \"%s\"\n", buf);
130
131 SetLastError( 0xdeadbeef );
132 memset(bufW,'x',sizeof(bufW));
133 len = MultiByteToWideChar(CP_ACP, 0, "foobar", -2002, bufW, 10);
134 ok(len == 7 && !lstrcmpW(bufW, foobarW) && GetLastError() == 0xdeadbeef,
135 "MultiByteToWideChar(-2002): len=%d error=%u\n", len, GetLastError());
136
137 SetLastError(0xdeadbeef);
138 memset(bufW, 'x', sizeof(bufW));
139 len = MultiByteToWideChar(CP_ACP, 0, "foobar", -1, bufW, 6);
141 "MultiByteToWideChar(-1): len=%d error=%u\n", len, GetLastError());
142}
143
144#define LONGBUFLEN 100000
146{
147 int len, i;
148 static WCHAR bufW[LONGBUFLEN];
149 static char bufA[LONGBUFLEN];
150 static WCHAR originalW[LONGBUFLEN];
151 static char originalA[LONGBUFLEN];
152 DWORD theError;
153
154 /* Test return on -1 dest length */
155 SetLastError( 0xdeadbeef );
156 memset(bufA,'x',sizeof(bufA));
157 len = WideCharToMultiByte(CP_ACP, 0, foobarW, -1, bufA, -1, NULL, NULL);
159 "WideCharToMultiByte(destlen -1): len=%d error=%x\n", len, GetLastError());
160
161 SetLastError( 0xdeadbeef );
162 memset(bufW,'x',sizeof(bufW));
163 len = MultiByteToWideChar(CP_ACP, 0, foobarA, -1, bufW, -1);
165 "MultiByteToWideChar(destlen -1): len=%d error=%x\n", len, GetLastError());
166
167 /* Test return on -1000 dest length */
168 SetLastError( 0xdeadbeef );
169 memset(bufA,'x',sizeof(bufA));
170 len = WideCharToMultiByte(CP_ACP, 0, foobarW, -1, bufA, -1000, NULL, NULL);
172 "WideCharToMultiByte(destlen -1000): len=%d error=%x\n", len, GetLastError());
173
174 SetLastError( 0xdeadbeef );
175 memset(bufW,'x',sizeof(bufW));
176 len = MultiByteToWideChar(CP_ACP, 0, foobarA, -1000, bufW, -1);
178 "MultiByteToWideChar(destlen -1000): len=%d error=%x\n", len, GetLastError());
179
180 /* Test return on INT_MAX dest length */
181 SetLastError( 0xdeadbeef );
182 memset(bufA,'x',sizeof(bufA));
184 ok(len == 7 && !lstrcmpA(bufA, "foobar") && GetLastError() == 0xdeadbeef,
185 "WideCharToMultiByte(destlen INT_MAX): len=%d error=%x\n", len, GetLastError());
186
187 /* Test return on INT_MAX dest length and very long input */
188 SetLastError( 0xdeadbeef );
189 memset(bufA,'x',sizeof(bufA));
190 for (i=0; i < LONGBUFLEN - 1; i++) {
191 originalW[i] = 'Q';
192 originalA[i] = 'Q';
193 }
194 originalW[LONGBUFLEN-1] = 0;
195 originalA[LONGBUFLEN-1] = 0;
196 len = WideCharToMultiByte(CP_ACP, 0, originalW, -1, bufA, INT_MAX, NULL, NULL);
197 theError = GetLastError();
198 ok(len == LONGBUFLEN && !lstrcmpA(bufA, originalA) && theError == 0xdeadbeef,
199 "WideCharToMultiByte(srclen %d, destlen INT_MAX): len %d error=%x\n", LONGBUFLEN, len, theError);
200
201}
202
204{
205 char c_string[] = "Hello World";
206 size_t c_string_len = sizeof(c_string);
207 WCHAR w_string[] = {'H','e','l','l','o',' ','W','o','r','l','d',0};
208 size_t w_string_len = sizeof(w_string) / sizeof(WCHAR);
209 BOOL used;
210 INT len;
211
212 /* Unrecognized flag => ERROR_INVALID_FLAGS */
213 SetLastError(0xdeadbeef);
214 len = WideCharToMultiByte(CP_ACP, 0x100, w_string, -1, c_string, c_string_len, NULL, NULL);
215 ok(len == 0 && GetLastError() == ERROR_INVALID_FLAGS, "len=%d error=%x\n", len, GetLastError());
216
217 SetLastError(0xdeadbeef);
218 len = WideCharToMultiByte(CP_ACP, 0x800, w_string, -1, c_string, c_string_len, NULL, NULL);
219 ok(len == 0 && GetLastError() == ERROR_INVALID_FLAGS, "len=%d error=%x\n", len, GetLastError());
220
221 SetLastError(0xdeadbeef);
222 len = MultiByteToWideChar(CP_ACP, 0x10, c_string, -1, w_string, w_string_len);
223 ok(len == 0 && GetLastError() == ERROR_INVALID_FLAGS, "len=%d error=%x\n", len, GetLastError());
224
225
226 /* Unrecognized flag and invalid codepage => ERROR_INVALID_PARAMETER */
227 SetLastError(0xdeadbeef);
228 len = WideCharToMultiByte(0xdeadbeef, 0x100, w_string, w_string_len, c_string, c_string_len, NULL, NULL);
229 ok(len == 0 && GetLastError() == ERROR_INVALID_PARAMETER, "len=%d error=%x\n", len, GetLastError());
230
231 SetLastError(0xdeadbeef);
232 len = MultiByteToWideChar(0xdeadbeef, 0x10, c_string, c_string_len, w_string, w_string_len);
233 ok(len == 0 && GetLastError() == ERROR_INVALID_PARAMETER, "len=%d error=%x\n", len, GetLastError());
234
235
236 /* Unrecognized flag and src is NULL => ERROR_INVALID_PARAMETER */
237 SetLastError(0xdeadbeef);
238 len = WideCharToMultiByte(CP_ACP, 0x100, NULL, -1, c_string, c_string_len, NULL, NULL);
239 ok(len == 0 && GetLastError() == ERROR_INVALID_PARAMETER, "len=%d error=%x\n", len, GetLastError());
240
241 SetLastError(0xdeadbeef);
242 len = MultiByteToWideChar(CP_ACP, 0x10, NULL, -1, w_string, w_string_len);
243 ok(len == 0 && GetLastError() == ERROR_INVALID_PARAMETER, "len=%d error=%x\n", len, GetLastError());
244
245
246 /* srclen=0 => ERROR_INVALID_PARAMETER */
247 SetLastError(0xdeadbeef);
248 len = WideCharToMultiByte(CP_ACP, 0, w_string, 0, c_string, c_string_len, NULL, NULL);
249 ok(len == 0 && GetLastError() == ERROR_INVALID_PARAMETER, "len=%d error=%x\n", len, GetLastError());
250
251 SetLastError(0xdeadbeef);
252 len = MultiByteToWideChar(CP_ACP, 0, c_string, 0, w_string, w_string_len);
253 ok(len == 0 && GetLastError() == ERROR_INVALID_PARAMETER, "len=%d error=%x\n", len, GetLastError());
254
255
256 /* dst=NULL but dstlen not 0 => ERROR_INVALID_PARAMETER */
257 SetLastError(0xdeadbeef);
258 len = WideCharToMultiByte(CP_ACP, 0, w_string, w_string_len, NULL, c_string_len, NULL, NULL);
259 ok(len == 0 && GetLastError() == ERROR_INVALID_PARAMETER, "len=%d error=%x\n", len, GetLastError());
260
261 SetLastError(0xdeadbeef);
262 len = MultiByteToWideChar(CP_ACP, 0, c_string, c_string_len, NULL, w_string_len);
263 ok(len == 0 && GetLastError() == ERROR_INVALID_PARAMETER, "len=%d error=%x\n", len, GetLastError());
264
265
266 /* CP_UTF7, CP_UTF8, or CP_SYMBOL and defchar not NULL => ERROR_INVALID_PARAMETER */
267 /* CP_SYMBOL's behavior here is undocumented */
268 SetLastError(0xdeadbeef);
269 len = WideCharToMultiByte(CP_UTF7, 0, w_string, w_string_len, c_string, c_string_len, c_string, NULL);
270 ok(len == 0 && GetLastError() == ERROR_INVALID_PARAMETER, "len=%d error=%x\n", len, GetLastError());
271
272 SetLastError(0xdeadbeef);
273 len = WideCharToMultiByte(CP_UTF8, 0, w_string, w_string_len, c_string, c_string_len, c_string, NULL);
274 ok(len == 0 && GetLastError() == ERROR_INVALID_PARAMETER, "len=%d error=%x\n", len, GetLastError());
275
276 SetLastError(0xdeadbeef);
277 len = WideCharToMultiByte(CP_SYMBOL, 0, w_string, w_string_len, c_string, c_string_len, c_string, NULL);
278 ok(len == 0 && GetLastError() == ERROR_INVALID_PARAMETER, "len=%d error=%x\n", len, GetLastError());
279
280
281 /* CP_UTF7, CP_UTF8, or CP_SYMBOL and used not NULL => ERROR_INVALID_PARAMETER */
282 /* CP_SYMBOL's behavior here is undocumented */
283 SetLastError(0xdeadbeef);
284 len = WideCharToMultiByte(CP_UTF7, 0, w_string, w_string_len, c_string, c_string_len, NULL, &used);
285 ok(len == 0 && GetLastError() == ERROR_INVALID_PARAMETER, "len=%d error=%x\n", len, GetLastError());
286
287 SetLastError(0xdeadbeef);
288 len = WideCharToMultiByte(CP_UTF8, 0, w_string, w_string_len, c_string, c_string_len, NULL, &used);
289 ok(len == 0 && GetLastError() == ERROR_INVALID_PARAMETER, "len=%d error=%x\n", len, GetLastError());
290
291 SetLastError(0xdeadbeef);
292 len = WideCharToMultiByte(CP_SYMBOL, 0, w_string, w_string_len, c_string, c_string_len, NULL, &used);
293 ok(len == 0 && GetLastError() == ERROR_INVALID_PARAMETER, "len=%d error=%x\n", len, GetLastError());
294
295
296 /* CP_UTF7, flags not 0 and used not NULL => ERROR_INVALID_PARAMETER */
297 /* (tests precedence of ERROR_INVALID_PARAMETER over ERROR_INVALID_FLAGS) */
298 /* The same test with CP_SYMBOL instead of CP_UTF7 gives ERROR_INVALID_FLAGS
299 instead except on Windows NT4 */
300 SetLastError(0xdeadbeef);
301 len = WideCharToMultiByte(CP_UTF7, 1, w_string, w_string_len, c_string, c_string_len, NULL, &used);
302 ok(len == 0 && GetLastError() == ERROR_INVALID_PARAMETER, "len=%d error=%x\n", len, GetLastError());
303
304 /* CP_UTF8, unrecognized flag and used not NULL => ERROR_INVALID_PARAMETER */
305 SetLastError(0xdeadbeef);
306 len = WideCharToMultiByte(CP_UTF8, 0x100, w_string, w_string_len, c_string, c_string_len, NULL, &used);
307 ok(len == 0 && GetLastError() == ERROR_INVALID_PARAMETER, "len=%d error=%x\n", len, GetLastError());
308}
309
310static void test_overlapped_buffers(void)
311{
312 static const WCHAR strW[] = {'j','u','s','t',' ','a',' ','t','e','s','t',0};
313 static const char strA[] = "just a test";
314 char buf[256];
315 int ret;
316
317 SetLastError(0xdeadbeef);
318 memcpy(buf + 1, strW, sizeof(strW));
319 ret = WideCharToMultiByte(CP_ACP, 0, (WCHAR *)(buf + 1), -1, buf, sizeof(buf), NULL, NULL);
320 ok(ret == sizeof(strA), "unexpected ret %d\n", ret);
321 ok(!memcmp(buf, strA, sizeof(strA)), "conversion failed: %s\n", buf);
322 ok(GetLastError() == 0xdeadbeef, "GetLastError() is %u\n", GetLastError());
323}
324
325static void test_string_conversion(LPBOOL bUsedDefaultChar)
326{
327 char mbc;
328 char mbs[15];
329 int ret;
330 WCHAR wc1 = 228; /* Western Windows-1252 character */
331 WCHAR wc2 = 1088; /* Russian Windows-1251 character not displayable for Windows-1252 */
332 static const WCHAR wcs[] = {'T', 'h', 1088, 'i', 0}; /* String with ASCII characters and a Russian character */
333 static const WCHAR dbwcs[] = {28953, 25152, 0}; /* String with Chinese (codepage 950) characters */
334 static const WCHAR dbwcs2[] = {0x7bb8, 0x3d, 0xc813, 0xac00, 0xb77d, 0};
335 static const char default_char[] = {0xa3, 0xbf, 0};
336
337 SetLastError(0xdeadbeef);
338 ret = WideCharToMultiByte(1252, 0, &wc1, 1, &mbc, 1, NULL, bUsedDefaultChar);
339 ok(ret == 1, "ret is %d\n", ret);
340 ok(mbc == '\xe4', "mbc is %d\n", mbc);
341 if(bUsedDefaultChar) ok(*bUsedDefaultChar == FALSE, "bUsedDefaultChar is %d\n", *bUsedDefaultChar);
342 ok(GetLastError() == 0xdeadbeef, "GetLastError() is %u\n", GetLastError());
343
344 SetLastError(0xdeadbeef);
345 ret = WideCharToMultiByte(1252, 0, &wc2, 1, &mbc, 1, NULL, bUsedDefaultChar);
346 ok(ret == 1, "ret is %d\n", ret);
347 ok(mbc == 63, "mbc is %d\n", mbc);
348 if(bUsedDefaultChar) ok(*bUsedDefaultChar == TRUE, "bUsedDefaultChar is %d\n", *bUsedDefaultChar);
349 ok(GetLastError() == 0xdeadbeef, "GetLastError() is %u\n", GetLastError());
350
351 if (IsValidCodePage(1251))
352 {
353 SetLastError(0xdeadbeef);
354 ret = WideCharToMultiByte(1251, 0, &wc2, 1, &mbc, 1, NULL, bUsedDefaultChar);
355 ok(ret == 1, "ret is %d\n", ret);
356 ok(mbc == '\xf0', "mbc is %d\n", mbc);
357 if(bUsedDefaultChar) ok(*bUsedDefaultChar == FALSE, "bUsedDefaultChar is %d\n", *bUsedDefaultChar);
358 ok(GetLastError() == 0xdeadbeef ||
359 broken(GetLastError() == 0), /* win95 */
360 "GetLastError() is %u\n", GetLastError());
361
362 SetLastError(0xdeadbeef);
363 ret = WideCharToMultiByte(1251, 0, &wc1, 1, &mbc, 1, NULL, bUsedDefaultChar);
364 ok(ret == 1, "ret is %d\n", ret);
365 ok(mbc == 97, "mbc is %d\n", mbc);
366 if(bUsedDefaultChar) ok(*bUsedDefaultChar == FALSE, "bUsedDefaultChar is %d\n", *bUsedDefaultChar);
367 ok(GetLastError() == 0xdeadbeef, "GetLastError() is %u\n", GetLastError());
368 }
369 else
370 skip("Codepage 1251 not available\n");
371
372 /* This call triggers the last Win32 error */
373 SetLastError(0xdeadbeef);
374 ret = WideCharToMultiByte(1252, 0, wcs, -1, &mbc, 1, NULL, bUsedDefaultChar);
375 ok(ret == 0, "ret is %d\n", ret);
376 ok(mbc == 84, "mbc is %d\n", mbc);
377 if(bUsedDefaultChar) ok(*bUsedDefaultChar == FALSE, "bUsedDefaultChar is %d\n", *bUsedDefaultChar);
378 ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER, "GetLastError() is %u\n", GetLastError());
379
380 SetLastError(0xdeadbeef);
381 ret = WideCharToMultiByte(1252, 0, wcs, -1, mbs, sizeof(mbs), NULL, bUsedDefaultChar);
382 ok(ret == 5, "ret is %d\n", ret);
383 ok(!strcmp(mbs, "Th?i"), "mbs is %s\n", mbs);
384 if(bUsedDefaultChar) ok(*bUsedDefaultChar == TRUE, "bUsedDefaultChar is %d\n", *bUsedDefaultChar);
385 ok(GetLastError() == 0xdeadbeef, "GetLastError() is %u\n", GetLastError());
386 mbs[0] = 0;
387
388 /* WideCharToMultiByte mustn't add any null character automatically.
389 So in this case, we should get the same string again, even if we only copied the first three bytes. */
390 SetLastError(0xdeadbeef);
391 ret = WideCharToMultiByte(1252, 0, wcs, 3, mbs, sizeof(mbs), NULL, bUsedDefaultChar);
392 ok(ret == 3, "ret is %d\n", ret);
393 ok(!strcmp(mbs, "Th?i"), "mbs is %s\n", mbs);
394 if(bUsedDefaultChar) ok(*bUsedDefaultChar == TRUE, "bUsedDefaultChar is %d\n", *bUsedDefaultChar);
395 ok(GetLastError() == 0xdeadbeef, "GetLastError() is %u\n", GetLastError());
396 ZeroMemory(mbs, 5);
397
398 /* Now this shouldn't be the case like above as we zeroed the complete string buffer. */
399 SetLastError(0xdeadbeef);
400 ret = WideCharToMultiByte(1252, 0, wcs, 3, mbs, sizeof(mbs), NULL, bUsedDefaultChar);
401 ok(ret == 3, "ret is %d\n", ret);
402 ok(!strcmp(mbs, "Th?"), "mbs is %s\n", mbs);
403 if(bUsedDefaultChar) ok(*bUsedDefaultChar == TRUE, "bUsedDefaultChar is %d\n", *bUsedDefaultChar);
404 ok(GetLastError() == 0xdeadbeef, "GetLastError() is %u\n", GetLastError());
405
406 /* Double-byte tests */
407 ret = WideCharToMultiByte(1252, 0, dbwcs, 3, mbs, sizeof(mbs), NULL, bUsedDefaultChar);
408 ok(ret == 3, "ret is %d\n", ret);
409 ok(!strcmp(mbs, "??"), "mbs is %s\n", mbs);
410 if(bUsedDefaultChar) ok(*bUsedDefaultChar == TRUE, "bUsedDefaultChar is %d\n", *bUsedDefaultChar);
411
412 ret = WideCharToMultiByte(936, WC_COMPOSITECHECK, dbwcs2, -1, mbs, sizeof(mbs), (const char *)default_char, bUsedDefaultChar);
413 ok(ret == 10, "ret is %d\n", ret);
414 ok(!strcmp(mbs, "\xf3\xe7\x3d\xa3\xbf\xa3\xbf\xa3\xbf"), "mbs is %s\n", mbs);
415 if(bUsedDefaultChar) ok(*bUsedDefaultChar == TRUE, "bUsedDefaultChar is %d\n", *bUsedDefaultChar);
416
417 /* Length-only tests */
418 SetLastError(0xdeadbeef);
419 ret = WideCharToMultiByte(1252, 0, &wc2, 1, NULL, 0, NULL, bUsedDefaultChar);
420 ok(ret == 1, "ret is %d\n", ret);
421 if(bUsedDefaultChar) ok(*bUsedDefaultChar == TRUE, "bUsedDefaultChar is %d\n", *bUsedDefaultChar);
422 ok(GetLastError() == 0xdeadbeef, "GetLastError() is %u\n", GetLastError());
423
424 SetLastError(0xdeadbeef);
425 ret = WideCharToMultiByte(1252, 0, wcs, -1, NULL, 0, NULL, bUsedDefaultChar);
426 ok(ret == 5, "ret is %d\n", ret);
427 if(bUsedDefaultChar) ok(*bUsedDefaultChar == TRUE, "bUsedDefaultChar is %d\n", *bUsedDefaultChar);
428 ok(GetLastError() == 0xdeadbeef, "GetLastError() is %u\n", GetLastError());
429
430 if (!IsValidCodePage(950))
431 {
432 skip("Codepage 950 not available\n");
433 return;
434 }
435
436 /* Double-byte tests */
437 SetLastError(0xdeadbeef);
438 ret = WideCharToMultiByte(950, 0, dbwcs, -1, mbs, sizeof(mbs), NULL, bUsedDefaultChar);
439 ok(ret == 5, "ret is %d\n", ret);
440 ok(!strcmp(mbs, "\xb5H\xa9\xd2"), "mbs is %s\n", mbs);
441 if(bUsedDefaultChar) ok(*bUsedDefaultChar == FALSE, "bUsedDefaultChar is %d\n", *bUsedDefaultChar);
442 ok(GetLastError() == 0xdeadbeef, "GetLastError() is %u\n", GetLastError());
443
444 SetLastError(0xdeadbeef);
445 ret = WideCharToMultiByte(950, 0, dbwcs, 1, &mbc, 1, NULL, bUsedDefaultChar);
446 ok(ret == 0, "ret is %d\n", ret);
447 if(bUsedDefaultChar) ok(*bUsedDefaultChar == FALSE, "bUsedDefaultChar is %d\n", *bUsedDefaultChar);
448 ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER, "GetLastError() is %u\n", GetLastError());
449 ZeroMemory(mbs, 5);
450
451 SetLastError(0xdeadbeef);
452 ret = WideCharToMultiByte(950, 0, dbwcs, 1, mbs, sizeof(mbs), NULL, bUsedDefaultChar);
453 ok(ret == 2, "ret is %d\n", ret);
454 ok(!strcmp(mbs, "\xb5H"), "mbs is %s\n", mbs);
455 if(bUsedDefaultChar) ok(*bUsedDefaultChar == FALSE, "bUsedDefaultChar is %d\n", *bUsedDefaultChar);
456 ok(GetLastError() == 0xdeadbeef, "GetLastError() is %u\n", GetLastError());
457
458 /* Length-only tests */
459 SetLastError(0xdeadbeef);
460 ret = WideCharToMultiByte(950, 0, dbwcs, 1, NULL, 0, NULL, bUsedDefaultChar);
461 ok(ret == 2, "ret is %d\n", ret);
462 if(bUsedDefaultChar) ok(*bUsedDefaultChar == FALSE, "bUsedDefaultChar is %d\n", *bUsedDefaultChar);
463 ok(GetLastError() == 0xdeadbeef, "GetLastError() is %u\n", GetLastError());
464
465 SetLastError(0xdeadbeef);
466 ret = WideCharToMultiByte(950, 0, dbwcs, -1, NULL, 0, NULL, bUsedDefaultChar);
467 ok(ret == 5, "ret is %d\n", ret);
468 if(bUsedDefaultChar) ok(*bUsedDefaultChar == FALSE, "bUsedDefaultChar is %d\n", *bUsedDefaultChar);
469 ok(GetLastError() == 0xdeadbeef, "GetLastError() is %u\n", GetLastError());
470}
471
472static void test_utf7_encoding(void)
473{
474 WCHAR input[16];
475 char output[16], expected[16];
476 int i, len, expected_len;
477
478 static const BOOL directly_encodable_table[] =
479 {
480 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, /* 0x00 - 0x0F */
481 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x10 - 0x1F */
482 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, /* 0x20 - 0x2F */
483 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, /* 0x30 - 0x3F */
484 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0x40 - 0x4F */
485 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, /* 0x50 - 0x5F */
486 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0x60 - 0x6F */
487 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0 /* 0x70 - 0x7F */
488 };
489 static const char base64_encoding_table[] =
490 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
491
492 const struct
493 {
494 /* inputs */
495 WCHAR src[16];
496 int srclen;
497 char *dst;
498 int dstlen;
499 /* expected outputs */
500 char expected_dst[16];
501 int chars_written;
502 int len;
503 }
504 tests[] =
505 {
506 /* tests string conversion with srclen=-1 */
507 {
508 {0x4F60,0x597D,0x5417,0}, -1, output, sizeof(output) - 1,
509 "+T2BZfVQX-", 11, 11
510 },
511 /* tests string conversion with srclen=-2 */
512 {
513 {0x4F60,0x597D,0x5417,0}, -2, output, sizeof(output) - 1,
514 "+T2BZfVQX-", 11, 11
515 },
516 /* tests string conversion with dstlen=strlen(expected_dst) */
517 {
518 {0x4F60,0x597D,0x5417,0}, -1, output, 10,
519 "+T2BZfVQX-", 10, 0
520 },
521 /* tests string conversion with dstlen=strlen(expected_dst)+1 */
522 {
523 {0x4F60,0x597D,0x5417,0}, -1, output, 11,
524 "+T2BZfVQX-", 11, 11
525 },
526 /* tests string conversion with dstlen=strlen(expected_dst)+2 */
527 {
528 {0x4F60,0x597D,0x5417,0}, -1, output, 12,
529 "+T2BZfVQX-", 11, 11
530 },
531 /* tests dry run with dst=NULL and dstlen=0 */
532 {
533 {0x4F60,0x597D,0x5417,0}, -1, NULL, 0,
534 {0}, 0, 11
535 },
536 /* tests dry run with dst!=NULL and dstlen=0 */
537 {
538 {0x4F60,0x597D,0x5417,0}, -1, output, 0,
539 {0}, 0, 11
540 },
541 /* tests srclen < strlenW(src) with directly encodable chars */
542 {
543 {'h','e','l','l','o',0}, 2, output, sizeof(output) - 1,
544 "he", 2, 2
545 },
546 /* tests srclen < strlenW(src) with non-directly encodable chars */
547 {
548 {0x4F60,0x597D,0x5417,0}, 2, output, sizeof(output) - 1,
549 "+T2BZfQ-", 8, 8
550 },
551 /* tests a single null char */
552 {
553 {0}, -1, output, sizeof(output) - 1,
554 "", 1, 1
555 },
556 /* tests a buffer that runs out while not encoding a UTF-7 sequence */
557 {
558 {'h','e','l','l','o',0}, -1, output, 2,
559 "he", 2, 0
560 },
561 /* tests a buffer that runs out after writing 1 base64 character */
562 {
563 {0x4F60,0x0001,0}, -1, output, 2,
564 "+T", 2, 0
565 },
566 /* tests a buffer that runs out after writing 2 base64 characters */
567 {
568 {0x4F60,0x0001,0}, -1, output, 3,
569 "+T2", 3, 0
570 },
571 /* tests a buffer that runs out after writing 3 base64 characters */
572 {
573 {0x4F60,0x0001,0}, -1, output, 4,
574 "+T2A", 4, 0
575 },
576 /* tests a buffer that runs out just after writing the + sign */
577 {
578 {0x4F60,0}, -1, output, 1,
579 "+", 1, 0
580 },
581 /* tests a buffer that runs out just before writing the - sign
582 * the number of bits to encode here is evenly divisible by 6 */
583 {
584 {0x4F60,0x597D,0x5417,0}, -1, output, 9,
585 "+T2BZfVQX", 9, 0
586 },
587 /* tests a buffer that runs out just before writing the - sign
588 * the number of bits to encode here is NOT evenly divisible by 6 */
589 {
590 {0x4F60,0}, -1, output, 4,
591 "+T2", 3, 0
592 },
593 /* tests a buffer that runs out in the middle of escaping a + sign */
594 {
595 {'+',0}, -1, output, 1,
596 "+", 1, 0
597 }
598 };
599
600 /* test which characters are encoded if surrounded by non-encoded characters */
601 for (i = 0; i <= 0xFFFF; i++)
602 {
603 input[0] = ' ';
604 input[1] = i;
605 input[2] = ' ';
606 input[3] = 0;
607
608 memset(output, '#', sizeof(output) - 1);
609 output[sizeof(output) - 1] = 0;
610
611 len = WideCharToMultiByte(CP_UTF7, 0, input, 4, output, sizeof(output) - 1, NULL, NULL);
612
613 if (i == '+')
614 {
615 /* '+' is a special case and is encoded as "+-" */
616 expected_len = 5;
617 strcpy(expected, " +- ");
618 }
619 else if (i <= 0x7F && directly_encodable_table[i])
620 {
621 /* encodes directly */
622 expected_len = 4;
623 sprintf(expected, " %c ", i);
624 }
625 else
626 {
627 /* base64-encodes */
628 expected_len = 8;
629 sprintf(expected, " +%c%c%c- ",
630 base64_encoding_table[(i & 0xFC00) >> 10],
631 base64_encoding_table[(i & 0x03F0) >> 4],
632 base64_encoding_table[(i & 0x000F) << 2]);
633 }
634
635 ok(len == expected_len, "i=0x%04x: expected len=%i, got len=%i\n", i, expected_len, len);
636 ok(memcmp(output, expected, expected_len) == 0,
637 "i=0x%04x: expected output='%s', got output='%s'\n", i, expected, output);
638 ok(output[expected_len] == '#', "i=0x%04x: expected output[%i]='#', got output[%i]=%i\n",
639 i, expected_len, expected_len, output[expected_len]);
640 }
641
642 /* test which one-byte characters are absorbed into surrounding base64 blocks
643 * (Windows always ends the base64 block when it encounters a directly encodable character) */
644 for (i = 0; i <= 0xFFFF; i++)
645 {
646 input[0] = 0x2672;
647 input[1] = i;
648 input[2] = 0x2672;
649 input[3] = 0;
650
651 memset(output, '#', sizeof(output) - 1);
652 output[sizeof(output) - 1] = 0;
653
654 len = WideCharToMultiByte(CP_UTF7, 0, input, 4, output, sizeof(output) - 1, NULL, NULL);
655
656 if (i == '+')
657 {
658 /* '+' is a special case and is encoded as "+-" */
659 expected_len = 13;
660 strcpy(expected, "+JnI-+-+JnI-");
661 }
662 else if (i <= 0x7F && directly_encodable_table[i])
663 {
664 /* encodes directly */
665 expected_len = 12;
666 sprintf(expected, "+JnI-%c+JnI-", i);
667 }
668 else
669 {
670 /* base64-encodes */
671 expected_len = 11;
672 sprintf(expected, "+Jn%c%c%c%cZy-",
673 base64_encoding_table[8 | ((i & 0xC000) >> 14)],
674 base64_encoding_table[(i & 0x3F00) >> 8],
675 base64_encoding_table[(i & 0x00FC) >> 2],
676 base64_encoding_table[((i & 0x0003) << 4) | 2]);
677 }
678
679 ok(len == expected_len, "i=0x%04x: expected len=%i, got len=%i\n", i, expected_len, len);
680 ok(memcmp(output, expected, expected_len) == 0,
681 "i=0x%04x: expected output='%s', got output='%s'\n", i, expected, output);
682 ok(output[expected_len] == '#', "i=0x%04x: expected output[%i]='#', got output[%i]=%i\n",
683 i, expected_len, expected_len, output[expected_len]);
684 }
685
686 for (i = 0; i < sizeof(tests) / sizeof(tests[0]); i++)
687 {
688 memset(output, '#', sizeof(output) - 1);
689 output[sizeof(output) - 1] = 0;
690 SetLastError(0xdeadbeef);
691
694
695 if (!tests[i].len)
696 {
698 "tests[%i]: expected error=0x%x, got error=0x%x\n",
700 }
701 ok(len == tests[i].len, "tests[%i]: expected len=%i, got len=%i\n", i, tests[i].len, len);
702
703 if (tests[i].dst)
704 {
705 ok(memcmp(tests[i].dst, tests[i].expected_dst, tests[i].chars_written) == 0,
706 "tests[%i]: expected dst='%s', got dst='%s'\n",
707 i, tests[i].expected_dst, tests[i].dst);
708 ok(tests[i].dst[tests[i].chars_written] == '#',
709 "tests[%i]: expected dst[%i]='#', got dst[%i]=%i\n",
710 i, tests[i].chars_written, tests[i].chars_written, tests[i].dst[tests[i].chars_written]);
711 }
712 }
713}
714
715static void test_utf7_decoding(void)
716{
717 char input[32];
718 WCHAR output[32], expected[32];
719 int i, len, expected_len;
720
721 static const signed char base64_decoding_table[] =
722 {
723 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x00-0x0F */
724 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x10-0x1F */
725 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63, /* 0x20-0x2F */
726 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1, /* 0x30-0x3F */
727 -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, /* 0x40-0x4F */
728 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1, /* 0x50-0x5F */
729 -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, /* 0x60-0x6F */
730 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1 /* 0x70-0x7F */
731 };
732
733 struct
734 {
735 /* inputs */
736 char src[32];
737 int srclen;
738 WCHAR *dst;
739 int dstlen;
740 /* expected outputs */
741 WCHAR expected_dst[32];
742 int chars_written;
743 int len;
744 }
745 tests[] =
746 {
747 /* tests string conversion with srclen=-1 */
748 {
749 "+T2BZfQ-", -1, output, sizeof(output) / sizeof(WCHAR) - 1,
750 {0x4F60,0x597D,0}, 3, 3
751 },
752 /* tests string conversion with srclen=-2 */
753 {
754 "+T2BZfQ-", -2, output, sizeof(output) / sizeof(WCHAR) - 1,
755 {0x4F60,0x597D,0}, 3, 3
756 },
757 /* tests string conversion with dstlen=strlen(expected_dst) */
758 {
759 "+T2BZfQ-", -1, output, 2,
760 {0x4F60,0x597D}, 2, 0
761 },
762 /* tests string conversion with dstlen=strlen(expected_dst)+1 */
763 {
764 "+T2BZfQ-", -1, output, 3,
765 {0x4F60,0x597D,0}, 3, 3
766 },
767 /* tests string conversion with dstlen=strlen(expected_dst)+2 */
768 {
769 "+T2BZfQ-", -1, output, 4,
770 {0x4F60,0x597D,0}, 3, 3
771 },
772 /* tests dry run with dst=NULL and dstlen=0 */
773 {
774 "+T2BZfQ-", -1, NULL, 0,
775 {0}, 0, 3
776 },
777 /* tests dry run with dst!=NULL and dstlen=0 */
778 {
779 "+T2BZfQ-", -1, output, 0,
780 {0}, 0, 3
781 },
782 /* tests ill-formed UTF-7: 6 bits, not enough for a byte pair */
783 {
784 "+T-+T-+T-hello", -1, output, sizeof(output) / sizeof(WCHAR) - 1,
785 {'h','e','l','l','o',0}, 6, 6
786 },
787 /* tests ill-formed UTF-7: 12 bits, not enough for a byte pair */
788 {
789 "+T2-+T2-+T2-hello", -1, output, sizeof(output) / sizeof(WCHAR) - 1,
790 {'h','e','l','l','o',0}, 6, 6
791 },
792 /* tests ill-formed UTF-7: 18 bits, not a multiple of 16 and the last bit is a 1 */
793 {
794 "+T2B-+T2B-+T2B-hello", -1, output, sizeof(output) / sizeof(WCHAR) - 1,
795 {0x4F60,0x4F60,0x4F60,'h','e','l','l','o',0}, 9, 9
796 },
797 /* tests ill-formed UTF-7: 24 bits, a multiple of 8 but not a multiple of 16 */
798 {
799 "+T2BZ-+T2BZ-+T2BZ-hello", -1, output, sizeof(output) / sizeof(WCHAR) - 1,
800 {0x4F60,0x4F60,0x4F60,'h','e','l','l','o',0}, 9, 9
801 },
802 /* tests UTF-7 followed by characters that should be encoded but aren't */
803 {
804 "+T2BZ-\x82\xFE", -1, output, sizeof(output) / sizeof(WCHAR) - 1,
805 {0x4F60,0x0082,0x00FE,0}, 4, 4
806 },
807 /* tests srclen > strlen(src) */
808 {
809 "a\0b", 4, output, sizeof(output) / sizeof(WCHAR) - 1,
810 {'a',0,'b',0}, 4, 4
811 },
812 /* tests srclen < strlen(src) outside of a UTF-7 sequence */
813 {
814 "hello", 2, output, sizeof(output) / sizeof(WCHAR) - 1,
815 {'h','e'}, 2, 2
816 },
817 /* tests srclen < strlen(src) inside of a UTF-7 sequence */
818 {
819 "+T2BZfQ-", 4, output, sizeof(output) / sizeof(WCHAR) - 1,
820 {0x4F60}, 1, 1
821 },
822 /* tests srclen < strlen(src) right at the beginning of a UTF-7 sequence */
823 {
824 "hi+T2A-", 3, output, sizeof(output) / sizeof(WCHAR) - 1,
825 {'h','i'}, 2, 2
826 },
827 /* tests srclen < strlen(src) right at the end of a UTF-7 sequence */
828 {
829 "+T2A-hi", 5, output, sizeof(output) / sizeof(WCHAR) - 1,
830 {0x4F60}, 1, 1
831 },
832 /* tests srclen < strlen(src) at the beginning of an escaped + sign */
833 {
834 "hi+-", 3, output, sizeof(output) / sizeof(WCHAR) - 1,
835 {'h','i'}, 2, 2
836 },
837 /* tests srclen < strlen(src) at the end of an escaped + sign */
838 {
839 "+-hi", 2, output, sizeof(output) / sizeof(WCHAR) - 1,
840 {'+'}, 1, 1
841 },
842 /* tests len=0 but no error */
843 {
844 "+", 1, output, sizeof(output) / sizeof(WCHAR) - 1,
845 {0}, 0, 0
846 },
847 /* tests a single null char */
848 {
849 "", -1, output, sizeof(output) / sizeof(WCHAR) - 1,
850 {0}, 1, 1
851 },
852 /* tests a buffer that runs out while not decoding a UTF-7 sequence */
853 {
854 "hello", -1, output, 2,
855 {'h','e'}, 2, 0
856 },
857 /* tests a buffer that runs out in the middle of decoding a UTF-7 sequence */
858 {
859 "+T2BZfQ-", -1, output, 1,
860 {0x4F60}, 1, 0
861 }
862 };
863
864 /* test which one-byte characters remove stray + signs */
865 for (i = 0; i < 256; i++)
866 {
867 sprintf(input, "+%c+AAA", i);
868
869 memset(output, 0x23, sizeof(output) - sizeof(WCHAR));
870 output[sizeof(output) / sizeof(WCHAR) - 1] = 0;
871
872 len = MultiByteToWideChar(CP_UTF7, 0, input, 7, output, sizeof(output) / sizeof(WCHAR) - 1);
873
874 if (i == '-')
875 {
876 /* removes the - sign */
877 expected_len = 3;
878 expected[0] = 0x002B;
879 expected[1] = 0;
880 expected[2] = 0;
881 }
882 else if (i <= 0x7F && base64_decoding_table[i] != -1)
883 {
884 /* absorbs the character into the base64 sequence */
885 expected_len = 2;
886 expected[0] = (base64_decoding_table[i] << 10) | 0x03E0;
887 expected[1] = 0;
888 }
889 else
890 {
891 /* removes the + sign */
892 expected_len = 3;
893 expected[0] = i;
894 expected[1] = 0;
895 expected[2] = 0;
896 }
897 expected[expected_len] = 0x2323;
898
899 ok(len == expected_len, "i=0x%02x: expected len=%i, got len=%i\n", i, expected_len, len);
900 ok(memcmp(output, expected, (expected_len + 1) * sizeof(WCHAR)) == 0,
901 "i=0x%02x: expected output=%s, got output=%s\n",
902 i, wine_dbgstr_wn(expected, expected_len + 1), wine_dbgstr_wn(output, expected_len + 1));
903 }
904
905 /* test which one-byte characters terminate a sequence
906 * also test whether the unfinished byte pair is discarded or not */
907 for (i = 0; i < 256; i++)
908 {
909 sprintf(input, "+B%c+AAA", i);
910
911 memset(output, 0x23, sizeof(output) - sizeof(WCHAR));
912 output[sizeof(output) / sizeof(WCHAR) - 1] = 0;
913
914 len = MultiByteToWideChar(CP_UTF7, 0, input, 8, output, sizeof(output) / sizeof(WCHAR) - 1);
915
916 if (i == '-')
917 {
918 /* explicitly terminates */
919 expected_len = 2;
920 expected[0] = 0;
921 expected[1] = 0;
922 }
923 else if (i <= 0x7F)
924 {
925 if (base64_decoding_table[i] != -1)
926 {
927 /* absorbs the character into the base64 sequence */
928 expected_len = 3;
929 expected[0] = 0x0400 | (base64_decoding_table[i] << 4) | 0x000F;
930 expected[1] = 0x8000;
931 expected[2] = 0;
932 }
933 else
934 {
935 /* implicitly terminates and discards the unfinished byte pair */
936 expected_len = 3;
937 expected[0] = i;
938 expected[1] = 0;
939 expected[2] = 0;
940 }
941 }
942 else
943 {
944 /* implicitly terminates but does not the discard unfinished byte pair */
945 expected_len = 3;
946 expected[0] = i;
947 expected[1] = 0x0400;
948 expected[2] = 0;
949 }
950 expected[expected_len] = 0x2323;
951
952 ok(len == expected_len, "i=0x%02x: expected len=%i, got len=%i\n", i, expected_len, len);
953 ok(memcmp(output, expected, (expected_len + 1) * sizeof(WCHAR)) == 0,
954 "i=0x%02x: expected output=%s, got output=%s\n",
955 i, wine_dbgstr_wn(expected, expected_len + 1), wine_dbgstr_wn(output, expected_len + 1));
956 }
957
958 for (i = 0; i < sizeof(tests) / sizeof(tests[0]); i++)
959 {
960 memset(output, 0x23, sizeof(output) - sizeof(WCHAR));
961 output[sizeof(output) / sizeof(WCHAR) - 1] = 0;
962 SetLastError(0xdeadbeef);
963
965 tests[i].dst, tests[i].dstlen);
966
967 tests[i].expected_dst[tests[i].chars_written] = 0x2323;
968
969 if (!tests[i].len && tests[i].chars_written)
970 {
972 "tests[%i]: expected error=0x%x, got error=0x%x\n",
974 }
975 ok(len == tests[i].len, "tests[%i]: expected len=%i, got len=%i\n", i, tests[i].len, len);
976
977 if (tests[i].dst)
978 {
979 ok(memcmp(tests[i].dst, tests[i].expected_dst, (tests[i].chars_written + 1) * sizeof(WCHAR)) == 0,
980 "tests[%i]: expected dst=%s, got dst=%s\n",
981 i, wine_dbgstr_wn(tests[i].expected_dst, tests[i].chars_written + 1),
982 wine_dbgstr_wn(tests[i].dst, tests[i].chars_written + 1));
983 }
984 }
985}
986
988{
989 static const struct tag_testset {
991 LPCSTR str;
992 BOOL is_error;
993 } testset[] = {
994 { 874, "\xdd", TRUE },
995 { 932, "\xfe", TRUE },
996 { 932, "\x80", FALSE },
997 { 936, "\xff", TRUE },
998 { 949, "\xff", TRUE },
999 { 950, "\xff", TRUE },
1000 { 1252, "\x90", FALSE },
1001 { 1253, "\xaa", TRUE },
1002 { 1255, "\xff", TRUE },
1003 { 1257, "\xa5", TRUE },
1004 };
1005 INT i, ret;
1006
1007 for (i = 0; i < (sizeof(testset) / sizeof(testset[0])); i++) {
1008 if (! IsValidCodePage(testset[i].codepage))
1009 {
1010 skip("Codepage %d not available\n", testset[i].codepage);
1011 continue;
1012 }
1013
1014 SetLastError(0xdeadbeef);
1016 testset[i].str, -1, NULL, 0);
1017 if (testset[i].is_error) {
1019 "ret is %d, GetLastError is %u (cp %d)\n",
1020 ret, GetLastError(), testset[i].codepage);
1021 }
1022 else {
1023 ok(ret == strlen(testset[i].str)+1 && GetLastError() == 0xdeadbeef,
1024 "ret is %d, GetLastError is %u (cp %d)\n",
1025 ret, GetLastError(), testset[i].codepage);
1026 }
1027
1028 SetLastError(0xdeadbeef);
1029 ret = MultiByteToWideChar(testset[i].codepage, 0,
1030 testset[i].str, -1, NULL, 0);
1031 ok(ret == strlen(testset[i].str)+1 && GetLastError() == 0xdeadbeef,
1032 "ret is %d, GetLastError is %u (cp %d)\n",
1033 ret, GetLastError(), testset[i].codepage);
1034 }
1035}
1036
1037static void test_threadcp(void)
1038{
1045
1046 BOOL islead, islead_acp;
1047 CPINFOEXA cpi;
1048 UINT cp, acp;
1049 int i, num;
1050 LCID last;
1051 BOOL ret;
1052
1053 struct test {
1054 LCID lcid;
1055 UINT threadcp;
1056 } lcids[] = {
1057 { HINDI, 0 },
1058 { GEORGIAN, 0 },
1059 { ENGLISH, 1252 },
1060 { RUSSIAN, 1251 },
1061 { JAPANESE, 932 },
1062 { CHINESE, 936 }
1063 };
1064
1065 struct test_islead_nocp {
1066 LCID lcid;
1067 BYTE testchar;
1068 } isleads_nocp[] = {
1069 { HINDI, 0x00 },
1070 { HINDI, 0x81 },
1071 { HINDI, 0xa0 },
1072 { HINDI, 0xe0 },
1073
1074 { GEORGIAN, 0x00 },
1075 { GEORGIAN, 0x81 },
1076 { GEORGIAN, 0xa0 },
1077 { GEORGIAN, 0xe0 },
1078 };
1079
1080 struct test_islead {
1081 LCID lcid;
1082 BYTE testchar;
1083 BOOL islead;
1084 } isleads[] = {
1085 { ENGLISH, 0x00, FALSE },
1086 { ENGLISH, 0x81, FALSE },
1087 { ENGLISH, 0xa0, FALSE },
1088 { ENGLISH, 0xe0, FALSE },
1089
1090 { RUSSIAN, 0x00, FALSE },
1091 { RUSSIAN, 0x81, FALSE },
1092 { RUSSIAN, 0xa0, FALSE },
1093 { RUSSIAN, 0xe0, FALSE },
1094
1095 { JAPANESE, 0x00, FALSE },
1096 { JAPANESE, 0x81, TRUE },
1097 { JAPANESE, 0xa0, FALSE },
1098 { JAPANESE, 0xe0, TRUE },
1099
1100 { CHINESE, 0x00, FALSE },
1101 { CHINESE, 0x81, TRUE },
1102 { CHINESE, 0xa0, TRUE },
1103 { CHINESE, 0xe0, TRUE },
1104 };
1105
1107 acp = GetACP();
1108
1109 for (i = 0; i < sizeof(lcids)/sizeof(lcids[0]); i++)
1110 {
1111 SetThreadLocale(lcids[i].lcid);
1112
1113 cp = 0xdeadbeef;
1114 GetLocaleInfoA(lcids[i].lcid, LOCALE_IDEFAULTANSICODEPAGE|LOCALE_RETURN_NUMBER, (LPSTR)&cp, sizeof(cp));
1115 ok(cp == lcids[i].threadcp, "wrong codepage %u for lcid %04x, should be %u\n", cp, lcids[i].threadcp, cp);
1116
1117 /* GetCPInfoEx/GetCPInfo - CP_ACP */
1118 SetLastError(0xdeadbeef);
1119 memset(&cpi, 0, sizeof(cpi));
1120 ret = GetCPInfoExA(CP_ACP, 0, &cpi);
1121 ok(ret, "GetCPInfoExA failed for lcid %04x, error %d\n", lcids[i].lcid, GetLastError());
1122 ok(cpi.CodePage == acp, "wrong codepage %u for lcid %04x, should be %u\n", cpi.CodePage, lcids[i].lcid, acp);
1123
1124 /* WideCharToMultiByte - CP_ACP */
1126 ok(num == 7, "ret is %d (%04x)\n", num, lcids[i].lcid);
1127
1128 /* MultiByteToWideChar - CP_ACP */
1129 num = MultiByteToWideChar(CP_ACP, 0, "foobar", -1, NULL, 0);
1130 ok(num == 7, "ret is %d (%04x)\n", num, lcids[i].lcid);
1131
1132 /* GetCPInfoEx/GetCPInfo - CP_THREAD_ACP */
1133 SetLastError(0xdeadbeef);
1134 memset(&cpi, 0, sizeof(cpi));
1135 ret = GetCPInfoExA(CP_THREAD_ACP, 0, &cpi);
1136 ok(ret, "GetCPInfoExA failed for lcid %04x, error %d\n", lcids[i].lcid, GetLastError());
1137 if (lcids[i].threadcp)
1138 ok(cpi.CodePage == lcids[i].threadcp, "wrong codepage %u for lcid %04x, should be %u\n",
1139 cpi.CodePage, lcids[i].lcid, lcids[i].threadcp);
1140 else
1141 ok(cpi.CodePage == acp, "wrong codepage %u for lcid %04x, should be %u\n",
1142 cpi.CodePage, lcids[i].lcid, acp);
1143
1144 /* WideCharToMultiByte - CP_THREAD_ACP */
1146 ok(num == 7, "ret is %d (%04x)\n", num, lcids[i].lcid);
1147
1148 /* MultiByteToWideChar - CP_THREAD_ACP */
1149 num = MultiByteToWideChar(CP_THREAD_ACP, 0, "foobar", -1, NULL, 0);
1150 ok(num == 7, "ret is %d (%04x)\n", num, lcids[i].lcid);
1151 }
1152
1153 /* IsDBCSLeadByteEx - locales without codepage */
1154 for (i = 0; i < sizeof(isleads_nocp)/sizeof(isleads_nocp[0]); i++)
1155 {
1156 SetThreadLocale(isleads_nocp[i].lcid);
1157
1158 islead_acp = IsDBCSLeadByteEx(CP_ACP, isleads_nocp[i].testchar);
1159 islead = IsDBCSLeadByteEx(CP_THREAD_ACP, isleads_nocp[i].testchar);
1160
1161 ok(islead == islead_acp, "wrong islead %i for test char %x in lcid %04x. should be %i\n",
1162 islead, isleads_nocp[i].testchar, isleads_nocp[i].lcid, islead_acp);
1163 }
1164
1165 /* IsDBCSLeadByteEx - locales with codepage */
1166 for (i = 0; i < sizeof(isleads)/sizeof(isleads[0]); i++)
1167 {
1168 SetThreadLocale(isleads[i].lcid);
1169
1170 islead = IsDBCSLeadByteEx(CP_THREAD_ACP, isleads[i].testchar);
1171 ok(islead == isleads[i].islead, "wrong islead %i for test char %x in lcid %04x. should be %i\n",
1172 islead, isleads[i].testchar, isleads[i].lcid, isleads[i].islead);
1173 }
1174
1176}
1177
1178static void test_dbcs_to_widechar(void)
1179{
1180 int i, count, count2;
1181 WCHAR wbuf[5];
1182 unsigned char buf[] = {0xbf, 0xb4, 0xc7, '\0', 'x'};
1183 static const DWORD flags[] = {
1186
1189
1192
1195 };
1196
1197 for (i = 0; i < sizeof(flags)/sizeof(DWORD); ++i)
1198 {
1199 memset(wbuf, 0xff, sizeof(wbuf));
1200 count = MultiByteToWideChar(936, flags[i], (char*)&buf[0], 2, NULL, 0);
1201 count2 = MultiByteToWideChar(936, flags[i], (char*)&buf[0], 2, wbuf, count);
1202
1203 ok(count == 1, "%04x: returned %d (expected 1)\n", flags[i], count);
1204 ok(count2 == 1, "%04x: returned %d (expected 1)\n", flags[i], count2);
1205 ok(wbuf[0] == 0x770b, "%04x: returned %04x (expected 770b)\n", flags[i], wbuf[0]);
1206 ok(wbuf[1] == 0xffff, "%04x: returned %04x (expected ffff)\n", flags[i], wbuf[1]);
1207 }
1208
1209 for (i = 0; i < sizeof(flags)/sizeof(DWORD); ++i)
1210 {
1211 memset(wbuf, 0xff, sizeof(wbuf));
1212 count = MultiByteToWideChar(936, flags[i], (char*)&buf[0], 3, NULL, 0);
1213 SetLastError( 0xdeadbeef );
1214 count2 = MultiByteToWideChar(936, flags[i], (char*)&buf[0], 3, wbuf, count);
1215
1217 {
1218 ok(count == 0, "%04x: returned %d (expected 0)\n", flags[i], count);
1219 ok(count2 == 0, "%04x: returned %d (expected 0)\n", flags[i], count2);
1220 ok(GetLastError() == ERROR_NO_UNICODE_TRANSLATION, "%04x: returned %d (expected %d)\n",
1222 }
1223 else
1224 {
1225 ok(count == 2, "%04x: returned %d (expected 2)\n", flags[i], count);
1226 ok(count2 == 2, "%04x: returned %d (expected 2)\n", flags[i], count2);
1227 ok(wbuf[0] == 0x770b, "%04x: returned %04x (expected 770b)\n", flags[i], wbuf[0]);
1228 ok(wbuf[1] == 0x003f || broken(wbuf[1] == 0), /*windows xp*/
1229 "%04x: wrong wide char: %04x\n", flags[i], wbuf[1]);
1230 ok(wbuf[2] == 0xffff, "%04x: returned %04x (expected ffff)\n", flags[i], wbuf[2]);
1231 }
1232 }
1233
1234 /* src ends with null character */
1235 for (i = 0; i < sizeof(flags)/sizeof(DWORD); ++i)
1236 {
1237 memset(wbuf, 0xff, sizeof(wbuf));
1238 count = MultiByteToWideChar(936, flags[i], (char*)&buf[0], 4, NULL, 0);
1239 SetLastError( 0xdeadbeef );
1240 count2 = MultiByteToWideChar(936, flags[i], (char*)&buf[0], 4, wbuf, count);
1241 ok(count == count2, "%04x: returned %d (expected %d)\n", flags[i], count2, count);
1242
1244 {
1245 ok(count == 0, "%04x: returned %d (expected 0)\n", flags[i], count);
1246 ok(GetLastError() == ERROR_NO_UNICODE_TRANSLATION, "%04x: returned %d (expected %d)\n",
1248 }
1249 else
1250 {
1251 WCHAR wbuf_ok[] = { 0x770b, 0x003f, '\0', 0xffff };
1252 WCHAR wbuf_broken[] = { 0x770b, '\0', 0xffff, 0xffff };
1253 ok(count == 3 || broken(count == 2 /*windows xp*/),
1254 "%04x: returned %d (expected 3)\n", flags[i], count);
1255 ok(!memcmp(wbuf, wbuf_ok, sizeof(wbuf_ok))
1256 || broken(!memcmp(wbuf, wbuf_broken, sizeof(wbuf_broken))),
1257 "%04x: returned %04x %04x %04x %04x (expected %04x %04x %04x %04x)\n",
1258 flags[i], wbuf[0], wbuf[1], wbuf[2], wbuf[3],
1259 wbuf_ok[0], wbuf_ok[1], wbuf_ok[2], wbuf_ok[3]);
1260 }
1261 }
1262
1263 /* src has null character, but not ends with it */
1264 for (i = 0; i < sizeof(flags)/sizeof(DWORD); ++i)
1265 {
1266 memset(wbuf, 0xff, sizeof(wbuf));
1267 count = MultiByteToWideChar(936, flags[i], (char*)&buf[0], 5, NULL, 0);
1268 SetLastError( 0xdeadbeef );
1269 count2 = MultiByteToWideChar(936, flags[i], (char*)&buf[0], 5, wbuf, count);
1270 ok(count == count2, "%04x: returned %d (expected %d)\n", flags[i], count2, count);
1271
1273 {
1274 ok(count == 0, "%04x: returned %d (expected 0)\n", flags[i], count);
1275 ok(GetLastError() == ERROR_NO_UNICODE_TRANSLATION, "%04x: returned %d (expected %d)\n",
1277 }
1278 else
1279 {
1280 WCHAR wbuf_ok[] = { 0x770b, 0x003f, '\0', 'x', 0xffff };
1281 WCHAR wbuf_broken[] = { 0x770b, '\0', 'x', 0xffff, 0xffff };
1282 ok(count == 4 || broken(count == 3),
1283 "%04x: returned %d (expected 4)\n", flags[i], count);
1284 ok(!memcmp(wbuf, wbuf_ok, sizeof(wbuf_ok))
1285 || broken(!memcmp(wbuf, wbuf_broken, sizeof(wbuf_broken))),
1286 "%04x: returned %04x %04x %04x %04x %04x (expected %04x %04x %04x %04x %04x)\n",
1287 flags[i], wbuf[0], wbuf[1], wbuf[2], wbuf[3], wbuf[4],
1288 wbuf_ok[0], wbuf_ok[1], wbuf_ok[2], wbuf_ok[3], wbuf_ok[4]);
1289 }
1290 }
1291}
1292
1294{
1295 BOOL bUsedDefaultChar;
1296
1303
1304 /* WideCharToMultiByte has two code paths, test both here */
1306 test_string_conversion(&bUsedDefaultChar);
1307
1310
1312 test_threadcp();
1313
1315}
#define broken(x)
Definition: _sntprintf.h:21
int strcmp(const char *String1, const char *String2)
Definition: utclib.c:469
int memcmp(void *Buffer1, void *Buffer2, ACPI_SIZE Count)
Definition: utclib.c:112
ACPI_SIZE strlen(const char *String)
Definition: utclib.c:269
char * strcpy(char *DstString, const char *SrcString)
Definition: utclib.c:388
static int used
Definition: adh-main.c:39
#define ok(value,...)
Definition: atltest.h:57
#define skip(...)
Definition: atltest.h:64
#define START_TEST(x)
Definition: atltest.h:75
static void test_threadcp(void)
Definition: codepage.c:1037
static const WCHAR foobarW[]
Definition: codepage.c:32
static void test_other_invalid_parameters(void)
Definition: codepage.c:203
static void test_undefined_byte_char(void)
Definition: codepage.c:987
static void test_negative_source_length(void)
Definition: codepage.c:116
static const char foobarA[]
Definition: codepage.c:31
static void test_null_source(void)
Definition: codepage.c:96
static void test_utf7_decoding(void)
Definition: codepage.c:715
static void test_destination_buffer(void)
Definition: codepage.c:34
#define LONGBUFLEN
Definition: codepage.c:144
static void test_negative_dest_length(void)
Definition: codepage.c:145
static void test_utf7_encoding(void)
Definition: codepage.c:472
static void test_overlapped_buffers(void)
Definition: codepage.c:310
static void test_dbcs_to_widechar(void)
Definition: codepage.c:1178
static void test_string_conversion(LPBOOL bUsedDefaultChar)
Definition: codepage.c:325
#define ERROR_INSUFFICIENT_BUFFER
Definition: dderror.h:10
#define NULL
Definition: types.h:112
#define TRUE
Definition: types.h:120
#define FALSE
Definition: types.h:117
const char * wine_dbgstr_wn(const WCHAR *str, int n)
Definition: compat.c:367
#define GetProcessHeap()
Definition: compat.h:736
#define ERROR_INVALID_PARAMETER
Definition: compat.h:101
#define CP_ACP
Definition: compat.h:109
#define SetLastError(x)
Definition: compat.h:752
#define HeapAlloc
Definition: compat.h:733
#define HeapFree(x, y, z)
Definition: compat.h:735
#define WideCharToMultiByte
Definition: compat.h:111
#define MultiByteToWideChar
Definition: compat.h:110
BOOL WINAPI IsDBCSLeadByteEx(UINT CodePage, BYTE TestByte)
Definition: nls.c:2337
BOOL WINAPI IsValidCodePage(UINT CodePage)
Definition: nls.c:1604
BOOL WINAPI GetCPInfoExA(UINT CodePage, DWORD dwFlags, LPCPINFOEXA lpCPInfoEx)
Definition: nls.c:2152
unsigned int BOOL
Definition: ntddk_ex.h:94
unsigned long DWORD
Definition: ntddk_ex.h:95
GLuint GLuint GLsizei count
Definition: gl.h:1545
GLenum src
Definition: glext.h:6340
GLuint buffer
Definition: glext.h:5915
GLenum GLuint GLenum GLsizei const GLchar * buf
Definition: glext.h:7751
GLenum GLenum dst
Definition: glext.h:6340
GLbitfield flags
Definition: glext.h:7161
GLuint GLuint num
Definition: glext.h:9618
GLenum GLsizei len
Definition: glext.h:6722
GLenum GLenum GLenum input
Definition: glext.h:9031
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat GLuint GLbitfield GLfloat GLint GLuint GLboolean GLenum GLfloat GLenum GLbitfield GLenum GLfloat GLfloat GLint GLint const GLfloat GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat const GLdouble const GLfloat const GLdouble const GLfloat GLint i
Definition: glfuncs.h:248
#define MB_COMPOSITE
Definition: unicode.h:40
#define WC_COMPOSITECHECK
Definition: unicode.h:43
#define MB_USEGLYPHCHARS
Definition: unicode.h:42
#define MB_ERR_INVALID_CHARS
Definition: unicode.h:41
#define INT_MAX
Definition: limits.h:40
LCID WINAPI GetThreadLocale(void)
Definition: lang.c:1459
BOOL WINAPI SetThreadLocale(LCID lcid)
Definition: lang.c:1478
INT WINAPI GetLocaleInfoA(LCID lcid, LCTYPE lctype, LPSTR buffer, INT len)
Definition: lang.c:1028
int WINAPI lstrcmpW(LPCWSTR lpString1, LPCWSTR lpString2)
Definition: lstring.c:170
int WINAPI lstrcmpA(LPCSTR lpString1, LPCSTR lpString2)
Definition: lstring.c:18
POINT cp
Definition: magnifier.c:59
#define memcpy(s1, s2, n)
Definition: mkisofs.h:878
static struct test_info tests[]
#define sprintf(buf, format,...)
Definition: sprintf.c:55
static DWORD GLE
Definition: registry.c:38
BOOL expected
Definition: store.c:2063
static UINT UINT last
Definition: font.c:45
static DWORD LPDWORD LPCSTR DWORD srclen
Definition: directory.c:52
static DWORD dstlen
Definition: directory.c:51
WCHAR strW[12]
Definition: clipboard.c:2029
char strA[12]
Definition: clipboard.c:2028
unsigned int UINT
Definition: ndis.h:50
#define SORT_DEFAULT
#define MAKELCID(lgid, srtid)
#define test
Definition: rosglue.h:37
const WCHAR * str
#define LANG_HINDI
Definition: nls.h:68
#define SUBLANG_JAPANESE_JAPAN
Definition: nls.h:271
#define SUBLANG_HINDI_INDIA
Definition: nls.h:261
#define MAKELANGID(p, s)
Definition: nls.h:15
#define LANG_GEORGIAN
Definition: nls.h:61
#define LANG_ENGLISH
Definition: nls.h:52
#define SUBLANG_RUSSIAN_RUSSIA
Definition: nls.h:315
#define SUBLANG_CHINESE_SIMPLIFIED
Definition: nls.h:209
#define LANG_RUSSIAN
Definition: nls.h:113
#define LANG_CHINESE
Definition: nls.h:42
DWORD LCID
Definition: nls.h:13
#define CP_UTF8
Definition: nls.h:20
#define LANG_JAPANESE
Definition: nls.h:76
#define SUBLANG_GEORGIAN_GEORGIA
Definition: nls.h:250
#define SUBLANG_ENGLISH_US
Definition: nls.h:222
#define memset(x, y, z)
Definition: compat.h:39
UINT CodePage
Definition: winnls.h:590
int32_t INT
Definition: typedefs.h:58
char mbs[5]
wchar_t dbwcs[3]
int ret
char mbc
wchar_t wc1
wchar_t wcs[5]
wchar_t wc2
int codepage
Definition: win_iconv.c:156
#define ZeroMemory
Definition: winbase.h:1712
DWORD WINAPI GetLastError(void)
Definition: except.c:1042
BOOL * LPBOOL
Definition: windef.h:162
#define ERROR_NO_UNICODE_TRANSLATION
Definition: winerror.h:649
#define ERROR_INVALID_FLAGS
Definition: winerror.h:583
#define CP_THREAD_ACP
Definition: winnls.h:233
UINT WINAPI GetACP(void)
Definition: nls.c:2307
#define CP_SYMBOL
Definition: winnls.h:234
#define CP_UTF7
Definition: winnls.h:235
#define MB_PRECOMPOSED
Definition: winnls.h:281
#define LOCALE_IDEFAULTANSICODEPAGE
Definition: winnls.h:38
const char * LPCSTR
Definition: xmlstorage.h:183
char * LPSTR
Definition: xmlstorage.h:182
__wchar_t WCHAR
Definition: xmlstorage.h:180
unsigned char BYTE
Definition: xxhash.c:193