ReactOS 0.4.16-dev-2207-geb15453
locale.c
Go to the documentation of this file.
1/*
2 * Unit tests for locale functions
3 *
4 * Copyright 2002 YASAR Mehmet
5 * Copyright 2003 Dmitry Timoshkov
6 * Copyright 2003 Jon Griffiths
7 *
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
12 *
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
17 *
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 *
22 * NOTES
23 * We must pass LOCALE_NOUSEROVERRIDE (NUO) to formatting functions so that
24 * even when the user has overridden their default i8n settings (e.g. in
25 * the control panel i8n page), we will still get the expected results.
26 */
27
28#define _CRT_NON_CONFORMING_WCSTOK
29
30#include <assert.h>
31#include <stdlib.h>
32#include <stdarg.h>
33#include <stdio.h>
34
35#include "ntstatus.h"
36#define WIN32_NO_STATUS
37#include "windef.h"
38#include "winbase.h"
39#include "winerror.h"
40#include "winnls.h"
41#include "winternl.h"
42#include "winreg.h"
43#include "wine/test.h"
44
45static const WCHAR upper_case[] = {'\t','J','U','S','T','!',' ','A',',',' ','T','E','S','T',';',' ','S','T','R','I','N','G',' ','1','/','*','+','-','.','\r','\n',0};
46static const WCHAR lower_case[] = {'\t','j','u','s','t','!',' ','a',',',' ','t','e','s','t',';',' ','s','t','r','i','n','g',' ','1','/','*','+','-','.','\r','\n',0};
47static const WCHAR title_case[] = {'\t','J','u','s','t','!',' ','A',',',' ','T','e','s','t',';',' ','S','t','r','i','n','g',' ','1','/','*','+','-','.','\r','\n',0};
48static const WCHAR symbols_stripped[] = {'j','u','s','t','a','t','e','s','t','s','t','r','i','n','g','1',0};
49static const WCHAR localeW[] = {'e','n','-','U','S',0};
50static const WCHAR fooW[] = {'f','o','o',0};
51static const WCHAR emptyW[] = {0};
52static const WCHAR invalidW[] = {'i','n','v','a','l','i','d',0};
53
54/* Some functions are only in later versions of kernel32.dll */
56
57static INT (WINAPI *pGetTimeFormatEx)(LPCWSTR, DWORD, const SYSTEMTIME *, LPCWSTR, LPWSTR, INT);
58static INT (WINAPI *pGetDateFormatEx)(LPCWSTR, DWORD, const SYSTEMTIME *, LPCWSTR, LPWSTR, INT, LPCWSTR);
59static BOOL (WINAPI *pEnumSystemLanguageGroupsA)(LANGUAGEGROUP_ENUMPROCA, DWORD, LONG_PTR);
60static BOOL (WINAPI *pEnumLanguageGroupLocalesA)(LANGGROUPLOCALE_ENUMPROCA, LGRPID, DWORD, LONG_PTR);
61static BOOL (WINAPI *pEnumUILanguagesA)(UILANGUAGE_ENUMPROCA, DWORD, LONG_PTR);
62static BOOL (WINAPI *pEnumSystemLocalesA)(LOCALE_ENUMPROCA, DWORD);
63static BOOL (WINAPI *pEnumSystemLocalesW)(LOCALE_ENUMPROCW, DWORD);
64static BOOL (WINAPI *pEnumSystemLocalesEx)(LOCALE_ENUMPROCEX, DWORD, LPARAM, LPVOID);
68static BOOLEAN (WINAPI *pRtlIsValidLocaleName)(const WCHAR *,ULONG);
70static INT (WINAPI *pLCIDToLocaleName)(LCID, LPWSTR, INT, DWORD);
71static BOOL (WINAPI *pIsValidLanguageGroup)(LGRPID, DWORD);
72static INT (WINAPI *pIdnToNameprepUnicode)(DWORD, LPCWSTR, INT, LPWSTR, INT);
73static INT (WINAPI *pIdnToAscii)(DWORD, LPCWSTR, INT, LPWSTR, INT);
74static INT (WINAPI *pIdnToUnicode)(DWORD, LPCWSTR, INT, LPWSTR, INT);
76static BOOL (WINAPI *pIsValidLocaleName)(LPCWSTR);
77static INT (WINAPI *pResolveLocaleName)(LPCWSTR,LPWSTR,INT);
78static INT (WINAPI *pCompareStringOrdinal)(const WCHAR *, INT, const WCHAR *, INT, BOOL);
79static INT (WINAPI *pCompareStringEx)(LPCWSTR, DWORD, LPCWSTR, INT, LPCWSTR, INT,
81static INT (WINAPI *pGetGeoInfoA)(GEOID, GEOTYPE, LPSTR, INT, LANGID);
82static INT (WINAPI *pGetGeoInfoW)(GEOID, GEOTYPE, LPWSTR, INT, LANGID);
83static INT (WINAPI *pGetGeoInfoEx)(const WCHAR *, GEOTYPE, PWSTR, INT);
84static INT (WINAPI *pGetUserDefaultGeoName)(LPWSTR, int);
85static BOOL (WINAPI *pSetUserGeoName)(PWSTR);
86static BOOL (WINAPI *pEnumSystemGeoID)(GEOCLASS, GEOID, GEO_ENUMPROC);
87static BOOL (WINAPI *pGetSystemPreferredUILanguages)(DWORD, ULONG*, WCHAR*, ULONG*);
88static BOOL (WINAPI *pGetThreadPreferredUILanguages)(DWORD, ULONG*, WCHAR*, ULONG*);
89static BOOL (WINAPI *pGetUserPreferredUILanguages)(DWORD, ULONG*, WCHAR*, ULONG*);
90static WCHAR (WINAPI *pRtlUpcaseUnicodeChar)(WCHAR);
91static INT (WINAPI *pGetNumberFormatEx)(LPCWSTR, DWORD, LPCWSTR, const NUMBERFMTW *, LPWSTR, int);
94static LANGID (WINAPI *pSetThreadUILanguage)(LANGID);
95static LANGID (WINAPI *pGetThreadUILanguage)(VOID);
96static INT (WINAPI *pNormalizeString)(NORM_FORM, LPCWSTR, INT, LPWSTR, INT);
97static INT (WINAPI *pFindStringOrdinal)(DWORD, LPCWSTR lpStringSource, INT, LPCWSTR, INT, BOOL);
98static BOOL (WINAPI *pGetNLSVersion)(NLS_FUNCTION,LCID,NLSVERSIONINFO*);
99static BOOL (WINAPI *pGetNLSVersionEx)(NLS_FUNCTION,LPCWSTR,NLSVERSIONINFOEX*);
100static DWORD (WINAPI *pIsValidNLSVersion)(NLS_FUNCTION,LPCWSTR,NLSVERSIONINFOEX*);
101static BOOL (WINAPI *pIsNLSDefinedString)(NLS_FUNCTION,DWORD,NLSVERSIONINFO*,const WCHAR *,int);
102static NTSTATUS (WINAPI *pRtlNormalizeString)(ULONG, LPCWSTR, INT, LPWSTR, INT*);
103static NTSTATUS (WINAPI *pRtlIsNormalizedString)(ULONG, LPCWSTR, INT, BOOLEAN*);
104static NTSTATUS (WINAPI *pNtGetNlsSectionPtr)(ULONG,ULONG,void*,void**,SIZE_T*);
105static NTSTATUS (WINAPI *pNtInitializeNlsFiles)(void**,LCID*,LARGE_INTEGER*);
106static NTSTATUS (WINAPI *pRtlGetLocaleFileMappingAddress)(void**,LCID*,LARGE_INTEGER*);
107static void (WINAPI *pRtlInitCodePageTable)(USHORT*,CPTABLEINFO*);
108static NTSTATUS (WINAPI *pRtlCustomCPToUnicodeN)(CPTABLEINFO*,WCHAR*,DWORD,DWORD*,const char*,DWORD);
109static NTSTATUS (WINAPI *pRtlGetSystemPreferredUILanguages)(DWORD,ULONG,ULONG*,WCHAR*,ULONG*);
110static NTSTATUS (WINAPI *pRtlGetThreadPreferredUILanguages)(DWORD,ULONG*,WCHAR*,ULONG*);
111static NTSTATUS (WINAPI *pRtlGetUserPreferredUILanguages)(DWORD,ULONG,ULONG*,WCHAR*,ULONG*);
112
113static void InitFunctionPointers(void)
114{
115 HMODULE mod = GetModuleHandleA("kernel32");
116
117#define X(f) p##f = (void*)GetProcAddress(mod, #f)
131 X(IdnToAscii);
138 X(GetGeoInfoA);
139 X(GetGeoInfoW);
157
158 mod = GetModuleHandleA("kernelbase");
160
161 mod = GetModuleHandleA("ntdll");
176#undef X
177}
178
179#define eq(received, expected, label, type) \
180 ok((received) == (expected), "%s: got " type " instead of " type "\n", \
181 (label), (received), (expected))
182
183#define BUFFER_SIZE 128
184
185#define expect_str(r,s,e) expect_str_(__LINE__, r, s, e)
186static void expect_str_(int line, int ret, const char *str, const char *expected)
187{
188 if (ret)
189 {
190 ok_(__FILE__, line)(GetLastError() == 0xdeadbeef, "unexpected gle %lu\n", GetLastError());
191 ok_(__FILE__, line)(ret == strlen(expected) + 1, "Expected ret %Id, got %d\n", strlen(expected) + 1, ret);
192 if (str)
193 ok_(__FILE__, line)(strcmp(str, expected) == 0, "Expected '%s', got '%s'\n", expected, str);
194 }
195 else
196 ok_(__FILE__, line)(0, "expected success, got error %ld\n", GetLastError());
197}
198
199#define expect_err(r,s,e) expect_err_(__LINE__, r, s, e, #e)
200static void expect_err_(int line, int ret, const char *str, DWORD err, const char* err_name)
201{
202 ok_(__FILE__, line)(!ret && GetLastError() == err,
203 "Expected %s, got %ld and ret=%d\n", err_name, GetLastError(), ret);
204 if (str)
205 ok_(__FILE__, line)(strcmp(str, "pristine") == 0, "Expected a pristine buffer, got '%s'\n", str);
206}
207
208#define expect_wstr(r,s,e) expect_wstr_(__LINE__, r, s, e)
209static void expect_wstr_(int line, int ret, const WCHAR *str, const WCHAR *expected)
210{
211 if (ret)
212 {
213 ok_(__FILE__, line)(GetLastError() == 0xdeadbeef, "unexpected gle %lu\n", GetLastError());
214 ok_(__FILE__, line)(ret == wcslen(expected) + 1, "Expected ret %Id, got %d\n", wcslen(expected) + 1, ret);
215 if (str)
216 ok_(__FILE__, line)(wcscmp(str, expected) == 0, "Expected %s, got %s\n", wine_dbgstr_w(expected), wine_dbgstr_w(str));
217 }
218 else
219 ok_(__FILE__, line)(0, "expected success, got error %ld\n", GetLastError());
220}
221
222#define expect_werr(r,s,e) expect_werr_(__LINE__, r, s, e, #e)
223static void expect_werr_(int line, int ret, const WCHAR *str, DWORD err, const char* err_name)
224{
225 ok_(__FILE__, line)(!ret && GetLastError() == err,
226 "Expected %s, got %ld and ret=%d\n", err_name, GetLastError(), ret);
227 if (str)
228 ok_(__FILE__, line)(wcscmp(str, L"pristine") == 0, "Expected a pristine buffer, got %s\n", wine_dbgstr_w(str));
229}
230
231static int get_utf16( const WCHAR *src, unsigned int srclen, unsigned int *ch )
232{
233 if (IS_HIGH_SURROGATE( src[0] ))
234 {
235 if (srclen <= 1) return 0;
236 if (!IS_LOW_SURROGATE( src[1] )) return 0;
237 *ch = 0x10000 + ((src[0] & 0x3ff) << 10) + (src[1] & 0x3ff);
238 return 2;
239 }
240 if (IS_LOW_SURROGATE( src[0] )) return 0;
241 *ch = src[0];
242 return 1;
243}
244
245static int put_utf16( WCHAR *str, unsigned int c )
246{
247 if (c < 0x10000)
248 {
249 *str = c;
250 return 1;
251 }
252 c -= 0x10000;
253 str[0] = 0xd800 | (c >> 10);
254 str[1] = 0xdc00 | (c & 0x3ff);
255 return 2;
256}
257
258#define NUO LOCALE_NOUSEROVERRIDE
259
260static void test_GetLocaleInfoA(void)
261{
262 int ret;
263 int len;
265 char buffer[BUFFER_SIZE];
266 char expected[BUFFER_SIZE];
267 DWORD val;
268
269 ok(lcid == 0x409, "wrong LCID calculated - %ld\n", lcid);
270
271 ret = GetLocaleInfoA(lcid, LOCALE_ILANGUAGE|LOCALE_RETURN_NUMBER, (char*)&val, sizeof(val));
272 ok(ret, "got %d\n", ret);
273 ok(val == lcid, "got 0x%08lx\n", val);
274
275 /* en and ar use SUBLANG_NEUTRAL, but GetLocaleInfo assume SUBLANG_DEFAULT
276 Same is true for zh on pre-Vista, but on Vista and higher GetLocaleInfo
277 assumes SUBLANG_NEUTRAL for zh */
280 SetLastError(0xdeadbeef);
283 ok((ret == len) && !lstrcmpA(buffer, expected),
284 "got %d with '%s' (expected %d with '%s')\n",
286
289 if (len) {
290 SetLastError(0xdeadbeef);
293 ok((ret == len) && !lstrcmpA(buffer, expected),
294 "got %d with '%s' (expected %d with '%s')\n",
296 }
297 else
298 win_skip("LANG_ARABIC not installed\n");
299
300 /* SUBLANG_DEFAULT is required for mlang.dll, but optional for GetLocaleInfo */
303 SetLastError(0xdeadbeef);
306 ok((ret == len) && !lstrcmpA(buffer, expected),
307 "got %d with '%s' (expected %d with '%s')\n",
309
312 ok( (ret == len) && !lstrcmpA(buffer, expected), "got %d with '%s' (expected %d with '%s')\n",
315#ifdef __REACTOS__
316 ok( ((ret == len) && !lstrcmpA(buffer, expected)) || broken(!ret) /* WS03 */, "got %d with '%s' (expected %d with '%s')\n",
318#else
319 ok( (ret == len) && !lstrcmpA(buffer, expected), "got %d with '%s' (expected %d with '%s')\n",
321#endif
323 ok( (ret == len && !lstrcmpA(buffer, expected)) || broken(!ret), /* <= win8 */
324 "got %d with '%s' (expected %d with '%s')\n", ret, buffer, len, expected);
327 if (ret) ok( (ret == len && !lstrcmpA(buffer, expected)),
328 "got %d with '%s' (expected %d with '%s')\n", ret, buffer, len, expected);
329
330 /* HTMLKit and "Font xplorer lite" expect GetLocaleInfoA to
331 * partially fill the buffer even if it is too short. See bug 637.
332 */
333 SetLastError(0xdeadbeef);
336 ok(ret == 7 && !buffer[0], "Expected len=7, got %d\n", ret);
337
338 SetLastError(0xdeadbeef);
342 "Expected ERROR_INSUFFICIENT_BUFFER, got %ld\n", GetLastError());
343 ok(!strcmp(buffer, "Mon"), "Expected 'Mon', got '%s'\n", buffer);
344
345 SetLastError(0xdeadbeef);
348 ok(ret == 7, "Expected ret == 7, got %d, error %ld\n", ret, GetLastError());
349 ok(!strcmp(buffer, "Monday"), "Expected 'Monday', got '%s'\n", buffer);
350}
351
358};
359
361 { {'a','r',0}, {'a','r','-','S','A',0},
363 { {'a','z',0}, {'a','z','-','L','a','t','n','-','A','Z',0},
365 { {'d','e',0}, {'d','e','-','D','E',0},
367 { {'e','n',0}, {'e','n','-','U','S',0},
369 { {'e','s',0}, {'e','s','-','E','S',0},
372 {'e','s','-','E','S','_','t','r','a','d','n','l',0} },
373 { {'g','a',0}, {'g','a','-','I','E',0},
375 { {'i','t',0}, {'i','t','-','I','T',0},
377 { {'m','s',0}, {'m','s','-','M','Y',0},
379 { {'n','l',0}, {'n','l','-','N','L',0},
381 { {'p','t',0}, {'p','t','-','B','R',0},
383 { {'s','r',0}, {'h','r','-','H','R',0},
385 { {'s','v',0}, {'s','v','-','S','E',0},
387 { {'u','z',0}, {'u','z','-','L','a','t','n','-','U','Z',0},
389 { {'z','h',0}, {'z','h','-','C','N',0},
391 { {0} }
392};
393
394static void test_GetLocaleInfoW(void)
395{
399 WCHAR bufferW[80], buffer2W[80];
400 CHAR bufferA[80];
401 DWORD val;
402 DWORD ret;
403 INT i;
404
405 ret = GetLocaleInfoW(lcid_en, LOCALE_SMONTHNAME1, bufferW, ARRAY_SIZE(bufferW));
406 if (!ret) {
407 win_skip("GetLocaleInfoW() isn't implemented\n");
408 return;
409 }
410
411 ret = GetLocaleInfoW(lcid_en, LOCALE_ILANGUAGE|LOCALE_RETURN_NUMBER, (WCHAR*)&val, sizeof(val)/sizeof(WCHAR));
412 ok(ret, "got %ld\n", ret);
413 ok(val == lcid_en, "got 0x%08lx\n", val);
414
415 ret = GetLocaleInfoW(lcid_en_neut, LOCALE_SNAME, bufferW, ARRAY_SIZE(bufferW));
416 if (ret)
417 {
418 static const WCHAR slangW[] = {'E','n','g','l','i','s','h',' ','(','U','n','i','t','e','d',' ',
419 'S','t','a','t','e','s',')',0};
420 static const WCHAR statesW[] = {'U','n','i','t','e','d',' ','S','t','a','t','e','s',0};
421 static const WCHAR enW[] = {'e','n','-','U','S',0};
423
424 ok(!lstrcmpW(bufferW, enW), "got wrong name %s\n", wine_dbgstr_w(bufferW));
425
426 ret = GetLocaleInfoW(lcid_en_neut, LOCALE_SCOUNTRY, bufferW, ARRAY_SIZE(bufferW));
427 ok(ret, "got %ld\n", ret);
430 {
431 skip("Non-English locale\n");
432 }
433 else
434 ok(!lstrcmpW(statesW, bufferW), "got wrong name %s\n", wine_dbgstr_w(bufferW));
435
436 ret = GetLocaleInfoW(lcid_en_neut, LOCALE_SLANGUAGE, bufferW, ARRAY_SIZE(bufferW));
437 ok(ret, "got %ld\n", ret);
440 {
441 skip("Non-English locale\n");
442 }
443 else
444 ok(!lstrcmpW(slangW, bufferW), "got wrong name %s\n", wine_dbgstr_w(bufferW));
445
446 while (*ptr->name)
447 {
449 LCID lcid;
450
451 /* make neutral lcid */
454
455 val = 0;
456 GetLocaleInfoW(lcid, LOCALE_ILANGUAGE|LOCALE_RETURN_NUMBER, (WCHAR*)&val, sizeof(val)/sizeof(WCHAR));
457 ok(val == ptr->lcid || (val && broken(val == ptr->lcid_broken)), "%s: got wrong lcid 0x%04lx, expected 0x%04lx\n",
458 wine_dbgstr_w(ptr->name), val, ptr->lcid);
459
460 /* now check LOCALE_SNAME */
461 GetLocaleInfoW(lcid, LOCALE_SNAME, bufferW, ARRAY_SIZE(bufferW));
462 ok(!lstrcmpW(bufferW, ptr->sname) ||
463 (*ptr->sname_broken && broken(!lstrcmpW(bufferW, ptr->sname_broken))),
464 "%s: got %s\n", wine_dbgstr_w(ptr->name), wine_dbgstr_w(bufferW));
465 ptr++;
466 }
467 }
468 else
469 win_skip("English neutral locale not supported\n");
470
471 ret = GetLocaleInfoW(lcid_ru, LOCALE_SMONTHNAME1, bufferW, ARRAY_SIZE(bufferW));
472 if (!ret) {
473 win_skip("LANG_RUSSIAN locale data unavailable\n");
474 return;
475 }
477 bufferW, ARRAY_SIZE(bufferW));
478 if (!ret) {
479 win_skip("LOCALE_RETURN_GENITIVE_NAMES isn't supported\n");
480 return;
481 }
482
483 /* LOCALE_RETURN_GENITIVE_NAMES isn't supported for GetLocaleInfoA */
484 bufferA[0] = 'a';
485 SetLastError(0xdeadbeef);
487 bufferA, ARRAY_SIZE(bufferA));
488 ok(ret == 0, "LOCALE_RETURN_GENITIVE_NAMES should fail with GetLocaleInfoA\n");
489 ok(bufferA[0] == 'a', "Expected buffer to be untouched\n");
491 "Expected ERROR_INVALID_FLAGS, got %lx\n", GetLastError());
492
493 bufferW[0] = 'a';
494 SetLastError(0xdeadbeef);
495 ret = GetLocaleInfoW(lcid_ru, LOCALE_RETURN_GENITIVE_NAMES, bufferW, ARRAY_SIZE(bufferW));
496 ok(ret == 0,
497 "LOCALE_RETURN_GENITIVE_NAMES itself doesn't return anything, got %ld\n", ret);
498 ok(bufferW[0] == 'a', "Expected buffer to be untouched\n");
500 "Expected ERROR_INVALID_FLAGS, got %lx\n", GetLastError());
501
502 /* yes, test empty 13 month entry too */
503 for (i = 0; i < 12; i++) {
504 bufferW[0] = 0;
506 bufferW, ARRAY_SIZE(bufferW));
507 ok(ret, "Expected non zero result\n");
508 ok(ret == lstrlenW(bufferW)+1, "Expected actual length, got %ld, length %d\n",
509 ret, lstrlenW(bufferW));
510 buffer2W[0] = 0;
511 ret = GetLocaleInfoW(lcid_ru, LOCALE_SMONTHNAME1+i, buffer2W, ARRAY_SIZE(buffer2W));
512 ok(ret, "Expected non zero result\n");
513 ok(ret == lstrlenW(buffer2W)+1, "Expected actual length, got %ld, length %d\n",
514 ret, lstrlenW(buffer2W));
515
516 ok(lstrcmpW(bufferW, buffer2W) != 0,
517 "Expected genitive name to differ, got the same for month %d\n", i+1);
518
519 /* for locale without genitive names nominative returned in both cases */
520 bufferW[0] = 0;
522 bufferW, ARRAY_SIZE(bufferW));
523 ok(ret, "Expected non zero result\n");
524 ok(ret == lstrlenW(bufferW)+1, "Expected actual length, got %ld, length %d\n",
525 ret, lstrlenW(bufferW));
526 buffer2W[0] = 0;
527 ret = GetLocaleInfoW(lcid_en, LOCALE_SMONTHNAME1+i, buffer2W, ARRAY_SIZE(buffer2W));
528 ok(ret, "Expected non zero result\n");
529 ok(ret == lstrlenW(buffer2W)+1, "Expected actual length, got %ld, length %d\n",
530 ret, lstrlenW(buffer2W));
531
532 ok(lstrcmpW(bufferW, buffer2W) == 0,
533 "Expected same names, got different for month %d\n", i+1);
534 }
535}
536
537static void test_GetTimeFormatA(void)
538{
539 int ret;
540 SYSTEMTIME curtime;
542 char buffer[BUFFER_SIZE];
543
544 SetLastError(0xdeadbeef);
545
546 /* Invalid time */
547 memset(&curtime, 2, sizeof(SYSTEMTIME));
548 strcpy(buffer, "pristine");
549 ret = GetTimeFormatA(lcid, TIME_FORCE24HOURFORMAT, &curtime, "tt HH':'mm'@'ss", buffer, ARRAY_SIZE(buffer));
551 SetLastError(0xdeadbeef);
552
553 /* Valid time */
554 curtime.wHour = 8;
555 curtime.wMinute = 56;
556 curtime.wSecond = 13;
557 curtime.wMilliseconds = 22;
558 ret = GetTimeFormatA(lcid, TIME_FORCE24HOURFORMAT, &curtime, "tt HH':'mm'@'ss", buffer, ARRAY_SIZE(buffer));
559 expect_str(ret, buffer, "AM 08:56@13");
560
561 /* MSDN: LOCALE_NOUSEROVERRIDE can't be specified with a format string */
562 strcpy(buffer, "pristine");
565 SetLastError(0xdeadbeef);
566
567 /* Insufficient buffer */
568 ret = GetTimeFormatA(lcid, TIME_FORCE24HOURFORMAT, &curtime, " HH", buffer, 2);
569 /* The content of the buffer depends on implementation details:
570 * it may be " ristine" or " 0ristine" or unchanged and cannot be relied on.
571 */
573 SetLastError(0xdeadbeef);
574
575 /* Calculate length only */
576 ret = GetTimeFormatA(lcid, TIME_FORCE24HOURFORMAT, &curtime, "tt HH':'mm'@'ss", NULL, 0);
577 expect_str(ret, NULL, "AM 08:56@13");
578
579 /* TIME_NOMINUTESORSECONDS, default format */
581 expect_str(ret, buffer, "8 AM");
582
583 /* TIME_NOMINUTESORSECONDS/complex format */
585 expect_str(ret, buffer, "");
586
587 /* TIME_NOSECONDS/Default format */
589 expect_str(ret, buffer, "8:56 AM");
590
591 /* TIME_NOSECONDS */
592 strcpy(buffer, "pristine"); /* clear previous identical result */
593 ret = GetTimeFormatA(lcid, TIME_NOSECONDS, &curtime, "h:m:s tt", buffer, ARRAY_SIZE(buffer));
594 expect_str(ret, buffer, "8:56 AM");
595
596 /* Multiple delimiters */
597 ret = GetTimeFormatA(lcid, TIME_NOSECONDS, &curtime, "h.@:m.@:s.@:tt", buffer, ARRAY_SIZE(buffer));
598 expect_str(ret, buffer, "8.@:56AM");
599
600 /* Duplicate tokens */
601 ret = GetTimeFormatA(lcid, TIME_NOSECONDS, &curtime, "s1s2s3", buffer, ARRAY_SIZE(buffer));
602 expect_str(ret, buffer, "");
603
604 /* AM time marker */
605 ret = GetTimeFormatA(lcid, 0, &curtime, "t/tt", buffer, ARRAY_SIZE(buffer));
606 expect_str(ret, buffer, "A/AM");
607
608 /* PM time marker */
609 curtime.wHour = 13;
610 ret = GetTimeFormatA(lcid, 0, &curtime, "t/tt", buffer, ARRAY_SIZE(buffer));
611 expect_str(ret, buffer, "P/PM");
612
613 /* TIME_NOTIMEMARKER: removes text around time marker token */
614 ret = GetTimeFormatA(lcid, TIME_NOTIMEMARKER, &curtime, "h1t2tt3m", buffer, ARRAY_SIZE(buffer));
615 expect_str(ret, buffer, "156");
616
617 /* TIME_FORCE24HOURFORMAT */
619 expect_str(ret, buffer, "13:56:13 PM");
620
621 /* TIME_FORCE24HOURFORMAT doesn't add time marker */
623 expect_str(ret, buffer, "13:56:13");
624
625 /* 24 hrs, leading 0 */
626 curtime.wHour = 14; /* change this to 14 or 2pm */
627 curtime.wMinute = 5;
628 curtime.wSecond = 3;
629 ret = GetTimeFormatA(lcid, 0, &curtime, "h hh H HH m mm s ss t tt", buffer, ARRAY_SIZE(buffer));
630 expect_str(ret, buffer, "2 02 14 14 5 05 3 03 P PM");
631
632 /* "hh" and "HH" */
633 curtime.wHour = 0;
634 ret = GetTimeFormatA(lcid, 0, &curtime, "h/H/hh/HH", buffer, ARRAY_SIZE(buffer));
635 expect_str(ret, buffer, "12/0/12/00");
636
637 /* non-zero flags should fail with format, doesn't */
638 ret = GetTimeFormatA(lcid, 0, &curtime, "h:m:s tt", buffer, ARRAY_SIZE(buffer));
639 expect_str(ret, buffer, "12:5:3 AM");
640
641 /* try to convert formatting strings with more than two letters
642 * "h:hh:hhh:H:HH:HHH:m:mm:mmm:M:MM:MMM:s:ss:sss:S:SS:SSS"
643 * NOTE: We expect any letter for which there is an upper case value
644 * we should see a replacement. For letters that DO NOT have
645 * upper case values we should see NO REPLACEMENT.
646 */
647 curtime.wHour = 8;
648 curtime.wMinute = 56;
649 curtime.wSecond = 13;
650 curtime.wMilliseconds = 22;
651 ret = GetTimeFormatA(lcid, 0, &curtime, "h:hh:hhh H:HH:HHH m:mm:mmm M:MM:MMM s:ss:sss S:SS:SSS", buffer, ARRAY_SIZE(buffer));
652 expect_str(ret, buffer, "8:08:08 8:08:08 56:56:56 M:MM:MMM 13:13:13 S:SS:SSS");
653
654 /* Don't write to buffer if len is 0 */
655 strcpy(buffer, "pristine");
656 ret = GetTimeFormatA(lcid, 0, &curtime, "h:mm", buffer, 0);
657 expect_str(ret, NULL, "8:56");
658 ok(strcmp(buffer, "pristine") == 0, "Expected a pristine buffer, got '%s'\n", buffer);
659
660 /* "'" preserves tokens */
661 ret = GetTimeFormatA(lcid, 0, &curtime, "h 'h' H 'H' HH 'HH' m 'm' s 's' t 't' tt 'tt'", buffer, ARRAY_SIZE(buffer));
662 expect_str(ret, buffer, "8 h 8 H 08 HH 56 m 13 s A t AM tt");
663
664 /* invalid quoted string */
665 ret = GetTimeFormatA(lcid, 0, &curtime, "'''", buffer, ARRAY_SIZE(buffer));
666 expect_str(ret, buffer, "'");
667
668 /* check that MSDN's suggested single quotation usage works as expected */
669 strcpy(buffer, "pristine"); /* clear previous identical result */
670 ret = GetTimeFormatA(lcid, 0, &curtime, "''''", buffer, ARRAY_SIZE(buffer));
671 expect_str(ret, buffer, "'");
672
673 /* Normal use */
674 ret = GetTimeFormatA(lcid, 0, &curtime, "''HHHHHH", buffer, ARRAY_SIZE(buffer));
675 expect_str(ret, buffer, "08");
676
677 /* and test for normal use of the single quotation mark */
678 ret = GetTimeFormatA(lcid, 0, &curtime, "'''HHHHHH'", buffer, ARRAY_SIZE(buffer));
679 expect_str(ret, buffer, "'HHHHHH");
680
681 /* Odd use */
682 strcpy(buffer, "pristine"); /* clear previous identical result */
683 ret = GetTimeFormatA(lcid, 0, &curtime, "'''HHHHHH", buffer, ARRAY_SIZE(buffer));
684 expect_str(ret, buffer, "'HHHHHH");
685
686 /* TIME_NOTIMEMARKER drops literals too */
687 ret = GetTimeFormatA(lcid, TIME_NOTIMEMARKER, &curtime, "'123'tt", buffer, ARRAY_SIZE(buffer));
688 expect_str(ret, buffer, "");
689
690 /* Invalid time */
691 curtime.wHour = 25;
692 strcpy(buffer, "pristine");
693 ret = GetTimeFormatA(lcid, 0, &curtime, "'123'tt", buffer, ARRAY_SIZE(buffer));
695 SetLastError(0xdeadbeef);
696
697 /* Invalid date */
698 curtime.wHour = 12;
699 curtime.wMonth = 60;
700 ret = GetTimeFormatA(lcid, 0, &curtime, "h:m:s", buffer, ARRAY_SIZE(buffer));
701 expect_str(ret, buffer, "12:56:13");
702
703 /* The ANSI string may be longer than the Unicode one.
704 * In particular, in the Japanese code page, "\x93\xfa" = L"\x65e5".
705 */
706
708
709 ret = GetTimeFormatA(lcid, 0, &curtime, "h\x93\xfa", buffer, 5);
710 expect_str(ret, buffer, "12\x93\xfa"); /* only 3+1 WCHARs */
711
712 ret = GetTimeFormatA(lcid, 0, &curtime, "h\x93\xfa", buffer, 4);
714 SetLastError(0xdeadbeef);
715
716 ret = GetTimeFormatA(lcid, 0, &curtime, "h\x93\xfa", NULL, 0);
717 expect_str(ret, NULL, "12\x93\xfa");
718
719 strcpy(buffer, "pristine"); /* clear previous identical result */
720 ret = GetTimeFormatA(lcid, 0, &curtime, "h\x93\xfa", buffer, 0);
721 expect_str(ret, NULL, "12\x93\xfa");
722 ok(strcmp(buffer, "pristine") == 0, "Expected a pristine buffer, got '%s'\n", buffer);
723}
724
725static void test_GetTimeFormatEx(void)
726{
727 int ret;
728 SYSTEMTIME curtime;
730
731 if (!pGetTimeFormatEx)
732 {
733 win_skip("GetTimeFormatEx not supported\n");
734 return;
735 }
736
737 SetLastError(0xdeadbeef);
738
739 /* Invalid time */
740 memset(&curtime, 2, sizeof(SYSTEMTIME));
741 wcscpy(buffer, L"pristine");
742 ret = pGetTimeFormatEx(localeW, TIME_FORCE24HOURFORMAT, &curtime, L"tt HH':'mm'@'ss", buffer, ARRAY_SIZE(buffer));
744 SetLastError(0xdeadbeef);
745
746 /* Valid time */
747 curtime.wHour = 8;
748 curtime.wMinute = 56;
749 curtime.wSecond = 13;
750 curtime.wMilliseconds = 22;
751 ret = pGetTimeFormatEx(localeW, TIME_FORCE24HOURFORMAT, &curtime, L"tt HH':'mm'@'ss", buffer, ARRAY_SIZE(buffer));
752 expect_wstr(ret, buffer, L"AM 08:56@13");
753
754 /* MSDN: LOCALE_NOUSEROVERRIDE can't be specified with a format string */
755 wcscpy(buffer, L"pristine");
756 ret = pGetTimeFormatEx(localeW, NUO|TIME_FORCE24HOURFORMAT, &curtime, L"HH", buffer, ARRAY_SIZE(buffer));
758 SetLastError(0xdeadbeef);
759
760 /* Insufficient buffer */
761 ret = pGetTimeFormatEx(localeW, TIME_FORCE24HOURFORMAT, &curtime, L" tt", buffer, 2);
762 /* there is no guarantee on the buffer content, see GetTimeFormatA() */
764 SetLastError(0xdeadbeef);
765
766 /* Calculate length only */
767 ret = pGetTimeFormatEx(localeW, TIME_FORCE24HOURFORMAT, &curtime, L"tt HH':'mm'@'ss", NULL, 0);
768 expect_wstr(ret, NULL, L"AM 08:56@13");
769
770 /* TIME_NOMINUTESORSECONDS, default format */
771 ret = pGetTimeFormatEx(localeW, NUO|TIME_NOMINUTESORSECONDS, &curtime, NULL, buffer, ARRAY_SIZE(buffer));
772 expect_wstr(ret, buffer, L"8 AM");
773
774 /* TIME_NOMINUTESORSECONDS/complex format */
775 wcscpy(buffer, L"pristine");
776 ret = pGetTimeFormatEx(localeW, TIME_NOMINUTESORSECONDS, &curtime, L"m1s2m3s4", buffer, ARRAY_SIZE(buffer));
777 expect_wstr(ret, buffer, L"");
778
779 /* TIME_NOSECONDS/Default format */
780 ret = pGetTimeFormatEx(localeW, NUO|TIME_NOSECONDS, &curtime, NULL, buffer, ARRAY_SIZE(buffer));
781 expect_wstr(ret, buffer, L"8:56 AM");
782
783 /* TIME_NOSECONDS */
784 wcscpy(buffer, L"pristine"); /* clear previous identical result */
785 ret = pGetTimeFormatEx(localeW, TIME_NOSECONDS, &curtime, L"h:m:s tt", buffer, ARRAY_SIZE(buffer));
786 expect_wstr(ret, buffer, L"8:56 AM");
787
788 /* Multiple delimiters */
789 ret = pGetTimeFormatEx(localeW, TIME_NOSECONDS, &curtime, L"h.@:m.@:s.@:tt", buffer, ARRAY_SIZE(buffer));
790 expect_wstr(ret, buffer, L"8.@:56AM");
791
792 /* Duplicate tokens */
793 wcscpy(buffer, L"pristine");
794 ret = pGetTimeFormatEx(localeW, TIME_NOSECONDS, &curtime, L"s1s2s3", buffer, ARRAY_SIZE(buffer));
795 expect_wstr(ret, buffer, L"");
796
797 /* AM time marker */
798 ret = pGetTimeFormatEx(localeW, 0, &curtime, L"t/tt", buffer, ARRAY_SIZE(buffer));
799 expect_wstr(ret, buffer, L"A/AM");
800
801 /* PM time marker */
802 curtime.wHour = 13;
803 ret = pGetTimeFormatEx(localeW, 0, &curtime, L"t/tt", buffer, ARRAY_SIZE(buffer));
804 expect_wstr(ret, buffer, L"P/PM");
805
806 /* TIME_NOTIMEMARKER: removes text around time marker token */
807 ret = pGetTimeFormatEx(localeW, TIME_NOTIMEMARKER, &curtime, L"h1t2tt3m", buffer, ARRAY_SIZE(buffer));
808 expect_wstr(ret, buffer, L"156");
809
810 /* TIME_FORCE24HOURFORMAT */
811 ret = pGetTimeFormatEx(localeW, TIME_FORCE24HOURFORMAT, &curtime, L"h:m:s tt", buffer, ARRAY_SIZE(buffer));
812 expect_wstr(ret, buffer, L"13:56:13 PM");
813
814 /* TIME_FORCE24HOURFORMAT doesn't add time marker */
815 ret = pGetTimeFormatEx(localeW, TIME_FORCE24HOURFORMAT, &curtime, L"h:m:s", buffer, ARRAY_SIZE(buffer));
816 expect_wstr(ret, buffer, L"13:56:13");
817
818 /* 24 hrs, leading 0 */
819 curtime.wHour = 14; /* change this to 14 or 2pm */
820 curtime.wMinute = 5;
821 curtime.wSecond = 3;
822 ret = pGetTimeFormatEx(localeW, 0, &curtime, L"h hh H HH m mm s ss t tt", buffer, ARRAY_SIZE(buffer));
823 expect_wstr(ret, buffer, L"2 02 14 14 5 05 3 03 P PM");
824
825 /* "hh" and "HH" */
826 curtime.wHour = 0;
827 ret = pGetTimeFormatEx(localeW, 0, &curtime, L"h/H/hh/HH", buffer, ARRAY_SIZE(buffer));
828 expect_wstr(ret, buffer, L"12/0/12/00");
829
830 /* non-zero flags should fail with format, doesn't */
831 ret = pGetTimeFormatEx(localeW, 0, &curtime, L"h:m:s tt", buffer, ARRAY_SIZE(buffer));
832 expect_wstr(ret, buffer, L"12:5:3 AM");
833
834 /* try to convert formatting strings with more than two letters
835 * "h:hh:hhh:H:HH:HHH:m:mm:mmm:M:MM:MMM:s:ss:sss:S:SS:SSS"
836 * NOTE: We expect any letter for which there is an upper case value
837 * we should see a replacement. For letters that DO NOT have
838 * upper case values we should see NO REPLACEMENT.
839 */
840 curtime.wHour = 8;
841 curtime.wMinute = 56;
842 curtime.wSecond = 13;
843 curtime.wMilliseconds = 22;
844 ret = pGetTimeFormatEx(localeW, 0, &curtime, L"h:hh:hhh H:HH:HHH m:mm:mmm M:MM:MMM s:ss:sss S:SS:SSS", buffer, ARRAY_SIZE(buffer));
845 expect_wstr(ret, buffer, L"8:08:08 8:08:08 56:56:56 M:MM:MMM 13:13:13 S:SS:SSS");
846
847 /* Don't write to buffer if len is 0 */
848 wcscpy(buffer, L"pristine");
849 ret = pGetTimeFormatEx(localeW, 0, &curtime, L"h:mm", buffer, 0);
850 expect_wstr(ret, NULL, L"8:56");
851 ok(wcscmp(buffer, L"pristine") == 0, "Expected a pristine buffer, got %s\n", wine_dbgstr_w(buffer));
852
853 /* "'" preserves tokens */
854 ret = pGetTimeFormatEx(localeW, 0, &curtime, L"h 'h' H 'H' HH 'HH' m 'm' s 's' t 't' tt 'tt'", buffer, ARRAY_SIZE(buffer));
855 expect_wstr(ret, buffer, L"8 h 8 H 08 HH 56 m 13 s A t AM tt");
856
857 /* invalid quoted string */
858 ret = pGetTimeFormatEx(localeW, 0, &curtime, L"'''", buffer, ARRAY_SIZE(buffer));
859 expect_wstr(ret, buffer, L"'");
860
861 /* check that MSDN's suggested single quotation usage works as expected */
862 wcscpy(buffer, L"pristine"); /* clear previous identical result */
863 ret = pGetTimeFormatEx(localeW, 0, &curtime, L"''''", buffer, ARRAY_SIZE(buffer));
864 expect_wstr(ret, buffer, L"'");
865
866 /* Normal use */
867 ret = pGetTimeFormatEx(localeW, 0, &curtime, L"''HHHHHH", buffer, ARRAY_SIZE(buffer));
868 expect_wstr(ret, buffer, L"08");
869
870 /* and test for normal use of the single quotation mark */
871 ret = pGetTimeFormatEx(localeW, 0, &curtime, L"'''HHHHHH'", buffer, ARRAY_SIZE(buffer));
872 expect_wstr(ret, buffer, L"'HHHHHH");
873
874 /* Odd use */
875 wcscpy(buffer, L"pristine"); /* clear previous identical result */
876 ret = pGetTimeFormatEx(localeW, 0, &curtime, L"'''HHHHHH", buffer, ARRAY_SIZE(buffer));
877 expect_wstr(ret, buffer, L"'HHHHHH");
878
879 /* TIME_NOTIMEMARKER drops literals too */
880 ret = pGetTimeFormatEx(localeW, TIME_NOTIMEMARKER, &curtime, L"'123'tt", buffer, ARRAY_SIZE(buffer));
881 expect_wstr(ret, buffer, L"");
882
883 /* Invalid time */
884 curtime.wHour = 25;
885 wcscpy(buffer, L"pristine");
886 ret = pGetTimeFormatEx(localeW, 0, &curtime, L"'123'tt", buffer, ARRAY_SIZE(buffer));
888 SetLastError(0xdeadbeef);
889
890 /* Invalid date */
891 curtime.wHour = 12;
892 curtime.wMonth = 60;
893 ret = pGetTimeFormatEx(localeW, 0, &curtime, L"h:m:s", buffer, ARRAY_SIZE(buffer));
894 expect_wstr(ret, buffer, L"12:56:13");
895}
896
897static void test_GetDateFormatA(void)
898{
899 int ret;
900 SYSTEMTIME curtime;
905 char short_day[10], month[10], genitive_month[10];
906
907 SetLastError(0xdeadbeef);
908
909 /* Invalid time */
910 memset(&curtime, 2, sizeof(SYSTEMTIME));
911 strcpy(buffer, "pristine");
912 ret = GetDateFormatA(lcid, 0, &curtime, "ddd',' MMM dd yy", buffer, ARRAY_SIZE(buffer));
914 SetLastError(0xdeadbeef);
915
916 /* Simple case */
917 curtime.wYear = 2002;
918 curtime.wMonth = 5;
919 curtime.wDay = 4;
920 curtime.wDayOfWeek = 3;
921 ret = GetDateFormatA(lcid, 0, &curtime, "ddd',' MMM dd yy", buffer, ARRAY_SIZE(buffer));
922 expect_str(ret, buffer, "Sat, May 04 02");
923
924 /* Same as above but with LOCALE_NOUSEROVERRIDE */
925 strcpy(buffer, "pristine");
926 ret = GetDateFormatA(lcid, NUO, &curtime, "ddd',' MMM dd yy", buffer, ARRAY_SIZE(buffer));
928 SetLastError(0xdeadbeef);
929
930 /* Format containing "'" */
931 ret = GetDateFormatA(lcid, 0, &curtime, "ddd',' MMM dd yy", buffer, ARRAY_SIZE(buffer));
932 expect_str(ret, buffer, "Sat, May 04 02");
933
934 /* Invalid time */
935 curtime.wHour = 36;
936 ret = GetDateFormatA(lcid, 0, &curtime, "ddd',' MMM dd ''''yy", buffer, ARRAY_SIZE(buffer));
937 expect_str(ret, buffer, "Sat, May 04 '02");
938
939 /* Get size only */
940 ret = GetDateFormatA(lcid, 0, &curtime, "ddd',' MMM dd ''''yy", NULL, 0);
941 expect_str(ret, NULL, "Sat, May 04 '02");
942
943 /* Buffer too small */
944 strcpy(buffer, "pristine");
945 ret = GetDateFormatA(lcid, 0, &curtime, "ddd", buffer, 2);
946 /* there is no guarantee on the buffer content, see GetTimeFormatA() */
948 SetLastError(0xdeadbeef);
949
950 /* Default to DATE_SHORTDATE */
952 expect_str(ret, buffer, "5/4/2002");
953
954 /* DATE_LONGDATE */
956 ok(ret, "Expected ret != 0, got %d, error %ld\n", ret, GetLastError());
957 ok(strcmp(buffer, "Saturday, May 04, 2002") == 0 ||
958 strcmp(buffer, "Saturday, May 4, 2002") == 0 /* Win 8 */,
959 "got an unexpected date string '%s'\n", buffer);
960
961 /* test for expected DATE_YEARMONTH behavior with null format */
962 /* NT4 returns ERROR_INVALID_FLAGS for DATE_YEARMONTH */
963 strcpy(buffer, "pristine");
964 ret = GetDateFormatA(lcid, NUO|DATE_YEARMONTH, &curtime, "ddd',' MMM dd ''''yy", buffer, ARRAY_SIZE(buffer));
966 SetLastError(0xdeadbeef);
967
968 /* Test that using invalid DATE_* flags results in the correct error */
969 /* and return values */
970 ret = GetDateFormatA(lcid, DATE_YEARMONTH|DATE_SHORTDATE|DATE_LONGDATE, &curtime, "m/d/y", buffer, ARRAY_SIZE(buffer));
972 SetLastError(0xdeadbeef);
973
974 ret = GetDateFormatA(lcid_ru, 0, &curtime, "ddMMMM", buffer, ARRAY_SIZE(buffer));
975 if (!ret)
976 {
977 win_skip("LANG_RUSSIAN locale data unavailable\n");
978 return;
979 }
980
981 /* month part should be in genitive form */
982 strcpy(genitive_month, buffer + 2);
983 ret = GetDateFormatA(lcid_ru, 0, &curtime, "MMMM", buffer, ARRAY_SIZE(buffer));
984 ok(ret, "Expected ret != 0, got %d, error %ld\n", ret, GetLastError());
986 ok(strcmp(genitive_month, month) != 0, "Expected different month forms\n");
987
988 ret = GetDateFormatA(lcid_ru, 0, &curtime, "ddd", buffer, ARRAY_SIZE(buffer));
989 ok(ret, "Expected ret != 0, got %d, error %ld\n", ret, GetLastError());
990 strcpy(short_day, buffer);
991
992 ret = GetDateFormatA(lcid_ru, 0, &curtime, "dd MMMMddd dd", buffer, ARRAY_SIZE(buffer));
993 sprintf(Expected, "04 %s%s 04", genitive_month, short_day);
995
996 ret = GetDateFormatA(lcid_ru, 0, &curtime, "MMMMddd dd", buffer, ARRAY_SIZE(buffer));
997 sprintf(Expected, "%s%s 04", month, short_day);
999
1000 ret = GetDateFormatA(lcid_ru, 0, &curtime, "MMMMddd", buffer, ARRAY_SIZE(buffer));
1001 sprintf(Expected, "%s%s", month, short_day);
1003
1004 ret = GetDateFormatA(lcid_ru, 0, &curtime, "MMMMdd", buffer, ARRAY_SIZE(buffer));
1005 sprintf(Expected, "%s04", genitive_month);
1007
1008 ret = GetDateFormatA(lcid_ru, 0, &curtime, "MMMMdd ddd", buffer, ARRAY_SIZE(buffer));
1009 sprintf(Expected, "%s04 %s", genitive_month, short_day);
1011
1012 ret = GetDateFormatA(lcid_ru, 0, &curtime, "dd dddMMMM", buffer, ARRAY_SIZE(buffer));
1013 sprintf(Expected, "04 %s%s", short_day, month);
1015
1016 ret = GetDateFormatA(lcid_ru, 0, &curtime, "dd dddMMMM ddd MMMMdd", buffer, ARRAY_SIZE(buffer));
1017 sprintf(Expected, "04 %s%s %s %s04", short_day, month, short_day, genitive_month);
1019
1020 /* with literal part */
1021 ret = GetDateFormatA(lcid_ru, 0, &curtime, "ddd',' MMMM dd", buffer, ARRAY_SIZE(buffer));
1022 sprintf(Expected, "%s, %s 04", short_day, genitive_month);
1024
1025 /* The ANSI string may be longer than the Unicode one.
1026 * In particular, in the Japanese code page, "\x93\xfa" = L"\x65e5".
1027 * See the corresponding GetDateFormatW() test.
1028 */
1029
1030 ret = GetDateFormatA(lcid_ja, 0, &curtime, "d\x93\xfa", buffer, 4);
1031 expect_str(ret, buffer, "4\x93\xfa"); /* only 2+1 WCHARs */
1032
1033 ret = GetDateFormatA(lcid_ja, 0, &curtime, "d\x93\xfa", buffer, 3);
1035 SetLastError(0xdeadbeef);
1036
1037 strcpy(buffer, "pristine"); /* clear previous identical result */
1038 ret = GetDateFormatA(lcid_ja, 0, &curtime, "d\x93\xfa", NULL, 0);
1039 expect_str(ret, NULL, "4\x93\xfa");
1040}
1041
1042static void test_GetDateFormatEx(void)
1043{
1044 int ret;
1045 SYSTEMTIME curtime;
1047
1048 if (!pGetDateFormatEx)
1049 {
1050 win_skip("GetDateFormatEx not supported\n");
1051 return;
1052 }
1053
1054 SetLastError(0xdeadbeef);
1055
1056 /* If flags are set, then format must be NULL */
1057 wcscpy(buffer, L"pristine");
1058 ret = pGetDateFormatEx(localeW, DATE_LONGDATE, NULL, L"", buffer, ARRAY_SIZE(buffer), NULL);
1060 SetLastError(0xdeadbeef);
1061
1062 /* NULL buffer, len > 0 */
1063 wcscpy(buffer, L"pristine");
1064 ret = pGetDateFormatEx(localeW, 0, NULL, L"", NULL, ARRAY_SIZE(buffer), NULL);
1066 SetLastError(0xdeadbeef);
1067
1068 /* NULL buffer, len == 0 */
1069 ret = pGetDateFormatEx(localeW, 0, NULL, L"", NULL, 0, NULL);
1070 expect_wstr(ret, NULL, L"");
1071
1072 /* Invalid flag combination */
1073 wcscpy(buffer, L"pristine");
1074 ret = pGetDateFormatEx(localeW, DATE_LONGDATE|DATE_SHORTDATE, NULL,
1075 L"", NULL, 0, NULL);
1077 SetLastError(0xdeadbeef);
1078
1079 /* Incorrect DOW and time */
1080 curtime.wYear = 2002;
1081 curtime.wMonth = 10;
1082 curtime.wDay = 23;
1083 curtime.wDayOfWeek = 45612; /* Should be 3 - Wednesday */
1084 curtime.wHour = 65432; /* Invalid */
1085 curtime.wMinute = 34512; /* Invalid */
1086 curtime.wSecond = 65535; /* Invalid */
1087 curtime.wMilliseconds = 12345;
1088 ret = pGetDateFormatEx(localeW, 0, &curtime, L"dddd d MMMM yyyy", buffer, ARRAY_SIZE(buffer), NULL);
1089 expect_wstr(ret, buffer, L"Wednesday 23 October 2002");
1090
1091 curtime.wYear = 2002;
1092 curtime.wMonth = 10;
1093 curtime.wDay = 23;
1094 curtime.wDayOfWeek = 45612; /* Should be 3 - Wednesday */
1095 curtime.wHour = 65432; /* Invalid */
1096 curtime.wMinute = 34512; /* Invalid */
1097 curtime.wSecond = 65535; /* Invalid */
1098 curtime.wMilliseconds = 12345;
1099 wcscpy(buffer, L"pristine");
1100 ret = pGetDateFormatEx(localeW, 0, &curtime, L"dddd d MMMM yyyy", buffer, ARRAY_SIZE(buffer), emptyW); /* Use reserved arg */
1102 SetLastError(0xdeadbeef);
1103
1104 /* Limit tests */
1105
1106 curtime.wYear = 1601;
1107 curtime.wMonth = 1;
1108 curtime.wDay = 1;
1109 curtime.wDayOfWeek = 0; /* Irrelevant */
1110 curtime.wHour = 0;
1111 curtime.wMinute = 0;
1112 curtime.wSecond = 0;
1113 curtime.wMilliseconds = 0;
1114 ret = pGetDateFormatEx(localeW, 0, &curtime, L"dddd d MMMM yyyy", buffer, ARRAY_SIZE(buffer), NULL);
1115 expect_wstr(ret, buffer, L"Monday 1 January 1601");
1116
1117 curtime.wYear = 1600;
1118 curtime.wMonth = 12;
1119 curtime.wDay = 31;
1120 curtime.wDayOfWeek = 0; /* Irrelevant */
1121 curtime.wHour = 23;
1122 curtime.wMinute = 59;
1123 curtime.wSecond = 59;
1124 curtime.wMilliseconds = 999;
1125 wcscpy(buffer, L"pristine");
1126 ret = pGetDateFormatEx(localeW, 0, &curtime, L"dddd d MMMM yyyy", buffer, ARRAY_SIZE(buffer), NULL);
1128}
1129
1130static void test_GetDateFormatW(void)
1131{
1132 int ret;
1133 SYSTEMTIME curtime;
1136
1137 SetLastError(0xdeadbeef);
1138
1139 /* If flags is not zero then format must be NULL */
1140 wcscpy(buffer, L"pristine");
1143 {
1144 win_skip("GetDateFormatW is not implemented\n");
1145 return;
1146 }
1148 SetLastError(0xdeadbeef);
1149
1150 /* NULL buffer, len > 0 */
1151 wcscpy(buffer, L"pristine");
1154 SetLastError(0xdeadbeef);
1155
1156 /* NULL buffer, len == 0 */
1157 ret = GetDateFormatW (lcid, 0, NULL, L"", NULL, 0);
1158 expect_wstr(ret, NULL, L"");
1159
1160 /* Incorrect DOW and time */
1161 curtime.wYear = 2002;
1162 curtime.wMonth = 10;
1163 curtime.wDay = 23;
1164 curtime.wDayOfWeek = 45612; /* Should be 3 - Wednesday */
1165 curtime.wHour = 65432; /* Invalid */
1166 curtime.wMinute = 34512; /* Invalid */
1167 curtime.wSecond = 65535; /* Invalid */
1168 curtime.wMilliseconds = 12345;
1169 ret = GetDateFormatW (lcid, 0, &curtime, L"dddd d MMMM yyyy", buffer, ARRAY_SIZE(buffer));
1170 expect_wstr(ret, buffer, L"Wednesday 23 October 2002");
1171
1172 /* Limit tests */
1173
1174 curtime.wYear = 1601;
1175 curtime.wMonth = 1;
1176 curtime.wDay = 1;
1177 curtime.wDayOfWeek = 0; /* Irrelevant */
1178 curtime.wHour = 0;
1179 curtime.wMinute = 0;
1180 curtime.wSecond = 0;
1181 curtime.wMilliseconds = 0;
1182 ret = GetDateFormatW (lcid, 0, &curtime, L"dddd d MMMM yyyy", buffer, ARRAY_SIZE(buffer));
1183 expect_wstr(ret, buffer, L"Monday 1 January 1601");
1184
1185 curtime.wYear = 1600;
1186 curtime.wMonth = 12;
1187 curtime.wDay = 31;
1188 curtime.wDayOfWeek = 0; /* Irrelevant */
1189 curtime.wHour = 23;
1190 curtime.wMinute = 59;
1191 curtime.wSecond = 59;
1192 curtime.wMilliseconds = 999;
1193 wcscpy(buffer, L"pristine");
1194 ret = GetDateFormatW (lcid, 0, &curtime, L"dddd d MMMM yyyy", buffer, ARRAY_SIZE(buffer));
1196 SetLastError(0xdeadbeef);
1197
1198 /* See the corresponding GetDateFormatA() test */
1199
1201
1202 curtime.wYear = 2002;
1203 curtime.wMonth = 5;
1204 curtime.wDay = 4;
1205 ret = GetDateFormatW(lcid, 0, &curtime, L"d\x65e5", buffer, 3);
1206 expect_wstr(ret, buffer, L"4\x65e5");
1207
1208 ret = GetDateFormatW(lcid, 0, &curtime, L"d\x65e5", NULL, 0);
1209 expect_wstr(ret, NULL, L"4\x65e5");
1210}
1211
1212
1213#define CY_POS_LEFT 0
1214#define CY_POS_RIGHT 1
1215#define CY_POS_LEFT_SPACE 2
1216#define CY_POS_RIGHT_SPACE 3
1217
1219{
1220 static char szDot[] = { '.', '\0' };
1221 static char szComma[] = { ',', '\0' };
1222 static char szDollar[] = { '$', '\0' };
1223 static const char* const negative_order[] =
1224 {"($1.0)", /* 0 */
1225 "-$1.0",
1226 "$-1.0",
1227 "$1.0-",
1228 "(1.0$)",
1229 "-1.0$", /* 5 */
1230 "1.0-$",
1231 "1.0$-",
1232 "-1.0 $",
1233 "-$ 1.0",
1234 "1.0 $-", /* 10 */
1235 "$ 1.0-",
1236 "$ -1.0",
1237 "1.0- $",
1238 "($ 1.0)",
1239 "(1.0 $)", /* 15 */
1240 };
1241 int ret, o;
1243 char buffer[BUFFER_SIZE];
1245
1246 SetLastError(0xdeadbeef);
1247
1248 /* NULL output, length > 0 --> Error */
1251 SetLastError(0xdeadbeef);
1252
1253 /* Invalid character --> Error */
1254 strcpy(buffer, "pristine");
1257 SetLastError(0xdeadbeef);
1258
1259 /* Double '-' --> Error */
1260 strcpy(buffer, "pristine");
1263 SetLastError(0xdeadbeef);
1264
1265 /* Trailing '-' --> Error */
1266 strcpy(buffer, "pristine");
1269 SetLastError(0xdeadbeef);
1270
1271 /* Double '.' --> Error */
1272 strcpy(buffer, "pristine");
1275 SetLastError(0xdeadbeef);
1276
1277 /* Leading space --> Error */
1280 SetLastError(0xdeadbeef);
1281
1282 /* Length too small --> Write up to length chars */
1283 strcpy(buffer, "pristine");
1284 ret = GetCurrencyFormatA(lcid, NUO, "1234", NULL, buffer, 2);
1285 /* there is no guarantee on the buffer content, see GetTimeFormatA() */
1287 SetLastError(0xdeadbeef);
1288
1289 /* Valid number */
1291 expect_str(ret, buffer, "$2,353.00");
1292
1293 /* Valid negative number */
1295 expect_str(ret, buffer, "($2,353.00)");
1296
1297 /* Valid real number */
1299 expect_str(ret, buffer, "$2,353.10");
1300
1301 /* Too many DP --> Truncated */
1303 expect_str(ret, buffer, "$2,353.11");
1304
1305 /* Too many DP --> Rounded */
1307 expect_str(ret, buffer, "$2,353.12");
1308
1309 /* Format and flags given --> Error */
1310 memset(&format, 0, sizeof(format));
1311 strcpy(buffer, "pristine");
1314 SetLastError(0xdeadbeef);
1315
1316 /* Invalid format --> Error */
1317 strcpy(buffer, "pristine");
1320 SetLastError(0xdeadbeef);
1321
1322 format.NumDigits = 0; /* No decimal separator */
1323 format.LeadingZero = 0;
1324 format.Grouping = 0; /* No grouping char */
1325 format.NegativeOrder = 0;
1326 format.PositiveOrder = CY_POS_LEFT;
1327 format.lpDecimalSep = szDot;
1328 format.lpThousandSep = szComma;
1329 format.lpCurrencySymbol = szDollar;
1330
1331 /* No decimal or grouping chars expected */
1333 expect_str(ret, buffer, "$2353");
1334
1335 /* 1 DP --> Expect decimal separator */
1336 format.NumDigits = 1;
1338 expect_str(ret, buffer, "$2353.0");
1339
1340 /* Group by 100's */
1341 format.Grouping = 2;
1343 expect_str(ret, buffer, "$23,53.0");
1344
1345 /* Grouping of a positive number */
1346 format.Grouping = 3;
1348 expect_str(ret, buffer, "$235.0");
1349
1350 format.Grouping = 31;
1351 ret = GetCurrencyFormatA(lcid, 0, "1234567890", &format, buffer, ARRAY_SIZE(buffer));
1352 expect_str(ret, buffer, "$1,2,3,4,5,6,7,890.0");
1353
1354 format.Grouping = 312;
1355 ret = GetCurrencyFormatA(lcid, 0, "1234567890", &format, buffer, ARRAY_SIZE(buffer));
1356 expect_str(ret, buffer, "$12,34,56,7,890.0");
1357
1358 format.Grouping = 310;
1359 ret = GetCurrencyFormatA(lcid, 0, "1234567890", &format, buffer, ARRAY_SIZE(buffer));
1360 expect_str(ret, buffer, "$123456,7,890.0");
1361
1362 /* Grouping of a negative number */
1363 format.NegativeOrder = 2;
1365 expect_str(ret, buffer, "$-235.0");
1366
1367 /* Always provide leading zero */
1368 format.LeadingZero = 1;
1370 expect_str(ret, buffer, "$0.5");
1372 expect_str(ret, buffer, "$0.5");
1373
1374 format.LeadingZero = 0;
1376 expect_str(ret, buffer, "$.5");
1378 expect_str(ret, buffer, "$.5");
1379
1380 format.PositiveOrder = CY_POS_RIGHT;
1382 expect_str(ret, buffer, "1.0$");
1383
1384 format.PositiveOrder = CY_POS_LEFT_SPACE;
1386 expect_str(ret, buffer, "$ 1.0");
1387
1388 format.PositiveOrder = CY_POS_RIGHT_SPACE;
1390 expect_str(ret, buffer, "1.0 $");
1391
1392
1393 for (o = 0; o <= 15; o++)
1394 {
1395 winetest_push_context("%d", o);
1396 format.NegativeOrder = o;
1397 strcpy(buffer, "pristine");
1399 expect_str(ret, buffer, negative_order[o]);
1401 }
1402}
1403
1404#define NEG_PARENS 0 /* "(1.1)" */
1405#define NEG_LEFT 1 /* "-1.1" */
1406#define NEG_LEFT_SPACE 2 /* "- 1.1" */
1407#define NEG_RIGHT 3 /* "1.1-" */
1408#define NEG_RIGHT_SPACE 4 /* "1.1 -" */
1409
1410static void test_GetNumberFormatA(void)
1411{
1412 static char szDot[] = { '.', '\0' };
1413 static char szComma[] = { ',', '\0' };
1414 int ret;
1416 WCHAR grouping[32], t1000[8], dec[8], frac[8], lzero[8];
1417 char buffer[BUFFER_SIZE];
1419
1420 SetLastError(0xdeadbeef);
1421
1422 /* NULL output, length > 0 --> Error */
1423 strcpy(buffer, "pristine");
1426 SetLastError(0xdeadbeef);
1427
1428 /* Invalid character --> Error */
1429 strcpy(buffer, "pristine");
1432 SetLastError(0xdeadbeef);
1433
1434 /* Double '-' --> Error */
1435 strcpy(buffer, "pristine");
1438 SetLastError(0xdeadbeef);
1439
1440 /* Trailing '-' --> Error */
1441 strcpy(buffer, "pristine");
1444 SetLastError(0xdeadbeef);
1445
1446 /* Double '.' --> Error */
1447 strcpy(buffer, "pristine");
1450 SetLastError(0xdeadbeef);
1451
1452 /* Leading space --> Error */
1453 strcpy(buffer, "pristine");
1456 SetLastError(0xdeadbeef);
1457
1458 /* Length too small --> Write up to length chars */
1459 ret = GetNumberFormatA(lcid, NUO, "1234", NULL, buffer, 2);
1460 /* there is no guarantee on the buffer content, see GetTimeFormatA() */
1462 SetLastError(0xdeadbeef);
1463
1464 /* Valid number */
1466 expect_str(ret, buffer, "2,353.00");
1467
1468 /* Valid negative number */
1470 expect_str(ret, buffer, "-2,353.00");
1471
1472 /* test for off by one error in grouping */
1474 expect_str(ret, buffer, "-353.00");
1475
1476 /* Valid real number */
1478 expect_str(ret, buffer, "2,353.10");
1479
1480 /* Too many DP --> Truncated */
1482 expect_str(ret, buffer, "2,353.11");
1483
1484 /* Too many DP --> Rounded */
1486 expect_str(ret, buffer, "2,353.12");
1487
1488 /* Format and flags given --> Error */
1489 memset(&format, 0, sizeof(format));
1490 strcpy(buffer, "pristine");
1493 SetLastError(0xdeadbeef);
1494
1495 /* Invalid format --> Error */
1496 strcpy(buffer, "pristine");
1499 SetLastError(0xdeadbeef);
1500
1501 format.NumDigits = 0; /* No decimal separator */
1502 format.LeadingZero = 0;
1503 format.Grouping = 0; /* No grouping char */
1504 format.NegativeOrder = 0;
1505 format.lpDecimalSep = szDot;
1506 format.lpThousandSep = szComma;
1507
1508 /* No decimal or grouping chars expected */
1510 expect_str(ret, buffer, "2353");
1511
1512 format.NumDigits = 1; /* 1 DP --> Expect decimal separator */
1514 expect_str(ret, buffer, "2353.0");
1515
1516 format.Grouping = 2; /* Group by 100's */
1518 expect_str(ret, buffer, "23,53.0");
1519
1520 /* Grouping of a positive number */
1521 format.Grouping = 3;
1523 expect_str(ret, buffer, "235.0");
1524 ret = GetNumberFormatA(lcid, 0, "000235", &format, buffer, ARRAY_SIZE(buffer));
1525 expect_str(ret, buffer, "235.0");
1526
1527 format.Grouping = 23;
1528 ret = GetNumberFormatA(lcid, 0, "123456789", &format, buffer, ARRAY_SIZE(buffer));
1529 expect_str(ret, buffer, "1,234,567,89.0");
1530
1531 format.Grouping = 230;
1532 ret = GetNumberFormatA(lcid, 0, "123456789", &format, buffer, ARRAY_SIZE(buffer));
1533 expect_str(ret, buffer, "1234,567,89.0");
1534
1535 format.Grouping = 203;
1536 ret = GetNumberFormatA(lcid, 0, "123456789", &format, buffer, ARRAY_SIZE(buffer));
1537 expect_str(ret, buffer, "1,234,567,,89.0");
1538
1539 format.Grouping = 2030;
1540 ret = GetNumberFormatA(lcid, 0, "123456789", &format, buffer, ARRAY_SIZE(buffer));
1541 expect_str(ret, buffer, "1234,567,,89.0");
1542
1543 format.Grouping = 2003;
1544 ret = GetNumberFormatA(lcid, 0, "123456789", &format, buffer, ARRAY_SIZE(buffer));
1545 expect_str(ret, buffer, "1,234,567,,,89.0");
1546
1547 format.Grouping = 1200;
1548 ret = GetNumberFormatA(lcid, 0, "123456789", &format, buffer, ARRAY_SIZE(buffer));
1549 expect_str(ret, buffer, "123456,,78,9.0");
1550
1551 /* Grouping of a negative number */
1552 format.NegativeOrder = NEG_LEFT;
1553 format.Grouping = 3;
1555 expect_str(ret, buffer, "-235.0");
1556 ret = GetNumberFormatA(lcid, 0, "-000235", &format, buffer, ARRAY_SIZE(buffer));
1557 expect_str(ret, buffer, "-235.0");
1558
1559 format.LeadingZero = 1; /* Always provide leading zero */
1561 expect_str(ret, buffer, "0.5");
1562 ret = GetNumberFormatA(lcid, 0, "0000.5", &format, buffer, ARRAY_SIZE(buffer));
1563 expect_str(ret, buffer, "0.5");
1564
1565 format.NegativeOrder = NEG_PARENS;
1567 expect_str(ret, buffer, "(1.0)");
1568
1569 format.NegativeOrder = NEG_LEFT;
1571 expect_str(ret, buffer, "-1.0");
1572
1573 format.NegativeOrder = NEG_LEFT_SPACE;
1575 expect_str(ret, buffer, "- 1.0");
1576
1577 format.NegativeOrder = NEG_RIGHT;
1579 expect_str(ret, buffer, "1.0-");
1580
1581 format.NegativeOrder = NEG_RIGHT_SPACE;
1583 expect_str(ret, buffer, "1.0 -");
1584
1585 /* Test French formatting */
1587 if (IsValidLocale(lcid, 0))
1588 {
1590 expect_str(ret, buffer, "-12\xa0\x33\x34\x35,00"); /* Non breaking space */
1591 }
1592
1593 /* Test the actual LOCALE_SGROUPING string, the rules for repeats are opposite */
1599 {
1600 static const struct
1601 {
1602 const char *grouping;
1603 const char *expected;
1604 } tests[] = {
1605 { "3;0", "1,234,567,890.54321" },
1606 { "2;3", "12345,678,90.54321" },
1607 { "1", "123456789,0.54321" },
1608 { "1;0", "1,2,3,4,5,6,7,8,9,0.54321" },
1609 { "1;0;3", "123456,789,,0.54321" },
1610 { "0", "1234567890.54321" },
1611 { "0;0", "1234567890.54321" },
1612 { "0;1", "123456789,0.54321" },
1613 { "0;0;0", "1234567890.54321" },
1614 { "0;1;0", "1,2,3,4,5,6,7,8,9,0.54321" },
1615 { "2;0;0", "12345678,90.54321" },
1616 { "2;0;0;0", "12345678,,90.54321" },
1617 { "2;0;0;0;0", "12345678,,,90.54321" },
1618 { "2;0;0;1;0", "1,2,3,4,5,6,7,8,,,90.54321" },
1619 { "1;3;2", "1234,56,789,0.54321" },
1620 { "1;3;2;0", "12,34,56,789,0.54321" },
1621 { "3;1;1;2;0", "1,23,45,6,7,890.54321" },
1622 { "6;1", "123,4,567890.54321" },
1623 };
1624 unsigned i;
1625
1630
1631 for (i = 0; i < ARRAY_SIZE(tests); i++)
1632 {
1633#ifdef __REACTOS__
1634 /* Skip tests[4, 10-13] on WS03 */
1635 if (GetNTVersion() < _WIN32_WINNT_VISTA && (i == 4 || (i >= 10 && i <= 13)))
1636 continue;
1637#endif
1639 SetLastError(0xdeadbeef);
1640 ret = GetNumberFormatA(LOCALE_USER_DEFAULT, 0, "1234567890.54321", NULL, buffer, ARRAY_SIZE(buffer));
1641 if (ret)
1642 {
1643 ok(GetLastError() == 0xdeadbeef, "[%u] unexpected error %lu\n", i, GetLastError());
1644 ok(ret == strlen(tests[i].expected) + 1, "[%u] unexpected ret %d\n", i, ret);
1645 ok(!strcmp(buffer, tests[i].expected), "[%u] unexpected string %s\n", i, buffer);
1646 }
1647 else
1648 ok(0, "[%u] expected success, got error %ld\n", i, GetLastError());
1649 }
1650
1651 /* Restore */
1652 ok(SetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_SGROUPING, grouping), "Restoring SGROUPING failed\n");
1653 ok(SetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_STHOUSAND, t1000), "Restoring STHOUSAND failed\n");
1654 ok(SetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_SDECIMAL, dec), "Restoring SDECIMAL failed\n");
1655 ok(SetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IDIGITS, frac), "Restoring IDIGITS failed\n");
1656 ok(SetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_ILZERO, lzero), "Restoring ILZERO failed\n");
1657 }
1658}
1659
1660static void test_GetNumberFormatEx(void)
1661{
1662 int ret;
1664 static WCHAR dotW[] = {'.',0};
1665 static WCHAR commaW[] = {',',0};
1666 static const WCHAR enW[] = {'e','n','-','U','S',0};
1667 static const WCHAR frW[] = {'f','r','-','F','R',0};
1668 static const WCHAR bogusW[] = {'b','o','g','u','s',0};
1670
1671 if (!pGetNumberFormatEx)
1672 {
1673 win_skip("GetNumberFormatEx is not available.\n");
1674 return;
1675 }
1676
1677 SetLastError(0xdeadbeef);
1678
1679 /* NULL output, length > 0 --> Error */
1680 wcscpy(buffer, L"pristine");
1681 ret = pGetNumberFormatEx(enW, 0, L"23", NULL, NULL, ARRAY_SIZE(buffer));
1683 SetLastError(0xdeadbeef);
1684
1685 /* Invalid character --> Error */
1686 wcscpy(buffer, L"pristine");
1687 ret = pGetNumberFormatEx(enW, 0, L"23,53", NULL, buffer, ARRAY_SIZE(buffer));
1689 SetLastError(0xdeadbeef);
1690
1691 /* Double '-' --> Error */
1692 wcscpy(buffer, L"pristine");
1693 ret = pGetNumberFormatEx(enW, 0, L"--", NULL, buffer, ARRAY_SIZE(buffer));
1695 SetLastError(0xdeadbeef);
1696
1697 /* Trailing '-' --> Error */
1698 wcscpy(buffer, L"pristine");
1699 ret = pGetNumberFormatEx(enW, 0, L"0-", NULL, buffer, ARRAY_SIZE(buffer));
1701 SetLastError(0xdeadbeef);
1702
1703 /* Double '.' --> Error */
1704 wcscpy(buffer, L"pristine");
1705 ret = pGetNumberFormatEx(enW, 0, L"0..", NULL, buffer, ARRAY_SIZE(buffer));
1707 SetLastError(0xdeadbeef);
1708
1709 /* Leading space --> Error */
1710 wcscpy(buffer, L"pristine");
1711 ret = pGetNumberFormatEx(enW, 0, L" 0.1", NULL, buffer, ARRAY_SIZE(buffer));
1713 SetLastError(0xdeadbeef);
1714
1715 /* Length too small --> Write up to length chars */
1716 wcscpy(buffer, L"pristine");
1717 ret = pGetNumberFormatEx(enW, NUO, L"1234", NULL, buffer, 2);
1718 /* there is no guarantee on the buffer content, see GetTimeFormatA() */
1720 SetLastError(0xdeadbeef);
1721
1722 /* Bogus locale --> Error */
1723 wcscpy(buffer, L"pristine");
1724 ret = pGetNumberFormatEx(bogusW, NUO, L"23", NULL, buffer, ARRAY_SIZE(buffer));
1726 SetLastError(0xdeadbeef);
1727
1728 memset(&format, 0, sizeof(format));
1729
1730 /* Format and flags given --> Error */
1731 wcscpy(buffer, L"pristine");
1732 ret = pGetNumberFormatEx(enW, NUO, L"2353", &format, buffer, ARRAY_SIZE(buffer));
1734 SetLastError(0xdeadbeef);
1735
1736 /* Invalid format --> Error */
1737 wcscpy(buffer, L"pristine");
1738 ret = pGetNumberFormatEx(enW, 0, L"2353", &format, buffer, ARRAY_SIZE(buffer));
1740 SetLastError(0xdeadbeef);
1741
1742 /* Valid number */
1743 ret = pGetNumberFormatEx(enW, NUO, L"2353", NULL, buffer, ARRAY_SIZE(buffer));
1744 expect_wstr(ret, buffer, L"2,353.00");
1745
1746 /* Valid negative number */
1747 ret = pGetNumberFormatEx(enW, NUO, L"-2353", NULL, buffer, ARRAY_SIZE(buffer));
1748 expect_wstr(ret, buffer, L"-2,353.00");
1749
1750 /* test for off by one error in grouping */
1751 ret = pGetNumberFormatEx(enW, NUO, L"-353", NULL, buffer, ARRAY_SIZE(buffer));
1752 expect_wstr(ret, buffer, L"-353.00");
1753
1754 /* Valid real number */
1755 ret = pGetNumberFormatEx(enW, NUO, L"2353.1", NULL, buffer, ARRAY_SIZE(buffer));
1756 expect_wstr(ret, buffer, L"2,353.10");
1757
1758 /* Too many DP --> Truncated */
1759 ret = pGetNumberFormatEx(enW, NUO, L"2353.111", NULL, buffer, ARRAY_SIZE(buffer));
1760 expect_wstr(ret, buffer, L"2,353.11");
1761
1762 /* Too many DP --> Rounded */
1763 ret = pGetNumberFormatEx(enW, NUO, L"2353.119", NULL, buffer, ARRAY_SIZE(buffer));
1764 expect_wstr(ret, buffer, L"2,353.12");
1765
1766 format.NumDigits = 0; /* No decimal separator */
1767 format.LeadingZero = 0;
1768 format.Grouping = 0; /* No grouping char */
1769 format.NegativeOrder = 0;
1770 format.lpDecimalSep = dotW;
1771 format.lpThousandSep = commaW;
1772
1773 /* No decimal or grouping chars expected */
1774 ret = pGetNumberFormatEx(enW, 0, L"2353", &format, buffer, ARRAY_SIZE(buffer));
1775 expect_wstr(ret, buffer, L"2353");
1776
1777 /* 1 DP --> Expect decimal separator */
1778 format.NumDigits = 1;
1779 ret = pGetNumberFormatEx(enW, 0, L"2353", &format, buffer, ARRAY_SIZE(buffer));
1780 expect_wstr(ret, buffer, L"2353.0");
1781
1782 /* Group by 100's */
1783 format.Grouping = 2;
1784 ret = pGetNumberFormatEx(enW, 0, L"2353", &format, buffer, ARRAY_SIZE(buffer));
1785 expect_wstr(ret, buffer, L"23,53.0");
1786
1787 /* Grouping of a positive number */
1788 format.Grouping = 3;
1789 ret = pGetNumberFormatEx(enW, 0, L"235", &format, buffer, ARRAY_SIZE(buffer));
1790 expect_wstr(ret, buffer, L"235.0");
1791
1792 /* Grouping of a negative number */
1793 format.NegativeOrder = NEG_LEFT;
1794 ret = pGetNumberFormatEx(enW, 0, L"-235", &format, buffer, ARRAY_SIZE(buffer));
1795 expect_wstr(ret, buffer, L"-235.0");
1796
1797 /* Always provide leading zero */
1798 format.LeadingZero = 1;
1799 ret = pGetNumberFormatEx(enW, 0, L".5", &format, buffer, ARRAY_SIZE(buffer));
1800 expect_wstr(ret, buffer, L"0.5");
1801 ret = pGetNumberFormatEx(enW, 0, L"0.5", &format, buffer, ARRAY_SIZE(buffer));
1802 expect_wstr(ret, buffer, L"0.5");
1803
1804 format.LeadingZero = 0;
1805 ret = pGetNumberFormatEx(enW, 0, L".5", &format, buffer, ARRAY_SIZE(buffer));
1806 expect_wstr(ret, buffer, L".5");
1807 ret = pGetNumberFormatEx(enW, 0, L"0.5", &format, buffer, ARRAY_SIZE(buffer));
1808 expect_wstr(ret, buffer, L".5");
1809
1810 format.NegativeOrder = NEG_PARENS;
1811 ret = pGetNumberFormatEx(enW, 0, L"-1", &format, buffer, ARRAY_SIZE(buffer));
1812 expect_wstr(ret, buffer, L"(1.0)");
1813
1814 format.NegativeOrder = NEG_LEFT;
1815 ret = pGetNumberFormatEx(enW, 0, L"-1", &format, buffer, ARRAY_SIZE(buffer));
1816 expect_wstr(ret, buffer, L"-1.0");
1817
1818 format.NegativeOrder = NEG_LEFT_SPACE;
1819 ret = pGetNumberFormatEx(enW, 0, L"-1", &format, buffer, ARRAY_SIZE(buffer));
1820 expect_wstr(ret, buffer, L"- 1.0");
1821
1822 format.NegativeOrder = NEG_RIGHT;
1823 ret = pGetNumberFormatEx(enW, 0, L"-1", &format, buffer, ARRAY_SIZE(buffer));
1824 expect_wstr(ret, buffer, L"1.0-");
1825
1826 format.NegativeOrder = NEG_RIGHT_SPACE;
1827 ret = pGetNumberFormatEx(enW, 0, L"-1", &format, buffer, ARRAY_SIZE(buffer));
1828 expect_wstr(ret, buffer, L"1.0 -");
1829
1830 /* Test French formatting */
1831 if (pIsValidLocaleName(frW))
1832 {
1833 const WCHAR *expected;
1834 ret = pGetNumberFormatEx(frW, NUO, L"-12345", NULL, buffer, ARRAY_SIZE(buffer));
1835 expected = (ret && wcschr(buffer, 0x202f)) ?
1836 L"-12\x202f\x33\x34\x35,00" : /* Same but narrow (win11) */
1837 L"-12\xa0\x33\x34\x35,00"; /* Non breaking space */
1839 }
1840}
1841
1845 const char *first;
1847 const char *second;
1849 int ret;
1851};
1852
1854 { LOCALE_SYSTEM_DEFAULT, 0, "EndDialog", -1, "_Property", -1, CSTR_GREATER_THAN },
1855 { LOCALE_SYSTEM_DEFAULT, 0, "osp_vba.sreg0070", -1, "_IEWWBrowserComp", -1, CSTR_GREATER_THAN },
1856 { LOCALE_SYSTEM_DEFAULT, 0, "r", -1, "\\", -1, CSTR_GREATER_THAN },
1857 { LOCALE_SYSTEM_DEFAULT, 0, "osp_vba.sreg0031", -1, "OriginalDatabase", -1, CSTR_GREATER_THAN },
1858 { LOCALE_SYSTEM_DEFAULT, 0, "AAA", -1, "aaa", -1, CSTR_GREATER_THAN },
1859 { LOCALE_SYSTEM_DEFAULT, 0, "AAA", -1, "aab", -1, CSTR_LESS_THAN },
1860 { LOCALE_SYSTEM_DEFAULT, 0, "AAA", -1, "Aab", -1, CSTR_LESS_THAN },
1861 { LOCALE_SYSTEM_DEFAULT, 0, ".AAA", -1, "Aab", -1, CSTR_LESS_THAN },
1862 { LOCALE_SYSTEM_DEFAULT, 0, ".AAA", -1, "A.ab", -1, CSTR_LESS_THAN },
1863 { LOCALE_SYSTEM_DEFAULT, 0, "aa", -1, "AB", -1, CSTR_LESS_THAN },
1864 { LOCALE_SYSTEM_DEFAULT, 0, "aa", -1, "Aab", -1, CSTR_LESS_THAN },
1865 { LOCALE_SYSTEM_DEFAULT, 0, "aB", -1, "Aab", -1, CSTR_GREATER_THAN },
1866 { LOCALE_SYSTEM_DEFAULT, 0, "Ba", -1, "bab", -1, CSTR_LESS_THAN },
1867 { LOCALE_SYSTEM_DEFAULT, 0, "{100}{83}{71}{71}{71}", -1, "Global_DataAccess_JRO", -1, CSTR_LESS_THAN },
1868 { LOCALE_SYSTEM_DEFAULT, 0, "a", -1, "{", -1, CSTR_GREATER_THAN },
1869 { LOCALE_SYSTEM_DEFAULT, 0, "A", -1, "{", -1, CSTR_GREATER_THAN },
1870 { LOCALE_SYSTEM_DEFAULT, 0, "3.5", 0, "4.0", -1, CSTR_LESS_THAN },
1871 { LOCALE_SYSTEM_DEFAULT, 0, "3.5", -1, "4.0", -1, CSTR_LESS_THAN },
1872 { LOCALE_SYSTEM_DEFAULT, 0, "3.520.4403.2", -1, "4.0.2927.10", -1, CSTR_LESS_THAN },
1873 /* hyphen and apostrophe are treated differently depending on whether SORT_STRINGSORT specified or not */
1874 { LOCALE_SYSTEM_DEFAULT, 0, "-o", -1, "/m", -1, CSTR_GREATER_THAN },
1875 { LOCALE_SYSTEM_DEFAULT, 0, "/m", -1, "-o", -1, CSTR_LESS_THAN },
1876 { LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "-o", -1, "/m", -1, CSTR_LESS_THAN },
1878 { LOCALE_SYSTEM_DEFAULT, 0, "'o", -1, "/m", -1, CSTR_GREATER_THAN },
1879 { LOCALE_SYSTEM_DEFAULT, 0, "/m", -1, "'o", -1, CSTR_LESS_THAN },
1880 { LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "'o", -1, "/m", -1, CSTR_LESS_THAN },
1882 { LOCALE_SYSTEM_DEFAULT, 0, "aLuZkUtZ", 8, "aLuZkUtZ", 9, CSTR_EQUAL },
1883 { LOCALE_SYSTEM_DEFAULT, 0, "aLuZkUtZ", 7, "aLuZkUtZ\0A", 10, CSTR_LESS_THAN },
1884 { LOCALE_SYSTEM_DEFAULT, 0, "a-", 3, "a\0", 3, CSTR_GREATER_THAN },
1885 { LOCALE_SYSTEM_DEFAULT, 0, "a'", 3, "a\0", 3, CSTR_GREATER_THAN },
1888 { LOCALE_SYSTEM_DEFAULT, NORM_IGNORESYMBOLS, "a.", 3, "a\0", 3, CSTR_EQUAL },
1889 { LOCALE_SYSTEM_DEFAULT, NORM_IGNORESYMBOLS, "a ", 3, "a\0", 3, CSTR_EQUAL },
1890 { LOCALE_SYSTEM_DEFAULT, 0, "a", 1, "a\0\0", 4, CSTR_EQUAL },
1891 { LOCALE_SYSTEM_DEFAULT, 0, "a", 2, "a\0\0", 4, CSTR_EQUAL },
1892 { LOCALE_SYSTEM_DEFAULT, 0, "a\0\0", 4, "a", 1, CSTR_EQUAL },
1893 { LOCALE_SYSTEM_DEFAULT, 0, "a\0\0", 4, "a", 2, CSTR_EQUAL },
1894 { LOCALE_SYSTEM_DEFAULT, 0, "a", 1, "a\0x", 4, CSTR_LESS_THAN },
1895 { LOCALE_SYSTEM_DEFAULT, 0, "a", 2, "a\0x", 4, CSTR_LESS_THAN },
1896 { LOCALE_SYSTEM_DEFAULT, 0, "a\0x", 4, "a", 1, CSTR_GREATER_THAN },
1897 { LOCALE_SYSTEM_DEFAULT, 0, "a\0x", 4, "a", 2, CSTR_GREATER_THAN },
1898 /* flag tests */
1899 { LOCALE_SYSTEM_DEFAULT, LOCALE_USE_CP_ACP, "NULL", -1, "NULL", -1, CSTR_EQUAL },
1900 { LOCALE_SYSTEM_DEFAULT, LINGUISTIC_IGNORECASE, "NULL", -1, "NULL", -1, CSTR_EQUAL },
1901 { LOCALE_SYSTEM_DEFAULT, LINGUISTIC_IGNOREDIACRITIC, "NULL", -1, "NULL", -1, CSTR_EQUAL },
1902 { LOCALE_SYSTEM_DEFAULT, NORM_IGNOREKANATYPE, "NULL", -1, "NULL", -1, CSTR_EQUAL },
1903 { LOCALE_SYSTEM_DEFAULT, NORM_IGNORENONSPACE, "NULL", -1, "NULL", -1, CSTR_EQUAL },
1904 { LOCALE_SYSTEM_DEFAULT, NORM_IGNOREWIDTH, "NULL", -1, "NULL", -1, CSTR_EQUAL },
1905 { LOCALE_SYSTEM_DEFAULT, NORM_LINGUISTIC_CASING, "NULL", -1, "NULL", -1, CSTR_EQUAL },
1906 { LOCALE_SYSTEM_DEFAULT, SORT_DIGITSASNUMBERS, "NULL", -1, "NULL", -1, 0, ERROR_INVALID_FLAGS }
1907};
1908
1909static void test_CompareStringA(void)
1910{
1911 static const char ABC_EE[] = {'A','B','C',0,0xEE};
1912 static const char ABC_FF[] = {'A','B','C',0,0xFF};
1913 int ret, i;
1914 char a[256];
1915 BOOL is_utf8;
1916 CPINFOEXA cpinfo;
1918
1919 GetCPInfoExA( CP_ACP, 0, &cpinfo );
1920 is_utf8 = cpinfo.CodePage == CP_UTF8;
1921
1922 for (i = 0; i < ARRAY_SIZE(comparestringa_data); i++)
1923 {
1924#ifdef __REACTOS__
1925 /* Skip comparestringa_data[44, 45, 49] on WS03 */
1926 if (GetNTVersion() < _WIN32_WINNT_VISTA && (i == 44 || i == 45 || i == 49))
1927 continue;
1928#endif
1930
1931 SetLastError(0xdeadbeef);
1932 ret = CompareStringA(entry->lcid, entry->flags, entry->first, entry->first_len,
1933 entry->second, entry->second_len);
1934 ok(ret == entry->ret, "%d: got %d, expected %d\n", i, ret, entry->ret);
1935 ok(GetLastError() == (ret ? 0xdeadbeef : entry->le), "%d: got last error %ld, expected %ld\n",
1936 i, GetLastError(), (ret ? 0xdeadbeef : entry->le));
1937 }
1938
1939 ret = CompareStringA(lcid, NORM_IGNORECASE, "Salut", -1, "Salute", -1);
1940 ok (ret == CSTR_LESS_THAN, "(Salut/Salute) Expected CSTR_LESS_THAN, got %d\n", ret);
1941
1942 ret = CompareStringA(lcid, NORM_IGNORECASE, "Salut", -1, "SaLuT", -1);
1943 ok (ret == CSTR_EQUAL, "(Salut/SaLuT) Expected CSTR_EQUAL, got %d\n", ret);
1944
1945 ret = CompareStringA(lcid, NORM_IGNORECASE, "Salut", -1, "hola", -1);
1946 ok (ret == CSTR_GREATER_THAN, "(Salut/hola) Expected CSTR_GREATER_THAN, got %d\n", ret);
1947
1948 ret = CompareStringA(lcid, NORM_IGNORECASE, "haha", -1, "hoho", -1);
1949 ok (ret == CSTR_LESS_THAN, "(haha/hoho) Expected CSTR_LESS_THAN, got %d\n", ret);
1950
1952
1953 ret = CompareStringA(lcid, NORM_IGNORECASE, "haha", -1, "hoho", -1);
1954 ok (ret == CSTR_LESS_THAN, "(haha/hoho) Expected CSTR_LESS_THAN, got %d\n", ret);
1955
1956 ret = CompareStringA(lcid, NORM_IGNORECASE, "haha", -1, "hoho", 0);
1957 ok (ret == CSTR_GREATER_THAN, "(haha/hoho) Expected CSTR_GREATER_THAN, got %d\n", ret);
1958
1959 ret = CompareStringA(lcid, NORM_IGNORECASE, "Salut", 5, "saLuT", -1);
1960 ok (ret == CSTR_EQUAL, "(Salut/saLuT) Expected CSTR_EQUAL, got %d\n", ret);
1961
1962 ret = lstrcmpA("", "");
1963 ok (ret == 0, "lstrcmpA(\"\", \"\") should return 0, got %d\n", ret);
1964
1965 ret = lstrcmpA(NULL, NULL);
1966 ok (ret == 0 || broken(ret == -2) /* win9x */, "lstrcmpA(NULL, NULL) should return 0, got %d\n", ret);
1967
1968 ret = lstrcmpA("", NULL);
1969 ok (ret == 1 || broken(ret == -2) /* win9x */, "lstrcmpA(\"\", NULL) should return 1, got %d\n", ret);
1970
1971 ret = lstrcmpA(NULL, "");
1972 ok (ret == -1 || broken(ret == -2) /* win9x */, "lstrcmpA(NULL, \"\") should return -1, got %d\n", ret);
1973
1974 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "'o", -1, "-o", -1 );
1975 ok(ret == CSTR_LESS_THAN, "'o vs -o expected CSTR_LESS_THAN, got %d\n", ret);
1976
1978 ok(ret == CSTR_LESS_THAN, "'o vs -o expected CSTR_LESS_THAN, got %d\n", ret);
1979
1980 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "'", -1, "-", -1 );
1981 ok(ret == CSTR_LESS_THAN, "' vs - expected CSTR_LESS_THAN, got %d\n", ret);
1982
1984 ok(ret == CSTR_LESS_THAN, "' vs - expected CSTR_LESS_THAN, got %d\n", ret);
1985
1986 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "`o", -1, "/m", -1 );
1987 ok(ret == CSTR_GREATER_THAN, "`o vs /m CSTR_GREATER_THAN got %d\n", ret);
1988
1989 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "/m", -1, "`o", -1 );
1990 ok(ret == CSTR_LESS_THAN, "/m vs `o expected CSTR_LESS_THAN, got %d\n", ret);
1991
1993 ok(ret == CSTR_GREATER_THAN, "`o vs /m CSTR_GREATER_THAN got %d\n", ret);
1994
1996 ok(ret == CSTR_LESS_THAN, "/m vs `o expected CSTR_LESS_THAN, got %d\n", ret);
1997
1998 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "`o", -1, "-m", -1 );
1999 ok(ret == CSTR_LESS_THAN, "`o vs -m expected CSTR_LESS_THAN, got %d\n", ret);
2000
2001 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "-m", -1, "`o", -1 );
2002 ok(ret == CSTR_GREATER_THAN, "-m vs `o CSTR_GREATER_THAN got %d\n", ret);
2003
2005 ok(ret == CSTR_GREATER_THAN, "`o vs -m CSTR_GREATER_THAN got %d\n", ret);
2006
2008 ok(ret == CSTR_LESS_THAN, "-m vs `o expected CSTR_LESS_THAN, got %d\n", ret);
2009
2010 /* WinXP handles embedded NULLs differently than earlier versions */
2011 ret = CompareStringA(LOCALE_USER_DEFAULT, 0, "aLuZkUtZ", 8, "aLuZkUtZ\0A", 10);
2012 ok(ret == CSTR_LESS_THAN || ret == CSTR_EQUAL, "aLuZkUtZ vs aLuZkUtZ\\0A expected CSTR_LESS_THAN or CSTR_EQUAL, got %d\n", ret);
2013
2014 ret = CompareStringA(LOCALE_USER_DEFAULT, 0, "aLu\0ZkUtZ", 8, "aLu\0ZkUtZ\0A", 10);
2015 ok(ret == CSTR_LESS_THAN || ret == CSTR_EQUAL, "aLu\\0ZkUtZ vs aLu\\0ZkUtZ\\0A expected CSTR_LESS_THAN or CSTR_EQUAL, got %d\n", ret);
2016
2017 ret = CompareStringA(lcid, 0, "a\0b", -1, "a", -1);
2018 ok(ret == CSTR_EQUAL, "a vs a expected CSTR_EQUAL, got %d\n", ret);
2019
2020 ret = CompareStringA(lcid, 0, "a\0b", 4, "a", 2);
2021 ok(ret == CSTR_EQUAL || /* win2k */
2023 "a\\0b vs a expected CSTR_EQUAL or CSTR_GREATER_THAN, got %d\n", ret);
2024
2025 ret = CompareStringA(lcid, 0, "\2", 2, "\1", 2);
2026 ok(ret != CSTR_EQUAL, "\\2 vs \\1 expected unequal\n");
2027
2029 ok(ret == CSTR_LESS_THAN, "\"#\" vs \".\" expected CSTR_LESS_THAN, got %d\n", ret);
2030
2031 ret = CompareStringA(lcid, NORM_IGNORECASE, "_", -1, ".", -1);
2032 ok(ret == CSTR_GREATER_THAN, "\"_\" vs \".\" expected CSTR_GREATER_THAN, got %d\n", ret);
2033
2034 ret = lstrcmpiA("#", ".");
2035 ok(ret == -1, "\"#\" vs \".\" expected -1, got %d\n", ret);
2036
2038
2039 /* \xB9 character lies between a and b */
2040 ret = CompareStringA(lcid, 0, "a", 1, "\xB9", 1);
2041 ok(ret == CSTR_LESS_THAN, "\'\\xB9\' character should be greater than \'a\'\n");
2042 ret = CompareStringA(lcid, 0, "\xB9", 1, "b", 1);
2043 ok(ret == CSTR_LESS_THAN, "\'\\xB9\' character should be smaller than \'b\'\n");
2044
2045 memset(a, 'a', sizeof(a));
2046 SetLastError(0xdeadbeef);
2047 ret = CompareStringA(lcid, 0, a, sizeof(a), a, sizeof(a));
2048 ok (GetLastError() == 0xdeadbeef && ret == CSTR_EQUAL,
2049 "ret %d, error %ld, expected value %d\n", ret, GetLastError(), CSTR_EQUAL);
2050
2051 ret = CompareStringA(LOCALE_USER_DEFAULT, 0, ABC_EE, 3, ABC_FF, 3);
2052 ok(ret == CSTR_EQUAL, "expected CSTR_EQUAL, got %d\n", ret);
2053 ret = CompareStringA(LOCALE_USER_DEFAULT, 0, ABC_EE, 5, ABC_FF, 3);
2054 ok(ret == CSTR_GREATER_THAN || (is_utf8 && ret == CSTR_EQUAL), "expected CSTR_GREATER_THAN, got %d\n", ret);
2055 ret = CompareStringA(LOCALE_USER_DEFAULT, 0, ABC_EE, 3, ABC_FF, 5);
2056 ok(ret == CSTR_LESS_THAN || (is_utf8 && ret == CSTR_EQUAL), "expected CSTR_LESS_THAN, got %d\n", ret);
2057 ret = CompareStringA(LOCALE_USER_DEFAULT, 0, ABC_EE, 5, ABC_FF, 5);
2058 ok(ret == CSTR_LESS_THAN || (is_utf8 && ret == CSTR_EQUAL), "expected CSTR_LESS_THAN, got %d\n", ret);
2059 ret = CompareStringA(LOCALE_USER_DEFAULT, 0, ABC_FF, 5, ABC_EE, 5);
2060 ok(ret == CSTR_GREATER_THAN || (is_utf8 && ret == CSTR_EQUAL), "expected CSTR_GREATER_THAN, got %d\n", ret);
2061}
2062
2063static void test_CompareStringW(void)
2064{
2065 static const WCHAR ABC_EE[] = {'A','B','C',0,0xEE};
2066 static const WCHAR ABC_FF[] = {'A','B','C',0,0xFF};
2067 static const WCHAR A_ACUTE_BC[] = {0xc1,'B','C',0};
2068 static const WCHAR A_ACUTE_BC_DECOMP[] = {'A',0x301,'B','C',0};
2069 static const WCHAR A_NULL_BC[] = {'A',0,'B','C',0};
2070 WCHAR *str1, *str2;
2072 DWORD old_prot;
2073 BOOL success;
2074 char *buf;
2075 int ret;
2076
2077 GetSystemInfo(&si);
2079 ok(buf != NULL, "VirtualAlloc failed with %lu\n", GetLastError());
2081 ok(success, "VirtualProtect failed with %lu\n", GetLastError());
2083 ok(success, "VirtualProtect failed with %lu\n", GetLastError());
2084
2085 str1 = (WCHAR *)(buf + si.dwPageSize - sizeof(WCHAR));
2086 str2 = (WCHAR *)(buf + 3 * si.dwPageSize - sizeof(WCHAR));
2087 *str1 = 'A';
2088 *str2 = 'B';
2089
2090 /* CompareStringW should abort on the first non-matching character */
2092 0, str1, 100, str2, 100);
2093 ok(ret == CSTR_LESS_THAN, "expected CSTR_LESS_THAN, got %d\n", ret);
2094
2096 ok(success, "VirtualFree failed with %lu\n", GetLastError());
2097
2098 SetLastError(0xdeadbeef);
2100 ok(ret == CSTR_EQUAL || broken(!ret && GetLastError() == ERROR_INVALID_FLAGS) /* <Win7 */,
2101 "expected CSTR_EQUAL, got %d, last error %ld\n", ret, GetLastError());
2102
2103 ret = CompareStringW(LOCALE_USER_DEFAULT, 0, ABC_EE, 3, ABC_FF, 3);
2104 ok(ret == CSTR_EQUAL, "expected CSTR_EQUAL, got %d\n", ret);
2105 ret = CompareStringW(LOCALE_USER_DEFAULT, 0, ABC_EE, 5, ABC_FF, 3);
2106 ok(ret == CSTR_GREATER_THAN, "expected CSTR_GREATER_THAN, got %d\n", ret);
2107 ret = CompareStringW(LOCALE_USER_DEFAULT, 0, ABC_EE, 3, ABC_FF, 5);
2108 ok(ret == CSTR_LESS_THAN, "expected CSTR_LESS_THAN, got %d\n", ret);
2109 ret = CompareStringW(LOCALE_USER_DEFAULT, 0, ABC_EE, 5, ABC_FF, 5);
2110 ok(ret == CSTR_LESS_THAN, "expected CSTR_LESS_THAN, got %d\n", ret);
2111 ret = CompareStringW(LOCALE_USER_DEFAULT, 0, ABC_FF, 5, ABC_EE, 5);
2112 ok(ret == CSTR_GREATER_THAN, "expected CSTR_GREATER_THAN, got %d\n", ret);
2113
2114 ret = CompareStringW(LOCALE_USER_DEFAULT, 0, ABC_EE, 4, A_ACUTE_BC, 4);
2115 ok(ret == CSTR_LESS_THAN, "expected CSTR_LESS_THAN, got %d\n", ret);
2116 ret = CompareStringW(LOCALE_USER_DEFAULT, 0, ABC_EE, 4, A_ACUTE_BC_DECOMP, 5);
2117 ok(ret == CSTR_LESS_THAN, "expected CSTR_LESS_THAN, got %d\n", ret);
2118 ret = CompareStringW(LOCALE_USER_DEFAULT, 0, A_ACUTE_BC, 4, A_ACUTE_BC_DECOMP, 5);
2119 ok(ret == CSTR_EQUAL, "expected CSTR_EQUAL, got %d\n", ret);
2120
2121 ret = CompareStringW(LOCALE_USER_DEFAULT, NORM_IGNORENONSPACE, ABC_EE, 3, A_ACUTE_BC, 4);
2122 ok(ret == CSTR_EQUAL, "expected CSTR_EQUAL, got %d\n", ret);
2123 ret = CompareStringW(LOCALE_USER_DEFAULT, NORM_IGNORENONSPACE, ABC_EE, 4, A_ACUTE_BC_DECOMP, 5);
2124 ok(ret == CSTR_EQUAL, "expected CSTR_EQUAL, got %d\n", ret);
2125 ret = CompareStringW(LOCALE_USER_DEFAULT, NORM_IGNORENONSPACE, A_ACUTE_BC, 4, A_ACUTE_BC_DECOMP, 5);
2126 ok(ret == CSTR_EQUAL, "expected CSTR_EQUAL, got %d\n", ret);
2127
2128 ret = CompareStringW(LOCALE_USER_DEFAULT, 0, ABC_EE, 4, A_NULL_BC, 4);
2129 ok(ret == CSTR_EQUAL, "expected CSTR_LESS_THAN, got %d\n", ret);
2130 ret = CompareStringW(LOCALE_USER_DEFAULT, NORM_IGNORENONSPACE, ABC_EE, 4, A_NULL_BC, 4);
2131 ok(ret == CSTR_EQUAL, "expected CSTR_EQUAL, got %d\n", ret);
2132
2133 ret = CompareStringW(LOCALE_USER_DEFAULT, 0, A_NULL_BC, 4, A_ACUTE_BC, 4);
2134 ok(ret == CSTR_LESS_THAN, "expected CSTR_LESS_THAN, got %d\n", ret);
2135 ret = CompareStringW(LOCALE_USER_DEFAULT, NORM_IGNORENONSPACE, A_NULL_BC, 4, A_ACUTE_BC, 4);
2136 ok(ret == CSTR_EQUAL, "expected CSTR_EQUAL, got %d\n", ret);
2137
2138 ret = CompareStringW(LOCALE_USER_DEFAULT, 0, A_NULL_BC, 4, A_ACUTE_BC_DECOMP, 5);
2139 ok(ret == CSTR_LESS_THAN, "expected CSTR_LESS_THAN, got %d\n", ret);
2140 ret = CompareStringW(LOCALE_USER_DEFAULT, NORM_IGNORENONSPACE, A_NULL_BC, 4, A_ACUTE_BC_DECOMP, 5);
2141 ok(ret == CSTR_EQUAL, "expected CSTR_EQUAL, got %d\n", ret);
2142}
2143
2145 const char *locale;
2147 const WCHAR first[2];
2148 const WCHAR second[2];
2151};
2152
2154 /* default behavior */
2155 { /* 0 */
2156 "tr-TR", 0,
2157 {'i',0}, {'I',0}, CSTR_LESS_THAN, -1
2158 },
2159 { /* 1 */
2160 "tr-TR", 0,
2161 {'i',0}, {0x130,0}, CSTR_LESS_THAN, -1
2162 },
2163 { /* 2 */
2164 "tr-TR", 0,
2165 {'i',0}, {0x131,0}, CSTR_LESS_THAN, -1
2166 },
2167 { /* 3 */
2168 "tr-TR", 0,
2169 {'I',0}, {0x130,0}, CSTR_LESS_THAN, -1
2170 },
2171 { /* 4 */
2172 "tr-TR", 0,
2173 {'I',0}, {0x131,0}, CSTR_LESS_THAN, -1
2174 },
2175 { /* 5 */
2176 "tr-TR", 0,
2177 {0x130,0}, {0x131,0}, CSTR_GREATER_THAN, -1
2178 },
2179 /* with NORM_IGNORECASE */
2180 { /* 6 */
2181 "tr-TR", NORM_IGNORECASE,
2182 {'i',0}, {'I',0}, CSTR_EQUAL, -1
2183 },
2184 { /* 7 */
2185 "tr-TR", NORM_IGNORECASE,
2186 {'i',0}, {0x130,0}, CSTR_LESS_THAN, -1
2187 },
2188 { /* 8 */
2189 "tr-TR", NORM_IGNORECASE,
2190 {'i',0}, {0x131,0}, CSTR_LESS_THAN, -1
2191 },
2192 { /* 9 */
2193 "tr-TR", NORM_IGNORECASE,
2194 {'I',0}, {0x130,0}, CSTR_LESS_THAN, -1
2195 },
2196 { /* 10 */
2197 "tr-TR", NORM_IGNORECASE,
2198 {'I',0}, {0x131,0}, CSTR_LESS_THAN, -1
2199 },
2200 { /* 11 */
2201 "tr-TR", NORM_IGNORECASE,
2202 {0x130,0}, {0x131,0}, CSTR_GREATER_THAN, -1
2203 },
2204 /* with NORM_LINGUISTIC_CASING */
2205 { /* 12 */
2206 "tr-TR", NORM_LINGUISTIC_CASING,
2207 {'i',0}, {'I',0}, CSTR_GREATER_THAN, CSTR_LESS_THAN
2208 },
2209 { /* 13 */
2210 "tr-TR", NORM_LINGUISTIC_CASING,
2211 {'i',0}, {0x130,0}, CSTR_LESS_THAN, -1
2212 },
2213 { /* 14 */
2214 "tr-TR", NORM_LINGUISTIC_CASING,
2215 {'i',0}, {0x131,0}, CSTR_GREATER_THAN, CSTR_LESS_THAN
2216 },
2217 { /* 15 */
2218 "tr-TR", NORM_LINGUISTIC_CASING,
2219 {'I',0}, {0x130,0}, CSTR_LESS_THAN, -1
2220 },
2221 { /* 16 */
2222 "tr-TR", NORM_LINGUISTIC_CASING,
2223 {'I',0}, {0x131,0}, CSTR_GREATER_THAN, CSTR_LESS_THAN
2224 },
2225 { /* 17 */
2226 "tr-TR", NORM_LINGUISTIC_CASING,
2227 {0x130,0}, {0x131,0}, CSTR_GREATER_THAN, -1
2228 },
2229 /* with LINGUISTIC_IGNORECASE */
2230 { /* 18 */
2231 "tr-TR", LINGUISTIC_IGNORECASE,
2232 {'i',0}, {'I',0}, CSTR_EQUAL, -1
2233 },
2234 { /* 19 */
2235 "tr-TR", LINGUISTIC_IGNORECASE,
2236 {'i',0}, {0x130,0}, CSTR_LESS_THAN, -1
2237 },
2238 { /* 20 */
2239 "tr-TR", LINGUISTIC_IGNORECASE,
2240 {'i',0}, {0x131,0}, CSTR_LESS_THAN, -1
2241 },
2242 { /* 21 */
2243 "tr-TR", LINGUISTIC_IGNORECASE,
2244 {'I',0}, {0x130,0}, CSTR_LESS_THAN, -1
2245 },
2246 { /* 22 */
2247 "tr-TR", LINGUISTIC_IGNORECASE,
2248 {'I',0}, {0x131,0}, CSTR_LESS_THAN, -1
2249 },
2250 { /* 23 */
2251 "tr-TR", LINGUISTIC_IGNORECASE,
2252 {0x130,0}, {0x131,0}, CSTR_GREATER_THAN, -1
2253 },
2254 /* with NORM_LINGUISTIC_CASING | NORM_IGNORECASE */
2255 { /* 24 */
2257 {'i',0}, {'I',0}, CSTR_GREATER_THAN, CSTR_EQUAL
2258 },
2259 { /* 25 */
2261 {'i',0}, {0x130,0}, CSTR_EQUAL, CSTR_LESS_THAN
2262 },
2263 { /* 26 */
2265 {'i',0}, {0x131,0}, CSTR_GREATER_THAN, CSTR_LESS_THAN
2266 },
2267 { /* 27 */
2269 {'I',0}, {0x130,0}, CSTR_LESS_THAN, -1
2270 },
2271 { /* 28 */
2273 {'I',0}, {0x131,0}, CSTR_EQUAL, CSTR_LESS_THAN
2274 },
2275 { /* 29 */
2277 {0x130,0}, {0x131,0}, CSTR_GREATER_THAN, -1
2278 },
2279 /* with NORM_LINGUISTIC_CASING | LINGUISTIC_IGNORECASE */
2280 { /* 30 */
2282 {'i',0}, {'I',0}, CSTR_GREATER_THAN, CSTR_EQUAL
2283 },
2284 { /* 31 */
2286 {'i',0}, {0x130,0}, CSTR_EQUAL, CSTR_LESS_THAN
2287 },
2288 { /* 32 */
2290 {'i',0}, {0x131,0}, CSTR_GREATER_THAN, CSTR_LESS_THAN
2291 },
2292 { /* 33 */
2294 {'I',0}, {0x130,0}, CSTR_LESS_THAN, -1
2295 },
2296 { /* 34 */
2298 {'I',0}, {0x131,0}, CSTR_EQUAL, CSTR_LESS_THAN
2299 },
2300 { /* 35 */
2302 {0x130,0}, {0x131,0}, CSTR_GREATER_THAN, CSTR_LESS_THAN
2303 }
2304};
2305
2306static void test_CompareStringEx(void)
2307{
2308 const char *op[] = {"ERROR", "CSTR_LESS_THAN", "CSTR_EQUAL", "CSTR_GREATER_THAN"};
2309 WCHAR locale[6];
2310 INT ret, i;
2311
2312 /* CompareStringEx is only available on Vista+ */
2313 if (!pCompareStringEx)
2314 {
2315 win_skip("CompareStringEx not supported\n");
2316 return;
2317 }
2318
2319 for (i = 0; i < ARRAY_SIZE(comparestringex_tests); i++)
2320 {
2322
2323 MultiByteToWideChar(CP_ACP, 0, e->locale, -1, locale, ARRAY_SIZE(locale));
2324 ret = pCompareStringEx(locale, e->flags, e->first, -1, e->second, -1, NULL, NULL, 0);
2325 ok(ret == e->ret || broken(ret == e->broken),
2326 "%d: got %s, expected %s\n", i, op[ret], op[e->ret]);
2327 }
2328
2329}
2330
2331static const DWORD lcmap_invalid_flags[] = {
2332 0,
2357};
2358
2359static void test_LCMapStringA(void)
2360{
2361 int ret, ret2, i;
2362 char buf[256], buf2[256];
2363 static const char upper_case[] = "\tJUST! A, TEST; STRING 1/*+-.\r\n";
2364 static const char lower_case[] = "\tjust! a, test; string 1/*+-.\r\n";
2365 static const char symbols_stripped[] = "justateststring1";
2366
2367 SetLastError(0xdeadbeef);
2369 lower_case, -1, buf, sizeof(buf));
2370 ok(ret == lstrlenA(lower_case) + 1,
2371 "ret %d, error %ld, expected value %d\n",
2373 ok(!memcmp(buf, lower_case, ret), "LCMapStringA should return %s, but not %s\n", lower_case, buf);
2374
2376 upper_case, -1, buf, sizeof(buf));
2377 ok(!ret, "LCMAP_LOWERCASE and LCMAP_UPPERCASE are mutually exclusive\n");
2379 "unexpected error code %ld\n", GetLastError());
2380
2381 /* test invalid flag combinations */
2382 for (i = 0; i < ARRAY_SIZE(lcmap_invalid_flags); i++) {
2383 lstrcpyA(buf, "foo");
2384 SetLastError(0xdeadbeef);
2386 lower_case, -1, buf, sizeof(buf));
2388 "LCMapStringA (flag %08lx) unexpected error code %ld\n",
2390 ok(!ret, "LCMapStringA (flag %08lx) should return 0, got %d\n",
2392 }
2393
2394 /* test LCMAP_LOWERCASE */
2396 upper_case, -1, buf, sizeof(buf));
2397 ok(ret == lstrlenA(upper_case) + 1,
2398 "ret %d, error %ld, expected value %d\n",
2400 ok(!lstrcmpA(buf, lower_case), "LCMapStringA should return %s, but not %s\n", lower_case, buf);
2401
2402 /* test LCMAP_UPPERCASE */
2404 lower_case, -1, buf, sizeof(buf));
2405 ok(ret == lstrlenA(lower_case) + 1,
2406 "ret %d, error %ld, expected value %d\n",
2408 ok(!lstrcmpA(buf, upper_case), "LCMapStringA should return %s, but not %s\n", upper_case, buf);
2409
2410 /* test buffer overflow */
2411 SetLastError(0xdeadbeef);
2413 lower_case, -1, buf, 4);
2415 "should return 0 and ERROR_INSUFFICIENT_BUFFER, got %d\n", ret);
2416
2417 /* LCMAP_UPPERCASE or LCMAP_LOWERCASE should accept src == dst */
2420 buf, -1, buf, sizeof(buf));
2421 if (!ret) /* Win9x */
2422 trace("Ignoring LCMapStringA(LCMAP_UPPERCASE, buf, buf) error on Win9x\n");
2423 else
2424 {
2425 ok(ret == lstrlenA(lower_case) + 1,
2426 "ret %d, error %ld, expected value %d\n",
2428 ok(!lstrcmpA(buf, upper_case), "LCMapStringA should return %s, but not %s\n", upper_case, buf);
2429 }
2432 buf, -1, buf, sizeof(buf));
2433 if (!ret) /* Win9x */
2434 trace("Ignoring LCMapStringA(LCMAP_LOWERCASE, buf, buf) error on Win9x\n");
2435 else
2436 {
2437 ok(ret == lstrlenA(upper_case) + 1,
2438 "ret %d, error %ld, expected value %d\n",
2440 ok(!lstrcmpA(buf, lower_case), "LCMapStringA should return %s, but not %s\n", lower_case, buf);
2441 }
2442
2443 /* otherwise src == dst should fail */
2444 SetLastError(0xdeadbeef);
2446 buf, 10, buf, sizeof(buf));
2447 ok(GetLastError() == ERROR_INVALID_FLAGS /* NT */ ||
2448 GetLastError() == ERROR_INVALID_PARAMETER /* Win9x */,
2449 "unexpected error code %ld\n", GetLastError());
2450 ok(!ret, "src == dst without LCMAP_UPPERCASE or LCMAP_LOWERCASE must fail\n");
2451
2452 /* test whether '\0' is always appended */
2453 memset(buf, 0xff, sizeof(buf));
2455 upper_case, -1, buf, sizeof(buf));
2456 ok(ret, "LCMapStringA must succeed\n");
2457 ok(buf[ret-1] == 0, "LCMapStringA not null-terminated\n");
2459 upper_case, lstrlenA(upper_case), buf2, sizeof(buf2));
2460 ok(ret2, "LCMapStringA must succeed\n");
2461 ok(buf2[ret2-1] == 0, "LCMapStringA not null-terminated\n" );
2462 ok(ret == ret2, "lengths of sort keys must be equal\n");
2463 ok(!memcmp(buf, buf2, ret), "sort keys must be equal\n");
2464
2465 /* test we get the same length when no dest buffer is provided */
2468 ok(ret2, "LCMapStringA must succeed\n");
2469 ok(ret == ret2, "lengths of sort keys must be equal (%d vs %d)\n", ret, ret2);
2470
2471 /* test LCMAP_SORTKEY | NORM_IGNORECASE */
2473 upper_case, -1, buf, sizeof(buf));
2474 ok(ret, "LCMapStringA must succeed\n");
2476 lower_case, -1, buf2, sizeof(buf2));
2477 ok(ret2, "LCMapStringA must succeed\n");
2478 ok(ret == ret2, "lengths of sort keys must be equal\n");
2479 ok(!memcmp(buf, buf2, ret), "sort keys must be equal\n");
2480
2481 /* Don't test LCMAP_SORTKEY | NORM_IGNORENONSPACE, produces different
2482 results from plain LCMAP_SORTKEY on Vista */
2483
2484 /* test LCMAP_SORTKEY | NORM_IGNORESYMBOLS */
2486 lower_case, -1, buf, sizeof(buf));
2487 ok(ret, "LCMapStringA must succeed\n");
2489 symbols_stripped, -1, buf2, sizeof(buf2));
2490 ok(ret2, "LCMapStringA must succeed\n");
2491 ok(ret == ret2, "lengths of sort keys must be equal\n");
2492 ok(!memcmp(buf, buf2, ret), "sort keys must be equal\n");
2493
2494 /* test NORM_IGNORENONSPACE */
2495 lstrcpyA(buf, "foo");
2497 lower_case, -1, buf, sizeof(buf));
2498 ok(ret == lstrlenA(lower_case) + 1, "LCMapStringA should return %d, ret = %d\n",
2499 lstrlenA(lower_case) + 1, ret);
2500 ok(!lstrcmpA(buf, lower_case), "LCMapStringA should return %s, but not %s\n", lower_case, buf);
2501
2502 /* test NORM_IGNORESYMBOLS */
2503 lstrcpyA(buf, "foo");
2505 lower_case, -1, buf, sizeof(buf));
2506 ok(ret == lstrlenA(symbols_stripped) + 1, "LCMapStringA should return %d, ret = %d\n",
2508 ok(!lstrcmpA(buf, symbols_stripped), "LCMapStringA should return %s, but not %s\n", lower_case, buf);
2509
2510 /* test NORM_IGNORESYMBOLS | NORM_IGNORENONSPACE */
2511 lstrcpyA(buf, "foo");
2513 lower_case, -1, buf, sizeof(buf));
2514 ok(ret == lstrlenA(symbols_stripped) + 1, "LCMapStringA should return %d, ret = %d\n",
2516 ok(!lstrcmpA(buf, symbols_stripped), "LCMapStringA should return %s, but not %s\n", lower_case, buf);
2517
2518 /* test srclen = 0 */
2519 SetLastError(0xdeadbeef);
2521 ok(!ret, "LCMapStringA should fail with srclen = 0\n");
2523 "unexpected error code %ld\n", GetLastError());
2524}
2525
2527
2529{
2530 const static WCHAR japanese_text[] = {
2531 0x3044, 0x309d, 0x3084, 0x3001, 0x30a4, 0x30fc, 0x30cf, 0x30c8,
2532 0x30fc, 0x30f4, 0x30a9, 0x306e, 0x91ce, 0x539f, 0x306f, 0x5e83,
2533 0x3044, 0x3093, 0x3060, 0x3088, 0x3002, 0
2534 };
2535 const static WCHAR hiragana_text[] = {
2536 0x3044, 0x309d, 0x3084, 0x3001, 0x3044, 0x30fc, 0x306f, 0x3068,
2537 0x30fc, 0x3094, 0x3049, 0x306e, 0x91ce, 0x539f, 0x306f, 0x5e83,
2538 0x3044, 0x3093, 0x3060, 0x3088, 0x3002, 0
2539 };
2540 const static WCHAR katakana_text[] = {
2541 0x30a4, 0x30fd, 0x30e4, 0x3001, 0x30a4, 0x30fc, 0x30cf, 0x30c8,
2542 0x30fc, 0x30f4, 0x30a9, 0x30ce, 0x91ce, 0x539f, 0x30cf, 0x5e83,
2543 0x30a4, 0x30f3, 0x30c0, 0x30e8, 0x3002, 0
2544 };
2545 const static WCHAR halfwidth_text[] = {
2546 0x3044, 0x309d, 0x3084, 0xff64, 0xff72, 0xff70, 0xff8a, 0xff84,
2547 0xff70, 0xff73, 0xff9e, 0xff6b, 0x306e, 0x91ce, 0x539f, 0x306f,
2548 0x5e83, 0x3044, 0x3093, 0x3060, 0x3088, 0xff61, 0
2549 };
2550 const static WCHAR halfwidth_text2[] = {
2551 0xff72, 0x30fd, 0xff94, 0xff64, 0xff72, 0xff70, 0xff8a, 0xff84,
2552 0xff70, 0xff73, 0xff9e, 0xff6b, 0xff89, 0x91ce, 0x539f, 0xff8a,
2553 0x5e83, 0xff72, 0xff9d, 0xff80, 0xff9e, 0xff96, 0xff61, 0
2554 };
2555 const static WCHAR math_text[] = {
2556 0xd835, 0xdc00, 0xd835, 0xdc01, 0xd835, 0xdc02, 0xd835, 0xdc03,
2557 0xd835, 0xdd52, 0xd835, 0xdd53, 0xd835, 0xdd54, 0xd835, 0xdd55, 0
2558 };
2559 const static WCHAR math_result[] = L"ABCDabcd";
2560 const static WCHAR math_arabic_text[] = {
2561 0xd83b, 0xde00, 0xd83b, 0xde01, 0xd83b, 0xde02, 0xd83b, 0xde03,
2562 0xd83b, 0xde10, 0xd83b, 0xde11, 0xd83b, 0xde12, 0xd83b, 0xde13, 0
2563 };
2564 const static WCHAR math_arabic_result[] = {
2565 0x0627, 0x0628, 0x062c, 0x062f, 0x0641, 0x0635, 0x0642, 0x0631, 0
2566 };
2567 const static WCHAR cjk_compat_text[] = {
2568 0xd87e, 0xdc20, 0xd87e, 0xdc21, 0xd87e, 0xdc22, 0xd87e, 0xdc23,
2569 0xd87e, 0xdc24, 0xd87e, 0xdc25, 0xd87e, 0xdc26, 0xd87e, 0xdc27, 0
2570 };
2571 const static WCHAR cjk_compat_result[] = {
2572 0x523b, 0x5246, 0x5272, 0x5277, 0x3515, 0x52c7, 0x52c9, 0x52e4, 0
2573 };
2574 const static WCHAR accents_text[] = {
2575 0x00e0, 0x00e7, ' ', 0x00e9, ',', 0x00ee, 0x00f1, '/', 0x00f6, 0x00fb, 0x00fd, '!', 0
2576 };
2577 const static WCHAR accents_result[] = L"ac e,in/ouy!";
2578 const static WCHAR accents_result2[] = L"aceinouy";
2579 int ret, ret2, i;
2580 WCHAR buf[256], buf2[256];
2581 char *p_buf = (char *)buf, *p_buf2 = (char *)buf2;
2582
2583 /* LCMAP_LOWERCASE | LCMAP_UPPERCASE makes LCMAP_TITLECASE, so it's valid now. */
2586 "%s ret %d, error %ld, expected value %d\n", func_name,
2589 "Expected title case string\n");
2590
2591 /* test invalid flag combinations */
2592 for (i = 0; i < ARRAY_SIZE(lcmap_invalid_flags); i++) {
2593 lstrcpyW(buf, fooW);
2594 SetLastError(0xdeadbeef);
2596 lower_case, -1, buf, sizeof(buf));
2598 "%s (flag %08lx) unexpected error code %ld\n",
2600 ok(!ret, "%s (flag %08lx) should return 0, got %d\n",
2602 }
2603
2604 /* test LCMAP_LOWERCASE */
2606 ok(ret == lstrlenW(upper_case) + 1, "%s ret %d, error %ld, expected value %d\n", func_name,
2608 ok(!lstrcmpW(buf, lower_case), "%s string compare mismatch\n", func_name);
2609
2610 /* test LCMAP_UPPERCASE */
2612 ok(ret == lstrlenW(lower_case) + 1, "%s ret %d, error %ld, expected value %d\n", func_name,
2614 ok(!lstrcmpW(buf, upper_case), "%s string compare mismatch\n", func_name);
2615
2616 /* test LCMAP_HIRAGANA */
2617 ret = func_ptr(LCMAP_HIRAGANA, japanese_text, -1, buf, ARRAY_SIZE(buf));
2618 ok(ret == lstrlenW(hiragana_text) + 1, "%s ret %d, error %ld, expected value %d\n", func_name,
2619 ret, GetLastError(), lstrlenW(hiragana_text) + 1);
2620 ok(!lstrcmpW(buf, hiragana_text), "%s string compare mismatch\n", func_name);
2621
2622 buf[0] = 0x30f5; /* KATAKANA LETTER SMALL KA */
2623 ret = func_ptr(LCMAP_HIRAGANA, buf, 1, buf2, 1);
2624 ok(ret == 1, "%s ret %d, error %ld, expected value 1\n", func_name,
2625 ret, GetLastError());
2626 /* U+3095: HIRAGANA LETTER SMALL KA was added in Unicode 3.2 */
2627 ok(buf2[0] == 0x3095 || broken(buf2[0] == 0x30f5 /* Vista and earlier versions */),
2628 "%s expected %04x, got %04x\n", func_name, 0x3095, buf2[0]);
2629
2630 /* test LCMAP_KATAKANA | LCMAP_LOWERCASE */
2631 ret = func_ptr(LCMAP_KATAKANA | LCMAP_LOWERCASE, japanese_text, -1, buf, ARRAY_SIZE(buf));
2632 ok(ret == lstrlenW(katakana_text) + 1, "%s ret %d, error %ld, expected value %d\n", func_name,
2633 ret, GetLastError(), lstrlenW(katakana_text) + 1);
2634 ok(!lstrcmpW(buf, katakana_text), "%s string compare mismatch\n", func_name);
2635
2636 /* test LCMAP_FULLWIDTH */
2637 ret = func_ptr(LCMAP_FULLWIDTH, halfwidth_text, -1, buf, ARRAY_SIZE(buf));
2638 ok(ret == lstrlenW(japanese_text) + 1, "%s ret %d, error %ld, expected value %d\n", func_name,
2639 ret, GetLastError(), lstrlenW(japanese_text) + 1);
2640 ok(!lstrcmpW(buf, japanese_text), "%s string compare mismatch\n", func_name);
2641
2642 ret2 = func_ptr(LCMAP_FULLWIDTH, halfwidth_text, -1, NULL, 0);
2643 ok(ret == ret2, "%s ret %d, expected value %d\n", func_name, ret2, ret);
2644
2645 ret = func_ptr(LCMAP_FULLWIDTH, math_text, -1, buf, ARRAY_SIZE(buf));
2646 ok(ret == lstrlenW(buf) + 1, "%s ret %d, error %ld, expected value %d\n", func_name,
2647 ret, GetLastError(), lstrlenW(buf) + 1);
2648#ifdef __REACTOS__
2649 ok(!lstrcmpW(buf, math_result) || broken(!lstrcmpW(buf, math_text)) /* WS03 */, "%s string compare mismatch %s\n", func_name, debugstr_w(buf));
2650#else
2651 ok(!lstrcmpW(buf, math_result), "%s string compare mismatch %s\n", func_name, debugstr_w(buf));
2652#endif
2653
2654 ret = func_ptr(LCMAP_FULLWIDTH, math_arabic_text, -1, buf, ARRAY_SIZE(buf));
2655 ok(ret == lstrlenW(buf) + 1, "%s ret %d, error %ld, expected value %d\n", func_name,
2656 ret, GetLastError(), lstrlenW(buf) + 1);
2657 ok(!lstrcmpW(buf, math_arabic_result) ||
2658 broken(!lstrcmpW( buf, math_arabic_text )), /* win7 */
2659 "%s string compare mismatch %s\n", func_name, debugstr_w(buf));
2660
2661 ret = func_ptr(LCMAP_FULLWIDTH, cjk_compat_text, -1, buf, ARRAY_SIZE(buf));
2662 ok(ret == lstrlenW(buf) + 1, "%s ret %d, error %ld, expected value %d\n", func_name,
2663 ret, GetLastError(), lstrlenW(buf) + 1);
2664#ifdef __REACTOS__
2665 ok(!lstrcmpW(buf, cjk_compat_result) || broken(!lstrcmpW(buf, cjk_compat_text)) /* WS03 */, "%s string compare mismatch %s\n", func_name, debugstr_w(buf));
2666#else
2667 ok(!lstrcmpW(buf, cjk_compat_result), "%s string compare mismatch %s\n", func_name, debugstr_w(buf));
2668#endif
2669
2670 /* test LCMAP_FULLWIDTH | LCMAP_HIRAGANA
2671 (half-width katakana is converted into full-width hiragana) */
2672 ret = func_ptr(LCMAP_FULLWIDTH | LCMAP_HIRAGANA, halfwidth_text, -1, buf, ARRAY_SIZE(buf));
2673 ok(ret == lstrlenW(hiragana_text) + 1, "%s ret %d, error %ld, expected value %d\n", func_name,
2674 ret, GetLastError(), lstrlenW(hiragana_text) + 1);
2675 ok(!lstrcmpW(buf, hiragana_text), "%s string compare mismatch\n", func_name);
2676
2677 ret2 = func_ptr(LCMAP_FULLWIDTH | LCMAP_HIRAGANA, halfwidth_text, -1, NULL, 0);
2678 ok(ret == ret2, "%s ret %d, expected value %d\n", func_name, ret, ret2);
2679
2680 /* LCMAP_FULLWIDTH | LCMAP_KATAKANA maps to full-width first */
2681 ret = func_ptr(LCMAP_FULLWIDTH | LCMAP_KATAKANA, halfwidth_text, -1, buf, ARRAY_SIZE(buf));
2682 ok(ret == lstrlenW(katakana_text) + 1, "%s ret %d, error %ld, expected value %d\n", func_name,
2683 ret, GetLastError(), lstrlenW(katakana_text) + 1);
2684 ok(!lstrcmpW(buf, katakana_text), "%s string compare mismatch\n", func_name);
2685
2686 /* test LCMAP_HALFWIDTH */
2687 ret = func_ptr(LCMAP_HALFWIDTH, japanese_text, -1, buf, ARRAY_SIZE(buf));
2688 ok(ret == lstrlenW(halfwidth_text) + 1, "%s ret %d, error %ld, expected value %d\n", func_name,
2689 ret, GetLastError(), lstrlenW(halfwidth_text) + 1);
2690 ok(!lstrcmpW(buf, halfwidth_text), "%s string compare mismatch\n", func_name);
2691
2692 ret2 = func_ptr(LCMAP_HALFWIDTH, japanese_text, -1, NULL, 0);
2693 ok(ret == ret2, "%s ret %d, expected value %d\n", func_name, ret, ret2);
2694
2695 /* test LCMAP_HALFWIDTH | LCMAP_KATAKANA
2696 (hiragana character is converted into half-width katakana) */
2697 ret = func_ptr(LCMAP_HALFWIDTH | LCMAP_KATAKANA, japanese_text, -1, buf, ARRAY_SIZE(buf));
2698 ok(ret == lstrlenW(halfwidth_text2) + 1, "%s ret %d, error %ld, expected value %d\n", func_name,
2699 ret, GetLastError(), lstrlenW(halfwidth_text2) + 1);
2700 ok(!lstrcmpW(buf, halfwidth_text2), "%s string compare mismatch\n", func_name);
2701
2702 ret2 = func_ptr(LCMAP_HALFWIDTH | LCMAP_KATAKANA, japanese_text, -1, NULL, 0);
2703 ok(ret == ret2, "%s ret %d, expected value %d\n", func_name, ret, ret2);
2704
2705 /* LCMAP_HALFWIDTH | LCMAP_HIRAGANA maps to Hiragana first */
2706 ret = func_ptr(LCMAP_HALFWIDTH | LCMAP_HIRAGANA, japanese_text, -1, buf, ARRAY_SIZE(buf));
2707 ret2 = func_ptr(LCMAP_HALFWIDTH, hiragana_text, -1, buf2, ARRAY_SIZE(buf2));
2708 ok(ret == ret2, "%s ret %d, expected value %d\n", func_name, ret, ret2);
2709 ok(!lstrcmpW(buf, buf2), "%s string compare mismatch %s vs %s\n", func_name, debugstr_w(buf), debugstr_w(buf2));
2710
2711 /* test buffer overflow */
2712 SetLastError(0xdeadbeef);
2714 lower_case, -1, buf, 4);
2716 "%s should return 0 and ERROR_INSUFFICIENT_BUFFER, got %d\n", func_name, ret);
2717
2718 /* KATAKANA LETTER GA (U+30AC) is converted into two half-width characters.
2719 Thus, it requires two WCHARs. */
2720 buf[0] = 0x30ac;
2721 SetLastError(0xdeadbeef);
2722 ret = func_ptr(LCMAP_HALFWIDTH, buf, 1, buf2, 1);
2724 "%s should return 0 and ERROR_INSUFFICIENT_BUFFER, got %d\n", func_name, ret);
2725
2726 buf[0] = 'a';
2727 buf[1] = 0x30ac;
2729 ok(ret == 3, "%s ret %d, expected value 3\n", func_name, ret);
2730
2731 SetLastError(0xdeadbeef);
2734 "%s should return 0 and ERROR_INSUFFICIENT_BUFFER, got %d\n", func_name, ret);
2735
2736 SetLastError(0xdeadbeef);
2739 "%s should return 0 and ERROR_INSUFFICIENT_BUFFER, got %d\n", func_name, ret);
2740
2742 ok(ret == 3, "%s ret %d, expected value 3\n", func_name, ret);
2743
2745 ok(ret == 3, "%s ret %d, expected value 3\n", func_name, ret);
2746
2747 /* LCMAP_UPPERCASE or LCMAP_LOWERCASE should accept src == dst */
2750 ok(ret == lstrlenW(lower_case) + 1, "%s ret %d, error %ld, expected value %d\n", func_name,
2752 ok(!lstrcmpW(buf, upper_case), "%s string compare mismatch\n", func_name);
2753
2756 ok(ret == lstrlenW(upper_case) + 1, "%s ret %d, error %ld, expected value %d\n", func_name,
2758 ok(!lstrcmpW(buf, lower_case), "%s string compare mismatch\n", func_name);
2759
2760 /* otherwise src == dst should fail */
2761 SetLastError(0xdeadbeef);
2763 buf, 10, buf, sizeof(buf));
2764 ok(GetLastError() == ERROR_INVALID_FLAGS /* NT */ ||
2765 GetLastError() == ERROR_INVALID_PARAMETER /* Win7+ */,
2766 "%s unexpected error code %ld\n", func_name, GetLastError());
2767 ok(!ret, "%s src == dst without LCMAP_UPPERCASE or LCMAP_LOWERCASE must fail\n", func_name);
2768
2769 /* test whether '\0' is always appended */
2771 upper_case, -1, buf, sizeof(buf));
2772 ok(ret, "%s func_ptr must succeed\n", func_name);
2773 ret2 = func_ptr(LCMAP_SORTKEY,
2774 upper_case, lstrlenW(upper_case), buf2, sizeof(buf2));
2775 ok(ret, "%s func_ptr must succeed\n", func_name);
2776 ok(ret == ret2, "%s lengths of sort keys must be equal\n", func_name);
2777 ok(!memcmp(p_buf, p_buf2, ret), "%s sort keys must be equal\n", func_name);
2778
2779 /* test contents with short buffer */
2780#if defined(__REACTOS__) && defined(_WIN64)
2781 if (is_reactos()) {
2782 ok(FALSE, "FIXME: These tests crash on ReactOS x64\n");
2783 } else {
2784#endif
2785 memset( buf, 0xcc, sizeof(buf) );
2787 ok( !ret, "%s succeeded with %u\n", func_name, ret );
2788 ok( GetLastError() == ERROR_INSUFFICIENT_BUFFER, "%s wrong error %lu\n", func_name, GetLastError() );
2789 ret = (char *)memchr( p_buf, 0xcc, sizeof(buf) ) - p_buf;
2790 ok( ret, "%s buffer not filled\n", func_name );
2791 ok( p_buf[ret - 1] == 0x01, "%s buffer filled up to %02x\n", func_name, (BYTE)p_buf[ret - 1] );
2792 ok( !memcmp( p_buf, p_buf2, ret - 1 ), "%s buffers differ\n", func_name );
2793
2794 memset( buf, 0xcc, sizeof(buf) );
2795 ret = func_ptr(LCMAP_SORTKEY, upper_case, -1, buf, ret2 - 20);
2796 ok( !ret, "%s succeeded with %u\n", func_name, ret );
2797 ok( GetLastError() == ERROR_INSUFFICIENT_BUFFER, "%s wrong error %lu\n", func_name, GetLastError() );
2798 ret = (char *)memchr( p_buf, 0xcc, sizeof(buf) ) - p_buf;
2799 ok( ret, "%s buffer not filled\n", func_name );
2800 ok( p_buf[ret - 1] == 0x01, "%s buffer filled up to %02x\n", func_name, (BYTE)p_buf[ret - 1] );
2801 ok( !memcmp( p_buf, p_buf2, ret - 1 ), "%s buffers differ\n", func_name );
2802#if defined(__REACTOS__) && defined(_WIN64)
2803 }
2804#endif
2805
2806 /* test LCMAP_SORTKEY | NORM_IGNORECASE */
2808 upper_case, -1, buf, sizeof(buf));
2809 ok(ret, "%s func_ptr must succeed\n", func_name);
2810 ret2 = func_ptr(LCMAP_SORTKEY,
2811 lower_case, -1, buf2, sizeof(buf2));
2812 ok(ret2, "%s func_ptr must succeed\n", func_name);
2813 ok(ret == ret2, "%s lengths of sort keys must be equal\n", func_name);
2814 ok(!memcmp(p_buf, p_buf2, ret), "%s sort keys must be equal\n", func_name);
2815
2816 /* Don't test LCMAP_SORTKEY | NORM_IGNORENONSPACE, produces different
2817 results from plain LCMAP_SORTKEY on Vista */
2818
2819 /* test LCMAP_SORTKEY | NORM_IGNORESYMBOLS */
2821 lower_case, -1, buf, sizeof(buf));
2822 ok(ret, "%s func_ptr must succeed\n", func_name);
2823 ret2 = func_ptr(LCMAP_SORTKEY,
2824 symbols_stripped, -1, buf2, sizeof(buf2));
2825 ok(ret2, "%s func_ptr must succeed\n", func_name);
2826 ok(ret == ret2, "%s lengths of sort keys must be equal\n", func_name);
2827 ok(!memcmp(p_buf, p_buf2, ret), "%s sort keys must be equal\n", func_name);
2828
2829 /* test NORM_IGNORENONSPACE */
2830 lstrcpyW(buf, fooW);
2832 ok(ret == lstrlenW(lower_case) + 1, "%s func_ptr should return %d, ret = %d\n", func_name,
2833 lstrlenW(lower_case) + 1, ret);
2834 ok(!lstrcmpW(buf, lower_case), "%s string comparison mismatch\n", func_name);
2835
2836 lstrcpyW(buf, fooW);
2837 ret = func_ptr(NORM_IGNORENONSPACE, accents_text, -1, buf, ARRAY_SIZE(buf));
2838 ok(ret == lstrlenW(buf) + 1, "%s func_ptr should return %d, ret = %d\n", func_name,
2839 lstrlenW(buf) + 1, ret);
2840 ok(!lstrcmpW(buf, accents_result), "%s string comparison mismatch %s\n", func_name, debugstr_w(buf));
2841
2842 /* test NORM_IGNORESYMBOLS */
2843 lstrcpyW(buf, fooW);
2845 ok(ret == lstrlenW(symbols_stripped) + 1, "%s func_ptr should return %d, ret = %d\n", func_name,
2847 ok(!lstrcmpW(buf, symbols_stripped), "%s string comparison mismatch\n", func_name);
2848
2849 /* test NORM_IGNORESYMBOLS | NORM_IGNORENONSPACE */
2850 lstrcpyW(buf, fooW);
2852 ok(ret == lstrlenW(symbols_stripped) + 1, "%s func_ptr should return %d, ret = %d\n", func_name,
2854 ok(!lstrcmpW(buf, symbols_stripped), "%s string comparison mismatch\n", func_name);
2855
2856 lstrcpyW(buf, fooW);
2858 ok(ret == lstrlenW(buf) + 1, "%s func_ptr should return %d, ret = %d\n", func_name,
2859 lstrlenW(buf) + 1, ret);
2860 ok(!lstrcmpW(buf, accents_result2), "%s string comparison mismatch %s\n", func_name, debugstr_w(buf));
2861
2862 /* test small buffer */
2863 lstrcpyW(buf, fooW);
2865 ok(ret == 0, "Expected a failure\n");
2867 "%s unexpected error code %ld\n", func_name, GetLastError());
2868
2869 /* test srclen = 0 */
2870 SetLastError(0xdeadbeef);
2872 ok(!ret, "%s func_ptr should fail with srclen = 0\n", func_name);
2874 "%s unexpected error code %ld\n", func_name, GetLastError());
2875}
2876
2878{
2880}
2881
2882static void test_LCMapStringW(void)
2883{
2884 int ret;
2885 WCHAR buf[256];
2886
2887 trace("testing LCMapStringW\n");
2888
2889 SetLastError(0xdeadbeef);
2891 ok(!ret, "LCMapStringW should fail with bad lcid\n");
2892 ok(GetLastError() == ERROR_INVALID_PARAMETER, "unexpected error code %ld\n", GetLastError());
2893
2894 SetLastError(0xdeadbeef);
2896 ok(!ret, "LCMapStringW should fail with bad lcid\n");
2897 ok(GetLastError() == ERROR_INVALID_PARAMETER, "unexpected error code %ld\n", GetLastError());
2898
2900}
2901
2903{
2904 return pLCMapStringEx(LOCALE_NAME_USER_DEFAULT, flags, src, srclen, dst, dstlen, NULL, NULL, 0);
2905}
2906
2907static void test_LCMapStringEx(void)
2908{
2909 int ret;
2910 WCHAR buf[256];
2911
2912 if (!pLCMapStringEx)
2913 {
2914 win_skip( "LCMapStringEx not available\n" );
2915 return;
2916 }
2917
2918 trace("testing LCMapStringEx\n");
2919
2920 SetLastError(0xdeadbeef);
2921 ret = pLCMapStringEx(invalidW, LCMAP_LOWERCASE,
2922 upper_case, -1, buf, ARRAY_SIZE(buf), NULL, NULL, 0);
2923 ok(!ret, "LCMapStringEx should fail with bad locale name\n");
2924 ok(GetLastError() == ERROR_INVALID_PARAMETER, "unexpected error code %ld\n", GetLastError());
2925
2926 SetLastError(0xdeadbeef);
2927 ret = pLCMapStringEx(invalidW, LCMAP_HIRAGANA,
2928 upper_case, -1, buf, ARRAY_SIZE(buf), NULL, NULL, 0);
2929#ifdef __REACTOS__
2930 ok(ret || broken(GetNTVersion() == _WIN32_WINNT_VISTA), "LCMapStringEx should not fail with bad locale name\n");
2931#else
2932 ok(ret, "LCMapStringEx should not fail with bad locale name\n");
2933#endif
2934
2935 /* test reserved parameters */
2937 upper_case, -1, buf, ARRAY_SIZE(buf), NULL, NULL, 1);
2938 ok(ret == lstrlenW(upper_case) + 1, "ret %d, error %ld, expected value %d\n",
2940 ok(!lstrcmpW(buf, lower_case), "string compare mismatch\n");
2941
2943 upper_case, -1, buf, ARRAY_SIZE(buf), NULL, (void*)1, 0);
2944 ok(ret == lstrlenW(upper_case) + 1, "ret %d, error %ld, expected value %d\n",
2946 ok(!lstrcmpW(buf, lower_case), "string compare mismatch\n");
2947
2948 /* crashes on native */
2949 if(0)
2951 upper_case, -1, buf, ARRAY_SIZE(buf), (void*)1, NULL, 0);
2952
2954}
2955
2960};
2961
2963 { {'a','r',0}, {'a','r','-','S','A',0}, MAKELCID(MAKELANGID(LANG_ARABIC, SUBLANG_ARABIC_SAUDI_ARABIA), SORT_DEFAULT) },
2964 { {'a','z',0}, {'a','z','-','L','a','t','n','-','A','Z',0}, MAKELCID(MAKELANGID(LANG_AZERI, SUBLANG_AZERI_LATIN), SORT_DEFAULT) },
2965 { {'d','e',0}, {'d','e','-','D','E',0}, MAKELCID(MAKELANGID(LANG_GERMAN, SUBLANG_GERMAN), SORT_DEFAULT) },
2966 { {'e','n',0}, {'e','n','-','U','S',0}, MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT) },
2967 { {'e','s',0}, {'e','s','-','E','S',0}, MAKELCID(MAKELANGID(LANG_SPANISH, SUBLANG_SPANISH_MODERN), SORT_DEFAULT) },
2968 { {'g','a',0}, {'g','a','-','I','E',0}, MAKELCID(MAKELANGID(LANG_IRISH, SUBLANG_IRISH_IRELAND), SORT_DEFAULT) },
2969 { {'i','t',0}, {'i','t','-','I','T',0}, MAKELCID(MAKELANGID(LANG_ITALIAN, SUBLANG_ITALIAN), SORT_DEFAULT) },
2970 { {'m','s',0}, {'m','s','-','M','Y',0}, MAKELCID(MAKELANGID(LANG_MALAY, SUBLANG_MALAY_MALAYSIA), SORT_DEFAULT) },
2971 { {'n','l',0}, {'n','l','-','N','L',0}, MAKELCID(MAKELANGID(LANG_DUTCH, SUBLANG_DUTCH), SORT_DEFAULT) },
2972 { {'p','t',0}, {'p','t','-','B','R',0}, MAKELCID(MAKELANGID(LANG_PORTUGUESE, SUBLANG_PORTUGUESE_BRAZILIAN), SORT_DEFAULT) },
2973 { {'s','r',0}, {'s','r','-','L','a','t','n','-','R','S',0}, MAKELCID(MAKELANGID(LANG_SERBIAN, SUBLANG_SERBIAN_SERBIA_LATIN), SORT_DEFAULT) },
2974 { {'s','v',0}, {'s','v','-','S','E',0}, MAKELCID(MAKELANGID(LANG_SWEDISH, SUBLANG_SWEDISH), SORT_DEFAULT) },
2975 { {'u','z',0}, {'u','z','-','L','a','t','n','-','U','Z',0}, MAKELCID(MAKELANGID(LANG_UZBEK, SUBLANG_UZBEK_LATIN), SORT_DEFAULT) },
2976 { {'z','h',0}, {'z','h','-','C','N',0}, MAKELCID(MAKELANGID(LANG_CHINESE, SUBLANG_CHINESE_SIMPLIFIED), SORT_DEFAULT) },
2977 { {0} }
2978};
2979
2980static void test_LocaleNameToLCID(void)
2981{
2982 LCID lcid, expect;
2984 INT ret;
2987 const struct neutralsublang_name_t *ptr;
2988
2989 if (!pLocaleNameToLCID)
2990 {
2991 win_skip( "LocaleNameToLCID not available\n" );
2992 return;
2993 }
2994#if defined(__REACTOS__) && defined(_WIN64)
2995 if (is_reactos()) {
2996 ok(FALSE, "FIXME: Most of test_LocaleNameToLCID() crashes on ReactOS x64\n");
2997 return;
2998 }
2999#endif
3000
3001 /* special cases */
3002 buffer[0] = 0;
3003 SetLastError(0xdeadbeef);
3006 "Expected lcid == %08lx, got %08lx, error %ld\n", GetUserDefaultLCID(), lcid, GetLastError());
3007 ret = pLCIDToLocaleName(lcid, buffer, LOCALE_NAME_MAX_LENGTH, 0);
3008 ok(ret > 0, "Expected ret > 0, got %d, error %ld\n", ret, GetLastError());
3009 trace("%08lx, %s\n", lcid, wine_dbgstr_w(buffer));
3010
3011 buffer[0] = 0;
3012 SetLastError(0xdeadbeef);
3013#if !defined(__REACTOS__) || DLL_EXPORT_VERSION >= 0x600
3014 lcid = LocaleNameToLCID(LOCALE_NAME_SYSTEM_DEFAULT, 0);
3016#if defined(__REACTOS__) && defined(_WIN64)
3017 ok(lcid == expect || broken(lcid == 0) /* x86_64 */, "Expected lcid == %08lx, got %08lx, error %ld\n", expect, lcid, GetLastError());
3018#else
3019 ok(lcid == expect, "Expected lcid == %08lx, got %08lx, error %ld\n", expect, lcid, GetLastError());
3020#endif
3021#endif
3022 ret = pLCIDToLocaleName(lcid, buffer, LOCALE_NAME_MAX_LENGTH, 0);
3023 ok(ret > 0, "Expected ret > 0, got %d, error %ld\n", ret, GetLastError());
3024 trace("%08lx, %s\n", lcid, wine_dbgstr_w(buffer));
3025
3026 buffer[0] = 0;
3027 SetLastError(0xdeadbeef);
3028 lcid = pLocaleNameToLCID(LOCALE_NAME_INVARIANT, 0);
3029 ok(lcid == 0x7F, "Expected lcid = 0x7F, got %08lx, error %ld\n", lcid, GetLastError());
3030 ret = pLCIDToLocaleName(lcid, buffer, LOCALE_NAME_MAX_LENGTH, 0);
3031 ok(ret > 0, "Expected ret > 0, got %d, error %ld\n", ret, GetLastError());
3032 trace("%08lx, %s\n", lcid, wine_dbgstr_w(buffer));
3033
3034 pLCIDToLocaleName(GetUserDefaultLCID(), expbuff, LOCALE_NAME_MAX_LENGTH, 0);
3035 ret = pLCIDToLocaleName(LOCALE_NEUTRAL, buffer, LOCALE_NAME_MAX_LENGTH, 0);
3036 ok(ret > 0, "Expected ret > 0, got %d, error %ld\n", ret, GetLastError());
3037 ok( !wcscmp( buffer, expbuff ), "got %s / %s\n", debugstr_w(buffer), debugstr_w(expbuff));
3038
3039 ret = pLCIDToLocaleName(LOCALE_CUSTOM_DEFAULT, buffer, LOCALE_NAME_MAX_LENGTH, 0);
3040 ok(ret > 0, "Expected ret > 0, got %d, error %ld\n", ret, GetLastError());
3041 ok( !wcscmp( buffer, expbuff ), "got %s / %s\n", debugstr_w(buffer), debugstr_w(expbuff));
3042
3043 SetLastError( 0xdeadbeef );
3045 ok(ret > 0 || broken(!ret), /* <= win8 */ "Expected ret > 0, got %d, error %ld\n", ret, GetLastError());
3046 if (ret) ok( !wcscmp( buffer, expbuff ), "got %s / %s\n", debugstr_w(buffer), debugstr_w(expbuff));
3047
3048 SetLastError( 0xdeadbeef );
3050 if (ret) trace("%08x, %s\n", GetUserDefaultUILanguage(), wine_dbgstr_w(buffer));
3051 else ok( GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %lu\n", GetLastError());
3052
3053 /* bad name */
3054 SetLastError(0xdeadbeef);
3057 "Expected lcid == 0, got %08lx, error %ld\n", lcid, GetLastError());
3058
3059 /* lower-case */
3060 lcid = pLocaleNameToLCID(L"es-es", 0);
3061 ok(lcid == MAKELCID(MAKELANGID(LANG_SPANISH, SUBLANG_SPANISH_MODERN), SORT_DEFAULT), "Got wrong lcid for es-es: 0x%lx\n", lcid);
3062
3063 /* english neutral name */
3066 broken(lcid == 0) /* Vista */, "got 0x%04lx\n", lcid);
3067 lcid = pLocaleNameToLCID(L"en", 0);
3069 broken(lcid == 0) /* Vista */, "got 0x%04lx\n", lcid);
3070 if (lcid)
3071 {
3072 for (ptr = neutralsublang_names; *ptr->name; ptr++)
3073 {
3074 lcid = pLocaleNameToLCID(ptr->name, 0);
3075 ok(lcid == ptr->lcid, "%s: got wrong lcid 0x%04lx, expected 0x%04lx\n",
3076 wine_dbgstr_w(ptr->name), lcid, ptr->lcid);
3077
3078 *buffer = 0;
3079 ret = pLCIDToLocaleName(lcid, buffer, ARRAY_SIZE(buffer), 0);
3080 ok(ret > 0, "%s: got %d\n", wine_dbgstr_w(ptr->name), ret);
3081 ok(!lstrcmpW(ptr->sname, buffer), "%s: got wrong locale name %s\n",
3083
3084 }
3085
3086 /* zh-Hant has LCID 0x7c04, but LocaleNameToLCID actually returns 0x0c04, which is the LCID of zh-HK */
3087 lcid = pLocaleNameToLCID(L"zh-Hant", 0);
3089 "%s: got wrong lcid 0x%04lx\n", wine_dbgstr_w(L"zh-Hant"), lcid);
3090 ret = pLCIDToLocaleName(lcid, buffer, ARRAY_SIZE(buffer), 0);
3091 ok(ret > 0, "%s: got %d\n", wine_dbgstr_w(L"zh-Hant"), ret);
3092 ok(!lstrcmpW(L"zh-HK", buffer), "%s: got wrong locale name %s\n",
3093 wine_dbgstr_w(L"zh-Hant"), wine_dbgstr_w(buffer));
3094 /* check that 0x7c04 also works and is mapped to zh-HK */
3096 buffer, ARRAY_SIZE(buffer), 0);
3097 ok(ret > 0, "%s: got %d\n", wine_dbgstr_w(L"zh-Hant"), ret);
3098 ok(!lstrcmpW(L"zh-HK", buffer), "%s: got wrong locale name %s\n",
3099 wine_dbgstr_w(L"zh-Hant"), wine_dbgstr_w(buffer));
3100
3101 /* zh-hant */
3102 lcid = pLocaleNameToLCID(L"zh-hant", 0);
3104 "%s: got wrong lcid 0x%04lx\n", wine_dbgstr_w(L"zh-hant"), lcid);
3105 ret = pLCIDToLocaleName(lcid, buffer, ARRAY_SIZE(buffer), 0);
3106 ok(ret > 0, "%s: got %d\n", wine_dbgstr_w(L"zh-hant"), ret);
3107 ok(!lstrcmpW(L"zh-HK", buffer), "%s: got wrong locale name %s\n",
3108 wine_dbgstr_w(L"zh-hant"), wine_dbgstr_w(buffer));
3109
3110 /* zh-Hans has LCID 0x0004, but LocaleNameToLCID actually returns 0x0804, which is the LCID of zh-CN */
3111 lcid = pLocaleNameToLCID(L"zh-Hans", 0);
3112 /* check that LocaleNameToLCID actually returns 0x0804 */
3114 "%s: got wrong lcid 0x%04lx\n", wine_dbgstr_w(L"zh-Hans"), lcid);
3115 ret = pLCIDToLocaleName(lcid, buffer, ARRAY_SIZE(buffer), 0);
3116 ok(ret > 0, "%s: got %d\n", wine_dbgstr_w(L"zh-Hans"), ret);
3117 ok(!lstrcmpW(L"zh-CN", buffer), "%s: got wrong locale name %s\n",
3118 wine_dbgstr_w(L"zh-Hans"), wine_dbgstr_w(buffer));
3119 /* check that 0x0004 also works and is mapped to zh-CN */
3120 ret = pLCIDToLocaleName(MAKELANGID(LANG_CHINESE, SUBLANG_NEUTRAL), buffer, ARRAY_SIZE(buffer), 0);
3121 ok(ret > 0, "%s: got %d\n", wine_dbgstr_w(L"zh-Hans"), ret);
3122 ok(!lstrcmpW(L"zh-CN", buffer), "%s: got wrong locale name %s\n",
3123 wine_dbgstr_w(L"zh-Hans"), wine_dbgstr_w(buffer));
3124
3125 /* zh-hans */
3126 lcid = pLocaleNameToLCID(L"zh-hans", 0);
3128 "%s: got wrong lcid 0x%04lx\n", wine_dbgstr_w(L"zh-hans"), lcid);
3129 ret = pLCIDToLocaleName(lcid, buffer, ARRAY_SIZE(buffer), 0);
3130 ok(ret > 0, "%s: got %d\n", wine_dbgstr_w(L"zh-hans"), ret);
3131 ok(!lstrcmpW(L"zh-CN", buffer), "%s: got wrong locale name %s\n",
3132 wine_dbgstr_w(L"zh-hans"), wine_dbgstr_w(buffer));
3133
3134 /* de-DE_phoneb */
3135 lcid = pLocaleNameToLCID(L"de-DE_phoneb", 0);
3137 "%s: got wrong lcid 0x%04lx\n", wine_dbgstr_w(L"zh-hans"), lcid);
3138 ret = pLCIDToLocaleName(lcid, buffer, ARRAY_SIZE(buffer), 0);
3139 ok(!lstrcmpW(L"de-DE_phoneb", buffer), "got wrong locale name %s\n",
3141 }
3142
3144 {
3146 ok( status == STATUS_INVALID_PARAMETER_1, "wrong error %lx\n", status );
3147 status = pRtlLocaleNameToLcid( LOCALE_NAME_SYSTEM_DEFAULT, &lcid, 0 );
3148 ok( status == STATUS_INVALID_PARAMETER_1, "wrong error %lx\n", status );
3150 ok( status == STATUS_INVALID_PARAMETER_1, "wrong error %lx\n", status );
3151
3152 lcid = 0;
3153 status = pRtlLocaleNameToLcid( LOCALE_NAME_INVARIANT, &lcid, 0 );
3154 ok( !status, "failed error %lx\n", status );
3155 ok( lcid == LANG_INVARIANT, "got %08lx\n", lcid );
3156
3157 lcid = 0;
3159 ok( !status, "failed error %lx\n", status );
3160 ok( lcid == MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), "got %08lx\n", lcid );
3161
3162 lcid = 0;
3163 status = pRtlLocaleNameToLcid( L"es-es", &lcid, 0 );
3164 ok( !status, "failed error %lx\n", status );
3165 ok( lcid == MAKELANGID(LANG_SPANISH, SUBLANG_SPANISH_MODERN), "got %08lx\n", lcid );
3166
3167 lcid = 0;
3168 status = pRtlLocaleNameToLcid( L"de-DE_phoneb", &lcid, 0 );
3169 ok( !status, "failed error %lx\n", status );
3170 ok( lcid == 0x00010407, "got %08lx\n", lcid );
3171
3172 lcid = 0;
3173 status = pRtlLocaleNameToLcid( L"DE_de-PHONEB", &lcid, 0 );
3174 ok( !status || broken( status == STATUS_INVALID_PARAMETER_1 ), "failed error %lx\n", status );
3175 if (!status) ok( lcid == 0x00010407, "got %08lx\n", lcid );
3176
3177 lcid = 0xdeadbeef;
3178 status = pRtlLocaleNameToLcid( L"de+de+phoneb", &lcid, 0 );
3179 ok( status == STATUS_INVALID_PARAMETER_1, "failed error %lx\n", status );
3180 ok( lcid == 0xdeadbeef, "got %08lx\n", lcid );
3181
3182 lcid = 0;
3183 status = pRtlLocaleNameToLcid( L"en", &lcid, 0 );
3184 ok( status == STATUS_INVALID_PARAMETER_1, "wrong error %lx\n", status );
3185 status = pRtlLocaleNameToLcid( L"en", &lcid, 1 );
3186 ok( status == STATUS_INVALID_PARAMETER_1, "wrong error %lx\n", status );
3187 status = pRtlLocaleNameToLcid( L"en", &lcid, 2 );
3188 ok( !status, "failed error %lx\n", status );
3189 ok( lcid == MAKELANGID(LANG_ENGLISH, SUBLANG_NEUTRAL), "got %08lx\n", lcid );
3190 status = pRtlLocaleNameToLcid( L"en-RR", &lcid, 2 );
3191 ok( status == STATUS_INVALID_PARAMETER_1, "wrong error %lx\n", status );
3192 status = pRtlLocaleNameToLcid( L"en-Latn-RR", &lcid, 2 );
3193 ok( status == STATUS_INVALID_PARAMETER_1, "wrong error %lx\n", status );
3194
3195 for (ptr = neutralsublang_names; *ptr->name; ptr++)
3196 {
3197 switch (LANGIDFROMLCID(ptr->lcid))
3198 {
3201 case MAKELANGID( LANG_CHINESE, SUBLANG_CHINESE_SIMPLIFIED ): expect = 0x7804; break;
3203 default: expect = MAKELANGID( PRIMARYLANGID(ptr->lcid), SUBLANG_NEUTRAL ); break;
3204 }
3205
3206 status = pRtlLocaleNameToLcid( ptr->name, &lcid, 2 );
3208 "%s failed error %lx\n", wine_dbgstr_w(ptr->name), status );
3209 if (!status) ok( lcid == expect, "%s: got wrong lcid 0x%04lx, expected 0x%04lx\n",
3210 wine_dbgstr_w(ptr->name), lcid, expect );
3211 status = pRtlLocaleNameToLcid( ptr->sname, &lcid, 0 );
3213 "%s failed error %lx\n", wine_dbgstr_w(ptr->name), status );
3214 if (!status) ok( lcid == ptr->lcid, "%s: got wrong lcid 0x%04lx, expected 0x%04lx\n",
3215 wine_dbgstr_w(ptr->name), lcid, ptr->lcid );
3216 }
3217 }
3218 else win_skip( "RtlLocaleNameToLcid not available\n" );
3219
3221 {
3222#if !defined(__REACTOS__) || DLL_EXPORT_VERSION >= 0x600
3223 WCHAR buffer[128], expect[128];
3224#else
3225 WCHAR buffer[128];
3226#endif
3228
3229 str.Buffer = buffer;
3230 str.MaximumLength = sizeof( buffer );
3231 memset( buffer, 0xcc, sizeof(buffer) );
3232
3233 ok( !IsValidLocale( LOCALE_NEUTRAL, 0 ), "expected invalid\n" );
3235 ok( status == STATUS_INVALID_PARAMETER_1, "wrong error %lx\n", status );
3237 ok( status == STATUS_INVALID_PARAMETER_1, "wrong error %lx\n", status );
3239 ok( status == STATUS_INVALID_PARAMETER_2, "wrong error %lx\n", status );
3240
3241 memset( buffer, 0xcc, sizeof(buffer) );
3243 ok( status == STATUS_SUCCESS, "wrong error %lx\n", status );
3244 ok( !wcscmp( buffer, L"en-US" ), "wrong name %s\n", debugstr_w(buffer) );
3245 ok( str.Length == wcslen(buffer) * sizeof(WCHAR), "wrong len %u\n", str.Length );
3246 ok( str.MaximumLength == sizeof(buffer), "wrong max len %u\n", str.MaximumLength );
3247
3249 ok( status == STATUS_INVALID_PARAMETER_1, "wrong error %lx\n", status );
3250
3251 memset( buffer, 0xcc, sizeof(buffer) );
3253 ok( status == STATUS_SUCCESS, "wrong error %lx\n", status );
3254 ok( str.Length == wcslen(buffer) * sizeof(WCHAR), "wrong len %u\n", str.Length );
3255 ok( !wcscmp( buffer, L"en" ), "wrong name %s\n", debugstr_w(buffer) );
3256
3257 ok( IsValidLocale( 0x00010407, 0 ), "expected valid\n" );
3258 memset( buffer, 0xcc, sizeof(buffer) );
3259 status = pRtlLcidToLocaleName( 0x00010407, &str, 0, 0 );
3260 ok( status == STATUS_SUCCESS, "wrong error %lx\n", status );
3261 ok( str.Length == wcslen(buffer) * sizeof(WCHAR), "wrong len %u\n", str.Length );
3262 ok( !wcscmp( buffer, L"de-DE_phoneb" ), "wrong name %s\n", debugstr_w(buffer) );
3263
3264 ok( !IsValidLocale( LOCALE_SYSTEM_DEFAULT, 0 ), "expected invalid\n" );
3265 memset( buffer, 0xcc, sizeof(buffer) );
3267 ok( status == STATUS_SUCCESS, "wrong error %lx\n", status );
3268 ok( str.Length == wcslen(buffer) * sizeof(WCHAR), "wrong len %u\n", str.Length );
3269#if !defined(__REACTOS__) || DLL_EXPORT_VERSION >= 0x600
3271 ok( !wcscmp( buffer, expect ), "wrong name %s / %s\n", debugstr_w(buffer), debugstr_w(expect) );
3272#endif
3273
3274 ok( !IsValidLocale( LOCALE_USER_DEFAULT, 0 ), "expected invalid\n" );
3275 memset( buffer, 0xcc, sizeof(buffer) );
3277 ok( status == STATUS_SUCCESS, "wrong error %lx\n", status );
3278 ok( str.Length == wcslen(buffer) * sizeof(WCHAR), "wrong len %u\n", str.Length );
3279#if !defined(__REACTOS__) || DLL_EXPORT_VERSION >= 0x600
3281 ok( !wcscmp( buffer, expect ), "wrong name %s / %s\n", debugstr_w(buffer), debugstr_w(expect) );
3282#endif
3283
3284 ok( IsValidLocale( LOCALE_INVARIANT, 0 ), "expected valid\n" );
3285 memset( buffer, 0xcc, sizeof(buffer) );
3287 ok( status == STATUS_SUCCESS, "wrong error %lx\n", status );
3288 ok( str.Length == wcslen(buffer) * sizeof(WCHAR), "wrong len %u\n", str.Length );
3289 ok( !wcscmp( buffer, L"" ), "wrong name %s\n", debugstr_w(buffer) );
3290
3291 memset( buffer, 0xcc, sizeof(buffer) );
3293 ok( status == STATUS_SUCCESS, "wrong error %lx\n", status );
3294 ok( str.Length == wcslen(buffer) * sizeof(WCHAR), "wrong len %u\n", str.Length );
3295#if !defined(__REACTOS__) || DLL_EXPORT_VERSION >= 0x600
3297 ok( !wcscmp( buffer, expect ), "wrong name %s / %s\n", debugstr_w(buffer), debugstr_w(expect) );
3298#endif
3299
3301 ok( status == STATUS_SUCCESS || status == STATUS_UNSUCCESSFUL, "wrong error %lx\n", status );
3302
3304 ok( status == STATUS_INVALID_PARAMETER_1, "wrong error %lx\n", status );
3305
3306 memset( buffer, 0xcc, sizeof(buffer) );
3307 str.Length = 0xbeef;
3308 str.MaximumLength = 5 * sizeof(WCHAR);
3309 status = pRtlLcidToLocaleName( 0x00010407, &str, 0, 0 );
3310 ok( status == STATUS_BUFFER_TOO_SMALL, "wrong error %lx\n", status );
3311 ok( str.Length == 0xbeef, "wrong len %u\n", str.Length );
3312 ok( str.MaximumLength == 5 * sizeof(WCHAR), "wrong len %u\n", str.MaximumLength );
3313 ok( buffer[0] == 0xcccc, "wrong name %s\n", debugstr_w(buffer) );
3314
3315 memset( &str, 0xcc, sizeof(str) );
3317 ok( status == STATUS_SUCCESS, "wrong error %lx\n", status );
3318 ok( str.Length == wcslen(str.Buffer) * sizeof(WCHAR), "wrong len %u\n", str.Length );
3319 ok( str.MaximumLength == str.Length + sizeof(WCHAR), "wrong max len %u\n", str.MaximumLength );
3320 ok( !wcscmp( str.Buffer, L"en-US" ), "wrong name %s\n", debugstr_w(str.Buffer) );
3322 }
3323 else win_skip( "RtlLcidToLocaleName not available\n" );
3324
3326 {
3327 void *ret, *ret2;
3328 LCID lcid;
3329
3331 ret = pNlsValidateLocale( &lcid, 0 );
3332 ok( !!ret, "failed for %04lx\n", lcid );
3333 ok( lcid == GetUserDefaultLCID(), "wrong lcid %04lx\n", lcid );
3334
3336 ret = pNlsValidateLocale( &lcid, 0 );
3337 ok( !!ret, "failed for %04lx\n", lcid );
3338 ok( lcid == MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT), "wrong lcid %04lx\n", lcid );
3339
3341 ret2 = pNlsValidateLocale( &lcid, 0 );
3342 ok( !!ret2, "failed for %04lx\n", lcid );
3343 ok( ret == ret2, "got different pointer for neutral\n" );
3344 ok( lcid == MAKELANGID(LANG_ENGLISH, SUBLANG_NEUTRAL), "wrong lcid %04lx\n", lcid );
3345
3348 ok( !!ret2, "failed for %04lx\n", lcid );
3349 ok( ret != ret2, "got same pointer for neutral\n" );
3350 ok( lcid == MAKELANGID(LANG_ENGLISH, SUBLANG_NEUTRAL), "wrong lcid %04lx\n", lcid );
3351
3352 lcid = 0x00010407;
3353 ret = pNlsValidateLocale( &lcid, 0 );
3354 ok( !!ret, "failed for %04lx\n", lcid );
3355 ok( lcid == 0x00010407, "wrong lcid %04lx\n", lcid );
3356
3358 ret = pNlsValidateLocale( &lcid, 0 );
3359 ok( !!ret, "failed for %04lx\n", lcid );
3360 ok( lcid == GetSystemDefaultLCID(), "wrong lcid %04lx\n", lcid );
3361 ret2 = pNlsValidateLocale( &lcid, 0 );
3362 ok( ret == ret2, "got different pointer for system\n" );
3363
3365 ret = pNlsValidateLocale( &lcid, 0 );
3366 ok( !!ret, "failed for %04lx\n", lcid );
3367 ok( lcid == GetUserDefaultLCID(), "wrong lcid %04lx\n", lcid );
3368 ret2 = pNlsValidateLocale( &lcid, 0 );
3369 ok( ret == ret2, "got different pointer for user\n" );
3370
3372 ret = pNlsValidateLocale( &lcid, 0 );
3373 ok( !!ret, "failed for %04lx\n", lcid );
3374 ok( lcid == LOCALE_INVARIANT, "wrong lcid %04lx\n", lcid );
3375 ret2 = pNlsValidateLocale( &lcid, 0 );
3376 ok( ret == ret2, "got different pointer for invariant\n" );
3377
3379 ret = pNlsValidateLocale( &lcid, 0 );
3380 ok( !!ret, "failed for %04lx\n", lcid );
3381 ok( lcid == GetUserDefaultLCID(), "wrong lcid %04lx\n", lcid );
3382 ret2 = pNlsValidateLocale( &lcid, 0 );
3383 ok( ret == ret2, "got different pointer for custom default\n" );
3384
3386 ret = pNlsValidateLocale( &lcid, 0 );
3387 ok( ret || broken(!ret), /* <= win8 */ "failed for %04lx\n", lcid );
3388 if (ret) ok( lcid == GetUserDefaultLCID(), "wrong lcid %04lx\n", lcid );
3389
3390 SetLastError( 0xdeadbeef );
3392 ret = pNlsValidateLocale( &lcid, 0 );
3393 if (!ret) ok( GetLastError() == 0xdeadbeef, "error %lu\n", GetLastError());
3394
3395 lcid = 0xbeef;
3396 ret = pNlsValidateLocale( &lcid, 0 );
3397 ok( !ret, "succeeded\n" );
3398 ok( lcid == 0xbeef, "wrong lcid %04lx\n", lcid );
3399 ok( GetLastError() == 0xdeadbeef, "error %lu\n", GetLastError());
3400 }
3401 else win_skip( "NlsValidateLocale not available\n" );
3402}
3403
3404static const char * const strings_sorted[] =
3405{
3406"'",
3407"-",
3408"!",
3409"\"",
3410".",
3411":",
3412"\\",
3413"_",
3414"`",
3415"{",
3416"}",
3417"+",
3418"0",
3419"1",
3420"2",
3421"3",
3422"4",
3423"5",
3424"6",
3425"7",
3426"8",
3427"9",
3428"a",
3429"A",
3430"b",
3431"B",
3432"c",
3433"C"
3434};
3435
3436static const char * const strings[] =
3437{
3438"C",
3439"\"",
3440"9",
3441"'",
3442"}",
3443"-",
3444"7",
3445"+",
3446"`",
3447"1",
3448"a",
3449"5",
3450"\\",
3451"8",
3452"B",
3453"3",
3454"_",
3455"6",
3456"{",
3457"2",
3458"c",
3459"4",
3460"!",
3461"0",
3462"A",
3463":",
3464"b",
3465"."
3466};
3467
3468static int compare_string1(const void *e1, const void *e2)
3469{
3470 const char *s1 = *(const char *const *)e1;
3471 const char *s2 = *(const char *const *)e2;
3472
3473 return lstrcmpA(s1, s2);
3474}
3475
3476static int compare_string2(const void *e1, const void *e2)
3477{
3478 const char *s1 = *(const char *const *)e1;
3479 const char *s2 = *(const char *const *)e2;
3480
3481 return CompareStringA(0, 0, s1, -1, s2, -1) - 2;
3482}
3483
3484static int compare_string3(const void *e1, const void *e2)
3485{
3486 const char *s1 = *(const char *const *)e1;
3487 const char *s2 = *(const char *const *)e2;
3488 char key1[256], key2[256];
3489
3490 int len1 = LCMapStringA(0, LCMAP_SORTKEY, s1, -1, key1, sizeof(key1));
3491 int len2 = LCMapStringA(0, LCMAP_SORTKEY, s2, -1, key2, sizeof(key2));
3492 int ret = memcmp(key1, key2, min(len1, len2));
3493 if (!ret) ret = len1 - len2;
3494 return ret;
3495}
3496
3497static void test_sorting(void)
3498{
3499 char buf[256];
3500 char **str_buf = (char **)buf;
3501 int i;
3502
3503 assert(sizeof(buf) >= sizeof(strings));
3504
3505 /* 1. sort using lstrcmpA */
3506 memcpy(buf, strings, sizeof(strings));
3508 for (i = 0; i < ARRAY_SIZE(strings); i++)
3509 {
3511 "qsort using lstrcmpA failed for element %d\n", i);
3512 }
3513 /* 2. sort using CompareStringA */
3514 memcpy(buf, strings, sizeof(strings));
3516 for (i = 0; i < ARRAY_SIZE(strings); i++)
3517 {
3519 "qsort using CompareStringA failed for element %d\n", i);
3520 }
3521 /* 3. sort using sort keys */
3522 memcpy(buf, strings, sizeof(strings));
3524 for (i = 0; i < ARRAY_SIZE(strings); i++)
3525 {
3527 "qsort using sort keys failed for element %d\n", i);
3528 }
3529}
3530
3536 const WCHAR *first;
3538};
3539
3541{
3542 /* Normal character */
3543 { L"en-US", -1, CSTR_LESS_THAN, 0, L"\x0037", L"\x277c" },
3544 { L"en-US", 1, CSTR_GREATER_THAN, 0, L"\x1eca", L"\x1ecb" },
3545 { L"en-US", 1, CSTR_GREATER_THAN, 0, L"\x1d05", L"\x1d48" },
3546 /* Normal character diacritics */
3547 { L"en-US", 1, CSTR_GREATER_THAN, 0, L"\x19d7", L"\x096d" },
3548 { L"en-US", -1, CSTR_LESS_THAN, 0, L"\x00f5", L"\x1ecf" },
3549 { L"en-US", -1, CSTR_LESS_THAN, 0, L"\x2793", L"\x0d70" },
3550 /* Normal character case weights */
3551 { L"en-US", 1, CSTR_GREATER_THAN, 0, L"A", L"a" },
3552 { L"en-US", -1, CSTR_LESS_THAN, 0, L"z", L"Z" },
3553 /* PUA character */
3554 { L"en-US", 1, CSTR_GREATER_THAN, 0, L"\xe5a6", L"\xe5a5\x0333" },
3555 { L"en-US", 1, CSTR_GREATER_THAN, 0, L"\xe5d7", L"\xe5d6\x0330" },
3556 /* Symbols add diacritic weight */
3557 { L"en-US", 1, CSTR_GREATER_THAN, 0, L"\u276a", L"\u2768" },
3558 /* Symbols add case weight */
3559 { L"en-US", -1, CSTR_LESS_THAN, 0, L"\u204d", L"\uff02" },
3560 /* Default character, when there is main weight extra there must be no diacritic weight */
3561 { L"en-US", -1, CSTR_LESS_THAN, 0, L"\ue6e3\u0a02", L"\ue6e3\u20dc" },
3562 /* Unsortable characters */
3563 { L"en-US", 0, CSTR_EQUAL, 0, L"a \u2060 b", L"a b" },
3564 /* Invalid/undefined characters */
3565 { L"en-US", 0, CSTR_EQUAL, 0, L"a \xfff0 b", L"a b" },
3566 { L"en-US", 0, CSTR_EQUAL, 0, L"a\x139F a", L"a a" },
3567 { L"en-US", -1, CSTR_LESS_THAN, 0, L"a\x139F a", L"a b" },
3568 /* Default characters */
3569 { L"en-US", -1, CSTR_LESS_THAN, 0, L"\x00fc", L"\x016d" },
3570 { L"en-US", 1, CSTR_GREATER_THAN, 0, L"\x3fcb\x7fd5", L"\x0006\x3032" },
3571 { L"en-US", -1, CSTR_LESS_THAN, 0, L"\x00fc\x30fd", L"\x00fa\x1833" },
3572 /* Diacritic is added */
3573 { L"en-US", 1, CSTR_GREATER_THAN, 0, L"\x1B56\x0330", L"\x1096" },
3574 { L"en-US", 1, CSTR_GREATER_THAN, 0, L"\x1817\x0333", L"\x19d7" },
3575 { L"en-US", 1, CSTR_GREATER_THAN, 0, L"\x04de\x05ac", L"\x0499" },
3576 /* Diacritic can overflow */
3577 { L"en-US", -1, CSTR_LESS_THAN, 0, L"\x01ba\x0654", L"\x01b8" },
3578 { L"en-US", -1, CSTR_LESS_THAN, 0, L"\x06b7\x06eb", L"\x06b6" },
3579 { L"en-US", -1, CSTR_LESS_THAN, 0, L"\x1420\x0333", L"\x141f" },
3580 { L"en-US", 1, CSTR_GREATER_THAN, 0, L"\x1b56\x0654", L"\x1b56\x0655" },
3581 { L"en-US", -1, CSTR_LESS_THAN, 0, L"\x1b56\x0654\x0654", L"\x1b56\x0655" },
3582 /* Jamo case weight */
3583 { L"en-US", 1, CSTR_GREATER_THAN, 0, L"\x11bc", L"\x110b" },
3584 { L"en-US", 1, CSTR_GREATER_THAN, 0, L"\x11c1", L"\x1111" },
3585 { L"en-US", 1, CSTR_GREATER_THAN, 0, L"\x11af", L"\x1105" },
3586 /* Jamo main weight */
3587 { L"en-US", -1, CSTR_LESS_THAN, 0, L"\x11c2", L"\x11f5" },
3588 { L"en-US", -1, CSTR_LESS_THAN, 0, L"\x1108", L"\x1121" },
3589 { L"en-US", -1, CSTR_LESS_THAN, 0, L"\x1116", L"\x11c7" },
3590 { L"en-US", -1, CSTR_LESS_THAN, 0, L"\x11b1", L"\x11d1" },
3591 /* CJK main weight 1 */
3592 { L"en-US", 1, CSTR_GREATER_THAN, 0, L"\x4550\x73d2", L"\x3211\x23ad" },
3593 { L"en-US", -1, CSTR_LESS_THAN, 0, L"\x3265", L"\x4079" },
3594 { L"en-US", 1, CSTR_GREATER_THAN, 0, L"\x4c19\x68d0\x52d0", L"\x316d" },
3595 /* CJK main weight 2 */
3596 { L"en-US", 1, CSTR_GREATER_THAN, 0, L"\x72dd", L"\x6b8a" },
3597 { L"en-US", -1, CSTR_LESS_THAN, 0, L"\x6785\x3bff\x6f83", L"\x7550\x34c9\x71a7" },
3598 { L"en-US", -1, CSTR_LESS_THAN, 0, L"\x5d61", L"\x3aef" },
3599 /* Symbols case weights */
3600 { L"en-US", 1, CSTR_GREATER_THAN, 0, L"\x207a", L"\xfe62" },
3601 { L"en-US", 1, CSTR_GREATER_THAN, 0, L"\xfe65", L"\xff1e" },
3602 { L"en-US", 1, CSTR_GREATER_THAN, 0, L"\x2502", L"\xffe8" },
3603 /* Symbols diacritic weights */
3604 { L"en-US", -1, CSTR_LESS_THAN, 0, L"\x21da", L"\x21dc" },
3605 { L"en-US", -1, CSTR_LESS_THAN, 0, L"\x29fb", L"\x2295" },
3606 { L"en-US", -1, CSTR_LESS_THAN, 0, L"\x0092", L"\x009c" },
3607 /* NORM_IGNORESYMBOLS */
3608 { L"en-US", 0, CSTR_EQUAL, NORM_IGNORESYMBOLS, L"\x21da", L"\x21dc" },
3609 { L"en-US", 0, CSTR_EQUAL, NORM_IGNORESYMBOLS, L"\x29fb", L"\x2295" },
3610 { L"en-US", 0, CSTR_EQUAL, NORM_IGNORESYMBOLS, L"\x0092", L"\x009c" },
3611 { L"en-US", 0, CSTR_EQUAL, 0, L"\x3099", L"\x309b" }, /* Small diacritic weights at the end get ignored */
3612 /* Main weights have priority over diacritic weights */
3613 { L"en-US", 1, CSTR_GREATER_THAN, 0, L"a b", L"\x0103 a" },
3614 { L"en-US", -1, CSTR_LESS_THAN, 0, L"a", L"\x0103" },
3615 { L"en-US", 1, CSTR_GREATER_THAN, 0, L"e x", L"\x0113 v" },
3616 { L"en-US", -1, CSTR_LESS_THAN, 0, L"e", L"\x0113" },
3617 { L"en-US", 1, CSTR_GREATER_THAN, 0, L"c s", L"\x0109 r" },
3618 { L"en-US", -1, CSTR_LESS_THAN, 0, L"c", L"\x0109" },
3619 /* Diacritic weights have priority over case weights */
3620 { L"en-US", 1, CSTR_GREATER_THAN, 0, L"a \x0103", L"A a" },
3621 { L"en-US", -1, CSTR_LESS_THAN, 0, L"a", L"A" },
3622 { L"en-US", 1, CSTR_GREATER_THAN, 0, L"e \x0113", L"E e" },
3623 { L"en-US", -1, CSTR_LESS_THAN, 0, L"e", L"E" },
3624 { L"en-US", 1, CSTR_GREATER_THAN, 0, L"c \x0109", L"C c" },
3625 { L"en-US", -1, CSTR_LESS_THAN, 0, L"c", L"C" },
3626 /* Diacritic values for Jamo are not ignored */
3627 { L"en-US", -1, CSTR_LESS_THAN, NORM_IGNORENONSPACE, L"\x1152", L"\x1153" },
3628 { L"en-US", -1, CSTR_LESS_THAN, NORM_IGNORENONSPACE, L"\x1143", L"\x1145" },
3629 { L"en-US", -1, CSTR_LESS_THAN, NORM_IGNORENONSPACE, L"\x1196", L"\x1174" },
3630 /* Jungseong < PUA */
3631 { L"en-US", -1, CSTR_LESS_THAN, 0, L"\x318e", L"\x382a" },
3632 { L"en-US", -1, CSTR_LESS_THAN, 0, L"\xffcb", L"\x3d13" },
3633 { L"en-US", -1, CSTR_LESS_THAN, 0, L"\xffcc", L"\x8632" },
3634 /* Surrogate > PUA */
3635 { L"en-US", 1, CSTR_GREATER_THAN, 0, L"\xd847", L"\x382a" },
3636 { L"en-US", 1, CSTR_GREATER_THAN, 0, L"\xd879", L"\x3d13" },
3637 { L"en-US", 1, CSTR_GREATER_THAN, 0, L"\xd850", L"\x8632" },
3638 /* Unsortable combined with diacritics */
3639 { L"en-US", 0, CSTR_EQUAL, 0, L"A\x0301\x0301", L"A\x0301\x00ad\x0301" },
3640 { L"en-US", 0, CSTR_EQUAL, 0, L"b\x07f2\x07f2", L"b\x07f2\x2064\x07f2" },
3641 { L"en-US", 0, CSTR_EQUAL, 0, L"X\x0337\x0337", L"X\x0337\xfffd\x0337" },
3642 { L"en-US", 0, CSTR_EQUAL, NORM_IGNORECASE, L"c", L"C" },
3643 { L"en-US", 0, CSTR_EQUAL, NORM_IGNORECASE, L"e", L"E" },
3644 { L"en-US", 0, CSTR_EQUAL, NORM_IGNORECASE, L"A", L"a" },
3645 /* Punctuation primary weight */
3646 { L"en-US", -1, CSTR_LESS_THAN, 0, L"\x001b", L"\x001c" },
3647 { L"en-US", -1, CSTR_LESS_THAN, 0, L"\x0005", L"\x0006" },
3648 /* Punctuation diacritic/case weight */
3649 { L"en-US", -1, CSTR_LESS_THAN, 0, L"\x0027", L"\xff07" },
3650 { L"en-US", -1, CSTR_LESS_THAN, 0, L"\x07f4", L"\x07f5" },
3651 { L"en-US", 1, CSTR_GREATER_THAN, 0, L"\x207b", L"\x0008" },
3652 /* Punctuation primary weight has priority */
3653 { L"en-US", -1, CSTR_LESS_THAN, 0, L"\xff07", L"\x07f4" },
3654 { L"en-US", -1, CSTR_LESS_THAN, 0, L"\xfe32", L"\x2014" },
3655 { L"en-US", -1, CSTR_LESS_THAN, 0, L"\x058a", L"\x2027" },
3656 /* Punctuation */
3657 { L"en-US", 1, CSTR_GREATER_THAN, 0, L"\x207b", L"\x0008" },
3658 { L"en-US", -1, CSTR_LESS_THAN, 0, L"\x0004", L"\x0011" },
3659 { L"en-US", 0, CSTR_EQUAL, NORM_IGNORESYMBOLS, L"\x207b", L"\x0008" },
3660 { L"en-US", 0, CSTR_EQUAL, NORM_IGNORESYMBOLS, L"\x0004", L"\x0011" },
3661 { L"en-US", 1, CSTR_GREATER_THAN, SORT_STRINGSORT, L"\x207b", L"\x0008" },
3662 { L"en-US", -1, CSTR_LESS_THAN, SORT_STRINGSORT, L"\x0004", L"\x0011" },
3663 { L"en-US", 0, CSTR_EQUAL, NORM_IGNORESYMBOLS | SORT_STRINGSORT, L"\x207b", L"\x0008" },
3664 { L"en-US", 0, CSTR_EQUAL, NORM_IGNORESYMBOLS | SORT_STRINGSORT, L"\x0004", L"\x0011" },
3665 /* Punctuation main weight */
3666 { L"en-US", -1, CSTR_LESS_THAN, SORT_STRINGSORT, L"\x001a", L"\x001b" },
3667 { L"en-US", 1, CSTR_GREATER_THAN, SORT_STRINGSORT, L"\x2027", L"\x2011" },
3668 { L"en-US", 1, CSTR_GREATER_THAN, SORT_STRINGSORT, L"\x3030", L"\x301c" },
3669 /* Punctuation diacritic weight */
3670 { L"en-US", 1, CSTR_GREATER_THAN, SORT_STRINGSORT, L"\x058a", L"\x2010" },
3671 { L"en-US", 1, CSTR_GREATER_THAN, SORT_STRINGSORT, L"\x07F5", L"\x07F4" },
3672 /* Punctuation case weight */
3673 { L"en-US", 1, CSTR_GREATER_THAN, SORT_STRINGSORT, L"\xfe32", L"\x2013" },
3674 { L"en-US", 1, CSTR_GREATER_THAN, SORT_STRINGSORT, L"\xfe31", L"\xfe58" },
3675 { L"en-US", 1, CSTR_GREATER_THAN, SORT_STRINGSORT, L"\xff07", L"\x0027" },
3676 /* Punctuation NORM_IGNORESYMBOLS */
3677 { L"en-US", 0, CSTR_EQUAL, NORM_IGNORESYMBOLS, L"\x207b", L"\x0008" },
3678 { L"en-US", 0, CSTR_EQUAL, NORM_IGNORESYMBOLS, L"\x0004", L"\x0011" },
3679 /* Punctuation NORM_IGNORESYMBOLS SORT_STRINGSORT */
3680 { L"en-US", 0, CSTR_EQUAL, NORM_IGNORESYMBOLS | SORT_STRINGSORT, L"\x207b", L"\x0008" },
3681 { L"en-US", 0, CSTR_EQUAL, NORM_IGNORESYMBOLS | SORT_STRINGSORT, L"\x0004", L"\x0011" },
3682 /* Punctuation SORT_STRINGSORT main weight */
3683 { L"en-US", -1, CSTR_LESS_THAN, SORT_STRINGSORT, L"\x001a", L"\x001b" },
3684 { L"en-US", 1, CSTR_GREATER_THAN, SORT_STRINGSORT, L"\x2027", L"\x2011", },
3685 { L"en-US", 1, CSTR_GREATER_THAN, SORT_STRINGSORT, L"\x3030", L"\x301c", },
3686 /* Punctuation SORT_STRINGSORT diacritic weight */
3687 { L"en-US", 1, CSTR_GREATER_THAN, SORT_STRINGSORT, L"\x058a", L"\x2010" },
3688 { L"en-US", 1, CSTR_GREATER_THAN, SORT_STRINGSORT, L"\x07F5", L"\x07F4" },
3689 /* Punctuation SORT_STRINGSORT case weight */
3690 { L"en-US", 1, CSTR_GREATER_THAN, SORT_STRINGSORT, L"\xfe32", L"\x2013" },
3691 { L"en-US", 1, CSTR_GREATER_THAN, SORT_STRINGSORT, L"\xfe31", L"\xfe58" },
3692 { L"en-US", 1, CSTR_GREATER_THAN, SORT_STRINGSORT, L"\xff07", L"\x0027" },
3693 /* Japanese main weight */
3694 { L"en-US", -1, CSTR_LESS_THAN, 0, L"\x04b0", L"\x32db" },
3695 { L"en-US", 1, CSTR_GREATER_THAN, 0, L"\x3093", L"\x1e62\x013f" },
3696 /* Japanese diacritic weight */
3697 { L"en-US", -1, CSTR_LESS_THAN, 0, L"\x30d3", L"\x30d4" },
3698 { L"en-US", -1, CSTR_LESS_THAN, 0, L"\x307b", L"\x307c" },
3699 { L"en-US", -1, CSTR_LESS_THAN, 0, L"\x30ea", L"\x32f7" },
3700 /* Japanese case weight small */
3701 { L"en-US", -1, CSTR_LESS_THAN, 0, L"\x31fb", L"\x30e9" },
3702 { L"en-US", 1, CSTR_GREATER_THAN, 0, L"\x30db", L"\x31f9" },
3703 { L"en-US", -1, CSTR_LESS_THAN, 0, L"\xff6d", L"\xff95" },
3704 { L"en-US", 0, CSTR_EQUAL, NORM_IGNORENONSPACE, L"\x31fb", L"\x30e9" },
3705 { L"en-US", 0, CSTR_EQUAL, NORM_IGNORENONSPACE, L"\x30db", L"\x31f9" },
3706 { L"en-US", 0, CSTR_EQUAL, NORM_IGNORENONSPACE, L"\xff6d", L"\xff95" },
3707 /* Japanese case weight kana */
3708 { L"en-US", -1, CSTR_LESS_THAN, 0, L"\x30d5", L"\x3075" },
3709 { L"en-US", 1, CSTR_GREATER_THAN, 0, L"\x306a", L"\x30ca" },
3710 { L"en-US", 1, CSTR_GREATER_THAN, 0, L"\x305a", L"\x30ba" },
3711 { L"en-US", 0, CSTR_EQUAL, NORM_IGNOREKANATYPE, L"\x30d5", L"\x3075" },
3712 { L"en-US", 0, CSTR_EQUAL, NORM_IGNOREKANATYPE, L"\x306a", L"\x30ca" },
3713 { L"en-US", 0, CSTR_EQUAL, NORM_IGNOREKANATYPE, L"\x305a", L"\x30ba" },
3714 /* Japanese case weight width */
3715 { L"en-US", 1, CSTR_GREATER_THAN, 0, L"\x30bf", L"\xff80" },
3716 { L"en-US", 1, CSTR_GREATER_THAN, 0, L"\x30ab", L"\xff76" },
3717 { L"en-US", 1, CSTR_GREATER_THAN, 0, L"\x30a2", L"\xff71" },
3718 { L"en-US", 0, CSTR_EQUAL, NORM_IGNOREWIDTH, L"\x30bf", L"\xff80" },
3719 { L"en-US", 0, CSTR_EQUAL, NORM_IGNOREWIDTH, L"\x30ab", L"\xff76" },
3720 { L"en-US", 0, CSTR_EQUAL, NORM_IGNOREWIDTH, L"\x30a2", L"\xff71" },
3721 { L"en-US", 0, CSTR_EQUAL, NORM_IGNORENONSPACE, L"\x31a2", L"\x3110" },
3722 { L"en-US", 0, CSTR_EQUAL, NORM_IGNORENONSPACE, L"\x1342", L"\x133a" },
3723 { L"en-US", 0, CSTR_EQUAL, NORM_IGNORENONSPACE, L"\x16a4", L"\x16a5" },
3724 /* Kana small data must have priority over width data */
3725 { L"en-US", -1, CSTR_LESS_THAN, 0, L"\x30b1\x30f6", L"\xff79\x30b1" },
3726 { L"en-US", -1, CSTR_LESS_THAN, 0, L"\x30a6\x30a5", L"\xff73\x30a6" },
3727 { L"en-US", -1, CSTR_LESS_THAN, 0, L"\x30a8\x30a7", L"\xff74\x30a8" },
3728 { L"en-US", 1, CSTR_GREATER_THAN, 0, L"\x30b1", L"\xff79" },
3729 { L"en-US", 1, CSTR_GREATER_THAN, 0, L"\x30a6", L"\xff73" },
3730 { L"en-US", 1, CSTR_GREATER_THAN, 0, L"\x30a8", L"\xff74" },
3731 /* Kana small data must have priority over kana type data */
3732 { L"en-US", -1, CSTR_LESS_THAN, 0, L"\x3046\x30a9", L"\x30a6\x30aa" },
3733 { L"en-US", -1, CSTR_LESS_THAN, 0, L"\x304a\x3041", L"\x30aa\x3042" },
3734 { L"en-US", -1, CSTR_LESS_THAN, 0, L"\x3059\x30a7", L"\x30b9\x30a8" },
3735 { L"en-US", 1, CSTR_GREATER_THAN, 0, L"\x3046", L"\x30a6" },
3736 { L"en-US", 1, CSTR_GREATER_THAN, 0, L"\x304a", L"\x30aa" },
3737 { L"en-US", 1, CSTR_GREATER_THAN, 0, L"\x3059", L"\x30b9" },
3738 /* Kana type data must have priority over width data */
3739 { L"en-US", -1, CSTR_LESS_THAN, 0, L"\x30a6\x30a8", L"\xff73\x3048" },
3740 { L"en-US", -1, CSTR_LESS_THAN, 0, L"\x30ab\x30a3", L"\xff76\x3043" },
3741 { L"en-US", -1, CSTR_LESS_THAN, 0, L"\x30b5\x30ac", L"\xff7b\x304c" },
3742 { L"en-US", 1, CSTR_GREATER_THAN, 0, L"\x30a6", L"\xff73" },
3743 { L"en-US", 1, CSTR_GREATER_THAN, 0, L"\x30ab", L"\xff76" },
3744 { L"en-US", 1, CSTR_GREATER_THAN, 0, L"\x30b5", L"\xff7b" },
3745 /* Case weights have priority over extra weights */
3746 { L"en-US", -1, CSTR_LESS_THAN, 0, L"\x305a a", L"\x30ba A" },
3747 { L"en-US", -1, CSTR_LESS_THAN, 0, L"\x30c1 b", L"\xff81 B" },
3748 { L"en-US", -1, CSTR_LESS_THAN, 0, L"\xff8b x", L"\x31f6 X" },
3749 { L"en-US", 1, CSTR_GREATER_THAN, 0, L"\x305a", L"\x30ba" },
3750 { L"en-US", 1, CSTR_GREATER_THAN, 0, L"\x30c1", L"\xff81" },
3751 { L"en-US", 1, CSTR_GREATER_THAN, 0, L"\xff8b", L"\x31f6" },
3752 /* Extra weights have priority over special weights */
3753 { L"en-US", -1, CSTR_LESS_THAN, 0, L"\x0027\x31ff", L"\x007f\xff9b" },
3754 { L"en-US", -1, CSTR_LESS_THAN, 0, L"\x07f5\x30f3", L"\x07f4\x3093" },
3755 { L"en-US", -1, CSTR_LESS_THAN, 0, L"\xfe63\x30e0", L"\xff0d\x3080" },
3756 { L"en-US", 1, CSTR_GREATER_THAN, 0, L"\x0027", L"\x007f" },
3757 { L"en-US", 1, CSTR_GREATER_THAN, 0, L"\x07f5", L"\x07f4" },
3758 { L"en-US", 1, CSTR_GREATER_THAN, 0, L"\xfe63", L"\xff0d" },
3759 { L"en-US", 0, CSTR_EQUAL, NORM_IGNOREWIDTH, L"\xff68", L"\x30a3" },
3760 { L"en-US", 0, CSTR_EQUAL, NORM_IGNOREWIDTH, L"\xff75", L"\x30aa" },
3761 { L"en-US", 0, CSTR_EQUAL, NORM_IGNOREWIDTH, L"\x30e2", L"\xff93" },
3762 { L"en-US", -1, CSTR_LESS_THAN, 0, L"\xff68", L"\x30a3" },
3763 { L"en-US", -1, CSTR_LESS_THAN, 0, L"\xff75", L"\x30aa" },
3764 { L"en-US", 1, CSTR_GREATER_THAN, 0, L"\x30e2", L"\xff93" },
3765 { L"en-US", 0, CSTR_EQUAL, NORM_IGNOREKANATYPE, L"\x30a8", L"\x3048" },
3766 { L"en-US", 0, CSTR_EQUAL, NORM_IGNOREKANATYPE, L"\x30af", L"\x304f" },
3767 { L"en-US", 0, CSTR_EQUAL, NORM_IGNOREKANATYPE, L"\x3067", L"\x30c7" },
3768 { L"en-US", -1, CSTR_LESS_THAN, 0, L"\x30a8", L"\x3048" },
3769 { L"en-US", -1, CSTR_LESS_THAN, 0, L"\x30af", L"\x304f" },
3770 { L"en-US", 1, CSTR_GREATER_THAN, 0, L"\x3067", L"\x30c7" },
3771 { L"en-US", 0, CSTR_EQUAL, NORM_IGNOREWIDTH, L"\xffb7", L"\x3147" },
3772 { L"en-US", 0, CSTR_EQUAL, NORM_IGNOREWIDTH, L"\xffb6", L"\x3146" },
3773 { L"en-US", 0, CSTR_EQUAL, NORM_IGNOREWIDTH, L"\x3145", L"\xffb5" },
3774 { L"en-US", -1, CSTR_LESS_THAN, NORM_IGNORECASE, L"\xffb7", L"\x3147" },
3775 { L"en-US", -1, CSTR_LESS_THAN, NORM_IGNORECASE, L"\xffb6", L"\x3146" },
3776 { L"en-US", 1, CSTR_GREATER_THAN, NORM_IGNORECASE, L"\x3145", L"\xffb5" },
3777 { L"en-US", 1, CSTR_GREATER_THAN, 0, L"\x3075\x30fc", L"\x30d5\x30fc" },
3778 { L"en-US", -1, CSTR_LESS_THAN, 0, L"\x30a1\x30fc", L"\x30a2\x30fc" },
3779 /* Coptic < Japanese */
3780 { L"en-US", -1, CSTR_LESS_THAN, NORM_IGNORECASE, L"\x2cff", L"\x30ba" },
3781 { L"en-US", -1, CSTR_LESS_THAN, NORM_IGNORECASE, L"\x2cdb", L"\x32de" },
3782 { L"en-US", -1, CSTR_LESS_THAN, NORM_IGNORECASE, L"\x2ce0", L"\x30c6" },
3783 /* Hebrew > Japanese */
3784 { L"en-US", 1, CSTR_GREATER_THAN, NORM_IGNORECASE, L"\x05d3", L"\x30ba" },
3785 { L"en-US", 1, CSTR_GREATER_THAN, NORM_IGNORECASE, L"\x05e3", L"\x32de" },
3786 { L"en-US", 1, CSTR_GREATER_THAN, NORM_IGNORECASE, L"\x05d7", L"\x30c6" },
3787 /* Expansion */
3788 { L"en-US", 0, CSTR_EQUAL, 0, L"\x00c6", L"\x0041\x0045" },
3789 { L"en-US", 0, CSTR_EQUAL, 0, L"\x0f5c", L"\x0f5b\x0fb7" },
3790 { L"en-US", 0, CSTR_EQUAL, 0, L"\x05f0", L"\x05d5\x05d5" },
3791 { L"en-US", -1, CSTR_EQUAL, 0, L"\x0f75", L"\x0f71\x0f74" },
3792 { L"en-US", -1, CSTR_EQUAL, 0, L"\xfc5e", L"\x064c\x0651" },
3793 { L"en-US", -1, CSTR_EQUAL, 0, L"\xfb2b", L"\x05e9\x05c2" },
3794 { L"en-US", -1, CSTR_EQUAL, 0, L"\xfe71", L"\x0640\x064b" },
3795 /* Japanese locale */
3796 { L"ja-JP", -1, CSTR_LESS_THAN, 0, L"\x6df8", L"\x654b\x29e9" },
3797 { L"ja-JP", -1, CSTR_LESS_THAN, 0, L"\x685d\x1239\x1b61", L"\x59b6\x6542\x2a62\x04a7" },
3798 { L"ja-JP", -1, CSTR_LESS_THAN, 0, L"\x62f3\x43e9", L"\x5760" },
3799 { L"ja-JP", -1, CSTR_LESS_THAN, 0, L"\x634c", L"\x2f0d\x5f1c\x7124" },
3800 { L"ja-JP", -1, CSTR_LESS_THAN, 0, L"\x69e7\x0502", L"\x57cc" },
3801 { L"ja-JP", -1, CSTR_LESS_THAN, 0, L"\x7589", L"\x67c5" },
3802 { L"ja-JP", 1, CSTR_GREATER_THAN, 0, L"\x5ede\x765c", L"\x7324" },
3803 { L"ja-JP", 1, CSTR_GREATER_THAN, 0, L"\x5c7f\x5961", L"\x7cbe" },
3804 { L"ja-JP", 1, CSTR_GREATER_THAN, 0, L"\x3162", L"\x6a84\x1549\x0b60" },
3805 { L"ja-JP", -1, CSTR_LESS_THAN, 0, L"\x769e\x448e", L"\x4e6e" },
3806 { L"ja-JP", 1, CSTR_GREATER_THAN, 0, L"\x59a4", L"\x5faa\x607c" },
3807 { L"ja-JP", 1, CSTR_GREATER_THAN, 0, L"\x529b", L"\x733f" },
3808 { L"ja-JP", 1, CSTR_GREATER_THAN, 0, L"\x6ff8\x2a0a", L"\x7953\x6712" },
3809 { L"ja-JP", -1, CSTR_LESS_THAN, 0, L"\x6dfb", L"\x6793" },
3810 { L"ja-JP", 1, CSTR_GREATER_THAN, 0, L"\x67ed", L"\x6aa2" },
3811 { L"ja-JP", 1, CSTR_GREATER_THAN, 0, L"\x4e61", L"\x6350\x6b08" },
3812 { L"ja-JP", 1, CSTR_GREATER_THAN, 0, L"\x5118", L"\x53b3\x75b4" },
3813 { L"ja-JP", -1, CSTR_LESS_THAN, 0, L"\x6bbf", L"\x65a3" },
3814 { L"ja-JP", 1, CSTR_GREATER_THAN, 0, L"\x5690", L"\x5fa8" },
3815 { L"ja-JP", 1, CSTR_GREATER_THAN, 0, L"\x61e2", L"\x76e5" },
3816 /* Misc locales */
3817 { L"ko-KR", -1, CSTR_LESS_THAN, 0, L"\x8db6", L"\xd198" },
3818 { L"ko-KR", -1, CSTR_LESS_THAN, 0, L"\x8f72", L"\xd2b9" },
3819 { L"ko-KR", -1, CSTR_LESS_THAN, 0, L"\x91d8", L"\xd318" },
3820 { L"en-US", 1, CSTR_GREATER_THAN, 0, L"\x8db6", L"\xd198" },
3821 { L"en-US", 1, CSTR_GREATER_THAN, 0, L"\x8f72", L"\xd2b9" },
3822 { L"en-US", 1, CSTR_GREATER_THAN, 0, L"\x91d8", L"\xd318" },
3823 { L"cs-CZ", 1, CSTR_GREATER_THAN, 0, L"\x0160", L"\x0219" },
3824 { L"cs-CZ", 1, CSTR_GREATER_THAN, 0, L"\x059a", L"\x0308" },
3825 { L"cs-CZ", 1, CSTR_GREATER_THAN, 0, L"\x013a", L"\x013f" },
3826 { L"en-US", -1, CSTR_LESS_THAN, 0, L"\x0160", L"\x0219" },
3827 { L"en-US", -1, CSTR_LESS_THAN, 0, L"\x059a", L"\x0308" },
3828 { L"en-US", -1, CSTR_LESS_THAN, 0, L"\x013a", L"\x013f" },
3829 { L"vi-VN", -1, CSTR_LESS_THAN, 0, L"\x1d8f", L"\x1ea8" },
3830 { L"vi-VN", -1, CSTR_LESS_THAN, 0, L"\x0323", L"\xfe26" },
3831 { L"vi-VN", 1, CSTR_GREATER_THAN, 0, L"R", L"\xff32" },
3832 { L"en-US", 1, CSTR_GREATER_THAN, 0, L"\x1d8f", L"\x1ea8" },
3833 { L"en-US", 1, CSTR_GREATER_THAN, 0, L"\x0323", L"\xfe26" },
3834 { L"en-US", -1, CSTR_LESS_THAN, 0, L"R", L"\xff32" },
3835 { L"zh-HK", -1, CSTR_LESS_THAN, 0, L"\x83ae", L"\x71b9" },
3836 { L"zh-HK", -1, CSTR_LESS_THAN, 0, L"\x7e50", L"\xc683" },
3837 { L"zh-HK", 1, CSTR_GREATER_THAN, 0, L"\x6c69", L"\x7f8a" },
3838 { L"en-US", 1, CSTR_GREATER_THAN, 0, L"\x83ae", L"\x71b9" },
3839 { L"en-US", 1, CSTR_GREATER_THAN, 0, L"\x7e50", L"\xc683" },
3840 { L"en-US", -1, CSTR_LESS_THAN, 0, L"\x6c69", L"\x7f8a" },
3841 { L"tr-TR", 1, CSTR_GREATER_THAN, 0, L"\x00dc", L"\x1ee9" },
3842 { L"tr-TR", 1, CSTR_GREATER_THAN, 0, L"\x00fc", L"\x1ee6" },
3843 { L"tr-TR", -1, CSTR_LESS_THAN, 0, L"\x0152", L"\x00d6" },
3844 { L"en-US", -1, CSTR_LESS_THAN, 0, L"\x00dc", L"\x1ee9" },
3845 { L"en-US", -1, CSTR_LESS_THAN, 0, L"\x00fc", L"\x1ee6" },
3846 { L"en-US", 1, CSTR_GREATER_THAN, 0, L"\x0152", L"\x00d6" },
3847 /* Diacritic is added */
3848 { L"en-US", 1, CSTR_GREATER_THAN, 0, L"\xa042\x09bc", L"\xa042" },
3849 { L"en-US", 1, CSTR_GREATER_THAN, 0, L"\xa063\x302b", L"\xa063" },
3850 { L"en-US", 1, CSTR_GREATER_THAN, 0, L"\xa07e\x0c56", L"\xa07e" },
3851 /* Reversed diacritics */
3852 { L"en-US", -1, CSTR_LESS_THAN, 0, L"\x00e9\x00e8", L"\x00e8\x00e9" },
3853 { L"fr-FR", 1, CSTR_GREATER_THAN, 0, L"\x00e9\x00e8", L"\x00e8\x00e9" },
3854 /* Digit sort */
3855 { L"en-US", -1, CSTR_LESS_THAN, 0, L"1230", L"321" },
3856 { L"en-US", 1, CSTR_GREATER_THAN, SORT_DIGITSASNUMBERS, L"1230", L"321" },
3857 { L"en-US", 1, CSTR_GREATER_THAN, SORT_DIGITSASNUMBERS, L"\xc6f\xc6c\xc6a", L"\xc6f\xc6e" },
3858 /* Compressions */
3859 { L"en-US", -1, CSTR_LESS_THAN, 0, L"E\x0300", L"F" },
3860 { L"rm-CH", 1, CSTR_GREATER_THAN, 0, L"E\x0300", L"F" },
3861};
3862
3863static void test_unicode_sorting(void)
3864{
3865 int i;
3866 int ret1;
3867 int ret2;
3868 BYTE buffer[1000];
3869 if (!pLCMapStringEx)
3870 {
3871 win_skip("LCMapStringEx not available\n");
3872 return;
3873 }
3874 for (i = 0; i < ARRAY_SIZE(unicode_sorting_tests); i++)
3875 {
3876 BYTE buff1[1000];
3877 BYTE buff2[1000];
3878 int len1, len2;
3879 int result;
3881
3882 len1 = pLCMapStringEx(entry->locale, LCMAP_SORTKEY | entry->flags, entry->first, -1, (WCHAR*)buff1, ARRAY_SIZE(buff1), NULL, NULL, 0);
3883 len2 = pLCMapStringEx(entry->locale, LCMAP_SORTKEY | entry->flags, entry->second, -1, (WCHAR*)buff2, ARRAY_SIZE(buff2), NULL, NULL, 0);
3884
3885 result = memcmp(buff1, buff2, min(len1, len2));
3886 if (result < 0) result = -1;
3887 else if (result > 0) result = 1;
3888 else if (len1 < len2) result = -1;
3889 else if (len1 > len2) result = 1;
3890
3891#ifdef __REACTOS__
3892 ok (result == entry->result_sortkey || broken(GetNTVersion() == _WIN32_WINNT_VISTA), "Test %d (%s, %s) - Expected %d, got %d\n",
3893#else
3894 ok (result == entry->result_sortkey, "Test %d (%s, %s) - Expected %d, got %d\n",
3895#endif
3896 i, wine_dbgstr_w(entry->first), wine_dbgstr_w(entry->second), entry->result_sortkey, result);
3897
3898#if !defined(__REACTOS__) || DLL_EXPORT_VERSION >= 0x600
3899#if defined(__REACTOS__) && defined(_WIN64)
3900 if ((i == 0 || i == 5 || i == 8 || i == 9 || i == 17 || i == 80 || i == 81 || i == 84 ||
3901 i == 199 || i == 200 || i == 202 || i == 235 || i == 236 || i == 250 || i == 251 ||
3902 i == 259 || i == 260) && (GetNTVersion() == _WIN32_WINNT_VISTA))
3903 continue;
3904#endif
3905 result = CompareStringEx(entry->locale, entry->flags, entry->first, -1, entry->second, -1, NULL, NULL, 0);
3906 ok (result == entry->result_compare, "Test %d (%s, %s) - Expected %d, got %d\n",
3907 i, wine_dbgstr_w(entry->first), wine_dbgstr_w(entry->second), entry->result_compare, result);
3908#endif
3909 }
3910 /* Test diacritics when buffer is short */
3911 ret1 = pLCMapStringEx(L"en-US", LCMAP_SORTKEY, L"\x0e49\x0e49\x0e49\x0e49\x0e49", -1, (WCHAR*)buffer, 20, NULL, NULL, 0);
3912 ret2 = pLCMapStringEx(L"en-US", LCMAP_SORTKEY, L"\x0e49\x0e49\x0e49\x0e49\x0e49", -1, (WCHAR*)buffer, 0, NULL, NULL, 0);
3913 ok(ret1 == ret2, "Got ret1=%d, ret2=%d\n", ret1, ret2);
3914}
3915
3916static void test_FoldStringA(void)
3917{
3918 int ret, i, j;
3919 BOOL is_special;
3920 char src[256], dst[256];
3921 static const char digits_src[] = { 0xB9,0xB2,0xB3,'\0' };
3922 static const char digits_dst[] = { '1','2','3','\0' };
3923 static const char composite_src[] =
3924 {
3925 0x8a,0x8e,0x9a,0x9e,0x9f,0xc0,0xc1,0xc2,
3926 0xc3,0xc4,0xc5,0xc7,0xc8,0xc9,0xca,0xcb,
3927 0xcc,0xcd,0xce,0xcf,0xd1,0xd2,0xd3,0xd4,
3928 0xd5,0xd6,0xd8,0xd9,0xda,0xdb,0xdc,0xdd,
3929 0xe0,0xe1,0xe2,0xe3,0xe4,0xe5,0xe7,0xe8,
3930 0xe9,0xea,0xeb,0xec,0xed,0xee,0xef,0xf1,
3931 0xf2,0xf3,0xf4,0xf5,0xf6,0xf8,0xf9,0xfa,
3932 0xfb,0xfc,0xfd,0xff,'\0'
3933 };
3934 static const char composite_dst[] =
3935 {
3936 0x53,0x3f,0x5a,0x3f,0x73,0x3f,0x7a,0x3f,
3937 0x59,0xa8,0x41,0x60,0x41,0xb4,0x41,0x5e,
3938 0x41,0x7e,0x41,0xa8,0x41,0xb0,0x43,0xb8,
3939 0x45,0x60,0x45,0xb4,0x45,0x5e,0x45,0xa8,
3940 0x49,0x60,0x49,0xb4,0x49,0x5e,0x49,0xa8,
3941 0x4e,0x7e,0x4f,0x60,0x4f,0xb4,0x4f,0x5e,
3942 0x4f,0x7e,0x4f,0xa8,0x4f,0x3f,0x55,0x60,
3943 0x55,0xb4,0x55,0x5e,0x55,0xa8,0x59,0xb4,
3944 0x61,0x60,0x61,0xb4,0x61,0x5e,0x61,0x7e,
3945 0x61,0xa8,0x61,0xb0,0x63,0xb8,0x65,0x60,
3946 0x65,0xb4,0x65,0x5e,0x65,0xa8,0x69,0x60,
3947 0x69,0xb4,0x69,0x5e,0x69,0xa8,0x6e,0x7e,
3948 0x6f,0x60,0x6f,0xb4,0x6f,0x5e,0x6f,0x7e,
3949 0x6f,0xa8,0x6f,0x3f,0x75,0x60,0x75,0xb4,
3950 0x75,0x5e,0x75,0xa8,0x79,0xb4,0x79,0xa8,'\0'
3951 };
3952 static const char composite_dst_alt[] =
3953 {
3954 0x53,0x3f,0x5a,0x3f,0x73,0x3f,0x7a,0x3f,
3955 0x59,0xa8,0x41,0x60,0x41,0xb4,0x41,0x5e,
3956 0x41,0x7e,0x41,0xa8,0x41,0xb0,0x43,0xb8,
3957 0x45,0x60,0x45,0xb4,0x45,0x5e,0x45,0xa8,
3958 0x49,0x60,0x49,0xb4,0x49,0x5e,0x49,0xa8,
3959 0x4e,0x7e,0x4f,0x60,0x4f,0xb4,0x4f,0x5e,
3960 0x4f,0x7e,0x4f,0xa8,0xd8,0x55,0x60,0x55,
3961 0xb4,0x55,0x5e,0x55,0xa8,0x59,0xb4,0x61,
3962 0x60,0x61,0xb4,0x61,0x5e,0x61,0x7e,0x61,
3963 0xa8,0x61,0xb0,0x63,0xb8,0x65,0x60,0x65,
3964 0xb4,0x65,0x5e,0x65,0xa8,0x69,0x60,0x69,
3965 0xb4,0x69,0x5e,0x69,0xa8,0x6e,0x7e,0x6f,
3966 0x60,0x6f,0xb4,0x6f,0x5e,0x6f,0x7e,0x6f,
3967 0xa8,0xf8,0x75,0x60,0x75,0xb4,0x75,0x5e,
3968 0x75,0xa8,0x79,0xb4,0x79,0xa8,'\0'
3969 };
3970 static const char ligatures_src[] =
3971 {
3972 0x8C,0x9C,0xC6,0xDE,0xDF,0xE6,0xFE,'\0'
3973 };
3974 static const char ligatures_dst[] =
3975 {
3976 'O','E','o','e','A','E','T','H','s','s','a','e','t','h','\0'
3977 };
3978 static const struct special
3979 {
3980 char src;
3981 char dst[4];
3982 } foldczone_special[] =
3983 {
3984 /* src dst */
3985 { 0x85, { 0x2e, 0x2e, 0x2e, 0x00 } },
3986 { 0x98, { 0x20, 0x7e, 0x00 } },
3987 { 0x99, { 0x54, 0x4d, 0x00 } },
3988 { 0xa0, { 0x20, 0x00 } },
3989 { 0xa8, { 0x20, 0xa8, 0x00 } },
3990 { 0xaa, { 0x61, 0x00 } },
3991 { 0xaf, { 0x20, 0xaf, 0x00 } },
3992 { 0xb2, { 0x32, 0x00 } },
3993 { 0xb3, { 0x33, 0x00 } },
3994 { 0xb4, { 0x20, 0xb4, 0x00 } },
3995 { 0xb8, { 0x20, 0xb8, 0x00 } },
3996 { 0xb9, { 0x31, 0x00 } },
3997 { 0xba, { 0x6f, 0x00 } },
3998 { 0xbc, { 0x31, 0x2f, 0x34, 0x00 } },
3999 { 0xbd, { 0x31, 0x2f, 0x32, 0x00 } },
4000 { 0xbe, { 0x33, 0x2f, 0x34, 0x00 } },
4001 { 0x00 }
4002 };
4003
4004 /* these tests are locale specific */
4005 if (GetACP() != 1252)
4006 {
4007 trace("Skipping FoldStringA tests for a not Latin 1 locale\n");
4008 return;
4009 }
4010
4011 /* MAP_FOLDDIGITS */
4012 SetLastError(0xdeadbeef);
4013 ret = FoldStringA(MAP_FOLDDIGITS, digits_src, -1, dst, 256);
4014 ok(ret == 4, "Expected ret == 4, got %d, error %ld\n", ret, GetLastError());
4015 ok(strcmp(dst, digits_dst) == 0,
4016 "MAP_FOLDDIGITS: Expected '%s', got '%s'\n", digits_dst, dst);
4017 for (i = 1; i < 256; i++)
4018 {
4019 if (!strchr(digits_src, i))
4020 {
4021 src[0] = i;
4022 src[1] = '\0';
4023 ret = FoldStringA(MAP_FOLDDIGITS, src, -1, dst, 256);
4024 ok(ret == 2, "Expected ret == 2, got %d, error %ld\n", ret, GetLastError());
4025 ok(dst[0] == src[0],
4026 "MAP_FOLDDIGITS: Expected '%s', got '%s'\n", src, dst);
4027 }
4028 }
4029
4030 /* MAP_EXPAND_LIGATURES */
4031 SetLastError(0xdeadbeef);
4032 ret = FoldStringA(MAP_EXPAND_LIGATURES, ligatures_src, -1, dst, 256);
4033 ok(ret == sizeof(ligatures_dst), "Got %d, error %ld\n", ret, GetLastError());
4034 ok(strcmp(dst, ligatures_dst) == 0,
4035 "MAP_EXPAND_LIGATURES: Expected '%s', got '%s'\n", ligatures_dst, dst);
4036 for (i = 1; i < 256; i++)
4037 {
4038 if (!strchr(ligatures_src, i))
4039 {
4040 src[0] = i;
4041 src[1] = '\0';
4042 ret = FoldStringA(MAP_EXPAND_LIGATURES, src, -1, dst, 256);
4043 if (ret == 3)
4044 {
4045 /* Vista */
4046 ok((i == 0xDC && lstrcmpA(dst, "UE") == 0) ||
4047 (i == 0xFC && lstrcmpA(dst, "ue") == 0),
4048 "Got %s for %d\n", dst, i);
4049 }
4050 else
4051 {
4052 ok(ret == 2, "Expected ret == 2, got %d, error %ld\n", ret, GetLastError());
4053 ok(dst[0] == src[0],
4054 "MAP_EXPAND_LIGATURES: Expected '%s', got '%s'\n", src, dst);
4055 }
4056 }
4057 }
4058
4059 /* MAP_COMPOSITE */
4060 SetLastError(0xdeadbeef);
4061 ret = FoldStringA(MAP_COMPOSITE, composite_src, -1, dst, 256);
4062 ok(ret, "Expected ret != 0, got %d, error %ld\n", ret, GetLastError());
4063 ok( GetLastError() == 0xdeadbeef || broken(!GetLastError()), /* vista */
4064 "wrong error %lu\n", GetLastError());
4065 ok(ret == 121 || ret == 119, "Expected 121 or 119, got %d\n", ret);
4066 ok(strcmp(dst, composite_dst) == 0 || strcmp(dst, composite_dst_alt) == 0,
4067 "MAP_COMPOSITE: Mismatch, got '%s'\n", dst);
4068
4069 for (i = 1; i < 256; i++)
4070 {
4071 if (!strchr(composite_src, i))
4072 {
4073 src[0] = i;
4074 src[1] = '\0';
4075 ret = FoldStringA(MAP_COMPOSITE, src, -1, dst, 256);
4076 ok(ret == 2, "Expected ret == 2, got %d, error %ld\n", ret, GetLastError());
4077 ok(dst[0] == src[0],
4078 "0x%02x, 0x%02x,0x%02x,0x%02x,\n", (unsigned char)src[0],
4079 (unsigned char)dst[0],(unsigned char)dst[1],(unsigned char)dst[2]);
4080 }
4081 }
4082
4083 /* MAP_FOLDCZONE */
4084 for (i = 1; i < 256; i++)
4085 {
4086 src[0] = i;
4087 src[1] = '\0';
4088 SetLastError(0xdeadbeef);
4089 ret = FoldStringA(MAP_FOLDCZONE, src, -1, dst, 256);
4090 is_special = FALSE;
4091 for (j = 0; foldczone_special[j].src != 0 && ! is_special; j++)
4092 {
4093 if (foldczone_special[j].src == src[0])
4094 {
4095 ok(ret == 2 || ret == lstrlenA(foldczone_special[j].dst) + 1,
4096 "Expected ret == 2 or %d, got %d, error %ld\n",
4097 lstrlenA(foldczone_special[j].dst) + 1, ret, GetLastError());
4098 ok(src[0] == dst[0] || lstrcmpA(foldczone_special[j].dst, dst) == 0,
4099 "MAP_FOLDCZONE: string mismatch for 0x%02x\n",
4100 (unsigned char)src[0]);
4101 is_special = TRUE;
4102 }
4103 }
4104 if (! is_special)
4105 {
4106 ok(ret == 2, "Expected ret == 2, got %d, error %ld\n", ret, GetLastError());
4107 ok(src[0] == dst[0],
4108 "MAP_FOLDCZONE: Expected 0x%02x, got 0x%02x\n",
4109 (unsigned char)src[0], (unsigned char)dst[0]);
4110 }
4111 }
4112
4113 /* MAP_PRECOMPOSED */
4114 for (i = 1; i < 256; i++)
4115 {
4116 src[0] = i;
4117 src[1] = '\0';
4118 ret = FoldStringA(MAP_PRECOMPOSED, src, -1, dst, 256);
4119 ok(ret == 2, "Expected ret == 2, got %d, error %ld\n", ret, GetLastError());
4120 ok(src[0] == dst[0],
4121 "MAP_PRECOMPOSED: Expected 0x%02x, got 0x%02x\n",
4122 (unsigned char)src[0], (unsigned char)dst[0]);
4123 }
4124}
4125
4126static void test_FoldStringW(void)
4127{
4128 int ret;
4129 WORD type;
4130 unsigned int i, j, len;
4131 WCHAR src[256], dst[256];
4132 UINT ch, prev_ch = 1;
4133 static const DWORD badFlags[] =
4134 {
4135 0,
4137 MAP_PRECOMPOSED|MAP_EXPAND_LIGATURES,
4138 MAP_COMPOSITE|MAP_EXPAND_LIGATURES
4139 };
4140 /* Ranges of digits 0-9 : Must be sorted! */
4141 static const struct { UINT ch, first, last; int broken; } digitRanges[] =
4142 {
4143 { 0x0030, 0, 9 }, /* '0'-'9' */
4144 { 0x00b2, 2, 3 }, /* Superscript 2, 3 */
4145 { 0x00b9, 1, 1 }, /* Superscript 1 */
4146 { 0x0660, 0, 9 }, /* Eastern Arabic */
4147 { 0x06f0, 0, 9 }, /* Arabic - Hindu */
4148#ifdef __REACTOS__
4149 { 0x07c0, 0, 9, TRUE /* WS03 */ }, /* Nko */
4150#else
4151 { 0x07c0, 0, 9 }, /* Nko */
4152#endif
4153 { 0x0966, 0, 9 }, /* Devengari */
4154 { 0x09e6, 0, 9 }, /* Bengalii */
4155 { 0x0a66, 0, 9 }, /* Gurmukhi */
4156 { 0x0ae6, 0, 9 }, /* Gujarati */
4157#ifdef __REACTOS__
4158 { 0x0b66, 0, 9, TRUE /* WS03 */ }, /* Oriya */
4159 { 0x0be6, 0, 9, TRUE /* WS03 */ }, /* Tamil */
4160#else
4161 { 0x0b66, 0, 9 }, /* Oriya */
4162 { 0x0be6, 0, 9 }, /* Tamil */
4163#endif
4164 { 0x0c66, 0, 9 }, /* Telugu */
4165 { 0x0c78, 0, 3, TRUE /*win7*/ }, /* Telugu Fraction */
4166 { 0x0c7c, 1, 3, TRUE /*win7*/ }, /* Telugu Fraction */
4167 { 0x0ce6, 0, 9 }, /* Kannada */
4168 { 0x0d66, 0, 9 }, /* Maylayalam */
4169 { 0x0de6, 0, 9, TRUE /*win10*/ }, /* Sinhala Lith */
4170 { 0x0e50, 0, 9 }, /* Thai */
4171 { 0x0ed0, 0, 9 }, /* Laos */
4172#ifdef __REACTOS__
4173 { 0x0f20, 0, 9, TRUE /* WS03 */ }, /* Tibet */
4174 { 0x1040, 0, 9, TRUE /* WS03 */ }, /* Myanmar */
4175 { 0x1090, 0, 9, TRUE /* WS03 */ }, /* Myanmar Shan */
4176 { 0x1369, 1, 9, TRUE /* WS03 */ }, /* Ethiopic */
4177 { 0x17e0, 0, 9, TRUE /* WS03 */ }, /* Khmer */
4178 { 0x1810, 0, 9, TRUE /* WS03 */ }, /* Mongolian */
4179 { 0x1946, 0, 9, TRUE /* WS03 */ }, /* Limbu */
4180 { 0x19d0, 0, 9, TRUE /* WS03 */ }, /* New Tai Lue */
4181#else
4182 { 0x0f20, 0, 9 }, /* Tibet */
4183 { 0x1040, 0, 9 }, /* Myanmar */
4184 { 0x1090, 0, 9 }, /* Myanmar Shan */
4185 { 0x1369, 1, 9 }, /* Ethiopic */
4186 { 0x17e0, 0, 9 }, /* Khmer */
4187 { 0x1810, 0, 9 }, /* Mongolian */
4188 { 0x1946, 0, 9 }, /* Limbu */
4189 { 0x19d0, 0, 9 }, /* New Tai Lue */
4190#endif
4191 { 0x19da, 1, 1, TRUE /*win7*/ }, /* New Tai Lue Tham 1 */
4192 { 0x1a80, 0, 9, TRUE /*win7*/ }, /* Tai Tham Hora */
4193 { 0x1a90, 0, 9, TRUE /*win7*/ }, /* Tai Tham Tham */
4194#ifdef __REACTOS__
4195 { 0x1b50, 0, 9, TRUE /* WS03 */ }, /* Balinese */
4196 { 0x1bb0, 0, 9, TRUE /* WS03 */ }, /* Sundanese */
4197 { 0x1c40, 0, 9, TRUE /* WS03 */ }, /* Lepcha */
4198 { 0x1c50, 0, 9, TRUE /* WS03 */ }, /* Ol Chiki */
4199#else
4200 { 0x1b50, 0, 9 }, /* Balinese */
4201 { 0x1bb0, 0, 9 }, /* Sundanese */
4202 { 0x1c40, 0, 9 }, /* Lepcha */
4203 { 0x1c50, 0, 9 }, /* Ol Chiki */
4204#endif
4205 { 0x2070, 0, 0 }, /* Superscript 0 */
4206 { 0x2074, 4, 9 }, /* Superscript 4-9 */
4207 { 0x2080, 0, 9 }, /* Subscript */
4208 { 0x2460, 1, 9 }, /* Circled */
4209 { 0x2474, 1, 9 }, /* Bracketed */
4210 { 0x2488, 1, 9 }, /* Full stop */
4211 { 0x24ea, 0, 0 }, /* Circled 0 */
4212#ifdef __REACTOS__
4213 { 0x24f5, 1, 9, TRUE /* WS03 */ }, /* Double Circled */
4214 { 0x24ff, 0, 0, TRUE /* WS03 */ }, /* Negative Circled 0 */
4215#else
4216 { 0x24f5, 1, 9 }, /* Double Circled */
4217 { 0x24ff, 0, 0 }, /* Negative Circled 0 */
4218#endif
4219 { 0x2776, 1, 9 }, /* Inverted Circled */
4220 { 0x2780, 1, 9 }, /* Patterned Circled */
4221 { 0x278a, 1, 9 }, /* Inverted Patterned Circled */
4222#ifdef __REACTOS__
4223 { 0x3007, 0, 0, TRUE /* WS03 */ }, /* Ideographic Number 0 */
4224 { 0x3021, 1, 9, TRUE /* WS03 */ }, /* Hangzhou */
4225 { 0xa620, 0, 9, TRUE /* WS03 */ }, /* Vai */
4226 { 0xa8d0, 0, 9, TRUE /* WS03 */ }, /* Saurashtra */
4227#else
4228 { 0x3007, 0, 0 }, /* Ideographic Number 0 */
4229 { 0x3021, 1, 9 }, /* Hangzhou */
4230 { 0xa620, 0, 9 }, /* Vai */
4231 { 0xa8d0, 0, 9 }, /* Saurashtra */
4232#endif
4233 { 0xa8e0, 0, 9, TRUE /*win7*/ }, /* Combining Devanagari */
4234#ifdef __REACTOS__
4235 { 0xa900, 0, 9, TRUE /* WS03 */ }, /* Kayah Li */
4236#else
4237 { 0xa900, 0, 9 }, /* Kayah Li */
4238#endif
4239 { 0xa9d0, 0, 9, TRUE /*win7*/ }, /* Javanese */
4240 { 0xa9f0, 0, 9, TRUE /*win10*/ }, /* Myanmar Tai Laing */
4241#ifdef __REACTOS__
4242 { 0xaa50, 0, 9, TRUE /* WS03 */ }, /* Cham */
4243#else
4244 { 0xaa50, 0, 9 }, /* Cham */
4245#endif
4246 { 0xabf0, 0, 9, TRUE /*win7*/ }, /* Meetei Mayek */
4247 { 0xff10, 0, 9 }, /* Full Width */
4248#ifdef __REACTOS__
4249 { 0x10107, 1, 9, TRUE /* WS03 */ }, /* Aegean */
4250 { 0x10320, 1, 1, TRUE /* WS03 */ }, /* Old Italic Numeral 1 */
4251 { 0x10321, 5, 5, TRUE /* WS03 */ }, /* Old Italic Numeral 5 */
4252 { 0x104a0, 0, 9, TRUE /* WS03 */ }, /* Osmanya */
4253#else
4254 { 0x10107, 1, 9 }, /* Aegean */
4255 { 0x10320, 1, 1 }, /* Old Italic Numeral 1 */
4256 { 0x10321, 5, 5 }, /* Old Italic Numeral 5 */
4257 { 0x104a0, 0, 9 }, /* Osmanya */
4258#endif
4259 { 0x10a40, 1, 4, TRUE /*win10*/ }, /* Kharoshthi */
4260 { 0x10d30, 0, 9, TRUE /*win10*/ }, /* Hanifi Rohingya */
4261 { 0x10d40, 0, 9, TRUE /*win10*/ }, /* Garay */
4262 { 0x10e60, 1, 9, TRUE /*win10*/ }, /* Rumi */
4263 { 0x11052, 1, 9, TRUE /*win10*/ }, /* Brahmi Number */
4264 { 0x11066, 0, 9, TRUE /*win10*/ }, /* Brahmi Digit */
4265 { 0x110f0, 0, 9, TRUE /*win10*/ }, /* Sora Sompeng */
4266 { 0x11136, 0, 9, TRUE /*win10*/ }, /* Chakma */
4267 { 0x111d0, 0, 9, TRUE /*win10*/ }, /* Sharada */
4268 { 0x112f0, 0, 9, TRUE /*win10*/ }, /* Khudawadi */
4269 { 0x11450, 0, 9, TRUE /*win10*/ }, /* Newa */
4270 { 0x114d0, 0, 9, TRUE /*win10*/ }, /* Tirhuta */
4271 { 0x11650, 0, 9, TRUE /*win10*/ }, /* Modi */
4272 { 0x116c0, 0, 9, TRUE /*win10*/ }, /* Takri */
4273 { 0x116d0, 0, 9, TRUE /*win10*/ }, /* Myanmar Pa-O */
4274 { 0x116da, 0, 9, TRUE /*win10*/ }, /* Myanmar Eastern Pwo */
4275 { 0x11730, 0, 9, TRUE /*win10*/ }, /* Ahom */
4276 { 0x118e0, 0, 9, TRUE /*win10*/ }, /* Warang */
4277 { 0x11950, 0, 9, TRUE /*win10*/ }, /* Dives Akuru */
4278 { 0x11bf0, 0, 9, TRUE /*win10*/ }, /* Sunuwar */
4279 { 0x11c50, 0, 9, TRUE /*win10*/ }, /* Bhaiksuki */
4280 { 0x11d50, 0, 9, TRUE /*win10*/ }, /* Masaram Gondi */
4281 { 0x11da0, 0, 9, TRUE /*win10*/ }, /* Gunjala Gondi */
4282 { 0x11f50, 0, 9, TRUE /*win10*/ }, /* Kawi */
4283 { 0x16130, 0, 9, TRUE /*win10*/ }, /* Gurung Khema */
4284 { 0x16a60, 0, 9, TRUE /*win10*/ }, /* Mro */
4285 { 0x16ac0, 0, 9, TRUE /*win10*/ }, /* Tangsa */
4286 { 0x16b50, 0, 9, TRUE /*win10*/ }, /* Pahawh Hmong */
4287 { 0x16d70, 0, 9, TRUE /*win10*/ }, /* Kirat Rai */
4288 { 0x1ccf0, 0, 9, TRUE /*win10*/ }, /* Outlined digits */
4289#ifdef __REACTOS__
4290 { 0x1d7ce, 0, 9, TRUE /* WS03 */ }, /* Mathematical Bold */
4291 { 0x1d7d8, 0, 9, TRUE /* WS03 */ }, /* Mathematical Double Struck */
4292 { 0x1d7e2, 0, 9, TRUE /* WS03 */ }, /* Mathematical Sans Serif */
4293 { 0x1d7ec, 0, 9, TRUE /* WS03 */ }, /* Mathematical Sans Serif Bold */
4294 { 0x1d7f6, 0, 9, TRUE /* WS03 */ }, /* Mathematical Monospace */
4295#else
4296 { 0x1d7ce, 0, 9 }, /* Mathematical Bold */
4297 { 0x1d7d8, 0, 9 }, /* Mathematical Double Struck */
4298 { 0x1d7e2, 0, 9 }, /* Mathematical Sans Serif */
4299 { 0x1d7ec, 0, 9 }, /* Mathematical Sans Serif Bold */
4300 { 0x1d7f6, 0, 9 }, /* Mathematical Monospace */
4301#endif
4302 { 0x1e140, 0, 9, TRUE /*win10*/ }, /* Nyiakeng Puachue Hmong */
4303 { 0x1e2f0, 0, 9, TRUE /*win10*/ }, /* Wancho */
4304 { 0x1e4f0, 0, 9, TRUE /*win10*/ }, /* Nag Mundari */
4305 { 0x1e5f1, 0, 9, TRUE /*win10*/ }, /* Ol Onal */
4306 { 0x1e950, 0, 9, TRUE /*win10*/ }, /* Adlam */
4307 { 0x1f100, 0, 0, TRUE /*win10*/ }, /* Full Stop */
4308 { 0x1f101, 0, 9, TRUE /*win10*/ }, /* Comma */
4309 { 0x1fbf0, 0, 9, TRUE /*win10*/ }, /* Segmented */
4310 { 0x10ffff } /* Terminator */
4311 };
4312 static const WCHAR foldczone_src[] =
4313 {
4314 'W', 'i', 'n', 'e', 0x0348, 0x0551, 0x1323, 0x280d,
4315 0xff37, 0xff49, 0xff4e, 0xff45, 0x3c5, 0x308, 0x6a, 0x30c, 0xa0, 0xaa, 0
4316 };
4317 static const WCHAR foldczone_dst[] =
4318 {
4319 'W','i','n','e',0x0348,0x0551,0x1323,0x280d,'W','i','n','e',0x3cb,0x1f0,' ','a',0
4320 };
4321 static const WCHAR foldczone_broken_dst[] =
4322 {
4323 'W','i','n','e',0x0348,0x0551,0x1323,0x280d,'W','i','n','e',0x03c5,0x0308,'j',0x030c,0x00a0,0x00aa,0
4324 };
4325 static const WCHAR ligatures_src[] =
4326 {
4327 'W', 'i', 'n', 'e', 0x03a6, 0x03b9, 0x03bd, 0x03b5,
4328 0x00c6, 0x00de, 0x00df, 0x00e6, 0x00fe, 0x0132, 0x0133, 0x0152,
4329 0x0153, 0x01c4, 0x01c5, 0x01c6, 0x01c7, 0x01c8, 0x01c9, 0x01ca,
4330 0x01cb, 0x01cc, 0x01e2, 0x01e3, 0x01f1, 0x01f2, 0x01f3, 0x01fc,
4331 0x01fd, 0x05f0, 0x05f1, 0x05f2, 0xfb00, 0xfb01, 0xfb02, 0xfb03,
4332 0xfb04, 0xfb05, 0xfb06, '\0'
4333 };
4334 static const WCHAR ligatures_dst[] =
4335 {
4336 'W','i','n','e',0x03a6,0x03b9,0x03bd,0x03b5,
4337 'A','E','T','H','s','s','a','e','t','h','I','J','i','j','O','E','o','e',
4338 'D',0x017d,'D',0x017e,'d',0x017e,'L','J','L','j','l','j','N','J','N','j',
4339 'n','j',0x0100,0x0112,0x0101,0x0113,'D','Z','D','z','d','z',0x00c1,0x00c9,
4340 0x00e1,0x00e9,0x05d5,0x05d5,0x05d5,0x05d9,0x05d9,0x05d9,'f','f','f','i',
4341 'f','l','f','f','i','f','f','l',0x017f,'t','s','t','\0'
4342 };
4343
4344 /* Invalid flag combinations */
4345 for (i = 0; i < ARRAY_SIZE(badFlags); i++)
4346 {
4347 src[0] = dst[0] = '\0';
4348 SetLastError(0xdeadbeef);
4349 ret = FoldStringW(badFlags[i], src, 256, dst, 256);
4351 "Expected ERROR_INVALID_FLAGS, got %ld\n", GetLastError());
4352 }
4353
4354 /* src & dst cannot be the same */
4355 SetLastError(0xdeadbeef);
4356 ret = FoldStringW(MAP_FOLDCZONE, src, -1, src, 256);
4358 "Expected ERROR_INVALID_PARAMETER, got %ld\n", GetLastError());
4359
4360 /* src can't be NULL */
4361 SetLastError(0xdeadbeef);
4362 ret = FoldStringW(MAP_FOLDCZONE, NULL, -1, dst, 256);
4364 "Expected ERROR_INVALID_PARAMETER, got %ld\n", GetLastError());
4365
4366 /* srclen can't be 0 */
4367 SetLastError(0xdeadbeef);
4368 ret = FoldStringW(MAP_FOLDCZONE, src, 0, dst, 256);
4370 "Expected ERROR_INVALID_PARAMETER, got %ld\n", GetLastError());
4371
4372 /* dstlen can't be < 0 */
4373 SetLastError(0xdeadbeef);
4374 ret = FoldStringW(MAP_FOLDCZONE, src, -1, dst, -1);
4376 "Expected ERROR_INVALID_PARAMETER, got %ld\n", GetLastError());
4377
4378 /* Ret includes terminating NUL which is appended if srclen = -1 */
4379 SetLastError(0xdeadbeef);
4380 src[0] = 'A';
4381 src[1] = '\0';
4382 dst[0] = '\0';
4383 ret = FoldStringW(MAP_FOLDCZONE, src, -1, dst, 256);
4384 ok(ret == 2, "Expected ret == 2, got %d, error %ld\n", ret, GetLastError());
4385 ok(dst[0] == 'A' && dst[1] == '\0',
4386 "srclen=-1: Expected ret=2 [%d,%d], got ret=%d [%d,%d], err=%ld\n",
4387 'A', '\0', ret, dst[0], dst[1], GetLastError());
4388
4389 /* If size is given, result is not NUL terminated */
4390 SetLastError(0xdeadbeef);
4391 src[0] = 'A';
4392 src[1] = 'A';
4393 dst[0] = 'X';
4394 dst[1] = 'X';
4395 ret = FoldStringW(MAP_FOLDCZONE, src, 1, dst, 256);
4396 ok(ret == 1, "Expected ret == 1, got %d, error %ld\n", ret, GetLastError());
4397 ok(dst[0] == 'A' && dst[1] == 'X',
4398 "srclen=1: Expected ret=1, [%d,%d], got ret=%d,[%d,%d], err=%ld\n",
4399 'A','X', ret, dst[0], dst[1], GetLastError());
4400
4401 /* MAP_FOLDDIGITS */
4402 for (j = 0; j < ARRAY_SIZE(digitRanges); j++)
4403 {
4404 /* Check everything before this range */
4405 for (ch = prev_ch; ch < digitRanges[j].ch; ch++)
4406 {
4407 len = put_utf16( src, ch );
4408 src[len] = 0;
4409 SetLastError(0xdeadbeef);
4410 ret = FoldStringW(MAP_FOLDDIGITS, src, -1, dst, 256);
4411 if (ret == 3)
4412 {
4413 ok( !wcscmp( src, dst ), "%s changed to %s\n", debugstr_w(src), debugstr_w(dst) );
4414 continue;
4415 }
4416 ok(ret == 2, "Expected ret == 2, got %d, error %ld\n", ret, GetLastError());
4417#ifdef __REACTOS__
4418 ok(dst[0] == ch || broken(GetNTVersion() == _WIN32_WINNT_VISTA), "MAP_FOLDDIGITS: ch 0x%04x Expected unchanged got %04x\n", ch, dst[0]);
4419#else
4420 ok(dst[0] == ch, "MAP_FOLDDIGITS: ch 0x%04x Expected unchanged got %04x\n", ch, dst[0]);
4421#endif
4422 if (ch < 0x10000)
4423 {
4424 WCHAR wch = ch;
4425 GetStringTypeW( CT_CTYPE1, &wch, 1, &type );
4426 ok(!(type & C1_DIGIT), "char %04x should not be a digit\n", wch );
4427 }
4428 }
4429 if (digitRanges[j].ch == 0x10ffff)
4430 break; /* Finished the whole code point space */
4431
4432 for (ch = digitRanges[j].ch; ch <= digitRanges[j].ch + digitRanges[j].last - digitRanges[j].first; ch++)
4433 {
4434 UINT exp = '0' + digitRanges[j].first + ch - digitRanges[j].ch;
4435
4436 SetLastError(0xdeadbeef);
4437 len = put_utf16( src, ch );
4438 src[len] = 0;
4439 ret = FoldStringW(MAP_FOLDDIGITS, src, -1, dst, 256);
4440 ok(ret == 2 || broken( digitRanges[j].broken && ch >= 0x10000 ),
4441 "%04x: Expected ret == 2, got %d, error %ld\n", ch, ret, GetLastError());
4442 ok((dst[0] == exp && dst[1] == '\0') || broken( digitRanges[j].broken ),
4443 "MAP_FOLDDIGITS: ch %04x Expected %04x got %04x\n", ch, exp, dst[0]);
4444 }
4445 prev_ch = ch;
4446 }
4447
4448 /* MAP_FOLDCZONE */
4449 SetLastError(0xdeadbeef);
4450 ret = FoldStringW(MAP_FOLDCZONE, foldczone_src, -1, dst, 256);
4451 ok(ret == ARRAY_SIZE(foldczone_dst)
4452 || broken(ret == ARRAY_SIZE(foldczone_broken_dst)), /* winxp, win2003 */
4453 "Got %d, error %ld.\n", ret, GetLastError());
4454 ok(!memcmp(dst, foldczone_dst, sizeof(foldczone_dst))
4455 || broken(!memcmp(dst, foldczone_broken_dst, sizeof(foldczone_broken_dst))), /* winxp, win2003 */
4456 "Got unexpected string %s.\n", wine_dbgstr_w(dst));
4457
4458 /* MAP_EXPAND_LIGATURES */
4459 SetLastError(0xdeadbeef);
4460 ret = FoldStringW(MAP_EXPAND_LIGATURES, ligatures_src, -1, dst, 256);
4461 ok(ret == ARRAY_SIZE(ligatures_dst), "Got %d, error %ld\n", ret, GetLastError());
4462 ok(!memcmp(dst, ligatures_dst, sizeof(ligatures_dst)),
4463 "Got unexpected string %s.\n", wine_dbgstr_w(dst));
4464
4465 /* FIXME: MAP_PRECOMPOSED : MAP_COMPOSITE */
4466}
4467
4468
4469
4470#define LCID_OK(l) \
4471 ok(lcid == l, "Expected lcid = %08lx, got %08lx\n", l, lcid)
4472#define MKLCID(x,y,z) MAKELCID(MAKELANGID(x, y), z)
4473#define LCID_RES(src, res) do { lcid = ConvertDefaultLocale(src); LCID_OK(res); } while (0)
4474#define TEST_LCIDLANG(a,b) LCID_RES(MAKELCID(a,b), MAKELCID(a,b))
4475#define TEST_LCID(a,b,c) LCID_RES(MKLCID(a,b,c), MKLCID(a,b,c))
4476
4478{
4479 /* some languages use a different default than SUBLANG_DEFAULT */
4480 static const struct { WORD lang, sublang; } nondefault_langs[] =
4481 {
4491 };
4492 LCID lcid;
4493 unsigned int i;
4494
4495 /* Doesn't change lcid, even if non default sublang/sort used */
4503 "Expected lcid = %08lx got %08lx\n",
4508 "Expected lcid = %08lx got %08lx\n",
4510
4511 /* SUBLANG_NEUTRAL -> SUBLANG_DEFAULT */
4516 for (i = 0; i < ARRAY_SIZE(nondefault_langs); i++)
4517 {
4518 lcid = ConvertDefaultLocale( MAKELANGID( nondefault_langs[i].lang, SUBLANG_NEUTRAL ));
4519 ok( lcid == MAKELANGID( nondefault_langs[i].lang, nondefault_langs[i].sublang ) ||
4520 broken( lcid == MAKELANGID( nondefault_langs[i].lang, SUBLANG_DEFAULT )) || /* <= vista */
4521 broken( lcid == MAKELANGID( nondefault_langs[i].lang, SUBLANG_NEUTRAL )), /* w7 */
4522 "Expected lcid = %08x got %08lx\n",
4523 MAKELANGID( nondefault_langs[i].lang, nondefault_langs[i].sublang ), lcid );
4524 }
4525 lcid = ConvertDefaultLocale( 0x7804 );
4527 broken( lcid == 0x7804 ), /* <= vista */
4528 "Expected lcid = %08x got %08lx\n", MAKELANGID( LANG_CHINESE, SUBLANG_CHINESE_SIMPLIFIED ), lcid );
4529 lcid = ConvertDefaultLocale( 0x7c04 );
4531 broken( lcid == 0x7c04 ) || /* winxp */
4532 broken( lcid == 0x0404 ), /* vista */
4533 "Expected lcid = %08x got %08lx\n", MAKELANGID( LANG_CHINESE, SUBLANG_CHINESE_HONGKONG ), lcid );
4536#ifdef __REACTOS__
4538 broken( lcid == LANG_SERBIAN_NEUTRAL ), /* WS03 */
4539#else
4540 broken( lcid == MAKELANGID( LANG_SERBIAN, SUBLANG_SERBIAN_LATIN ) ), /* <= vista */
4541#endif
4542 "Expected lcid = %08x got %08lx\n", MAKELANGID( LANG_SERBIAN, SUBLANG_SERBIAN_SERBIA_LATIN ), lcid );
4543
4544 /* Invariant language is not treated specially */
4546
4547 /* User/system default languages alone are not mapped */
4550
4551 /* Default lcids */
4555#ifdef __REACTOS__
4557 ok(lcid == GetUserDefaultLCID() ||
4558 broken(lcid == 0x0c00) /* WS03 */,
4559 "Expected lcid = %08lx, got %08lx\n", GetUserDefaultLCID(), lcid);
4560#else
4562#endif
4565 "wrong lcid %04lx\n", lcid );
4567 ok( lcid == GetUserDefaultUILanguage() || lcid == LOCALE_CUSTOM_UI_DEFAULT, "wrong lcid %04lx\n", lcid );
4569 ok(lcid == LOCALE_INVARIANT || broken(lcid == 0x47f) /* win2k[3]/winxp */,
4570 "Expected lcid = %08lx, got %08lx\n", LOCALE_INVARIANT, lcid);
4571}
4572
4573static BOOL CALLBACK langgrp_procA(LGRPID lgrpid, LPSTR lpszNum, LPSTR lpszName,
4575{
4576 if (winetest_debug > 1)
4577 trace("%08lx, %s, %s, %08lx, %08Ix\n",
4578 lgrpid, lpszNum, lpszName, dwFlags, lParam);
4579
4580 ok(pIsValidLanguageGroup(lgrpid, dwFlags) == TRUE,
4581 "Enumerated grp %ld not valid (flags %ld)\n", lgrpid, dwFlags);
4582
4583 /* If lParam is one, we are calling with flags defaulted from 0 */
4585 "Expected dwFlags == LGRPID_INSTALLED || dwFlags == LGRPID_SUPPORTED, got %ld\n", dwFlags);
4586
4587 return TRUE;
4588}
4589
4591{
4592 BOOL ret;
4593
4594 if (!pEnumSystemLanguageGroupsA || !pIsValidLanguageGroup)
4595 {
4596 win_skip("EnumSystemLanguageGroupsA and/or IsValidLanguageGroup are not available\n");
4597 return;
4598 }
4599
4600 /* No enumeration proc */
4601 SetLastError(0);
4602 ret = pEnumSystemLanguageGroupsA(0, LGRPID_INSTALLED, 0);
4604 {
4605 win_skip("EnumSystemLanguageGroupsA is not implemented\n");
4606 return;
4607 }
4609 "Expected ERROR_INVALID_PARAMETER, got %ld\n", GetLastError());
4610
4611 /* Invalid flags */
4612 SetLastError(0);
4613 pEnumSystemLanguageGroupsA(langgrp_procA, LGRPID_INSTALLED|LGRPID_SUPPORTED, 0);
4614 ok(GetLastError() == ERROR_INVALID_FLAGS, "Expected ERROR_INVALID_FLAGS, got %ld\n", GetLastError());
4615
4616 /* No flags - defaults to LGRPID_INSTALLED */
4617 SetLastError(0xdeadbeef);
4618 pEnumSystemLanguageGroupsA(langgrp_procA, 0, 1);
4619 ok(GetLastError() == 0xdeadbeef, "got error %ld\n", GetLastError());
4620
4621 pEnumSystemLanguageGroupsA(langgrp_procA, LGRPID_INSTALLED, 0);
4622 pEnumSystemLanguageGroupsA(langgrp_procA, LGRPID_SUPPORTED, 0);
4623}
4624
4627
4629{
4630 LCID lcid;
4631 WORD sortid;
4632
4633 if (sscanf(str, "%lx", &lcid) != 1)
4634 {
4635 ok(FALSE, "EnumSystemLocalesA callback received unparsable LCID string \"%s\"\n", str);
4636 return FALSE;
4637 }
4638
4639 sortid = SORTIDFROMLCID(lcid);
4640 if (sortid == SORT_DEFAULT)
4641 {
4642 default_seen++;
4643 }
4644 else
4645 {
4647 }
4648
4649 return TRUE;
4650}
4651
4653{
4654 LCID lcid;
4655 WORD sortid;
4656
4657 if (swscanf(str, L"%lx", &lcid) != 1)
4658 {
4659 ok(FALSE, "unparsable LCID string %s\n", debugstr_w(str));
4660 return FALSE;
4661 }
4662
4663 sortid = SORTIDFROMLCID(lcid);
4664 if (sortid == SORT_DEFAULT)
4665 {
4666 default_seen++;
4667 }
4668 else
4669 {
4671 }
4672
4673 return TRUE;
4674}
4675
4677{
4678 if (!pEnumSystemLocalesA)
4679 {
4680 win_skip("EnumSystemLocalesA not available");
4681 return;
4682 }
4683
4684 default_seen = 0;
4685 alternate_seen = 0;
4686
4687 pEnumSystemLocalesA(test_EnumSystemLocalesA_callback, 0);
4688 ok(default_seen, "EnumSystemLocalesA(..., 0) returned 0 locales "
4689 "with default sort order, expected > 0\n");
4690 ok(!alternate_seen, "EnumSystemLocalesA(..., 0) returned %ld locales "
4691 "with alternate sort order, expected 0\n", alternate_seen);
4692
4693 default_seen = 0;
4694 alternate_seen = 0;
4695
4697 ok(default_seen, "EnumSystemLocalesA(..., LCID_INSTALLED) returned 0 locales "
4698 "with default sort order, expected > 0\n");
4699 ok(!alternate_seen, "EnumSystemLocalesA(..., LCID_INSTALLED) returned %ld locales "
4700 "with alternate sort order, expected 0\n", alternate_seen);
4701
4702 default_seen = 0;
4703 alternate_seen = 0;
4704
4706 ok(default_seen, "EnumSystemLocalesA(..., LCID_SUPPORTED) returned 0 locales "
4707 "with default sort order, expected > 0\n");
4708 ok(!alternate_seen, "EnumSystemLocalesA(..., LCID_SUPPORTED) returned %ld locales "
4709 "with alternate sort order, expected 0\n", alternate_seen);
4710
4711 default_seen = 0;
4712 alternate_seen = 0;
4713
4715 ok(alternate_seen, "EnumSystemLocalesA(..., LCID_ALTERNATE_SORTS) returned 0 locales "
4716 "with alternate sort order, expected > 0\n");
4717 ok(!default_seen, "EnumSystemLocalesA(..., LCID_ALTERNATE_SORTS) returned %ld locales "
4718 "with default sort order, expected 0\n", alternate_seen);
4719
4720 default_seen = 0;
4721 alternate_seen = 0;
4722
4724 ok(default_seen, "EnumSystemLocalesA(..., LCID_INSTALLED | LCID_ALTERNATE_SORTS) returned 0 locales "
4725 "with default sort order, expected > 0\n");
4726 ok(alternate_seen, "EnumSystemLocalesA(..., LCID_INSTALLED | LCID_ALTERNATE_SORTS) returned 0 locales "
4727 "with alternate sort order, expected > 0\n");
4728
4729 default_seen = 0;
4730 alternate_seen = 0;
4731
4733 ok(default_seen, "EnumSystemLocalesA(..., LCID_SUPPORTED | LCID_ALTERNATE_SORTS) returned 0 locales "
4734 "with default sort order, expected > 0\n");
4735 ok(alternate_seen, "EnumSystemLocalesA(..., LCID_SUPPORTED | LCID_ALTERNATE_SORTS) returned 0 locales "
4736 "with alternate sort order, expected > 0\n");
4737}
4738
4740{
4741 if (!pEnumSystemLocalesW)
4742 {
4743 win_skip("EnumSystemLocalesW not available");
4744 return;
4745 }
4746
4747 default_seen = 0;
4748 alternate_seen = 0;
4749
4750 pEnumSystemLocalesW(test_EnumSystemLocalesW_callback, 0);
4751 ok(default_seen, "EnumSystemLocalesW(..., 0) returned 0 locales "
4752 "with default sort order, expected > 0\n");
4753 ok(!alternate_seen, "EnumSystemLocalesW(..., 0) returned %ld locales "
4754 "with alternate sort order, expected 0\n", alternate_seen);
4755
4756 default_seen = 0;
4757 alternate_seen = 0;
4758
4760 ok(default_seen, "EnumSystemLocalesW(..., LCID_INSTALLED) returned 0 locales "
4761 "with default sort order, expected > 0\n");
4762 ok(!alternate_seen, "EnumSystemLocalesW(..., LCID_INSTALLED) returned %ld locales "
4763 "with alternate sort order, expected 0\n", alternate_seen);
4764
4765 default_seen = 0;
4766 alternate_seen = 0;
4767
4769 ok(default_seen, "EnumSystemLocalesW(..., LCID_SUPPORTED) returned 0 locales "
4770 "with default sort order, expected > 0\n");
4771 ok(!alternate_seen, "EnumSystemLocalesW(..., LCID_SUPPORTED) returned %ld locales "
4772 "with alternate sort order, expected 0\n", alternate_seen);
4773
4774 default_seen = 0;
4775 alternate_seen = 0;
4776
4778 ok(alternate_seen, "EnumSystemLocalesW(..., LCID_ALTERNATE_SORTS) returned 0 locales "
4779 "with alternate sort order, expected > 0\n");
4780 ok(!default_seen, "EnumSystemLocalesW(..., LCID_ALTERNATE_SORTS) returned %ld locales "
4781 "with default sort order, expected 0\n", alternate_seen);
4782
4783 default_seen = 0;
4784 alternate_seen = 0;
4785
4787 ok(default_seen, "EnumSystemLocalesW(..., LCID_INSTALLED | LCID_ALTERNATE_SORTS) returned 0 locales "
4788 "with default sort order, expected > 0\n");
4789 ok(alternate_seen, "EnumSystemLocalesW(..., LCID_INSTALLED | LCID_ALTERNATE_SORTS) returned 0 locales "
4790 "with alternate sort order, expected > 0\n");
4791
4792 default_seen = 0;
4793 alternate_seen = 0;
4794
4796 ok(default_seen, "EnumSystemLocalesW(..., LCID_SUPPORTED | LCID_ALTERNATE_SORTS) returned 0 locales "
4797 "with default sort order, expected > 0\n");
4798 ok(alternate_seen, "EnumSystemLocalesW(..., LCID_SUPPORTED | LCID_ALTERNATE_SORTS) returned 0 locales "
4799 "with alternate sort order, expected > 0\n");
4800}
4801
4803{
4804 if (winetest_debug > 1)
4805 trace( "%s %lx\n", wine_dbgstr_w(name), flags );
4806 return TRUE;
4807}
4808
4810{
4811 BOOL ret;
4812
4813 if (!pEnumSystemLocalesEx)
4814 {
4815 win_skip( "EnumSystemLocalesEx not available\n" );
4816 return;
4817 }
4818 SetLastError( 0xdeadbeef );
4819 ret = pEnumSystemLocalesEx( enum_func, LOCALE_ALL, 0, (void *)1 );
4820 ok( !ret, "should have failed\n" );
4821 ok( GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %lu\n", GetLastError() );
4822 SetLastError( 0xdeadbeef );
4823 ret = pEnumSystemLocalesEx( enum_func, 0, 0, NULL );
4824 ok( ret, "failed err %lu\n", GetLastError() );
4825}
4826
4829{
4830 if (winetest_debug > 1)
4831 trace("%08lx, %08lx, %s, %08Ix\n", lgrpid, lcid, lpszNum, lParam);
4832
4833 /* invalid locale enumerated on some platforms */
4834 if (lcid == 0)
4835 return TRUE;
4836
4837 ok(pIsValidLanguageGroup(lgrpid, LGRPID_SUPPORTED) == TRUE,
4838 "Enumerated grp %ld not valid\n", lgrpid);
4840 "Enumerated grp locale %04lx not valid\n", lcid);
4841 return TRUE;
4842}
4843
4845{
4846 BOOL ret;
4847
4848 if (!pEnumLanguageGroupLocalesA || !pIsValidLanguageGroup)
4849 {
4850 win_skip("EnumLanguageGroupLocalesA and/or IsValidLanguageGroup are not available\n");
4851 return;
4852 }
4853
4854 /* No enumeration proc */
4855 SetLastError(0);
4856 ret = pEnumLanguageGroupLocalesA(0, LGRPID_WESTERN_EUROPE, 0, 0);
4858 {
4859 win_skip("EnumLanguageGroupLocalesA is not implemented\n");
4860 return;
4861 }
4863 "Expected ERROR_INVALID_PARAMETER, got %ld\n", GetLastError());
4864
4865 /* lgrpid too small */
4866 SetLastError(0);
4867 ret = pEnumLanguageGroupLocalesA(lgrplocale_procA, 0, 0, 0);
4869 "Expected ERROR_INVALID_PARAMETER, got %ld\n", GetLastError());
4870
4871 /* lgrpid too big */
4872 SetLastError(0);
4873 ret = pEnumLanguageGroupLocalesA(lgrplocale_procA, LGRPID_ARMENIAN + 1, 0, 0);
4875 "Expected ERROR_INVALID_PARAMETER, got %ld\n", GetLastError());
4876
4877 /* dwFlags is reserved */
4878 SetLastError(0);
4879 ret = pEnumLanguageGroupLocalesA(0, LGRPID_WESTERN_EUROPE, 0x1, 0);
4881 "Expected ERROR_INVALID_PARAMETER, got %ld\n", GetLastError());
4882
4883 pEnumLanguageGroupLocalesA(lgrplocale_procA, LGRPID_WESTERN_EUROPE, 0, 0);
4884}
4885
4886static void test_SetLocaleInfo(void)
4887{
4888 BOOL bRet;
4890 UINT i;
4891
4892 /* Null data */
4893 SetLastError(0xdeadbeef);
4896 "Expected ERROR_INVALID_PARAMETER, got %ld\n", GetLastError());
4897
4898 SetLastError(0xdeadbeef);
4901 "Expected ERROR_INVALID_PARAMETER, got %ld\n", GetLastError());
4902
4903 SetLastError(0xdeadbeef);
4906 "Expected ERROR_INVALID_PARAMETER, got %ld\n", GetLastError());
4907
4908 for (i = 0; i <= 0x1014; i++)
4909 {
4910 WCHAR buffer[80];
4912 SetLastError(0xdeadbeef);
4913 bRet = SetLocaleInfoW(lcid, i, buffer);
4914 switch (i)
4915 {
4917 case LOCALE_ICURRDIGITS:
4918 case LOCALE_ICURRENCY:
4919 case LOCALE_IDIGITS:
4920 case LOCALE_IDIGITSUBSTITUTION:
4923 case LOCALE_ILZERO:
4924 case LOCALE_IMEASURE:
4925 case LOCALE_INEGCURR:
4926 case LOCALE_INEGNUMBER:
4927 case LOCALE_IPAPERSIZE:
4928 case LOCALE_ITIME:
4929 case LOCALE_S1159:
4930 case LOCALE_S2359:
4931 case LOCALE_SCURRENCY:
4932 case LOCALE_SDATE:
4933 case LOCALE_SDECIMAL:
4934 case LOCALE_SGROUPING:
4935 case LOCALE_SLIST:
4936 case LOCALE_SLONGDATE:
4943 case LOCALE_SSHORTDATE:
4944 case LOCALE_SSHORTTIME:
4945 case LOCALE_STHOUSAND:
4946 case LOCALE_STIME:
4947 case LOCALE_STIMEFORMAT:
4948 case LOCALE_SYEARMONTH:
4949 ok( bRet, "%04x: failed err %lu\n", i, GetLastError() );
4950 break;
4951 case LOCALE_SINTLSYMBOL:
4952 ok( bRet || broken(!bRet), /* win10 <= 1507 */
4953 "%04x: failed err %lu\n", i, GetLastError() );
4954 break;
4955 default:
4956 ok( !bRet, "%04x: succeeded\n", i );
4957 ok( GetLastError() == ERROR_INVALID_FLAGS, "%04x: wrong error %lu\n", i, GetLastError() );
4958 break;
4959 }
4960 }
4961}
4962
4964{
4965 if (winetest_debug > 1)
4966 trace("%s %08Ix\n", value, lParam);
4967 return(TRUE);
4968}
4969
4971{
4972 ok(!enumCount, "callback called again unexpected\n");
4973 enumCount++;
4974 return(FALSE);
4975}
4976
4978{
4979 ok(0,"callback called unexpected\n");
4980 return(FALSE);
4981}
4982
4983static void test_EnumUILanguageA(void)
4984{
4985 BOOL ret;
4986 if (!pEnumUILanguagesA) {
4987 win_skip("EnumUILanguagesA is not available on Win9x or NT4\n");
4988 return;
4989 }
4990
4992 ret = pEnumUILanguagesA(luilocale_proc1A, 0, 0);
4994 {
4995 win_skip("EnumUILanguagesA is not implemented\n");
4996 return;
4997 }
4998 ok(ret, "Expected ret != 0, got %d, error %ld\n", ret, GetLastError());
4999
5000 SetLastError(0xdeadbeef);
5001 ret = pEnumUILanguagesA(luilocale_proc1A, MUI_LANGUAGE_NAME, 0);
5002#ifdef __REACTOS__
5003 ok(ret || broken(!ret && GetLastError() == ERROR_INVALID_FLAGS) /* WS03 */, "Expected ret != 0, got %d, error %ld\n", ret, GetLastError());
5004#else
5005 ok(ret, "Expected ret != 0, got %d, error %ld\n", ret, GetLastError());
5006#endif
5007
5008 enumCount = 0;
5010 ret = pEnumUILanguagesA(luilocale_proc2A, 0, 0);
5011 ok(ret, "Expected ret != 0, got %d, error %ld\n", ret, GetLastError());
5012 ok(enumCount == 1, "enumCount = %u\n", enumCount);
5013
5014 enumCount = 0;
5016 ret = pEnumUILanguagesA(luilocale_proc2A, MUI_LANGUAGE_ID, 0);
5017 ok(ret || broken(!ret && GetLastError() == ERROR_INVALID_FLAGS), /* winxp */
5018 "Expected ret != 0, got %d, error %ld\n", ret, GetLastError());
5019 if (ret) ok(enumCount == 1, "enumCount = %u\n", enumCount);
5020
5022 ret = pEnumUILanguagesA(NULL, 0, 0);
5023 ok(!ret, "Expected return value FALSE, got %u\n", ret);
5025 "Expected ERROR_INVALID_PARAMETER, got %ld\n", GetLastError());
5026
5028 ret = pEnumUILanguagesA(luilocale_proc3A, 0x5a5a5a5a, 0);
5029 ok(!ret, "Expected return value FALSE, got %u\n", ret);
5030 ok(GetLastError() == ERROR_INVALID_FLAGS, "Expected ERROR_INVALID_FLAGS, got %ld\n", GetLastError());
5031
5033 ret = pEnumUILanguagesA(NULL, 0x5a5a5a5a, 0);
5034 ok(!ret, "Expected return value FALSE, got %u\n", ret);
5036 "Expected ERROR_INVALID_PARAMETER, got %ld\n", GetLastError());
5037}
5038
5039static char date_fmt_buf[1024];
5041
5043{
5045 lstrcatA(date_fmt_buf, "\n");
5046 return TRUE;
5047}
5048
5050{
5052 return FALSE;
5053}
5054
5055static void test_EnumDateFormatsA(void)
5056{
5057 char *p, buf[256];
5058 BOOL ret;
5060
5061 date_fmt_buf[0] = 0;
5062 SetLastError(0xdeadbeef);
5064 if (!ret && (GetLastError() == ERROR_INVALID_FLAGS))
5065 {
5066 win_skip("0 for dwFlags is not supported\n");
5067 }
5068 else
5069 {
5070 ok(ret, "EnumDateFormatsA(0) error %ld\n", GetLastError());
5071 trace("EnumDateFormatsA(0): %s\n", date_fmt_buf);
5072 /* test the 1st enumerated format */
5073 if ((p = strchr(date_fmt_buf, '\n'))) *p = 0;
5075 ok(ret, "GetLocaleInfoA(LOCALE_SSHORTDATE) error %ld\n", GetLastError());
5076 ok(!lstrcmpA(date_fmt_buf, buf), "expected \"%s\" got \"%s\"\n", date_fmt_buf, buf);
5077 }
5078
5079 date_fmt_buf[0] = 0;
5080 SetLastError(0xdeadbeef);
5082 if (!ret && (GetLastError() == ERROR_INVALID_FLAGS))
5083 {
5084 win_skip("LOCALE_USE_CP_ACP is not supported\n");
5085 }
5086 else
5087 {
5088 ok(ret, "EnumDateFormatsA(LOCALE_USE_CP_ACP) error %ld\n", GetLastError());
5089 trace("EnumDateFormatsA(LOCALE_USE_CP_ACP): %s\n", date_fmt_buf);
5090 /* test the 1st enumerated format */
5091 if ((p = strchr(date_fmt_buf, '\n'))) *p = 0;
5093 ok(ret, "GetLocaleInfoA(LOCALE_SSHORTDATE) error %ld\n", GetLastError());
5094 ok(!lstrcmpA(date_fmt_buf, buf), "expected \"%s\" got \"%s\"\n", date_fmt_buf, buf);
5095 }
5096
5097 date_fmt_buf[0] = 0;
5099 ok(ret, "EnumDateFormatsA(DATE_SHORTDATE) error %ld\n", GetLastError());
5100 trace("EnumDateFormatsA(DATE_SHORTDATE): %s\n", date_fmt_buf);
5101 /* test the 1st enumerated format */
5102 if ((p = strchr(date_fmt_buf, '\n'))) *p = 0;
5104 ok(ret, "GetLocaleInfoA(LOCALE_SSHORTDATE) error %ld\n", GetLastError());
5105 ok(!lstrcmpA(date_fmt_buf, buf), "expected \"%s\" got \"%s\"\n", date_fmt_buf, buf);
5106
5107 date_fmt_buf[0] = 0;
5109 ok(ret, "EnumDateFormatsA(DATE_LONGDATE) error %ld\n", GetLastError());
5110 trace("EnumDateFormatsA(DATE_LONGDATE): %s\n", date_fmt_buf);
5111 /* test the 1st enumerated format */
5112 if ((p = strchr(date_fmt_buf, '\n'))) *p = 0;
5114 ok(ret, "GetLocaleInfoA(LOCALE_SLONGDATE) error %ld\n", GetLastError());
5115 ok(!lstrcmpA(date_fmt_buf, buf), "expected \"%s\" got \"%s\"\n", date_fmt_buf, buf);
5116
5117 date_fmt_buf[0] = 0;
5118 SetLastError(0xdeadbeef);
5119 ret = EnumDateFormatsA(enum_datetime_procA, lcid, DATE_YEARMONTH);
5120 if (!ret && (GetLastError() == ERROR_INVALID_FLAGS))
5121 {
5122 win_skip("DATE_YEARMONTH is only present on W2K and later\n");
5123 return;
5124 }
5125 ok(ret, "EnumDateFormatsA(DATE_YEARMONTH) error %ld\n", GetLastError());
5126 trace("EnumDateFormatsA(DATE_YEARMONTH): %s\n", date_fmt_buf);
5127 /* test the 1st enumerated format */
5128 if ((p = strchr(date_fmt_buf, '\n'))) *p = 0;
5129 ret = GetLocaleInfoA(lcid, LOCALE_SYEARMONTH, buf, sizeof(buf));
5130 ok(ret, "GetLocaleInfoA(LOCALE_SYEARMONTH) error %ld\n", GetLastError());
5131 ok(!lstrcmpA(date_fmt_buf, buf) || broken(!buf[0]) /* win9x */,
5132 "expected \"%s\" got \"%s\"\n", date_fmt_buf, buf);
5133}
5134
5135static void test_EnumTimeFormatsA(void)
5136{
5137 char *p, buf[256];
5138 BOOL ret;
5140
5141 date_fmt_buf[0] = 0;
5143 ok(ret, "EnumTimeFormatsA(0) error %ld\n", GetLastError());
5144 trace("EnumTimeFormatsA(0): %s\n", date_fmt_buf);
5145 /* test the 1st enumerated format */
5146 if ((p = strchr(date_fmt_buf, '\n'))) *p = 0;
5148 ok(ret, "GetLocaleInfoA(LOCALE_STIMEFORMAT) error %ld\n", GetLastError());
5149 ok(!lstrcmpA(date_fmt_buf, buf), "expected \"%s\" got \"%s\"\n", date_fmt_buf, buf);
5150
5151 date_fmt_buf[0] = 0;
5153 ok(ret, "EnumTimeFormatsA(LOCALE_USE_CP_ACP) error %ld\n", GetLastError());
5154 trace("EnumTimeFormatsA(LOCALE_USE_CP_ACP): %s\n", date_fmt_buf);
5155 /* test the 1st enumerated format */
5156 if ((p = strchr(date_fmt_buf, '\n'))) *p = 0;
5158 ok(ret, "GetLocaleInfoA(LOCALE_STIMEFORMAT) error %ld\n", GetLastError());
5159 ok(!lstrcmpA(date_fmt_buf, buf), "expected \"%s\" got \"%s\"\n", date_fmt_buf, buf);
5160}
5161
5162static void test_EnumTimeFormatsW(void)
5163{
5165 WCHAR bufW[256];
5166 BOOL ret;
5167
5168 date_fmt_bufW[0] = 0;
5170 ok(ret, "EnumTimeFormatsW(0) error %ld\n", GetLastError());
5172 ok(ret, "GetLocaleInfoW(LOCALE_STIMEFORMAT) error %ld\n", GetLastError());
5173 ok(!lstrcmpW(date_fmt_bufW, bufW), "expected \"%s\" got \"%s\"\n", wine_dbgstr_w(date_fmt_bufW),
5174 wine_dbgstr_w(bufW));
5175
5176 date_fmt_bufW[0] = 0;
5178 ok(ret, "EnumTimeFormatsW(LOCALE_USE_CP_ACP) error %ld\n", GetLastError());
5180 ok(ret, "GetLocaleInfoW(LOCALE_STIMEFORMAT) error %ld\n", GetLastError());
5181 ok(!lstrcmpW(date_fmt_bufW, bufW), "expected \"%s\" got \"%s\"\n", wine_dbgstr_w(date_fmt_bufW),
5182 wine_dbgstr_w(bufW));
5183
5184 /* TIME_NOSECONDS is Win7+ feature */
5185 date_fmt_bufW[0] = 0;
5188 win_skip("EnumTimeFormatsW doesn't support TIME_NOSECONDS\n");
5189 else {
5190 char buf[256];
5191
5192 ok(ret, "EnumTimeFormatsW(TIME_NOSECONDS) error %ld\n", GetLastError());
5194 ok(ret, "GetLocaleInfoW(LOCALE_SSHORTTIME) error %ld\n", GetLastError());
5195 ok(!lstrcmpW(date_fmt_bufW, bufW), "expected \"%s\" got \"%s\"\n", wine_dbgstr_w(date_fmt_bufW),
5196 wine_dbgstr_w(bufW));
5197
5198 /* EnumTimeFormatsA doesn't support this flag */
5200 ok(!ret && GetLastError() == ERROR_INVALID_FLAGS, "EnumTimeFormatsA(TIME_NOSECONDS) ret %d, error %ld\n", ret,
5201 GetLastError());
5202
5204 ok(!ret && GetLastError() == ERROR_INVALID_FLAGS, "EnumTimeFormatsA(TIME_NOSECONDS) ret %d, error %ld\n", ret,
5205 GetLastError());
5206
5207 /* And it's not supported by GetLocaleInfoA either */
5209 ok(!ret && GetLastError() == ERROR_INVALID_FLAGS, "GetLocaleInfoA(LOCALE_SSHORTTIME) ret %d, error %ld\n", ret,
5210 GetLastError());
5211 }
5212}
5213
5214static void test_GetCPInfo(void)
5215{
5216 BOOL ret;
5217 CPINFO cpinfo;
5218 CPINFOEXW cpiw;
5219
5220 SetLastError(0xdeadbeef);
5221 ret = GetCPInfo(CP_SYMBOL, &cpinfo);
5222 ok(!ret, "GetCPInfo(CP_SYMBOL) should fail\n");
5224 "expected ERROR_INVALID_PARAMETER, got %lu\n", GetLastError());
5225
5226 memset(cpinfo.LeadByte, '-', ARRAY_SIZE(cpinfo.LeadByte));
5227 SetLastError(0xdeadbeef);
5228 ret = GetCPInfo(CP_UTF7, &cpinfo);
5230 {
5231 win_skip("Codepage CP_UTF7 is not installed/available\n");
5232 }
5233 else
5234 {
5235 unsigned int i;
5236
5237 ok(ret, "GetCPInfo(CP_UTF7) error %lu\n", GetLastError());
5238 ok(cpinfo.DefaultChar[0] == 0x3f, "expected 0x3f, got 0x%x\n", cpinfo.DefaultChar[0]);
5239 ok(cpinfo.DefaultChar[1] == 0, "expected 0, got 0x%x\n", cpinfo.DefaultChar[1]);
5240 for (i = 0; i < sizeof(cpinfo.LeadByte); i++)
5241 ok(!cpinfo.LeadByte[i], "expected NUL byte in index %u\n", i);
5242 ok(cpinfo.MaxCharSize == 5, "expected 5, got 0x%x\n", cpinfo.MaxCharSize);
5243
5244 memset( &cpiw, 0xcc, sizeof(cpiw) );
5245 ret = GetCPInfoExW( CP_UTF7, 0, &cpiw );
5246 ok( ret, "GetCPInfoExW failed err %lu\n", GetLastError() );
5247 ok( cpiw.DefaultChar[0] == 0x3f, "wrong DefaultChar[0] %02x\n", cpiw.DefaultChar[0] );
5248 ok( cpiw.DefaultChar[1] == 0, "wrong DefaultChar[1] %02x\n", cpiw.DefaultChar[1] );
5249 for (i = 0; i < 12; i++) ok( cpiw.LeadByte[i] == 0, "wrong LeadByte[%u] %02x\n", i, cpiw.LeadByte[i] );
5250 ok( cpiw.MaxCharSize == 5, "wrong MaxCharSize %02x\n", cpiw.MaxCharSize );
5251 ok( cpiw.CodePage == CP_UTF7, "wrong CodePage %02x\n", cpiw.CodePage );
5252#ifdef __REACTOS__
5253 ok( cpiw.UnicodeDefaultChar == 0xfffd ||
5254 broken(cpiw.UnicodeDefaultChar == 0x3f) /* WS03 */, "wrong UnicodeDefaultChar %02x\n", cpiw.UnicodeDefaultChar );
5255#else
5256 ok( cpiw.UnicodeDefaultChar == 0xfffd, "wrong UnicodeDefaultChar %02x\n", cpiw.UnicodeDefaultChar );
5257#endif
5258 ok( !wcscmp( cpiw.CodePageName, L"65000 (UTF-7)" ),
5259 "wrong CodePageName %s\n", debugstr_w(cpiw.CodePageName) );
5260 }
5261
5262 memset(cpinfo.LeadByte, '-', ARRAY_SIZE(cpinfo.LeadByte));
5263 SetLastError(0xdeadbeef);
5264 ret = GetCPInfo(CP_UTF8, &cpinfo);
5266 {
5267 win_skip("Codepage CP_UTF8 is not installed/available\n");
5268 }
5269 else
5270 {
5271 unsigned int i;
5272
5273 ok(ret, "GetCPInfo(CP_UTF8) error %lu\n", GetLastError());
5274 ok(cpinfo.DefaultChar[0] == 0x3f, "expected 0x3f, got 0x%x\n", cpinfo.DefaultChar[0]);
5275 ok(cpinfo.DefaultChar[1] == 0, "expected 0, got 0x%x\n", cpinfo.DefaultChar[1]);
5276 for (i = 0; i < sizeof(cpinfo.LeadByte); i++)
5277 ok(!cpinfo.LeadByte[i], "expected NUL byte in index %u\n", i);
5278 ok(cpinfo.MaxCharSize == 4, "expected 4, got %u\n", cpinfo.MaxCharSize);
5279
5280 memset( &cpiw, 0xcc, sizeof(cpiw) );
5281 ret = GetCPInfoExW( CP_UTF8, 0, &cpiw );
5282 ok( ret, "GetCPInfoExW failed err %lu\n", GetLastError() );
5283 ok( cpiw.DefaultChar[0] == 0x3f, "wrong DefaultChar[0] %02x\n", cpiw.DefaultChar[0] );
5284 ok( cpiw.DefaultChar[1] == 0, "wrong DefaultChar[1] %02x\n", cpiw.DefaultChar[1] );
5285 for (i = 0; i < 12; i++) ok( cpiw.LeadByte[i] == 0, "wrong LeadByte[%u] %02x\n", i, cpiw.LeadByte[i] );
5286 ok( cpiw.MaxCharSize == 4, "wrong MaxCharSize %02x\n", cpiw.MaxCharSize );
5287 ok( cpiw.CodePage == CP_UTF8, "wrong CodePage %02x\n", cpiw.CodePage );
5288#ifdef __REACTOS__
5289 ok( cpiw.UnicodeDefaultChar == 0xfffd ||
5290 broken(cpiw.UnicodeDefaultChar == 0x3f) /* WS03 */, "wrong UnicodeDefaultChar %02x\n", cpiw.UnicodeDefaultChar );
5291#else
5292 ok( cpiw.UnicodeDefaultChar == 0xfffd, "wrong UnicodeDefaultChar %02x\n", cpiw.UnicodeDefaultChar );
5293#endif
5294 ok( !wcscmp( cpiw.CodePageName, L"65001 (UTF-8)" ),
5295 "wrong CodePageName %s\n", debugstr_w(cpiw.CodePageName) );
5296 }
5297
5298
5299 SetLastError( 0xdeadbeef );
5300 ret = GetCPInfoExW( 0xbeef, 0, &cpiw );
5301 ok( !ret, "GetCPInfoExW succeeeded\n" );
5302 ok( GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %lu\n", GetLastError() );
5303
5304#if defined(__REACTOS__) && DLL_EXPORT_VERSION >= 0x600
5305 /* FIXME: NtGetNlsSectionPtr is a STUB on ReactOS! */
5306 if (!is_reactos() && pNtGetNlsSectionPtr)
5307#else
5308 if (pNtGetNlsSectionPtr)
5309#endif
5310 {
5313 void *ptr, *ptr2;
5314 SIZE_T size;
5315 int i;
5316
5317 for (i = 0; i < 100; i++)
5318 {
5319 ptr = NULL;
5320 size = 0;
5321 status = pNtGetNlsSectionPtr( i, 9999, NULL, &ptr, &size );
5322 switch (i)
5323 {
5324 case 9: /* sortkeys */
5325 case 13: /* unknown */
5327 "%u: failed %lx\n", i, status );
5328 break;
5329 case 10: /* casemap */
5331 "%u: failed %lx\n", i, status );
5332 break;
5333 case 11: /* codepage */
5334 case 12: /* normalization */
5335 ok( status == STATUS_OBJECT_NAME_NOT_FOUND, "%u: failed %lx\n", i, status );
5336 break;
5337 case 14: /* unknown */
5339 status == STATUS_SUCCESS, /* win11 */
5340 "%u: failed %lx\n", i, status );
5341 break;
5342 default:
5343 ok( status == STATUS_INVALID_PARAMETER_1, "%u: failed %lx\n", i, status );
5344 break;
5345 }
5346 }
5347
5348 /* casemap table */
5349
5350 status = pNtGetNlsSectionPtr( 10, 0, NULL, &ptr, &size );
5352 {
5353 ok( !status, "failed %lx\n", status );
5354 ok( size > 0x1000 && size <= 0x8000 , "wrong size %Ix\n", size );
5355 status = pNtGetNlsSectionPtr( 10, 0, NULL, &ptr2, &size );
5356 ok( !status, "failed %lx\n", status );
5357 ok( ptr != ptr2, "got same pointer\n" );
5358 ret = UnmapViewOfFile( ptr );
5359 ok( ret, "UnmapViewOfFile failed err %lu\n", GetLastError() );
5360 ret = UnmapViewOfFile( ptr2 );
5361 ok( ret, "UnmapViewOfFile failed err %lu\n", GetLastError() );
5362 }
5363
5364 /* codepage tables */
5365
5366 ptr = (void *)0xdeadbeef;
5367 size = 0xdeadbeef;
5368 status = pNtGetNlsSectionPtr( 11, 437, NULL, &ptr, &size );
5369 ok( !status, "failed %lx\n", status );
5370 ok( size > 0x10000 && size <= 0x20000, "wrong size %Ix\n", size );
5371 memset( &table, 0xcc, sizeof(table) );
5372 if (pRtlInitCodePageTable)
5373 {
5374 pRtlInitCodePageTable( ptr, &table );
5375 ok( table.CodePage == 437, "wrong codepage %u\n", table.CodePage );
5376 ok( table.MaximumCharacterSize == 1, "wrong char size %u\n", table.MaximumCharacterSize );
5377 ok( table.DefaultChar == '?', "wrong default char %x\n", table.DefaultChar );
5378 ok( !table.DBCSCodePage, "wrong dbcs %u\n", table.DBCSCodePage );
5379 }
5380 ret = UnmapViewOfFile( ptr );
5381 ok( ret, "UnmapViewOfFile failed err %lu\n", GetLastError() );
5382
5383 status = pNtGetNlsSectionPtr( 11, 936, NULL, &ptr, &size );
5384 ok( !status, "failed %lx\n", status );
5385 ok( size > 0x30000 && size <= 0x40000, "wrong size %Ix\n", size );
5386 memset( &table, 0xcc, sizeof(table) );
5387 if (pRtlInitCodePageTable)
5388 {
5389 pRtlInitCodePageTable( ptr, &table );
5390 ok( table.CodePage == 936, "wrong codepage %u\n", table.CodePage );
5391 ok( table.MaximumCharacterSize == 2, "wrong char size %u\n", table.MaximumCharacterSize );
5392 ok( table.DefaultChar == '?', "wrong default char %x\n", table.DefaultChar );
5393 ok( table.DBCSCodePage == TRUE, "wrong dbcs %u\n", table.DBCSCodePage );
5394
5395 if (pRtlCustomCPToUnicodeN)
5396 {
5397 static const unsigned char buf[] = { 0xbf, 0xb4, 0xc7, 0, 0x78 };
5398 static const WCHAR expect[][4] = { { 0xcccc, 0xcccc, 0xcccc, 0xcccc },
5399 { 0x0000, 0xcccc, 0xcccc, 0xcccc },
5400 { 0x770b, 0xcccc, 0xcccc, 0xcccc },
5401 { 0x770b, 0x0000, 0xcccc, 0xcccc },
5402 { 0x770b, 0x003f, 0xcccc, 0xcccc },
5403 { 0x770b, 0x003f, 0x0078, 0xcccc } };
5404 WCHAR wbuf[5];
5405 DWORD i, j, reslen;
5406
5407 for (i = 0; i <= sizeof(buf); i++)
5408 {
5409 memset( wbuf, 0xcc, sizeof(wbuf) );
5410 pRtlCustomCPToUnicodeN( &table, wbuf, sizeof(wbuf), &reslen, (char *)buf, i );
5411 for (j = 0; j < 4; j++) if (expect[i][j] == 0xcccc) break;
5412 ok( reslen == j * sizeof(WCHAR), "%lu: wrong len %lu\n", i, reslen );
5413 for (j = 0; j < 4; j++)
5414 ok( wbuf[j] == expect[i][j], "%lu: char %lu got %04x\n", i, j, wbuf[j] );
5415 }
5416 }
5417 }
5418 ret = UnmapViewOfFile( ptr );
5419 ok( ret, "UnmapViewOfFile failed err %lu\n", GetLastError() );
5420
5421 status = pNtGetNlsSectionPtr( 11, 65001, NULL, &ptr, &size );
5422 ok( status == STATUS_OBJECT_NAME_NOT_FOUND || broken(!status), /* win10 1709 */
5423 "failed %lx\n", status );
5424 if (!status) UnmapViewOfFile( ptr );
5425 if (pRtlInitCodePageTable)
5426 {
5427 static USHORT utf8[20] = { 0, CP_UTF8 };
5428
5429 memset( &table, 0xcc, sizeof(table) );
5430 pRtlInitCodePageTable( utf8, &table );
5431 ok( table.CodePage == CP_UTF8, "wrong codepage %u\n", table.CodePage );
5432 if (table.MaximumCharacterSize)
5433 {
5434 ok( table.MaximumCharacterSize == 4, "wrong char size %u\n", table.MaximumCharacterSize );
5435 ok( table.DefaultChar == '?', "wrong default char %x\n", table.DefaultChar );
5436 ok( table.UniDefaultChar == 0xfffd, "wrong default char %x\n", table.UniDefaultChar );
5437 ok( table.TransDefaultChar == '?', "wrong default char %x\n", table.TransDefaultChar );
5438 ok( table.TransUniDefaultChar == '?', "wrong default char %x\n", table.TransUniDefaultChar );
5439 ok( !table.DBCSCodePage, "wrong dbcs %u\n", table.DBCSCodePage );
5440 ok( !table.MultiByteTable, "wrong mbtable %p\n", table.MultiByteTable );
5441 ok( !table.WideCharTable, "wrong wctable %p\n", table.WideCharTable );
5442 ok( !table.DBCSRanges, "wrong ranges %p\n", table.DBCSRanges );
5443 ok( !table.DBCSOffsets, "wrong offsets %p\n", table.DBCSOffsets );
5444 }
5445 else win_skip( "utf-8 codepage not supported\n" );
5446 }
5447
5448 /* normalization tables */
5449
5450 for (i = 0; i < 100; i++)
5451 {
5452 status = pNtGetNlsSectionPtr( 12, i, NULL, &ptr, &size );
5453 switch (i)
5454 {
5455 case NormalizationC:
5456 case NormalizationD:
5457 case NormalizationKC:
5458 case NormalizationKD:
5459 case 13: /* IDN */
5460 ok( !status, "%u: failed %lx\n", i, status );
5461 if (status) break;
5462 ok( size > 0x8000 && size <= 0x30000 , "wrong size %Ix\n", size );
5463 ret = UnmapViewOfFile( ptr );
5464 ok( ret, "UnmapViewOfFile failed err %lu\n", GetLastError() );
5465 break;
5466 default:
5467 ok( status == STATUS_OBJECT_NAME_NOT_FOUND, "%u: failed %lx\n", i, status );
5468 break;
5469 }
5470 }
5471 }
5472 else win_skip( "NtGetNlsSectionPtr not supported\n" );
5473}
5474
5475/*
5476 * The CT_TYPE1 has varied over windows version.
5477 * The current target for correct behavior is windows 7.
5478 * There was a big shift between windows 2000 (first introduced) and windows Xp
5479 * Most of the old values below are from windows 2000.
5480 * A smaller subset of changes happened between windows Xp and Window vista/7
5481 */
5482static void test_GetStringTypeW(void)
5483{
5484 static const WCHAR blanks[] = {0x9, 0x20, 0xa0, 0x3000, 0xfeff};
5485 static const WORD blanks_new[] = {C1_SPACE | C1_CNTRL | C1_BLANK | C1_DEFINED,
5490 static const WORD blanks_old[] ={C1_SPACE | C1_CNTRL | C1_BLANK,
5494 C1_SPACE | C1_BLANK};
5495
5496 static const WCHAR undefined[] = {0x378, 0x379, 0x5ff, 0xfff8, 0xfffe};
5497
5498 /* Lu, Ll, Lt */
5499 static const WCHAR alpha[] = {0x47, 0x67, 0x1c5};
5500 static const WORD alpha_old[] = {C1_UPPER | C1_ALPHA,
5503 C1_ALPHA};
5504
5505 /* Sk, Sk, Mn, So, Me */
5506 static const WCHAR oldpunc[] = { 0x2c2, 0x2e5, 0x322, 0x482, 0x6de,
5507 /* Sc, Sm, No,*/
5508 0xffe0, 0xffe9, 0x2153};
5509
5510 /* Lm, Nl, Cf, 0xad(Cf), 0x1f88 (Lt), Lo, Mc */
5511 static const WCHAR changed[] = {0x2b0, 0x2160, 0x600, 0xad, 0x1f88, 0x294, 0x903};
5512 static const WORD changed_old[] = { C1_PUNCT, C1_PUNCT, 0, C1_PUNCT, C1_UPPER | C1_ALPHA, C1_ALPHA, C1_PUNCT };
5513 static const WORD changed_xp[] = {C1_ALPHA | C1_DEFINED,
5519 C1_ALPHA | C1_DEFINED };
5520 static const WORD changed_new[] = { C1_ALPHA | C1_DEFINED,
5527 };
5528 /* Pc, Pd, Ps, Pe, Pi, Pf, Po*/
5529 static const WCHAR punct[] = { 0x5f, 0x2d, 0x28, 0x29, 0xab, 0xbb, 0x21 };
5530
5531 static const WCHAR punct_special[] = {0x24, 0x2b, 0x3c, 0x3e, 0x5e, 0x60,
5532 0x7c, 0x7e, 0xa2, 0xbe, 0xd7, 0xf7};
5533 static const WCHAR digit_special[] = {0xb2, 0xb3, 0xb9};
5534 static const WCHAR lower_special[] = {0x2071, 0x207f};
5535 static const WCHAR cntrl_special[] = {0x070f, 0x200c, 0x200d,
5536 0x200e, 0x200f, 0x202a, 0x202b, 0x202c, 0x202d, 0x202e,
5537 0x206a, 0x206b, 0x206c, 0x206d, 0x206e, 0x206f, 0xfeff,
5538 0xfff9, 0xfffa, 0xfffb};
5539 static const WCHAR space_special[] = {0x09, 0x0d, 0x85};
5540 static const WCHAR alpha_thai[] = {0xe31, 0xe34, 0xe35, 0xe36, 0xe37, 0xe38, 0xe39, 0xe3a,
5541 0xe47, 0xe48, 0xe49, 0xe4a, 0xe4b, 0xe4c, 0xe4d, 0xe4e,
5542 0x1885, 0x1886};
5543
5544 WORD types[20];
5545 WCHAR ch[2];
5546 BOOL ret;
5547 int i;
5548
5549 /* NULL src */
5550 SetLastError(0xdeadbeef);
5552 ok(!ret, "got %d\n", ret);
5553 ok(GetLastError() == ERROR_INVALID_PARAMETER, "got error %ld\n", GetLastError());
5554
5555 SetLastError(0xdeadbeef);
5557 ok(!ret, "got %d\n", ret);
5558 ok(GetLastError() == ERROR_INVALID_PARAMETER, "got error %ld\n", GetLastError());
5559
5560 SetLastError(0xdeadbeef);
5562 ok(!ret, "got %d\n", ret);
5563 ok(GetLastError() == ERROR_INVALID_PARAMETER, "got error %ld\n", GetLastError());
5564
5565 memset(types,0,sizeof(types));
5566 GetStringTypeW(CT_CTYPE1, blanks, 5, types);
5567 for (i = 0; i < 5; i++)
5568 ok(types[i] == blanks_new[i] || broken(types[i] == blanks_old[i] || broken(types[i] == 0)), "incorrect type1 returned for %x -> (%x != %x)\n",blanks[i],types[i],blanks_new[i]);
5569
5570 memset(types,0,sizeof(types));
5572 for (i = 0; i < 3; i++)
5573 ok(types[i] == (C1_DEFINED | alpha_old[i]) || broken(types[i] == alpha_old[i]) || broken(types[i] == 0), "incorrect types returned for %x -> (%x != %x)\n",alpha[i], types[i],(C1_DEFINED | alpha_old[i]));
5574 memset(types,0,sizeof(types));
5576 for (i = 0; i < 5; i++)
5577 ok(types[i] == 0, "incorrect types returned for %x -> (%x != 0)\n",undefined[i], types[i]);
5578
5579 memset(types,0,sizeof(types));
5580 GetStringTypeW(CT_CTYPE1, oldpunc, 8, types);
5581 for (i = 0; i < 8; i++)
5582 ok(types[i] == C1_DEFINED || broken(types[i] == C1_PUNCT) || broken(types[i] == 0), "incorrect types returned for %x -> (%x != %x)\n",oldpunc[i], types[i], C1_DEFINED);
5583
5584 memset(types,0,sizeof(types));
5585 GetStringTypeW(CT_CTYPE1, changed, 7, types);
5586 for (i = 0; i < 7; i++)
5587 ok(types[i] == changed_new[i] || broken(types[i] == changed_old[i]) || broken(types[i] == changed_xp[i]) || broken(types[i] == 0), "incorrect types returned for %x -> (%x != %x)\n",changed[i], types[i], changed_new[i]);
5588
5589 memset(types,0,sizeof(types));
5590 GetStringTypeW(CT_CTYPE1, punct, 7, types);
5591 for (i = 0; i < 7; i++)
5592 ok(types[i] == (C1_PUNCT | C1_DEFINED) || broken(types[i] == C1_PUNCT) || broken(types[i] == 0), "incorrect types returned for %x -> (%x != %x)\n",punct[i], types[i], (C1_PUNCT | C1_DEFINED));
5593
5594
5595 memset(types,0,sizeof(types));
5596 GetStringTypeW(CT_CTYPE1, punct_special, 12, types);
5597 for (i = 0; i < 12; i++)
5598 ok(types[i] & C1_PUNCT || broken(types[i] == 0), "incorrect types returned for %x -> (%x doest not have %x)\n",punct_special[i], types[i], C1_PUNCT);
5599
5600 memset(types,0,sizeof(types));
5601 GetStringTypeW(CT_CTYPE1, digit_special, 3, types);
5602 for (i = 0; i < 3; i++)
5603 ok(types[i] & C1_DIGIT || broken(types[i] == 0), "incorrect types returned for %x -> (%x doest not have = %x)\n",digit_special[i], types[i], C1_DIGIT);
5604
5605 memset(types,0,sizeof(types));
5606 GetStringTypeW(CT_CTYPE1, lower_special, 2, types);
5607 for (i = 0; i < 2; i++)
5608 ok(types[i] & C1_LOWER || broken(types[i] == C1_PUNCT) || broken(types[i] == 0), "incorrect types returned for %x -> (%x does not have %x)\n",lower_special[i], types[i], C1_LOWER);
5609
5610 memset(types,0,sizeof(types));
5611 GetStringTypeW(CT_CTYPE1, cntrl_special, 20, types);
5612 for (i = 0; i < 20; i++)
5613 ok(types[i] & C1_CNTRL || broken(types[i] == (C1_BLANK|C1_SPACE)) || broken(types[i] == C1_PUNCT) || broken(types[i] == 0), "incorrect types returned for %x -> (%x does not have %x)\n",cntrl_special[i], types[i], C1_CNTRL);
5614
5615 memset(types,0,sizeof(types));
5616 GetStringTypeW(CT_CTYPE1, space_special, 3, types);
5617 for (i = 0; i < 3; i++)
5618 ok(types[i] & C1_SPACE || broken(types[i] == C1_CNTRL) || broken(types[i] == 0), "incorrect types returned for %x -> (%x does not have %x)\n",space_special[i], types[i], C1_SPACE );
5619
5620 /* alpha is set for certain Thai and Mongolian */
5621 memset(types, 0, sizeof(types));
5622 GetStringTypeW(CT_CTYPE1, alpha_thai, 18, types);
5623 for (i = 0; i < 18; i++)
5624 ok(types[i] == (C1_ALPHA|C1_DEFINED), "incorrect types returned for %x -> (%x does not have %x)\n",alpha_thai[i], types[i], (C1_ALPHA|C1_DEFINED));
5625
5626 /* surrogate pairs */
5627 ch[0] = 0xd800;
5628 memset(types, 0, sizeof(types));
5630 if (types[0] == C3_NOTAPPLICABLE)
5631 win_skip("C3_HIGHSURROGATE/C3_LOWSURROGATE are not supported.\n");
5632 else {
5633 ok(types[0] == C3_HIGHSURROGATE, "got %x\n", types[0]);
5634
5635 ch[0] = 0xdc00;
5636 memset(types, 0, sizeof(types));
5638 ok(types[0] == C3_LOWSURROGATE, "got %x\n", types[0]);
5639 }
5640
5641 /* Zl, Zp categories */
5642 ch[0] = 0x2028;
5643 ch[1] = 0x2029;
5644 memset(types, 0, sizeof(types));
5646 ok(types[0] == (C1_DEFINED|C1_SPACE), "got %x\n", types[0]);
5647 ok(types[1] == (C1_DEFINED|C1_SPACE), "got %x\n", types[1]);
5648
5649 /* check Arabic range for kashida flag */
5650 for (ch[0] = 0x600; ch[0] <= 0x6ff; ch[0] += 1)
5651 {
5652 types[0] = 0;
5654 ok(ret, "%#x: failed %d\n", ch[0], ret);
5655 if (ch[0] == 0x640) /* ARABIC TATWEEL (Kashida) */
5656 ok(types[0] & C3_KASHIDA, "%#x: type %#x\n", ch[0], types[0]);
5657 else
5658 ok(!(types[0] & C3_KASHIDA), "%#x: type %#x\n", ch[0], types[0]);
5659 }
5660}
5661
5663{
5664 struct {
5665 int in_len;
5666 const WCHAR in[80];
5667 DWORD flags;
5668 DWORD ret;
5669 DWORD broken_ret;
5670 const WCHAR out[80];
5672 NTSTATUS broken_status;
5673 } test_data[] = {
5674 /* 0 */
5675 { 5, L"test", 0, 5, 5, L"test" },
5676 { 3, L"a\xe111z", 0, 0, 0, L"a\xe111z", 0, STATUS_NO_UNICODE_TRANSLATION },
5678 { 1, L"T", 0, 1, 1, L"T" },
5679 { 1, {0}, 0, 0 },
5680 /* 5 */
5681 { 6, L" -/[]", 0, 6, 6, L" -/[]" },
5682 { 3, L"a-a", IDN_USE_STD3_ASCII_RULES, 3, 3, L"a-a" },
5683 { 3, L"aa-", IDN_USE_STD3_ASCII_RULES, 0, 0, L"aa-" },
5684 { -1, L"T\xdf\x130\x143\x37a\x6a\x30c \xaa", 0, 12, 12, L"tssi\x307\x144 \x3b9\x1f0 a" },
5685#ifndef __REACTOS__ // This test only passes on Win8 and WS03.
5686 { 11, L"t\xad\x34f\x2066\x180b\x180c\x180d\x200b\x200c\x200d", 0, 0, 2, L"t",
5688#endif
5689 /* 10 */
5690 { 2, {0x3b0}, 0, 2, 2, {0x3b0} },
5691 { 2, {0x380}, 0, 0, 2, {0x380} },
5692 { 2, {0x380}, IDN_ALLOW_UNASSIGNED, 2, 2, {0x380} },
5693 { 5, L"a..a", 0, 0, 0, L"a..a" },
5694 { 3, L"a.", 0, 3, 3, L"a." },
5695 /* 15 */
5696 { 5, L"T.\x105.A", 0, 5, 5, L"t.\x105.a" },
5697 { 5, L"T.*.A", 0, 5, 5, L"T.*.A" },
5698 { 5, L"X\xff0e.Z", 0, 0, 0, L"x..z" },
5699 { 63, L"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", 0,
5700 63, 63, L"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" },
5701 { 64, L"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", 0,
5702 0, 0, L"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" },
5703 };
5704
5705 WCHAR buf[1024];
5706 DWORD i, ret, err;
5707
5708 ret = pIdnToNameprepUnicode(0, test_data[0].in,
5709 test_data[0].in_len, NULL, 0);
5710 ok(ret == test_data[0].ret, "ret = %ld\n", ret);
5711
5712 SetLastError(0xdeadbeef);
5713 ret = pIdnToNameprepUnicode(0, test_data[1].in,
5714 test_data[1].in_len, NULL, 0);
5715 err = GetLastError();
5716 ok(ret == test_data[1].ret, "ret = %ld\n", ret);
5717 ok(err == ret ? 0xdeadbeef : ERROR_INVALID_NAME, "err = %ld\n", err);
5718
5719 SetLastError(0xdeadbeef);
5720 ret = pIdnToNameprepUnicode(0, test_data[0].in, -1, buf, ARRAY_SIZE(buf));
5721 err = GetLastError();
5722 ok(ret == test_data[0].ret, "ret = %ld\n", ret);
5723 ok(err == 0xdeadbeef, "err = %ld\n", err);
5724
5725 SetLastError(0xdeadbeef);
5726 ret = pIdnToNameprepUnicode(0, test_data[0].in, -2, buf, ARRAY_SIZE(buf));
5727 err = GetLastError();
5728 ok(ret == 0, "ret = %ld\n", ret);
5729 ok(err == ERROR_INVALID_PARAMETER, "err = %ld\n", err);
5730
5731 SetLastError(0xdeadbeef);
5732 ret = pIdnToNameprepUnicode(0, test_data[0].in, 0, buf, ARRAY_SIZE(buf));
5733 err = GetLastError();
5734 ok(ret == 0, "ret = %ld\n", ret);
5735 ok(err == ERROR_INVALID_NAME, "err = %ld\n", err);
5736
5737 ret = pIdnToNameprepUnicode(IDN_ALLOW_UNASSIGNED|IDN_USE_STD3_ASCII_RULES,
5738 test_data[0].in, -1, buf, ARRAY_SIZE(buf));
5739 ok(ret == test_data[0].ret, "ret = %ld\n", ret);
5740
5741 SetLastError(0xdeadbeef);
5742 ret = pIdnToNameprepUnicode(0, NULL, 0, NULL, 0);
5743 err = GetLastError();
5744 ok(ret == 0, "ret = %ld\n", ret);
5745 ok(err == ERROR_INVALID_PARAMETER, "err = %ld\n", err);
5746
5747 SetLastError(0xdeadbeef);
5748 ret = pIdnToNameprepUnicode(4, NULL, 0, NULL, 0);
5749 err = GetLastError();
5750 ok(ret == 0, "ret = %ld\n", ret);
5752 "err = %ld\n", err);
5753
5754 for (i=0; i<ARRAY_SIZE(test_data); i++)
5755 {
5756 SetLastError(0xdeadbeef);
5757 memset( buf, 0xcc, sizeof(buf) );
5758 ret = pIdnToNameprepUnicode(test_data[i].flags, test_data[i].in, test_data[i].in_len,
5759 buf, ARRAY_SIZE(buf));
5760 err = GetLastError();
5761
5762 ok(ret == test_data[i].ret || broken(ret == test_data[i].broken_ret), "%ld: ret = %ld\n", i, ret);
5763
5764 if (ret == test_data[i].ret)
5765 {
5766 ok(err == ret ? 0xdeadbeef : ERROR_INVALID_NAME, "%ld: err = %ld\n", i, err);
5767 ok(!wcsncmp(test_data[i].out, buf, ret), "%ld: buf = %s\n", i, wine_dbgstr_wn(buf, ret));
5768 }
5769 if (pRtlNormalizeString)
5770 {
5772 int len = ARRAY_SIZE(buf);
5773 memset( buf, 0xcc, sizeof(buf) );
5774 status = pRtlNormalizeString( 13, test_data[i].in, test_data[i].in_len, buf, &len );
5775 ok( status == test_data[i].status || broken(status == test_data[i].broken_status),
5776 "%ld: failed %lx\n", i, status );
5777 if (!status) ok( !wcsnicmp(test_data[i].out, buf, len), "%ld: buf = %s\n", i, wine_dbgstr_wn(buf, len));
5778 }
5779 }
5780}
5781
5782static void test_IdnToAscii(void)
5783{
5784 struct {
5785 int in_len;
5786 const WCHAR in[80];
5787 DWORD flags;
5788 DWORD ret;
5789 DWORD broken_ret;
5790 const WCHAR out[80];
5791 } test_data[] = {
5792 /* 0 */
5793 { 5, L"Test", 0, 5, 5, L"Test" },
5794 { 5, L"Te\x017cst", 0, 12, 12, L"xn--test-cbb" },
5795 { 12, L"te\x0105st.te\x017cst", 0, 26, 26, L"xn--test-cta.xn--test-cbb" },
5796 { 3, {0x0105,'.',0}, 0, 9, 9, L"xn--2da." },
5797 { 10, L"http://t\x106", 0, 17, 17, L"xn--http://t-78a" },
5798 /* 5 */
5799 { -1, L"\x4e3a\x8bf4\x4e0d\x4ed6\x5011\x10d\x11b\x305c\x306a", 0,
5800 35, 35, L"xn--bea2a1631avbav44tyha32b91egs2t" },
5801 { 2, L"\x380", IDN_ALLOW_UNASSIGNED, 8, 8, L"xn--7va" },
5802 { 63, L"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", 0,
5803 63, 63, L"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" },
5804 { 64, L"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", 0, 0 },
5805 { -1, L"\xe4z123456789012345678901234567890123456789012345678901234", 0,
5806 64, 64, L"xn--z123456789012345678901234567890123456789012345678901234-9te" },
5807 /* 10 */
5808 { -1, L"\xd803\xde78\x46b5-\xa861.\x2e87", 0, 28, 0, L"xn----bm3an932a1l5d.xn--xvj" },
5809 { -1, L"\x06ef\x06ef", 0, 9, 0, L"xn--cmba" },
5810 { -1, L"-\x07e1\xff61\x2184", 0, 18, 0, L"xn----8cd.xn--r5g" },
5811 };
5812
5813 WCHAR buf[1024];
5814 DWORD i, ret, err;
5815
5816 for (i=0; i<ARRAY_SIZE(test_data); i++)
5817 {
5818 SetLastError(0xdeadbeef);
5819 ret = pIdnToAscii(test_data[i].flags, test_data[i].in, test_data[i].in_len, buf, ARRAY_SIZE(buf));
5820 err = GetLastError();
5821 ok(ret == test_data[i].ret || broken(ret == test_data[i].broken_ret), "%ld: ret = %ld\n", i, ret);
5822 ok(err == ret ? 0xdeadbeef : ERROR_INVALID_NAME, "%ld: err = %ld\n", i, err);
5823 ok(!wcsnicmp(test_data[i].out, buf, ret), "%ld: buf = %s\n", i, wine_dbgstr_wn(buf, ret));
5824 }
5825}
5826
5827static void test_IdnToUnicode(void)
5828{
5829 struct {
5830 int in_len;
5831 const WCHAR in[80];
5832 DWORD flags;
5833 DWORD ret;
5834 DWORD broken_ret;
5835 const WCHAR out[80];
5836 } test_data[] = {
5837 /* 0 */
5838 { 5, L"Tes.", 0, 5, 5, L"Tes." },
5839 { 2, L"\x105", 0, 0 },
5840 { 33, L"xn--4dbcagdahymbxekheh6e0a7fei0b", 0,
5841 23, 23, L"\x05dc\x05de\x05d4\x05d4\x05dd\x05e4\x05e9\x05d5\x05d8\x05dc\x05d0\x05de\x05d3\x05d1\x05e8\x05d9\x05dd\x05e2\x05d1\x05e8\x05d9\x05ea" },
5842 { 34, L"test.xn--kda9ag5e9jnfsj.xn--pz-fna", 0,
5843 16, 16, L"test.\x0105\x0119\x015b\x0107\x0142\x00f3\x017c.p\x0119z" },
5844 { 63, L"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", 0,
5845 63, 63, L"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" },
5846 /* 5 */
5847 { 64, L"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", 0, 0 },
5848 { 8, L"xn--7va", IDN_ALLOW_UNASSIGNED, 2, 2, L"\x380" },
5849 { 8, L"xn--7va", 0, 0, 0, L"\x380" },
5850 { -1, L"xn----bm3an932a1l5d.xn--xvj", 0, 8, 0, L"\xd803\xde78\x46b5-\xa861.\x2e87" },
5851 { -1, L"xn--z123456789012345678901234567890123456789012345678901234-9te", 0,
5852 57, 57, L"\xe4z123456789012345678901234567890123456789012345678901234" },
5853 /* 10 */
5854 { -1, L"foo.bar", 0, 8, 8, L"foo.bar" },
5855 { -1, L"d.xn----dha", 0, 5, 5, L"d.\x00fc-" },
5856 };
5857
5858 WCHAR buf[1024];
5859 DWORD i, ret, err;
5860
5861 for (i=0; i<ARRAY_SIZE(test_data); i++)
5862 {
5863 ret = pIdnToUnicode(test_data[i].flags, test_data[i].in, test_data[i].in_len, NULL, 0);
5864 ok(ret == test_data[i].ret || broken(ret == test_data[i].broken_ret), "%ld: ret = %ld\n", i, ret);
5865
5866 SetLastError(0xdeadbeef);
5867 ret = pIdnToUnicode(test_data[i].flags, test_data[i].in, test_data[i].in_len, buf, ARRAY_SIZE(buf));
5868 err = GetLastError();
5869 ok(ret == test_data[i].ret || broken(ret == test_data[i].broken_ret), "%ld: ret = %ld\n", i, ret);
5870 ok(err == ret ? 0xdeadbeef : ERROR_INVALID_NAME, "%ld: err = %ld\n", i, err);
5871 ok(!wcsncmp(test_data[i].out, buf, ret), "%ld: buf = %s\n", i, wine_dbgstr_wn(buf, ret));
5872 }
5873}
5874
5875static BOOL is_idn_error( const WCHAR *str )
5876{
5877 WCHAR *p, err[256];
5878 lstrcpyW( err, str );
5879 for (p = wcstok( err, L" []" ); p; p = wcstok( NULL, L" []" ) )
5880 {
5881 if (*p == 'B' || !wcscmp( p, L"V8" )) continue; /* BiDi */
5882 if (!wcscmp( p, L"V2" )) continue; /* CheckHyphens */
5883 if (!wcscmp( p, L"V5" )) continue; /* Combining marks */
5884 return TRUE;
5885 }
5886 return FALSE;
5887}
5888
5889static void test_Idn(void)
5890{
5891 FILE *f;
5892
5893#if defined(__REACTOS__) && DLL_EXPORT_VERSION >= 0x600
5894 /* FIXME: Idn functions are STUBS on ReactOS */
5895 if (is_reactos() || !pIdnToAscii || !pIdnToUnicode || !pIdnToNameprepUnicode)
5896#else
5897 if (!pIdnToAscii || !pIdnToUnicode || !pIdnToNameprepUnicode)
5898#endif
5899 {
5900 win_skip("Idn support is not available\n");
5901 return;
5902 }
5903
5907
5908 /* optionally run the full test file from Unicode.org
5909 * available at https://www.unicode.org/Public/idna/latest/IdnaTestV2.txt
5910 */
5911 if ((f = fopen( "IdnaTestV2.txt", "r" )))
5912 {
5913 char *p, *end, buffer[2048];
5914 WCHAR columns[7][256], dst[256], *expect, *error;
5915 int i, ret, line = 0;
5916
5917 while (fgets( buffer, sizeof(buffer), f ))
5918 {
5919 line++;
5920 if ((p = strchr( buffer, '#' ))) *p = 0;
5921 if (!(p = strtok( buffer, ";" ))) continue;
5922 for (i = 0; i < 7 && p; i++)
5923 {
5924 while (*p == ' ') p++;
5925 for (end = p + strlen(p); end > p; end--) if (end[-1] != ' ') break;
5926 *end = 0;
5927 MultiByteToWideChar( CP_UTF8, 0, p, -1, columns[i], 256 );
5928 p = strtok( NULL, ";" );
5929 }
5930 if (i < 7) continue;
5931
5932 expect = columns[5];
5933 if (!*expect) expect = columns[3];
5934 if (!*expect) expect = columns[1];
5935 if (!*expect) expect = columns[0];
5936 error = columns[6];
5937 if (!*error) error = columns[4];
5938 if (!*error) error = columns[2];
5939 SetLastError( 0xdeadbeef );
5940 memset( dst, 0xcc, sizeof(dst) );
5941 ret = pIdnToAscii( 0, columns[0], -1, dst, ARRAY_SIZE(dst) );
5942 if (!is_idn_error( error ))
5943 {
5944 ok( ret, "line %u: toAscii failed for %s expected %s\n", line,
5945 debugstr_w(columns[0]), debugstr_w(expect) );
5946 if (ret) ok( !wcscmp( dst, expect ), "line %u: got %s expected %s\n",
5948 }
5949 else
5950 {
5951 ok( !ret, "line %u: toAscii didn't fail for %s got %s expected error %s\n",
5952 line, debugstr_w(columns[0]), debugstr_w(dst), debugstr_w(error) );
5953 }
5954
5955 expect = columns[1];
5956 if (!*expect) expect = columns[0];
5957 error = columns[2];
5958 SetLastError( 0xdeadbeef );
5959 memset( dst, 0xcc, sizeof(dst) );
5960 ret = pIdnToUnicode( IDN_USE_STD3_ASCII_RULES, columns[0], -1, dst, ARRAY_SIZE(dst) );
5961 for (i = 0; columns[0][i]; i++) if (columns[0][i] > 0x7f) break;
5962 if (columns[0][i])
5963 {
5964 ok( !ret, "line %u: didn't fail for unicode chars in %s\n", line, debugstr_w(columns[0]) );
5965 }
5966 else if (!is_idn_error( error ))
5967 {
5968 ok( ret, "line %u: toUnicode failed for %s expected %s\n", line,
5969 debugstr_w(columns[0]), debugstr_w(expect) );
5970 if (ret) ok( !wcscmp( dst, expect ), "line %u: got %s expected %s\n",
5972 }
5973 else
5974 {
5975 ok( !ret, "line %u: toUnicode didn't fail for %s got %s expected error %s\n",
5976 line, debugstr_w(columns[0]), debugstr_w(dst), debugstr_w(error) );
5977 }
5978 }
5979 fclose( f );
5980 }
5981}
5982
5983
5984static void test_GetLocaleInfoEx(void)
5985{
5986 static const WCHAR enW[] = {'e','n',0};
5987 WCHAR bufferW[80], buffer2[80];
5988 INT ret;
5989
5990 if (!pGetLocaleInfoEx)
5991 {
5992 win_skip("GetLocaleInfoEx not supported\n");
5993 return;
5994 }
5995
5996 ret = pGetLocaleInfoEx(enW, LOCALE_SNAME, bufferW, ARRAY_SIZE(bufferW));
5997 ok(ret || broken(ret == 0) /* Vista */, "got %d\n", ret);
5998 if (ret)
5999 {
6000 static const WCHAR statesW[] = {'U','n','i','t','e','d',' ','S','t','a','t','e','s',0};
6001 static const WCHAR dummyW[] = {'d','u','m','m','y',0};
6002 static const WCHAR enusW[] = {'e','n','-','U','S',0};
6003 static const WCHAR usaW[] = {'U','S','A',0};
6004 static const WCHAR enuW[] = {'E','N','U',0};
6006 DWORD val;
6007
6008 ok(ret == lstrlenW(bufferW)+1, "got %d\n", ret);
6009 ok(!lstrcmpW(bufferW, enW), "got %s\n", wine_dbgstr_w(bufferW));
6010
6011 SetLastError(0xdeadbeef);
6012 ret = pGetLocaleInfoEx(enW, LOCALE_SNAME, bufferW, 2);
6013 ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER, "got %d, %ld\n", ret, GetLastError());
6014
6015 SetLastError(0xdeadbeef);
6017 ok(ret == 3 && GetLastError() == 0xdeadbeef, "got %d, %ld\n", ret, GetLastError());
6018
6019 ret = pGetLocaleInfoEx(enusW, LOCALE_SNAME, bufferW, ARRAY_SIZE(bufferW));
6020 ok(ret == lstrlenW(bufferW)+1, "got %d\n", ret);
6021 ok(!lstrcmpW(bufferW, enusW), "got %s\n", wine_dbgstr_w(bufferW));
6022
6023 ret = pGetLocaleInfoEx(enW, LOCALE_SABBREVCTRYNAME, bufferW, ARRAY_SIZE(bufferW));
6024 ok(ret == lstrlenW(bufferW)+1, "got %d\n", ret);
6025 ok(!lstrcmpW(bufferW, usaW), "got %s\n", wine_dbgstr_w(bufferW));
6026
6027 ret = pGetLocaleInfoEx(enW, LOCALE_SABBREVLANGNAME, bufferW, ARRAY_SIZE(bufferW));
6028 ok(ret == lstrlenW(bufferW)+1, "got %d\n", ret);
6029 ok(!lstrcmpW(bufferW, enuW), "got %s\n", wine_dbgstr_w(bufferW));
6030
6031 ret = pGetLocaleInfoEx(enusW, LOCALE_SPARENT, bufferW, ARRAY_SIZE(bufferW));
6032 ok(ret == lstrlenW(bufferW)+1, "got %d\n", ret);
6033 ok(!lstrcmpW(bufferW, enW), "got %s\n", wine_dbgstr_w(bufferW));
6034
6035 ret = pGetLocaleInfoEx(enW, LOCALE_SPARENT, bufferW, ARRAY_SIZE(bufferW));
6036 ok(ret == 1, "got %d\n", ret);
6037 ok(!bufferW[0], "got %s\n", wine_dbgstr_w(bufferW));
6038
6039 ret = pGetLocaleInfoEx(enW, LOCALE_SPARENT | LOCALE_NOUSEROVERRIDE, bufferW, ARRAY_SIZE(bufferW));
6040 ok(ret == 1, "got %d\n", ret);
6041 ok(!bufferW[0], "got %s\n", wine_dbgstr_w(bufferW));
6042
6043 ret = pGetLocaleInfoEx(enW, LOCALE_SCOUNTRY, bufferW, ARRAY_SIZE(bufferW));
6044 ok(ret == lstrlenW(bufferW)+1, "got %d\n", ret);
6047 {
6048 skip("Non-English locale\n");
6049 }
6050 else
6051 ok(!lstrcmpW(bufferW, statesW), "got %s\n", wine_dbgstr_w(bufferW));
6052
6053 bufferW[0] = 0;
6054 SetLastError(0xdeadbeef);
6055 ret = pGetLocaleInfoEx(dummyW, LOCALE_SNAME, bufferW, ARRAY_SIZE(bufferW));
6056 ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER, "got %d, error %ld\n", ret, GetLastError());
6057
6058#if defined(__REACTOS__) && defined(_WIN64)
6059 if (is_reactos()) {
6060 ok(FALSE, "FIXME: These tests crash on ReactOS x64\n");
6061 } else {
6062#endif
6063 while (*ptr->name)
6064 {
6065 val = 0;
6066 pGetLocaleInfoEx(ptr->name, LOCALE_ILANGUAGE|LOCALE_RETURN_NUMBER, (WCHAR*)&val, sizeof(val)/sizeof(WCHAR));
6067 ok(val == ptr->lcid, "%s: got wrong lcid 0x%04lx, expected 0x%04lx\n", wine_dbgstr_w(ptr->name), val, ptr->lcid);
6068 bufferW[0] = 0;
6069 ret = pGetLocaleInfoEx(ptr->name, LOCALE_SNAME, bufferW, ARRAY_SIZE(bufferW));
6070 ok(ret == lstrlenW(bufferW)+1, "%s: got ret value %d\n", wine_dbgstr_w(ptr->name), ret);
6071 ok(!lstrcmpW(bufferW, ptr->name), "%s: got wrong LOCALE_SNAME %s\n", wine_dbgstr_w(ptr->name), wine_dbgstr_w(bufferW));
6072 ptr++;
6073 }
6074
6076 ok(ret && ret == lstrlenW(bufferW)+1, "got ret value %d\n", ret);
6078 ok(ret && ret == lstrlenW(buffer2)+1, "got ret value %d\n", ret);
6079 ok(!lstrcmpW(bufferW, buffer2), "LOCALE_SNAMEs don't match %s %s\n", wine_dbgstr_w(bufferW), wine_dbgstr_w(buffer2));
6080#if defined(__REACTOS__) && defined(_WIN64)
6081 }
6082#endif
6083 }
6084}
6085
6086static void test_IsValidLocaleName(void)
6087{
6088 BOOL ret;
6089
6090 if (!pIsValidLocaleName)
6091 {
6092 win_skip("IsValidLocaleName not supported\n");
6093 return;
6094 }
6095
6096 ret = pIsValidLocaleName(L"en-US");
6097 ok(ret, "IsValidLocaleName failed\n");
6098 ret = pIsValidLocaleName(L"en");
6099#ifdef __REACTOS__
6100 ok(ret || broken(GetNTVersion() == _WIN32_WINNT_VISTA), "IsValidLocaleName failed\n");
6101#else
6102 ok(ret, "IsValidLocaleName failed\n");
6103#endif
6104 ret = pIsValidLocaleName(L"es-es");
6105 ok(ret, "IsValidLocaleName failed\n");
6106 ret = pIsValidLocaleName(L"de-DE_phoneb");
6107 ok(ret, "IsValidLocaleName failed\n");
6108 ret = pIsValidLocaleName(L"DE_de-phoneb");
6109 ok(ret || broken(!ret), "IsValidLocaleName failed\n");
6110 ret = pIsValidLocaleName(L"DE_de_PHONEB");
6111 ok(ret || broken(!ret), "IsValidLocaleName failed\n");
6112 ret = pIsValidLocaleName(L"DE_de+phoneb");
6113 ok(!ret, "IsValidLocaleName should have failed\n");
6114 ret = pIsValidLocaleName(L"zz");
6115 ok(!ret || broken(ret), "IsValidLocaleName should have failed\n");
6116 ret = pIsValidLocaleName(L"zz-ZZ");
6117 ok(!ret || broken(ret), "IsValidLocaleName should have failed\n");
6118 ret = pIsValidLocaleName(L"zzz");
6119 ok(!ret || broken(ret), "IsValidLocaleName should have failed\n");
6120 ret = pIsValidLocaleName(L"zzz-ZZZ");
6121 ok(!ret, "IsValidLocaleName should have failed\n");
6122 ret = pIsValidLocaleName(L"zzzz");
6123 ok(!ret, "IsValidLocaleName should have failed\n");
6124 ret = pIsValidLocaleName(LOCALE_NAME_INVARIANT);
6125 ok(ret, "IsValidLocaleName failed\n");
6126 ret = pIsValidLocaleName(LOCALE_NAME_USER_DEFAULT);
6127 ok(!ret, "IsValidLocaleName should have failed\n");
6128 ret = pIsValidLocaleName(LOCALE_NAME_SYSTEM_DEFAULT);
6129 ok(!ret, "IsValidLocaleName should have failed\n");
6130
6131 if (!pRtlIsValidLocaleName)
6132 {
6133 win_skip( "RtlIsValidLocaleName not available\n" );
6134 return;
6135 }
6136
6137 ret = pRtlIsValidLocaleName( L"en-US", 0 );
6138 ok(ret, "RtlIsValidLocaleName failed\n");
6139 ret = pRtlIsValidLocaleName( L"en", 0 );
6140 ok(!ret, "RtlIsValidLocaleName should have failed\n");
6141 ret = pRtlIsValidLocaleName( L"en", 1 );
6142 ok(!ret, "RtlIsValidLocaleName should have failed\n");
6143 ret = pRtlIsValidLocaleName( L"en", 2 );
6144 ok(ret, "RtlIsValidLocaleName failed\n");
6145 ret = pRtlIsValidLocaleName( L"en-RR", 2 );
6146 ok(!ret, "RtlIsValidLocaleName should have failed\n");
6147 ret = pRtlIsValidLocaleName( L"es-es", 0 );
6148 ok(ret, "RtlIsValidLocaleName failed\n");
6149 ret = pRtlIsValidLocaleName( L"de-DE_phoneb", 0 );
6150 ok(ret, "RtlIsValidLocaleName failed\n");
6151 ret = pRtlIsValidLocaleName( L"DE_de_PHONEB", 0 );
6152 ok(ret || broken(!ret), "RtlIsValidLocaleName failed\n");
6153 ret = pRtlIsValidLocaleName( L"DE_de+phoneb", 0 );
6154 ok(!ret, "RtlIsValidLocaleName should have failed\n");
6155 ret = pRtlIsValidLocaleName( L"zz", 0 );
6156 ok(!ret, "RtlIsValidLocaleName should have failed\n");
6157 ret = pRtlIsValidLocaleName( L"zz", 2 );
6158 ok(!ret, "RtlIsValidLocaleName should have failed\n");
6159 ret = pRtlIsValidLocaleName( L"zz-ZZ", 0 );
6160 ok(!ret, "RtlIsValidLocaleName should have failed\n");
6161 ret = pRtlIsValidLocaleName( L"zzz", 0 );
6162 ok(!ret, "RtlIsValidLocaleName should have failed\n");
6163 ret = pRtlIsValidLocaleName( L"zzz-ZZZ", 0 );
6164 ok(!ret, "RtlIsValidLocaleName should have failed\n");
6165 ret = pRtlIsValidLocaleName( L"zzzz", 0 );
6166 ok(!ret, "RtlIsValidLocaleName should have failed\n");
6167 ret = pRtlIsValidLocaleName( LOCALE_NAME_INVARIANT, 0 );
6168 ok(ret, "RtlIsValidLocaleName failed\n");
6169 ret = pRtlIsValidLocaleName( LOCALE_NAME_USER_DEFAULT, 0 );
6170 ok(!ret, "RtlIsValidLocaleName should have failed\n");
6171 ret = pRtlIsValidLocaleName( LOCALE_NAME_SYSTEM_DEFAULT, 0 );
6172 ok(!ret, "RtlIsValidLocaleName should have failed\n");
6173}
6174
6175static void test_ResolveLocaleName(void)
6176{
6177 static const struct { const WCHAR *name, *exp; BOOL broken; } tests[] =
6178 {
6179 { L"en-US", L"en-US" },
6180 { L"en", L"en-US" },
6181 { L"en-RR", L"en-US" },
6182 { L"en-na", L"en-NA", TRUE /* <= win8 */ },
6183 { L"EN-zz", L"en-US" },
6184 { L"en-US", L"en-US" },
6185 { L"de-DE_phoneb", L"de-DE" },
6186 { L"DE-de-phoneb", L"de-DE" },
6187 { L"fr-029", L"fr-029", TRUE /* <= win8 */ },
6188 { L"fr-CH_XX", L"fr-CH", TRUE /* <= win10 1809 */ },
6189 { L"fr-CHXX", L"fr-FR" },
6190 { L"zh", L"zh-CN" },
6191 { L"zh-Hant", L"zh-HK" },
6192 { L"zh-hans", L"zh-CN" },
6193 { L"ja-jp_radstr", L"ja-JP" },
6194 { L"az", L"az-Latn-AZ" },
6195 { L"uz", L"uz-Latn-UZ" },
6196 { L"uz-cyrl", L"uz-Cyrl-UZ" },
6197 { L"ia", L"ia-001", TRUE /* <= win10 1809 */ },
6198 { L"zz", L"" },
6199 { L"zzz-ZZZ", L"" },
6200 { L"zzzz", L"" },
6201 { L"zz+XX", NULL },
6202 { L"zz.XX", NULL },
6203 { LOCALE_NAME_INVARIANT, L"" },
6204 };
6205 INT i, ret;
6206#if !defined(__REACTOS__) || DLL_EXPORT_VERSION >= 0x600
6208#else
6210#endif
6211
6212 if (!pResolveLocaleName)
6213 {
6214 win_skip( "ResolveLocaleName not available\n" );
6215 return;
6216 }
6217 for (i = 0; i < ARRAY_SIZE(tests); i++)
6218 {
6219 SetLastError( 0xdeadbeef );
6220 memset( buffer, 0xcc, sizeof(buffer) );
6221 ret = pResolveLocaleName( tests[i].name, buffer, ARRAY_SIZE(buffer) );
6222 if (tests[i].exp)
6223 {
6224 ok( !wcscmp( buffer, tests[i].exp ) || broken( tests[i].broken ),
6225 "%s: got %s\n", debugstr_w(tests[i].name), debugstr_w(buffer) );
6226 ok( ret == wcslen(buffer) + 1, "%s: got %u\n", debugstr_w(tests[i].name), ret );
6227 }
6228 else
6229 {
6230 ok( !ret || broken( ret == 1 ) /* win7 */,
6231 "%s: got %s\n", debugstr_w(tests[i].name), debugstr_w(buffer) );
6232 if (!ret)
6234 "%s: wrong error %lu\n", debugstr_w(tests[i].name), GetLastError() );
6235 }
6236 }
6237 SetLastError( 0xdeadbeef );
6238 memset( buffer, 0xcc, sizeof(buffer) );
6239 ret = pResolveLocaleName( LOCALE_NAME_SYSTEM_DEFAULT, buffer, ARRAY_SIZE(buffer) );
6240#ifdef __REACTOS__
6241 ok( ret || broken(GetLastError() == ERROR_INVALID_PARAMETER) /* Win8 */, "failed err %lu\n", GetLastError() );
6242#else
6243 ok( ret, "failed err %lu\n", GetLastError() );
6244#endif
6245#if !defined(__REACTOS__) || DLL_EXPORT_VERSION >= 0x600
6247#if !(defined(__REACTOS__) && defined(_WIN64))
6248 ok( !wcscmp( buffer, system ), "got wrong syslocale %s / %s\n", debugstr_w(buffer), debugstr_w(system));
6249 ok( ret == wcslen(system) + 1, "wrong len %u / %Iu\n", ret, wcslen(system) + 1 );
6250#endif
6251#endif
6252
6253 SetLastError( 0xdeadbeef );
6254 ret = pResolveLocaleName( L"en-US", buffer, 4 );
6255 ok( !ret, "got %u\n", ret );
6256 ok( GetLastError() == ERROR_INSUFFICIENT_BUFFER, "wrong error %lu\n", GetLastError() );
6257 ok( !wcscmp( buffer, L"en-" ), "got %s\n", debugstr_w(buffer) );
6258
6259 SetLastError( 0xdeadbeef );
6260 ret = pResolveLocaleName( L"en-US", NULL, 0 );
6261 ok( ret == 6, "got %u\n", ret );
6262 ok( GetLastError() == 0xdeadbeef, "wrong error %lu\n", GetLastError() );
6263}
6264
6266{
6267 INT ret;
6268 WCHAR test1[] = { 't','e','s','t',0 };
6269 WCHAR test2[] = { 'T','e','S','t',0 };
6270 WCHAR test3[] = { 't','e','s','t','3',0 };
6271 WCHAR null1[] = { 'a',0,'a',0 };
6272 WCHAR null2[] = { 'a',0,'b',0 };
6273 WCHAR bills1[] = { 'b','i','l','l','\'','s',0 };
6274 WCHAR bills2[] = { 'b','i','l','l','s',0 };
6275 WCHAR coop1[] = { 'c','o','-','o','p',0 };
6276 WCHAR coop2[] = { 'c','o','o','p',0 };
6277 WCHAR nonascii1[] = { 0x0102,0 };
6278 WCHAR nonascii2[] = { 0x0201,0 };
6279 WCHAR ch1, ch2;
6280
6281 if (!pCompareStringOrdinal)
6282 {
6283 win_skip("CompareStringOrdinal not supported\n");
6284 return;
6285 }
6286
6287 /* Check errors */
6288 SetLastError(0xdeadbeef);
6289 ret = pCompareStringOrdinal(NULL, 0, NULL, 0, FALSE);
6290 ok(!ret, "Got %u, expected 0\n", ret);
6292 SetLastError(0xdeadbeef);
6293 ret = pCompareStringOrdinal(test1, -1, NULL, 0, FALSE);
6294 ok(!ret, "Got %u, expected 0\n", ret);
6296 SetLastError(0xdeadbeef);
6297 ret = pCompareStringOrdinal(NULL, 0, test1, -1, FALSE);
6298 ok(!ret, "Got %u, expected 0\n", ret);
6300
6301 /* Check case */
6302 ret = pCompareStringOrdinal(test1, -1, test1, -1, FALSE);
6303 ok(ret == CSTR_EQUAL, "Got %u, expected %u\n", ret, CSTR_EQUAL);
6304 ret = pCompareStringOrdinal(test1, -1, test2, -1, FALSE);
6305 ok(ret == CSTR_GREATER_THAN, "Got %u, expected %u\n", ret, CSTR_GREATER_THAN);
6306 ret = pCompareStringOrdinal(test2, -1, test1, -1, FALSE);
6307 ok(ret == CSTR_LESS_THAN, "Got %u, expected %u\n", ret, CSTR_LESS_THAN);
6308 ret = pCompareStringOrdinal(test1, -1, test2, -1, TRUE);
6309 ok(ret == CSTR_EQUAL, "Got %u, expected %u\n", ret, CSTR_EQUAL);
6310
6311 /* Check different sizes */
6312 ret = pCompareStringOrdinal(test1, 3, test2, -1, TRUE);
6313 ok(ret == CSTR_LESS_THAN, "Got %u, expected %u\n", ret, CSTR_LESS_THAN);
6314 ret = pCompareStringOrdinal(test1, -1, test2, 3, TRUE);
6315 ok(ret == CSTR_GREATER_THAN, "Got %u, expected %u\n", ret, CSTR_GREATER_THAN);
6316
6317 /* Check null character */
6318 ret = pCompareStringOrdinal(null1, 3, null2, 3, FALSE);
6319 ok(ret == CSTR_LESS_THAN, "Got %u, expected %u\n", ret, CSTR_LESS_THAN);
6320 ret = pCompareStringOrdinal(null1, 3, null2, 3, TRUE);
6321 ok(ret == CSTR_LESS_THAN, "Got %u, expected %u\n", ret, CSTR_LESS_THAN);
6322 ret = pCompareStringOrdinal(test1, 5, test3, 5, FALSE);
6323 ok(ret == CSTR_LESS_THAN, "Got %u, expected %u\n", ret, CSTR_LESS_THAN);
6324 ret = pCompareStringOrdinal(test1, 4, test1, 5, FALSE);
6325 ok(ret == CSTR_LESS_THAN, "Got %u, expected %u\n", ret, CSTR_LESS_THAN);
6326
6327 /* Check ordinal behaviour */
6328 ret = pCompareStringOrdinal(bills1, -1, bills2, -1, FALSE);
6329 ok(ret == CSTR_LESS_THAN, "Got %u, expected %u\n", ret, CSTR_LESS_THAN);
6330 ret = pCompareStringOrdinal(coop2, -1, coop1, -1, FALSE);
6331 ok(ret == CSTR_GREATER_THAN, "Got %u, expected %u\n", ret, CSTR_GREATER_THAN);
6332 ret = pCompareStringOrdinal(nonascii1, -1, nonascii2, -1, FALSE);
6333 ok(ret == CSTR_LESS_THAN, "Got %u, expected %u\n", ret, CSTR_LESS_THAN);
6334 ret = pCompareStringOrdinal(nonascii1, -1, nonascii2, -1, TRUE);
6335 ok(ret == CSTR_LESS_THAN, "Got %u, expected %u\n", ret, CSTR_LESS_THAN);
6336
6337 for (ch1 = 0; ch1 < 512; ch1++)
6338 {
6339 for (ch2 = 0; ch2 < 1024; ch2++)
6340 {
6341 int diff = ch1 - ch2;
6342 ret = pCompareStringOrdinal( &ch1, 1, &ch2, 1, FALSE );
6343 ok( ret == (diff > 0 ? CSTR_GREATER_THAN : diff < 0 ? CSTR_LESS_THAN : CSTR_EQUAL),
6344 "wrong result %d %04x %04x\n", ret, ch1, ch2 );
6345 diff = pRtlUpcaseUnicodeChar( ch1 ) - pRtlUpcaseUnicodeChar( ch2 );
6346 ret = pCompareStringOrdinal( &ch1, 1, &ch2, 1, TRUE );
6347 ok( ret == (diff > 0 ? CSTR_GREATER_THAN : diff < 0 ? CSTR_LESS_THAN : CSTR_EQUAL),
6348 "wrong result %d %04x %04x\n", ret, ch1, ch2 );
6349 }
6350 }
6351}
6352
6353static void test_GetGeoInfo(void)
6354{
6355 char buffA[20];
6356 WCHAR buffW[20];
6357 INT ret;
6358
6359 if (!pGetGeoInfoA)
6360 {
6361 win_skip("GetGeoInfo is not available.\n");
6362 return;
6363 }
6364
6365 /* unassigned id */
6366 SetLastError(0xdeadbeef);
6367 ret = pGetGeoInfoA(344, GEO_ISO2, NULL, 0, 0);
6368 ok(ret == 0, "got %d\n", ret);
6370 broken(GetLastError() == 0xdeadbeef /* Win10 */), "got %ld\n", GetLastError());
6371
6372 ret = pGetGeoInfoA(203, GEO_ISO2, NULL, 0, 0);
6373 ok(ret == 3, "got %d\n", ret);
6374
6375 ret = pGetGeoInfoA(203, GEO_ISO3, NULL, 0, 0);
6376 ok(ret == 4, "got %d\n", ret);
6377
6378 ret = pGetGeoInfoA(203, GEO_ISO2, buffA, 3, 0);
6379 ok(ret == 3, "got %d\n", ret);
6380 ok(!strcmp(buffA, "RU"), "got %s\n", buffA);
6381
6382 /* buffer pointer not NULL, length is 0 - return required length */
6383 buffA[0] = 'a';
6384 SetLastError(0xdeadbeef);
6385 ret = pGetGeoInfoA(203, GEO_ISO2, buffA, 0, 0);
6386 ok(ret == 3, "got %d\n", ret);
6387 ok(buffA[0] == 'a', "got %c\n", buffA[0]);
6388
6389 ret = pGetGeoInfoA(203, GEO_ISO3, buffA, 4, 0);
6390 ok(ret == 4, "got %d\n", ret);
6391 ok(!strcmp(buffA, "RUS"), "got %s\n", buffA);
6392
6393 /* shorter buffer */
6394 SetLastError(0xdeadbeef);
6395 buffA[1] = buffA[2] = 0;
6396 ret = pGetGeoInfoA(203, GEO_ISO2, buffA, 2, 0);
6397 ok(ret == 0, "got %d\n", ret);
6398 ok(!strcmp(buffA, "RU"), "got %s\n", buffA);
6400
6401 /* GEO_NATION returns GEOID in a string form, but only for GEOCLASS_NATION-type IDs */
6402 ret = pGetGeoInfoA(203, GEO_NATION, buffA, 20, 0); /* GEOCLASS_NATION */
6403 ok(ret == 4, "GEO_NATION of nation: expected 4, got %d\n", ret);
6404 ok(!strcmp(buffA, "203"), "GEO_NATION of nation: expected 203, got %s\n", buffA);
6405
6406 buffA[0] = 0;
6407 ret = pGetGeoInfoA(39070, GEO_NATION, buffA, 20, 0); /* GEOCLASS_REGION */
6408 ok(ret == 0, "GEO_NATION of region: expected 0, got %d\n", ret);
6409 ok(*buffA == 0, "GEO_NATION of region: expected empty string, got %s\n", buffA);
6410
6411 buffA[0] = 0;
6412 ret = pGetGeoInfoA(333, GEO_NATION, buffA, 20, 0); /* LOCATION_BOTH internal Wine type */
6413 ok(ret == 0 ||
6414 broken(ret == 4) /* Win7 and older */,
6415 "GEO_NATION of LOCATION_BOTH: expected 0, got %d\n", ret);
6416 ok(*buffA == 0 ||
6417 broken(!strcmp(buffA, "333")) /* Win7 and older */,
6418 "GEO_NATION of LOCATION_BOTH: expected empty string, got %s\n", buffA);
6419
6420 /* GEO_ID is like GEO_NATION but works for any ID */
6421 buffA[0] = 0;
6422 ret = pGetGeoInfoA(203, GEO_ID, buffA, 20, 0); /* GEOCLASS_NATION */
6423 if (ret == 0)
6424 win_skip("GEO_ID not supported.\n");
6425 else
6426 {
6427 ok(ret == 4, "GEO_ID: expected 4, got %d\n", ret);
6428 ok(!strcmp(buffA, "203"), "GEO_ID: expected 203, got %s\n", buffA);
6429
6430 ret = pGetGeoInfoA(47610, GEO_ID, buffA, 20, 0); /* GEOCLASS_REGION */
6431 ok(ret == 6, "got %d\n", ret);
6432 ok(!strcmp(buffA, "47610"), "got %s\n", buffA);
6433
6434 ret = pGetGeoInfoA(333, GEO_ID, buffA, 20, 0); /* LOCATION_BOTH internal Wine type */
6435 ok(ret == 4, "got %d\n", ret);
6436 ok(!strcmp(buffA, "333"), "got %s\n", buffA);
6437 }
6438
6439 /* GEO_PARENT */
6440 buffA[0] = 0;
6441 ret = pGetGeoInfoA(203, GEO_PARENT, buffA, 20, 0);
6442 if (ret == 0)
6443 win_skip("GEO_PARENT not supported.\n");
6444 else
6445 {
6446 ok(ret == 6, "got %d\n", ret);
6447 ok(!strcmp(buffA, "47609"), "got %s\n", buffA);
6448 }
6449
6450 buffA[0] = 0;
6451 ret = pGetGeoInfoA(203, GEO_ISO_UN_NUMBER, buffA, 20, 0);
6452 if (ret == 0)
6453 win_skip("GEO_ISO_UN_NUMBER not supported.\n");
6454 else
6455 {
6456 ok(ret == 4, "got %d\n", ret);
6457 ok(!strcmp(buffA, "643"), "got %s\n", buffA);
6458 }
6459
6460 /* try invalid type value */
6461 SetLastError(0xdeadbeef);
6462 ret = pGetGeoInfoA(203, GEO_ID + 1, NULL, 0, 0);
6463 ok(ret == 0, "got %d\n", ret);
6464 ok(GetLastError() == ERROR_INVALID_FLAGS, "got %ld\n", GetLastError());
6465
6466 /* Test for GetGeoInfoEx */
6467 if (!pGetGeoInfoEx)
6468 {
6469 win_skip("GetGeoInfoEx is not available\n");
6470 return;
6471 }
6472
6473 /* Test with ISO 3166-1 */
6474 ret = pGetGeoInfoEx(L"AR", GEO_ISO3, buffW, ARRAYSIZE(buffW));
6475 ok(ret != 0, "GetGeoInfoEx failed %ld.\n", GetLastError());
6476 ok(!wcscmp(buffW, L"ARG"), "expected string to be ARG, got %ls\n", buffW);
6477
6478 /* Test with UN M.49 */
6479 SetLastError(0xdeadbeef);
6480 ret = pGetGeoInfoEx(L"032", GEO_ISO3, buffW, ARRAYSIZE(buffW));
6481 ok(ret == 0, "expected GetGeoInfoEx to fail.\n");
6483 "expected ERROR_INVALID_PARAMETER got %ld.\n", GetLastError());
6484
6485 /* Test GEO_ID */
6486 ret = pGetGeoInfoEx(L"AR", GEO_ID, buffW, ARRAYSIZE(buffW));
6487 ok(ret != 0, "GetGeoInfoEx failed %ld.\n", GetLastError());
6488 ok(!wcscmp(buffW, L"11"), "expected string to be 11, got %ls\n", buffW);
6489
6490 /* Test with invalid geo type */
6491 SetLastError(0xdeadbeef);
6492 ret = pGetGeoInfoEx(L"AR", GEO_LCID, buffW, ARRAYSIZE(buffW));
6493 ok(ret == 0, "expected GetGeoInfoEx to fail.\n");
6495 "expected ERROR_INVALID_PARAMETER got %ld.\n", GetLastError());
6496}
6497
6500{
6501 INT ret = pGetGeoInfoA(geoid, GEO_ISO2, NULL, 0, 0);
6502 ok(ret == 3, "got %d for %ld\n", ret, geoid);
6503 /* valid geoid starts at 2 */
6504 ok(geoid >= 2, "got geoid %ld\n", geoid);
6505
6506 return geoidenum_count++ < 5;
6507}
6508
6510{
6512 return TRUE;
6513}
6514
6515static void test_EnumSystemGeoID(void)
6516{
6517 BOOL ret;
6518
6519 if (!pEnumSystemGeoID)
6520 {
6521 win_skip("EnumSystemGeoID is not available.\n");
6522 return;
6523 }
6524
6525 SetLastError(0xdeadbeef);
6526 ret = pEnumSystemGeoID(GEOCLASS_NATION, 0, NULL);
6527 ok(!ret, "got %d\n", ret);
6529
6530 SetLastError(0xdeadbeef);
6531 ret = pEnumSystemGeoID(GEOCLASS_NATION+1, 0, test_geoid_enumproc);
6532 ok(!ret, "got %d\n", ret);
6533 ok(GetLastError() == ERROR_INVALID_FLAGS, "got %ld\n", GetLastError());
6534
6535 SetLastError(0xdeadbeef);
6536 ret = pEnumSystemGeoID(GEOCLASS_NATION+1, 0, NULL);
6537 ok(!ret, "got %d\n", ret);
6539
6540 ret = pEnumSystemGeoID(GEOCLASS_NATION, 0, test_geoid_enumproc);
6541 ok(ret, "got %d\n", ret);
6542
6543 /* only the first level is enumerated, not the whole hierarchy */
6544 geoidenum_count = 0;
6545 ret = pEnumSystemGeoID(GEOCLASS_NATION, 39070, test_geoid_enumproc2);
6546 if (ret == 0)
6547 win_skip("Parent GEOID is not supported in EnumSystemGeoID.\n");
6548 else
6549 ok(ret && geoidenum_count > 0, "got %d, count %d\n", ret, geoidenum_count);
6550
6551 geoidenum_count = 0;
6552 ret = pEnumSystemGeoID(GEOCLASS_REGION, 39070, test_geoid_enumproc2);
6553 if (ret == 0)
6554 win_skip("GEOCLASS_REGION is not supported in EnumSystemGeoID.\n");
6555 else
6556 {
6557 ok(ret && geoidenum_count > 0, "got %d, count %d\n", ret, geoidenum_count);
6558
6559 geoidenum_count = 0;
6560 ret = pEnumSystemGeoID(GEOCLASS_REGION, 0, test_geoid_enumproc2);
6561 ok(ret && geoidenum_count > 0, "got %d, count %d\n", ret, geoidenum_count);
6562 }
6563
6564 geoidenum_count = 0;
6565 ret = pEnumSystemGeoID(GEOCLASS_ALL, 39070, test_geoid_enumproc2);
6566 if (ret == 0)
6567 win_skip("GEOCLASS_ALL is not supported in EnumSystemGeoID.\n");
6568 else
6569 {
6570 ok(ret && geoidenum_count > 0, "got %d, count %d\n", ret, geoidenum_count);
6571
6572 geoidenum_count = 0;
6573 ret = pEnumSystemGeoID(GEOCLASS_ALL, 0, test_geoid_enumproc2);
6574 ok(ret && geoidenum_count > 0, "got %d, count %d\n", ret, geoidenum_count);
6575 }
6576}
6577
6579 const char *name;
6580 int id;
6581 const char *expect, *expect2;
6582};
6583
6584#define X(x) #x, x
6585static const struct invariant_entry invariant_list[] = {
6586 { X(LOCALE_ILANGUAGE), "007f" },
6587 { X(LOCALE_SENGLANGUAGE), "Invariant Language" },
6588 { X(LOCALE_SABBREVLANGNAME), "IVL" },
6589 { X(LOCALE_SNATIVELANGNAME), "Invariant Language" },
6590 { X(LOCALE_ICOUNTRY), "1" },
6591 { X(LOCALE_SENGCOUNTRY), "Invariant Country" },
6592 { X(LOCALE_SABBREVCTRYNAME), "IVC", "" },
6593 { X(LOCALE_SNATIVECTRYNAME), "Invariant Country" },
6594 { X(LOCALE_IDEFAULTLANGUAGE), "0409" },
6595 { X(LOCALE_IDEFAULTCOUNTRY), "1" },
6596 { X(LOCALE_IDEFAULTCODEPAGE), "437" },
6597 { X(LOCALE_IDEFAULTANSICODEPAGE), "1252" },
6598 { X(LOCALE_IDEFAULTMACCODEPAGE), "10000" },
6599 { X(LOCALE_SLIST), "," },
6600 { X(LOCALE_IMEASURE), "0" },
6601 { X(LOCALE_SDECIMAL), "." },
6602 { X(LOCALE_STHOUSAND), "," },
6603 { X(LOCALE_SGROUPING), "3;0" },
6604 { X(LOCALE_IDIGITS), "2" },
6605 { X(LOCALE_ILZERO), "1" },
6606 { X(LOCALE_INEGNUMBER), "1" },
6607 { X(LOCALE_SNATIVEDIGITS), "0123456789" },
6608 { X(LOCALE_SCURRENCY), "\x00a4" },
6609 { X(LOCALE_SINTLSYMBOL), "XDR" },
6610 { X(LOCALE_SMONDECIMALSEP), "." },
6611 { X(LOCALE_SMONTHOUSANDSEP), "," },
6612 { X(LOCALE_SMONGROUPING), "3;0" },
6613 { X(LOCALE_ICURRDIGITS), "2" },
6614 { X(LOCALE_IINTLCURRDIGITS), "2" },
6615 { X(LOCALE_ICURRENCY), "0" },
6616 { X(LOCALE_INEGCURR), "0" },
6617 { X(LOCALE_SDATE), "/" },
6618 { X(LOCALE_STIME), ":" },
6619 { X(LOCALE_SSHORTDATE), "MM/dd/yyyy" },
6620 { X(LOCALE_SLONGDATE), "dddd, dd MMMM yyyy" },
6621 { X(LOCALE_STIMEFORMAT), "HH:mm:ss" },
6622 { X(LOCALE_IDATE), "0" },
6623 { X(LOCALE_ILDATE), "1" },
6624 { X(LOCALE_ITIME), "1" },
6625 { X(LOCALE_ITIMEMARKPOSN), "0" },
6626 { X(LOCALE_ICENTURY), "1" },
6627 { X(LOCALE_ITLZERO), "1" },
6628 { X(LOCALE_IDAYLZERO), "1" },
6629 { X(LOCALE_IMONLZERO), "1" },
6630 { X(LOCALE_S1159), "AM" },
6631 { X(LOCALE_S2359), "PM" },
6632 { X(LOCALE_ICALENDARTYPE), "1" },
6633 { X(LOCALE_IOPTIONALCALENDAR), "0" },
6634 { X(LOCALE_IFIRSTDAYOFWEEK), "6" },
6635 { X(LOCALE_IFIRSTWEEKOFYEAR), "0" },
6636 { X(LOCALE_SDAYNAME1), "Monday" },
6637 { X(LOCALE_SDAYNAME2), "Tuesday" },
6638 { X(LOCALE_SDAYNAME3), "Wednesday" },
6639 { X(LOCALE_SDAYNAME4), "Thursday" },
6640 { X(LOCALE_SDAYNAME5), "Friday" },
6641 { X(LOCALE_SDAYNAME6), "Saturday" },
6642 { X(LOCALE_SDAYNAME7), "Sunday" },
6643 { X(LOCALE_SABBREVDAYNAME1), "Mon" },
6644 { X(LOCALE_SABBREVDAYNAME2), "Tue" },
6645 { X(LOCALE_SABBREVDAYNAME3), "Wed" },
6646 { X(LOCALE_SABBREVDAYNAME4), "Thu" },
6647 { X(LOCALE_SABBREVDAYNAME5), "Fri" },
6648 { X(LOCALE_SABBREVDAYNAME6), "Sat" },
6649 { X(LOCALE_SABBREVDAYNAME7), "Sun" },
6650 { X(LOCALE_SMONTHNAME1), "January" },
6651 { X(LOCALE_SMONTHNAME2), "February" },
6652 { X(LOCALE_SMONTHNAME3), "March" },
6653 { X(LOCALE_SMONTHNAME4), "April" },
6654 { X(LOCALE_SMONTHNAME5), "May" },
6655 { X(LOCALE_SMONTHNAME6), "June" },
6656 { X(LOCALE_SMONTHNAME7), "July" },
6657 { X(LOCALE_SMONTHNAME8), "August" },
6658 { X(LOCALE_SMONTHNAME9), "September" },
6659 { X(LOCALE_SMONTHNAME10), "October" },
6660 { X(LOCALE_SMONTHNAME11), "November" },
6661 { X(LOCALE_SMONTHNAME12), "December" },
6662 { X(LOCALE_SMONTHNAME13), "" },
6663 { X(LOCALE_SABBREVMONTHNAME1), "Jan" },
6664 { X(LOCALE_SABBREVMONTHNAME2), "Feb" },
6665 { X(LOCALE_SABBREVMONTHNAME3), "Mar" },
6666 { X(LOCALE_SABBREVMONTHNAME4), "Apr" },
6667 { X(LOCALE_SABBREVMONTHNAME5), "May" },
6668 { X(LOCALE_SABBREVMONTHNAME6), "Jun" },
6669 { X(LOCALE_SABBREVMONTHNAME7), "Jul" },
6670 { X(LOCALE_SABBREVMONTHNAME8), "Aug" },
6671 { X(LOCALE_SABBREVMONTHNAME9), "Sep" },
6672 { X(LOCALE_SABBREVMONTHNAME10), "Oct" },
6673 { X(LOCALE_SABBREVMONTHNAME11), "Nov" },
6674 { X(LOCALE_SABBREVMONTHNAME12), "Dec" },
6676 { X(LOCALE_SPOSITIVESIGN), "+" },
6677 { X(LOCALE_SNEGATIVESIGN), "-" },
6678 { X(LOCALE_IPOSSIGNPOSN), "3" },
6679 { X(LOCALE_INEGSIGNPOSN), "0" },
6680 { X(LOCALE_IPOSSYMPRECEDES), "1" },
6681 { X(LOCALE_IPOSSEPBYSPACE), "0" },
6682 { X(LOCALE_INEGSYMPRECEDES), "1" },
6683 { X(LOCALE_INEGSEPBYSPACE), "0" },
6684 { X(LOCALE_SISO639LANGNAME), "iv" },
6685 { X(LOCALE_SISO3166CTRYNAME), "IV" },
6686 { X(LOCALE_IDEFAULTEBCDICCODEPAGE), "037" },
6687 { X(LOCALE_IPAPERSIZE), "9" },
6688 { X(LOCALE_SENGCURRNAME), "International Monetary Fund" },
6689 { X(LOCALE_SNATIVECURRNAME), "International Monetary Fund" },
6690 { X(LOCALE_SYEARMONTH), "yyyy MMMM" },
6691 { X(LOCALE_IDIGITSUBSTITUTION), "1" },
6692 { X(LOCALE_SNAME), "" },
6693 { X(LOCALE_SSCRIPTS), "Latn;" },
6694 { 0 }
6695};
6696#undef X
6697
6698static void test_invariant(void)
6699{
6700 int ret;
6701 int len;
6702 char buffer[BUFFER_SIZE];
6703 const struct invariant_entry *ptr = invariant_list;
6704
6706 {
6707 win_skip("GetLocaleInfoA(LOCALE_INVARIANT) not supported\n"); /* win2k */
6708 return;
6709 }
6710
6711 while (ptr->name)
6712 {
6714 if (!ret && (ptr->id == LOCALE_SNAME || ptr->id == LOCALE_SSCRIPTS))
6715 win_skip("not supported\n"); /* winxp/win2k3 */
6716 else
6717 {
6718 len = strlen(ptr->expect)+1; /* include \0 */
6719 ok(ret == len || (ptr->expect2 && ret == strlen(ptr->expect2)+1),
6720 "For id %d, expected ret == %d, got %d, error %ld\n",
6721 ptr->id, len, ret, GetLastError());
6722 ok(!strcmp(buffer, ptr->expect) || (ptr->expect2 && !strcmp(buffer, ptr->expect2)),
6723 "For id %d, Expected %s, got '%s'\n",
6724 ptr->id, ptr->expect, buffer);
6725 }
6726
6727 ptr++;
6728 }
6729
6732 {
6733 skip("Non US-English locale\n");
6734 }
6735 else
6736 {
6737 /* some locales translate these */
6738 static const char lang[] = "Invariant Language (Invariant Country)";
6739 static const char cntry[] = "Invariant Country";
6740 static const char sortm[] = "Math Alphanumerics";
6741 static const char sortms[] = "Maths Alphanumerics";
6742 static const char sortd[] = "Default"; /* win2k3 */
6743
6745 len = lstrlenA(lang) + 1;
6746 ok(ret == len, "Expected ret == %d, got %d, error %ld\n", len, ret, GetLastError());
6747 ok(!strcmp(buffer, lang), "Expected %s, got '%s'\n", lang, buffer);
6748
6750 len = lstrlenA(cntry) + 1;
6751 ok(ret == len, "Expected ret == %d, got %d, error %ld\n", len, ret, GetLastError());
6752 ok(!strcmp(buffer, cntry), "Expected %s, got '%s'\n", cntry, buffer);
6753
6754 ret = GetLocaleInfoA(LOCALE_INVARIANT, NUO|LOCALE_SSORTNAME, buffer, sizeof(buffer));
6755 ok(ret, "Failed err %ld\n", GetLastError());
6756 ok(!strcmp(buffer, sortm) || !strcmp(buffer, sortd) || !strcmp(buffer, sortms), "Got '%s'\n", buffer);
6757 }
6758}
6759
6761{
6762 BOOL ret;
6764 ULONG i, count, size, size_id, size_name, size_buffer;
6765 WCHAR *buffer;
6766
6767 if (!pGetSystemPreferredUILanguages)
6768 {
6769 win_skip("GetSystemPreferredUILanguages is not available.\n");
6770 return;
6771 }
6772
6773 /* (in)valid first parameter */
6774 count = 0;
6775 size = 0;
6776 SetLastError(0xdeadbeef);
6777 ret = pGetSystemPreferredUILanguages(0, &count, NULL, &size);
6778 ok(ret, "Expected GetSystemPreferredUILanguages to succeed\n");
6779 ok(count, "Expected count > 0\n");
6780 ok(size % 6 == 1, "Expected size (%ld) %% 6 == 1\n", size);
6781
6782 size = 0;
6783 SetLastError(0xdeadbeef);
6784 ret = pGetSystemPreferredUILanguages(MUI_FULL_LANGUAGE, &count, NULL, &size);
6785 ok(!ret, "Expected GetSystemPreferredUILanguages to fail\n");
6787 "Expected error ERROR_INVALID_PARAMETER, got %ld\n", GetLastError());
6788
6789 size = 0;
6790 SetLastError(0xdeadbeef);
6791 ret = pGetSystemPreferredUILanguages(MUI_LANGUAGE_ID | MUI_FULL_LANGUAGE, &count, NULL, &size);
6792 ok(!ret, "Expected GetSystemPreferredUILanguages to fail\n");
6794 "Expected error ERROR_INVALID_PARAMETER, got %ld\n", GetLastError());
6795
6796 size = 0;
6797 SetLastError(0xdeadbeef);
6798 ret = pGetSystemPreferredUILanguages(MUI_LANGUAGE_ID | MUI_LANGUAGE_NAME, &count, NULL, &size);
6799 ok(!ret, "Expected GetSystemPreferredUILanguages to fail\n");
6801 "Expected error ERROR_INVALID_PARAMETER, got %ld\n", GetLastError());
6802
6803 count = 0;
6804 size = 0;
6805 SetLastError(0xdeadbeef);
6806 ret = pGetSystemPreferredUILanguages(MUI_LANGUAGE_ID | MUI_MACHINE_LANGUAGE_SETTINGS, &count, NULL, &size);
6807 ok(ret, "Expected GetSystemPreferredUILanguages to succeed\n");
6808 ok(count, "Expected count > 0\n");
6809 ok(size % 5 == 1, "Expected size (%ld) %% 5 == 1\n", size);
6810
6811 count = 0;
6812 size = 0;
6813 SetLastError(0xdeadbeef);
6814 ret = pGetSystemPreferredUILanguages(MUI_LANGUAGE_NAME | MUI_MACHINE_LANGUAGE_SETTINGS, &count, NULL, &size);
6815 ok(ret, "Expected GetSystemPreferredUILanguages to succeed\n");
6816 ok(count, "Expected count > 0\n");
6817 ok(size % 6 == 1, "Expected size (%ld) %% 6 == 1\n", size);
6818
6819 /* second parameter
6820 * ret = pGetSystemPreferredUILanguages(MUI_LANGUAGE_ID, NULL, NULL, &size);
6821 * -> unhandled exception c0000005
6822 */
6823
6824 /* invalid third parameter */
6825 size = 1;
6826 SetLastError(0xdeadbeef);
6827 ret = pGetSystemPreferredUILanguages(MUI_LANGUAGE_ID, &count, NULL, &size);
6828 ok(!ret, "Expected GetSystemPreferredUILanguages to fail\n");
6830 "Expected error ERROR_INVALID_PARAMETER, got %ld\n", GetLastError());
6831
6832 /* fourth parameter
6833 * ret = pGetSystemPreferredUILanguages(MUI_LANGUAGE_ID, &count, NULL, NULL);
6834 * -> unhandled exception c0000005
6835 */
6836
6837 count = 0;
6838 size_id = 0;
6839 SetLastError(0xdeadbeef);
6840 ret = pGetSystemPreferredUILanguages(MUI_LANGUAGE_ID, &count, NULL, &size_id);
6841 ok(ret, "Expected GetSystemPreferredUILanguages to succeed\n");
6842 ok(count, "Expected count > 0\n");
6843 ok(size_id % 5 == 1, "Expected size (%ld) %% 5 == 1\n", size_id);
6844
6845 count = 0;
6846 size_name = 0;
6847 SetLastError(0xdeadbeef);
6848 ret = pGetSystemPreferredUILanguages(MUI_LANGUAGE_NAME, &count, NULL, &size_name);
6849 ok(ret, "Expected GetSystemPreferredUILanguages to succeed\n");
6850 ok(count, "Expected count > 0\n");
6851 ok(size_name % 6 == 1, "Expected size (%ld) %% 6 == 1\n", size_name);
6852
6853 size_buffer = max(size_id, size_name);
6854 if(!size_buffer)
6855 {
6856 skip("No valid buffer size\n");
6857 return;
6858 }
6859
6860 buffer = HeapAlloc(GetProcessHeap(), 0, size_buffer * sizeof(WCHAR));
6861 if (!buffer)
6862 {
6863 skip("Failed to allocate memory for %ld chars\n", size_buffer);
6864 return;
6865 }
6866
6867 count = 0;
6868 size = size_buffer;
6869 memset(buffer, 0x5a, size_buffer * sizeof(WCHAR));
6870 SetLastError(0xdeadbeef);
6871 ret = pGetSystemPreferredUILanguages(0, &count, buffer, &size);
6872 ok(ret, "Expected GetSystemPreferredUILanguages to succeed\n");
6873 ok(count, "Expected count > 0\n");
6874 ok(size % 6 == 1, "Expected size (%ld) %% 6 == 1\n", size);
6875 if (ret && size % 6 == 1)
6876 ok(!buffer[size -2] && !buffer[size -1],
6877 "Expected last two WCHARs being empty, got 0x%x 0x%x\n",
6878 buffer[size -2], buffer[size -1]);
6879
6880 count = 0;
6881 size = size_buffer;
6882 memset(buffer, 0x5a, size_buffer * sizeof(WCHAR));
6883 SetLastError(0xdeadbeef);
6884 ret = pGetSystemPreferredUILanguages(MUI_LANGUAGE_ID, &count, buffer, &size);
6885 ok(ret, "Expected GetSystemPreferredUILanguages to succeed\n");
6886 ok(count, "Expected count > 0\n");
6887 ok(size % 5 == 1, "Expected size (%ld) %% 5 == 1\n", size);
6888 if (ret && size % 5 == 1)
6889 ok(!buffer[size -2] && !buffer[size -1],
6890 "Expected last two WCHARs being empty, got 0x%x 0x%x\n",
6891 buffer[size -2], buffer[size -1]);
6892 for (i = 0; buffer[i]; i++)
6893 ok(('0' <= buffer[i] && buffer[i] <= '9') ||
6894 ('A' <= buffer[i] && buffer[i] <= 'F'),
6895 "MUI_LANGUAGE_ID [%ld] is bad in %s\n", i, wine_dbgstr_w(buffer));
6896
6897 count = 0;
6898 size = size_buffer;
6899 SetLastError(0xdeadbeef);
6900 ret = pGetSystemPreferredUILanguages(MUI_LANGUAGE_NAME, &count, buffer, &size);
6901 ok(ret, "Expected GetSystemPreferredUILanguages to succeed\n");
6902 ok(count, "Expected count > 0\n");
6903 ok(size % 6 == 1, "Expected size (%ld) %% 6 == 1\n", size);
6904 if (ret && size % 5 == 1)
6905 ok(!buffer[size -2] && !buffer[size -1],
6906 "Expected last two WCHARs being empty, got 0x%x 0x%x\n",
6907 buffer[size -2], buffer[size -1]);
6908
6909 count = 0;
6910 size = 0;
6911 SetLastError(0xdeadbeef);
6912 ret = pGetSystemPreferredUILanguages(MUI_MACHINE_LANGUAGE_SETTINGS, &count, NULL, &size);
6913 ok(ret, "Expected GetSystemPreferredUILanguages to succeed\n");
6914 ok(count, "Expected count > 0\n");
6915 ok(size % 6 == 1, "Expected size (%ld) %% 6 == 1\n", size);
6916 if (ret && size % 6 == 1)
6917 ok(!buffer[size -2] && !buffer[size -1],
6918 "Expected last two WCHARs being empty, got 0x%x 0x%x\n",
6919 buffer[size -2], buffer[size -1]);
6920
6921 /* ntdll version is the same, but apparently takes an extra second parameter */
6922 count = 0;
6923 size = size_buffer;
6924 memset(buffer, 0x5a, size_buffer * sizeof(WCHAR));
6925 status = pRtlGetSystemPreferredUILanguages(MUI_LANGUAGE_ID, 0, &count, buffer, &size);
6926 ok(!status, "got %lx\n", status);
6927 ok(count, "Expected count > 0\n");
6928 ok(size % 5 == 1, "Expected size (%ld) %% 5 == 1\n", size);
6929 if (ret && size % 5 == 1)
6930 ok(!buffer[size -2] && !buffer[size -1],
6931 "Expected last two WCHARs being empty, got 0x%x 0x%x\n",
6932 buffer[size -2], buffer[size -1]);
6933
6934 count = 0;
6935 size = size_buffer;
6936 status = pRtlGetSystemPreferredUILanguages(MUI_LANGUAGE_NAME, 0, &count, buffer, &size);
6937 ok(!status, "got %lx\n", status);
6938 ok(count, "Expected count > 0\n");
6939 ok(size % 6 == 1, "Expected size (%ld) %% 6 == 1\n", size);
6940 if (ret && size % 5 == 1)
6941 ok(!buffer[size -2] && !buffer[size -1],
6942 "Expected last two WCHARs being empty, got 0x%x 0x%x\n",
6943 buffer[size -2], buffer[size -1]);
6944
6945 count = 0;
6946 size = 0;
6947 status = pRtlGetSystemPreferredUILanguages(MUI_MACHINE_LANGUAGE_SETTINGS, 0, &count, NULL, &size);
6948 ok(!status, "got %lx\n", status);
6949 ok(count, "Expected count > 0\n");
6950 ok(size % 6 == 1, "Expected size (%ld) %% 6 == 1\n", size);
6951 if (ret && size % 6 == 1)
6952 ok(!buffer[size -2] && !buffer[size -1],
6953 "Expected last two WCHARs being empty, got 0x%x 0x%x\n",
6954 buffer[size -2], buffer[size -1]);
6955
6956 size = 0;
6957 SetLastError(0xdeadbeef);
6958 ret = pGetSystemPreferredUILanguages(MUI_LANGUAGE_ID, &count, buffer, &size);
6959 ok(!ret, "Expected GetSystemPreferredUILanguages to fail\n");
6961 "Expected error ERROR_INSUFFICIENT_BUFFER, got %ld\n", GetLastError());
6962 ok(size == size_id, "expected %lu, got %lu\n", size_id, size);
6963
6964 size = 1;
6965 SetLastError(0xdeadbeef);
6966 ret = pGetSystemPreferredUILanguages(MUI_LANGUAGE_ID, &count, buffer, &size);
6967 ok(!ret, "Expected GetSystemPreferredUILanguages to fail\n");
6969 "Expected error ERROR_INSUFFICIENT_BUFFER, got %ld\n", GetLastError());
6970 ok(size == size_id, "expected %lu, got %lu\n", size_id, size);
6971
6972 size = size_id -1;
6973 memset(buffer, 0x5a, size_buffer * sizeof(WCHAR));
6974 SetLastError(0xdeadbeef);
6975 ret = pGetSystemPreferredUILanguages(MUI_LANGUAGE_ID, &count, buffer, &size);
6976 ok(!ret, "Expected GetSystemPreferredUILanguages to fail\n");
6978 "Expected error ERROR_INSUFFICIENT_BUFFER, got %ld\n", GetLastError());
6979 ok(size == size_id, "expected %lu, got %lu\n", size_id, size);
6980
6981 size = size_id -2;
6982 memset(buffer, 0x5a, size_buffer * sizeof(WCHAR));
6983 SetLastError(0xdeadbeef);
6984 ret = pGetSystemPreferredUILanguages(0, &count, buffer, &size);
6985 ok(!ret, "Expected GetSystemPreferredUILanguages to fail\n");
6987 "Expected error ERROR_INSUFFICIENT_BUFFER, got %ld\n", GetLastError());
6988 ok(size == size_id + 2 || size == size_id + 1 /* before win10 1809 */, "expected %lu, got %lu\n", size_id + 2, size);
6989
6991}
6992
6994{
6995 BOOL ret;
6997 ULONG count, size, size_id;
6998 WCHAR *buf;
6999
7000 if (!pGetThreadPreferredUILanguages)
7001 {
7002 win_skip("GetThreadPreferredUILanguages is not available.\n");
7003 return;
7004 }
7005
7006 size = count = 0;
7007 ret = pGetThreadPreferredUILanguages(MUI_LANGUAGE_ID|MUI_UI_FALLBACK, &count, NULL, &size);
7008 ok(ret, "got %lu\n", GetLastError());
7009 ok(count, "expected count > 0\n");
7010 ok(size, "expected size > 0\n");
7011
7012 count = 0;
7014 ret = pGetThreadPreferredUILanguages(MUI_LANGUAGE_ID|MUI_UI_FALLBACK, &count, buf, &size);
7015 ok(ret, "got %lu\n", GetLastError());
7016 ok(count, "expected count > 0\n");
7017
7018 size_id = count = 0;
7019 ret = pGetThreadPreferredUILanguages(MUI_LANGUAGE_ID, &count, NULL, &size_id);
7020 ok(ret, "got %lu\n", GetLastError());
7021 ok(count, "expected count > 0\n");
7022 ok(size_id, "expected size > 0\n");
7023 ok(size_id <= size, "expected size > 0\n");
7024
7025 /* ntdll function is the same */
7026 size_id = count = 0;
7027 status = pRtlGetThreadPreferredUILanguages(MUI_LANGUAGE_ID, &count, NULL, &size_id);
7028 ok(!status, "got %lx\n", status);
7029 ok(count, "expected count > 0\n");
7030 ok(size_id, "expected size > 0\n");
7031 ok(size_id <= size, "expected size > 0\n");
7032
7033 size = 0;
7034 SetLastError(0xdeadbeef);
7035 ret = pGetThreadPreferredUILanguages(MUI_LANGUAGE_ID, &count, buf, &size);
7036 ok(!ret, "Expected GetThreadPreferredUILanguages to fail\n");
7037 ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER,
7038 "Expected error ERROR_INSUFFICIENT_BUFFER, got %ld\n", GetLastError());
7039 ok(size == size_id, "expected %lu, got %lu\n", size_id, size);
7040
7041 size = 1;
7042 SetLastError(0xdeadbeef);
7043 ret = pGetThreadPreferredUILanguages(MUI_LANGUAGE_ID, &count, buf, &size);
7044 ok(!ret, "Expected GetThreadPreferredUILanguages to fail\n");
7045 ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER,
7046 "Expected error ERROR_INSUFFICIENT_BUFFER, got %ld\n", GetLastError());
7047 ok(size == size_id, "expected %lu, got %lu\n", size_id, size);
7048
7049 size = size_id - 1;
7050 SetLastError(0xdeadbeef);
7051 ret = pGetThreadPreferredUILanguages(MUI_LANGUAGE_ID, &count, buf, &size);
7052 ok(!ret, "Expected GetThreadPreferredUILanguages to fail\n");
7053 ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER,
7054 "Expected error ERROR_INSUFFICIENT_BUFFER, got %ld\n", GetLastError());
7055 ok(size == size_id, "expected %lu, got %lu\n", size_id, size);
7056
7057 size = size_id - 2;
7058 SetLastError(0xdeadbeef);
7059 ret = pGetThreadPreferredUILanguages(0, &count, buf, &size);
7060 ok(!ret, "Expected GetThreadPreferredUILanguages to fail\n");
7061 ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER,
7062 "Expected error ERROR_INSUFFICIENT_BUFFER, got %ld\n", GetLastError());
7063 todo_wine
7064 ok(size == size_id || size == size_id - 1 /* before win10 1809 */, "expected %lu, got %lu\n", size_id, size);
7065
7066 HeapFree(GetProcessHeap(), 0, buf);
7067}
7068
7069static void test_GetUserPreferredUILanguages(void)
7070{
7071 BOOL ret;
7072 NTSTATUS status;
7073 ULONG count, size, size_id, size_name, size_buffer;
7074 WCHAR *buffer;
7075
7076 if (!pGetUserPreferredUILanguages)
7077 {
7078 win_skip("GetUserPreferredUILanguages is not available.\n");
7079 return;
7080 }
7081
7082 size = 0;
7083 SetLastError(0xdeadbeef);
7084 ret = pGetUserPreferredUILanguages(MUI_FULL_LANGUAGE, &count, NULL, &size);
7085 ok(!ret, "Expected GetUserPreferredUILanguages to fail\n");
7086 ok(ERROR_INVALID_PARAMETER == GetLastError(),
7087 "Expected error ERROR_INVALID_PARAMETER, got %ld\n", GetLastError());
7088
7089 size = 0;
7090 SetLastError(0xdeadbeef);
7091 ret = pGetUserPreferredUILanguages(MUI_LANGUAGE_ID | MUI_FULL_LANGUAGE, &count, NULL, &size);
7092 ok(!ret, "Expected GetUserPreferredUILanguages to fail\n");
7093 ok(ERROR_INVALID_PARAMETER == GetLastError(),
7094 "Expected error ERROR_INVALID_PARAMETER, got %ld\n", GetLastError());
7095
7096 size = 0;
7097 SetLastError(0xdeadbeef);
7098 ret = pGetUserPreferredUILanguages(MUI_LANGUAGE_ID | MUI_MACHINE_LANGUAGE_SETTINGS, &count, NULL, &size);
7099 ok(!ret, "Expected GetUserPreferredUILanguages to fail\n");
7100 ok(ERROR_INVALID_PARAMETER == GetLastError(),
7101 "Expected error ERROR_INVALID_PARAMETER, got %ld\n", GetLastError());
7102
7103 size = 1;
7104 SetLastError(0xdeadbeef);
7105 ret = pGetUserPreferredUILanguages(MUI_LANGUAGE_ID, &count, NULL, &size);
7106 ok(!ret, "Expected GetUserPreferredUILanguages to fail\n");
7107 ok(ERROR_INVALID_PARAMETER == GetLastError(),
7108 "Expected error ERROR_INVALID_PARAMETER, got %ld\n", GetLastError());
7109
7110 count = 0;
7111 size_id = 0;
7112 SetLastError(0xdeadbeef);
7113 ret = pGetUserPreferredUILanguages(MUI_LANGUAGE_ID, &count, NULL, &size_id);
7115 ok(count, "Expected count > 0\n");
7116 ok(size_id % 5 == 1, "Expected size (%ld) %% 5 == 1\n", size_id);
7117
7118 count = 0;
7119 size_name = 0;
7120 SetLastError(0xdeadbeef);
7121 ret = pGetUserPreferredUILanguages(MUI_LANGUAGE_NAME, &count, NULL, &size_name);
7123 ok(count, "Expected count > 0\n");
7124 ok(size_name % 6 == 1, "Expected size (%ld) %% 6 == 1\n", size_name);
7125
7126 size_buffer = max(size_id, size_name);
7127 if(!size_buffer)
7128 {
7129 skip("No valid buffer size\n");
7130 return;
7131 }
7132
7133 /* ntdll version is the same, but apparently takes an extra second parameter */
7134 count = 0;
7135 size_id = 0;
7136 SetLastError(0xdeadbeef);
7137 status = pRtlGetUserPreferredUILanguages(MUI_LANGUAGE_ID, 0, &count, NULL, &size_id);
7138 ok(!status, "got %lx\n", status);
7139 ok(count, "Expected count > 0\n");
7140 ok(size_id % 5 == 1, "Expected size (%ld) %% 5 == 1\n", size_id);
7141
7142 buffer = HeapAlloc(GetProcessHeap(), 0, size_buffer * sizeof(WCHAR));
7143
7144 count = 0;
7145 size = size_buffer;
7146 memset(buffer, 0x5a, size_buffer * sizeof(WCHAR));
7147 SetLastError(0xdeadbeef);
7148 ret = pGetUserPreferredUILanguages(0, &count, buffer, &size);
7150 ok(count, "Expected count > 0\n");
7151 ok(size % 6 == 1, "Expected size (%ld) %% 6 == 1\n", size);
7152 if (ret && size % 6 == 1)
7153 ok(!buffer[size -2] && !buffer[size -1],
7154 "Expected last two WCHARs being empty, got 0x%x 0x%x\n",
7155 buffer[size -2], buffer[size -1]);
7156
7157 count = 0;
7158 size = size_buffer;
7159 memset(buffer, 0x5a, size_buffer * sizeof(WCHAR));
7160 SetLastError(0xdeadbeef);
7161 ret = pGetUserPreferredUILanguages(MUI_LANGUAGE_ID, &count, buffer, &size);
7163 ok(count, "Expected count > 0\n");
7164 ok(size % 5 == 1, "Expected size (%ld) %% 5 == 1\n", size);
7165 if (ret && size % 5 == 1)
7166 ok(!buffer[size -2] && !buffer[size -1],
7167 "Expected last two WCHARs being empty, got 0x%x 0x%x\n",
7168 buffer[size -2], buffer[size -1]);
7169
7170 count = 0;
7171 size = size_buffer;
7172 SetLastError(0xdeadbeef);
7173 ret = pGetUserPreferredUILanguages(MUI_LANGUAGE_NAME, &count, buffer, &size);
7175 ok(count, "Expected count > 0\n");
7176 ok(size % 6 == 1, "Expected size (%ld) %% 6 == 1\n", size);
7177 if (ret && size % 5 == 1)
7178 ok(!buffer[size -2] && !buffer[size -1],
7179 "Expected last two WCHARs being empty, got 0x%x 0x%x\n",
7180 buffer[size -2], buffer[size -1]);
7181
7182 size = 1;
7183 SetLastError(0xdeadbeef);
7184 ret = pGetUserPreferredUILanguages(MUI_LANGUAGE_ID, &count, buffer, &size);
7185 ok(!ret, "Expected GetUserPreferredUILanguages to fail\n");
7186 ok(ERROR_INSUFFICIENT_BUFFER == GetLastError(),
7187 "Expected error ERROR_INSUFFICIENT_BUFFER, got %ld\n", GetLastError());
7188
7189 size = size_id -1;
7190 memset(buffer, 0x5a, size_buffer * sizeof(WCHAR));
7191 SetLastError(0xdeadbeef);
7192 ret = pGetUserPreferredUILanguages(MUI_LANGUAGE_ID, &count, buffer, &size);
7193 ok(!ret, "Expected GetUserPreferredUILanguages to fail\n");
7194 ok(ERROR_INSUFFICIENT_BUFFER == GetLastError(),
7195 "Expected error ERROR_INSUFFICIENT_BUFFER, got %ld\n", GetLastError());
7196
7197 count = 0;
7198 size = size_id -2;
7199 memset(buffer, 0x5a, size_buffer * sizeof(WCHAR));
7200 SetLastError(0xdeadbeef);
7201 ret = pGetUserPreferredUILanguages(0, &count, buffer, &size);
7202 ok(!ret, "Expected GetUserPreferredUILanguages to fail\n");
7203 ok(ERROR_INSUFFICIENT_BUFFER == GetLastError(),
7204 "Expected error ERROR_INSUFFICIENT_BUFFER, got %ld\n", GetLastError());
7205
7206 HeapFree(GetProcessHeap(), 0, buffer);
7207}
7208
7209static void test_FindNLSStringEx(void)
7210{
7211 INT res;
7212 static const WCHAR comb_s_accent1W[] = {0x1e69, 'o','u','r','c','e',0};
7213 static const WCHAR comb_s_accent2W[] = {0x0073,0x323,0x307,'o','u','r','c','e',0};
7214 static const WCHAR comb_q_accent1W[] = {'a','b',0x0071,0x0307,0x323,'u','o','t','e','\n',0};
7215 static const WCHAR comb_q_accent2W[] = {0x0071,0x0323,0x307,'u','o','t','e',0};
7216 struct test_data {
7217 const WCHAR *locale;
7218 DWORD flags;
7219 const WCHAR *src;
7220 const WCHAR *value;
7221 INT expected_ret;
7222 INT expected_found;
7223 };
7224
7225 static struct test_data tests[] =
7226 {
7227 { localeW, FIND_FROMSTART, L"SimpleSimple", L"Simple", 0, 6},
7228 { localeW, FIND_FROMEND, L"SimpleSimple", L"Simp", 6, 4},
7229 { localeW, FIND_STARTSWITH, L"SimpleSimple", L"Simp", 0, 4},
7230 { localeW, FIND_ENDSWITH, L"SimpleSimple", L"Simple", 6, 6},
7231 { localeW, FIND_ENDSWITH, L"SimpleSimple", L"Simp", -1, 0xdeadbeef},
7232 { localeW, FIND_FROMSTART, comb_s_accent1W, comb_s_accent2W, 0, 6 },
7233 { localeW, FIND_FROMSTART, comb_q_accent1W, comb_q_accent2W, 2, 7 },
7234 { localeW, FIND_STARTSWITH, L"--Option", L"--", 0, 2},
7235 { localeW, FIND_ENDSWITH, L"Option--", L"--", 6, 2},
7236 { localeW, FIND_FROMSTART, L"----", L"--", 0, 2},
7237 { localeW, FIND_FROMEND, L"----", L"--", 2, 2},
7238 { localeW, FIND_FROMSTART, L"opt1--opt2--opt3", L"--", 4, 2},
7239 { localeW, FIND_FROMEND, L"opt1--opt2--opt3", L"--", 10, 2},
7240 { localeW, FIND_FROMSTART, L"x-oss-security", L"x-oss-", 0, 6},
7241 { localeW, FIND_FROMSTART, L"x-oss-security", L"-oss", 1, 4},
7242 { localeW, FIND_FROMSTART, L"x-oss-security", L"-oss--", -1, 0xdeadbeef},
7243 { localeW, FIND_FROMEND, L"x-oss-oss2", L"-oss", 5, 4},
7244 };
7245 unsigned int i;
7246
7247#if defined(__REACTOS__) && DLL_EXPORT_VERSION >= 0x600
7248 /* FIXME: FindNLSStringEx is a STUB on ReactOS! */
7249 if (is_reactos() || !pFindNLSStringEx)
7250#else
7251 if (!pFindNLSStringEx)
7252#endif
7253 {
7254 win_skip("FindNLSStringEx is not available.\n");
7255 return;
7256 }
7257
7258 SetLastError( 0xdeadbeef );
7259 res = pFindNLSStringEx(invalidW, FIND_FROMSTART, fooW, 3, fooW,
7260 3, NULL, NULL, NULL, 0);
7261 ok(res, "Expected failure of FindNLSStringEx. Return value was %d\n", res);
7262 ok(ERROR_INVALID_PARAMETER == GetLastError(),
7263 "Expected ERROR_INVALID_PARAMETER as last error; got %ld\n", GetLastError());
7264
7265 SetLastError( 0xdeadbeef );
7266 res = pFindNLSStringEx(localeW, FIND_FROMSTART, NULL, 3, fooW, 3,
7267 NULL, NULL, NULL, 0);
7268 ok(res, "Expected failure of FindNLSStringEx. Return value was %d\n", res);
7269 ok(ERROR_INVALID_PARAMETER == GetLastError(),
7270 "Expected ERROR_INVALID_PARAMETER as last error; got %ld\n", GetLastError());
7271
7272 SetLastError( 0xdeadbeef );
7273 res = pFindNLSStringEx(localeW, FIND_FROMSTART, fooW, -5, fooW, 3,
7274 NULL, NULL, NULL, 0);
7275 ok(res, "Expected failure of FindNLSStringEx. Return value was %d\n", res);
7276 ok(ERROR_INVALID_PARAMETER == GetLastError(),
7277 "Expected ERROR_INVALID_PARAMETER as last error; got %ld\n", GetLastError());
7278
7279 SetLastError( 0xdeadbeef );
7280 res = pFindNLSStringEx(localeW, FIND_FROMSTART, fooW, 3, NULL, 3,
7281 NULL, NULL, NULL, 0);
7282 ok(res, "Expected failure of FindNLSStringEx. Return value was %d\n", res);
7283 ok(ERROR_INVALID_PARAMETER == GetLastError(),
7284 "Expected ERROR_INVALID_PARAMETER as last error; got %ld\n", GetLastError());
7285
7286 SetLastError( 0xdeadbeef );
7287 res = pFindNLSStringEx(localeW, FIND_FROMSTART, fooW, 3, fooW, -5,
7288 NULL, NULL, NULL, 0);
7289 ok(res, "Expected failure of FindNLSStringEx. Return value was %d\n", res);
7290 ok(ERROR_INVALID_PARAMETER == GetLastError(),
7291 "Expected ERROR_INVALID_PARAMETER as last error; got %ld\n", GetLastError());
7292
7293 for (i = 0; i < ARRAY_SIZE(tests); i++)
7294 {
7295#ifdef __REACTOS__
7296 if (GetNTVersion() == _WIN32_WINNT_VISTA && i == 5) // Skip tests[5] on Vista
7297 continue;
7298#endif
7299 int found = 0xdeadbeef;
7300 res = pFindNLSStringEx(tests[i].locale, tests[i].flags, tests[i].src, -1,
7301 tests[i].value, -1, &found, NULL, NULL, 0);
7302 ok(res == tests[i].expected_ret,
7303 "%u: Expected FindNLSStringEx to return %d. Returned value was %d\n", i,
7304 tests[i].expected_ret, res);
7305 ok(found == tests[i].expected_found,
7306 "%u: Expected FindNLSStringEx to output %d. Value was %d\n", i,
7307 tests[i].expected_found, found);
7308 }
7309}
7310
7311static void test_FindStringOrdinal(void)
7312{
7313 static const WCHAR abc123aBcW[] = {'a', 'b', 'c', '1', '2', '3', 'a', 'B', 'c', 0};
7314 static const WCHAR abcW[] = {'a', 'b', 'c', 0};
7315 static const WCHAR aBcW[] = {'a', 'B', 'c', 0};
7316 static const WCHAR aaaW[] = {'a', 'a', 'a', 0};
7317 static const struct
7318 {
7319 DWORD flag;
7320 const WCHAR *src;
7321 INT src_size;
7322 const WCHAR *val;
7323 INT val_size;
7324 BOOL ignore_case;
7325 INT ret;
7326 DWORD err;
7327 }
7328 tests[] =
7329 {
7330 /* Invalid */
7331 {1, abc123aBcW, ARRAY_SIZE(abc123aBcW) - 1, abcW, ARRAY_SIZE(abcW) - 1, FALSE, -1, ERROR_INVALID_FLAGS},
7332 {FIND_FROMSTART, NULL, ARRAY_SIZE(abc123aBcW) - 1, abcW, ARRAY_SIZE(abcW) - 1, FALSE, -1,
7333 ERROR_INVALID_PARAMETER},
7334 {FIND_FROMSTART, abc123aBcW, ARRAY_SIZE(abc123aBcW) - 1, NULL, ARRAY_SIZE(abcW) - 1, FALSE, -1,
7335 ERROR_INVALID_PARAMETER},
7336 {FIND_FROMSTART, abc123aBcW, ARRAY_SIZE(abc123aBcW) - 1, NULL, 0, FALSE, -1, ERROR_INVALID_PARAMETER},
7337 {FIND_FROMSTART, NULL, 0, abcW, ARRAY_SIZE(abcW) - 1, FALSE, -1, ERROR_INVALID_PARAMETER},
7338 {FIND_FROMSTART, NULL, 0, NULL, 0, FALSE, -1, ERROR_INVALID_PARAMETER},
7339 /* Case-insensitive */
7340 {FIND_FROMSTART, abc123aBcW, ARRAY_SIZE(abc123aBcW) - 1, abcW, ARRAY_SIZE(abcW) - 1, FALSE, 0, NO_ERROR},
7341 {FIND_FROMEND, abc123aBcW, ARRAY_SIZE(abc123aBcW) - 1, abcW, ARRAY_SIZE(abcW) - 1, FALSE, 0, NO_ERROR},
7342 {FIND_STARTSWITH, abc123aBcW, ARRAY_SIZE(abc123aBcW) - 1, abcW, ARRAY_SIZE(abcW) - 1, FALSE, 0, NO_ERROR},
7343 {FIND_ENDSWITH, abc123aBcW, ARRAY_SIZE(abc123aBcW) - 1, abcW, ARRAY_SIZE(abcW) - 1, FALSE, -1, NO_ERROR},
7344 /* Case-sensitive */
7345 {FIND_FROMSTART, abc123aBcW, ARRAY_SIZE(abc123aBcW) - 1, aBcW, ARRAY_SIZE(aBcW) - 1, TRUE, 0, NO_ERROR},
7346 {FIND_FROMEND, abc123aBcW, ARRAY_SIZE(abc123aBcW) - 1, aBcW, ARRAY_SIZE(aBcW) - 1, TRUE, 6, NO_ERROR},
7347 {FIND_STARTSWITH, abc123aBcW, ARRAY_SIZE(abc123aBcW) - 1, aBcW, ARRAY_SIZE(aBcW) - 1, TRUE, 0, NO_ERROR},
7348 {FIND_ENDSWITH, abc123aBcW, ARRAY_SIZE(abc123aBcW) - 1, aBcW, ARRAY_SIZE(aBcW) - 1, TRUE, 6, NO_ERROR},
7349 /* Other */
7350 {FIND_FROMSTART, abc123aBcW, ARRAY_SIZE(abc123aBcW) - 1, aaaW, ARRAY_SIZE(aaaW) - 1, FALSE, -1, NO_ERROR},
7351 {FIND_FROMSTART, abc123aBcW, -1, abcW, ARRAY_SIZE(abcW) - 1, FALSE, 0, NO_ERROR},
7352 {FIND_FROMSTART, abc123aBcW, ARRAY_SIZE(abc123aBcW) - 1, abcW, -1, FALSE, 0, NO_ERROR},
7353 {FIND_FROMSTART, abc123aBcW, 0, abcW, ARRAY_SIZE(abcW) - 1, FALSE, -1, NO_ERROR},
7354 {FIND_FROMSTART, abc123aBcW, ARRAY_SIZE(abc123aBcW) - 1, abcW, 0, FALSE, 0, NO_ERROR},
7355 {FIND_FROMSTART, abc123aBcW, 0, abcW, 0, FALSE, 0, NO_ERROR},
7356 };
7357 INT ret;
7358 DWORD err;
7359 INT i;
7360
7361 if (!pFindStringOrdinal)
7362 {
7363 win_skip("FindStringOrdinal is not available.\n");
7364 return;
7365 }
7366
7367 for (i = 0; i < ARRAY_SIZE(tests); i++)
7368 {
7369 SetLastError(0xdeadbeef);
7370 ret = pFindStringOrdinal(tests[i].flag, tests[i].src, tests[i].src_size, tests[i].val, tests[i].val_size,
7371 tests[i].ignore_case);
7372 err = GetLastError();
7373 ok(ret == tests[i].ret, "Item %d expected %d, got %d\n", i, tests[i].ret, ret);
7374 ok(err == tests[i].err, "Item %d expected %#lx, got %#lx\n", i, tests[i].err, err);
7375 }
7376}
7377
7378static void test_SetThreadUILanguage(void)
7379{
7380 LANGID res;
7381
7382 if (!pGetThreadUILanguage)
7383 {
7384 win_skip("GetThreadUILanguage isn't implemented, skipping SetThreadUILanguage tests for version < Vista\n");
7385 return; /* BTW SetThreadUILanguage is present on winxp/2003 but doesn`t set the LANGID anyway when tested */
7386 }
7387
7388 res = pSetThreadUILanguage(0);
7389 ok(res == pGetThreadUILanguage(), "expected %d got %d\n", pGetThreadUILanguage(), res);
7390
7391 res = pSetThreadUILanguage(MAKELANGID(LANG_DUTCH, SUBLANG_DUTCH_BELGIAN));
7392 ok(res == MAKELANGID(LANG_DUTCH, SUBLANG_DUTCH_BELGIAN),
7393 "expected %d got %d\n", MAKELANGID(LANG_DUTCH, SUBLANG_DUTCH_BELGIAN), res);
7394
7395 res = pSetThreadUILanguage(0);
7396 todo_wine ok(res == MAKELANGID(LANG_DUTCH, SUBLANG_DUTCH_BELGIAN),
7397 "expected %d got %d\n", MAKELANGID(LANG_DUTCH, SUBLANG_DUTCH_BELGIAN), res);
7398}
7399
7400/* read a Unicode string from NormalizationTest.txt format; helper for test_NormalizeString */
7401static int read_str( char *str, WCHAR res[32] )
7402{
7403 int pos = 0;
7404 char *end;
7405
7406 while (*str && pos < 31)
7407 {
7408 unsigned int c = strtoul( str, &end, 16 );
7409 pos += put_utf16( res + pos, c );
7410 while (*end == ' ') end++;
7411 str = end;
7412 }
7413 res[pos] = 0;
7414 return pos;
7415}
7416
7417static void test_NormalizeString(void)
7418{
7419 /* part 0: specific cases */
7420 /* LATIN CAPITAL LETTER D WITH DOT ABOVE */
7421 static const WCHAR part0_str1[] = {0x1e0a,0};
7422 static const WCHAR part0_nfd1[] = {0x0044,0x0307,0};
7423
7424 /* LATIN CAPITAL LETTER D, COMBINING DOT BELOW, COMBINING DOT ABOVE */
7425 static const WCHAR part0_str2[] = {0x0044,0x0323,0x0307,0};
7426 static const WCHAR part0_nfc2[] = {0x1e0c,0x0307,0};
7427
7428 /* LATIN CAPITAL LETTER D, COMBINING HORN, COMBINING DOT BELOW, COMBINING DOT ABOVE */
7429 static const WCHAR part0_str3[] = {0x0044,0x031b,0x0323,0x0307,0};
7430 static const WCHAR part0_nfc3[] = {0x1e0c,0x031b,0x0307,0};
7431
7432 /* LATIN CAPITAL LETTER D, COMBINING HORN, COMBINING DOT BELOW, COMBINING DOT ABOVE */
7433 static const WCHAR part0_str4[] = {0x0044,0x031b,0x0323,0x0307,0};
7434 static const WCHAR part0_nfc4[] = {0x1e0c,0x031b,0x0307,0};
7435
7436 /*
7437 * HEBREW ACCENT SEGOL, HEBREW POINT PATAH, HEBREW POINT DAGESH OR MAPIQ,
7438 * HEBREW ACCENT MERKHA, HEBREW POINT SHEVA, HEBREW PUNCTUATION PASEQ,
7439 * HEBREW MARK UPPER DOT, HEBREW ACCENT DEHI
7440 */
7441 static const WCHAR part0_str5[] = {0x0592,0x05B7,0x05BC,0x05A5,0x05B0,0x05C0,0x05C4,0x05AD,0};
7442 static const WCHAR part0_nfc5[] = {0x05B0,0x05B7,0x05BC,0x05A5,0x0592,0x05C0,0x05AD,0x05C4,0};
7443
7444 /*
7445 * HEBREW POINT QAMATS, HEBREW POINT HOLAM, HEBREW POINT HATAF SEGOL,
7446 * HEBREW ACCENT ETNAHTA, HEBREW PUNCTUATION SOF PASUQ, HEBREW POINT SHEVA,
7447 * HEBREW ACCENT ILUY, HEBREW ACCENT QARNEY PARA
7448 */
7449 static const WCHAR part0_str6[] = {0x05B8,0x05B9,0x05B1,0x0591,0x05C3,0x05B0,0x05AC,0x059F,0};
7450 static const WCHAR part0_nfc6[] = {0x05B1,0x05B8,0x05B9,0x0591,0x05C3,0x05B0,0x05AC,0x059F,0};
7451
7452 /* LATIN CAPITAL LETTER D WITH DOT BELOW */
7453 static const WCHAR part0_str8[] = {0x1E0C,0};
7454 static const WCHAR part0_nfd8[] = {0x0044,0x0323,0};
7455
7456 /* LATIN CAPITAL LETTER D WITH DOT ABOVE, COMBINING DOT BELOW */
7457 static const WCHAR part0_str9[] = {0x1E0A,0x0323,0};
7458 static const WCHAR part0_nfc9[] = {0x1E0C,0x0307,0};
7459 static const WCHAR part0_nfd9[] = {0x0044,0x0323,0x0307,0};
7460
7461 /* LATIN CAPITAL LETTER D WITH DOT BELOW, COMBINING DOT ABOVE */
7462 static const WCHAR part0_str10[] = {0x1E0C,0x0307,0};
7463 static const WCHAR part0_nfd10[] = {0x0044,0x0323,0x0307,0};
7464
7465 /* LATIN CAPITAL LETTER E WITH MACRON AND GRAVE, COMBINING MACRON */
7466 static const WCHAR part0_str11[] = {0x1E14,0x0304,0};
7467 static const WCHAR part0_nfd11[] = {0x0045,0x0304,0x0300,0x0304,0};
7468
7469 /* LATIN CAPITAL LETTER E WITH MACRON, COMBINING GRAVE ACCENT */
7470 static const WCHAR part0_str12[] = {0x0112,0x0300,0};
7471 static const WCHAR part0_nfc12[] = {0x1E14,0};
7472 static const WCHAR part0_nfd12[] = {0x0045,0x0304,0x0300,0};
7473
7474 /* part 1: character by character */
7475 /* DIAERESIS */
7476 static const WCHAR part1_str1[] = {0x00a8,0};
7477 static const WCHAR part1_nfkc1[] = {0x0020,0x0308,0};
7478
7479 /* VULGAR FRACTION ONE QUARTER */
7480 static const WCHAR part1_str2[] = {0x00bc,0};
7481 static const WCHAR part1_nfkc2[] = {0x0031,0x2044,0x0034,0};
7482
7483 /* LATIN CAPITAL LETTER E WITH CIRCUMFLEX */
7484 static const WCHAR part1_str3[] = {0x00ca,0};
7485 static const WCHAR part1_nfd3[] = {0x0045,0x0302,0};
7486
7487 /* MODIFIER LETTER SMALL GAMMA */
7488 static const WCHAR part1_str4[] = {0x02e0,0};
7489 static const WCHAR part1_nfkc4[] = {0x0263,0};
7490
7491 /* CYRILLIC CAPITAL LETTER IE WITH GRAVE */
7492 static const WCHAR part1_str5[] = {0x0400,0};
7493 static const WCHAR part1_nfd5[] = {0x0415,0x0300,0};
7494
7495 /* CYRILLIC CAPITAL LETTER IZHITSA WITH DOUBLE GRAVE ACCENT */
7496 static const WCHAR part1_str6[] = {0x0476,0};
7497 static const WCHAR part1_nfd6[] = {0x0474,0x030F,0};
7498
7499 /* ARABIC LIGATURE HAH WITH JEEM INITIAL FORM */
7500 static const WCHAR part1_str7[] = {0xFCA9,0};
7501 static const WCHAR part1_nfkc7[] = {0x062D,0x062C,0};
7502
7503 /* GREEK SMALL LETTER OMICRON WITH PSILI AND VARIA */
7504 static const WCHAR part1_str8[] = {0x1F42,0};
7505 static const WCHAR part1_nfd8[] = {0x03BF,0x0313,0x0300,0};
7506
7507 /* QUADRUPLE PRIME */
7508 static const WCHAR part1_str9[] = {0x2057,0};
7509 static const WCHAR part1_nfkc9[] = {0x2032,0x2032,0x2032,0x2032,0};
7510
7511 /* KATAKANA-HIRAGANA VOICED SOUND MARK */
7512 static const WCHAR part1_str10[] = {0x309B,0};
7513 static const WCHAR part1_nfkc10[] = {0x20,0x3099,0};
7514
7515 /* ANGSTROM SIGN */
7516 static const WCHAR part1_str11[] = {0x212B,0};
7517 static const WCHAR part1_nfc11[] = {0xC5,0};
7518 static const WCHAR part1_nfd11[] = {'A',0x030A,0};
7519
7520 static const WCHAR composite_src[] =
7521 {
7522 0x008a, 0x008e, 0x009a, 0x009e, 0x009f, 0x00c0, 0x00c1, 0x00c2,
7523 0x00c3, 0x00c4, 0x00c5, 0x00c7, 0x00c8, 0x00c9, 0x00ca, 0x00cb,
7524 0x00cc, 0x00cd, 0x00ce, 0x00cf, 0x00d1, 0x00d2, 0x00d3, 0x00d4,
7525 0x00d5, 0x00d6, 0x00d8, 0x00d9, 0x00da, 0x00db, 0x00dc, 0x00dd,
7526 0x00e0, 0x00e1, 0x00e2, 0x00e3, 0x00e4, 0x00e5, 0x00e7, 0x00e8,
7527 0x00e9, 0x00ea, 0x00eb, 0x00ec, 0x00ed, 0x00ee, 0x00ef, 0x00f1,
7528 0x00f2, 0x00f3, 0x00f4, 0x00f5, 0x00f6, 0x00f8, 0x00f9, 0x00fa,
7529 0x00fb, 0x00fc, 0x00fd, 0x00ff, 0x212b
7530 };
7531
7532 struct test_data_normal {
7533 const WCHAR *str;
7534 const WCHAR *expected[4];
7535 };
7536 static const struct test_data_normal test_arr[] =
7537 {
7538 { part0_str1, { part0_str1, part0_nfd1, part0_str1, part0_nfd1 } },
7539 { part0_str2, { part0_nfc2, part0_str2, part0_nfc2, part0_str2 } },
7540 { part0_str3, { part0_nfc3, part0_str3, part0_nfc3, part0_str3 } },
7541 { part0_str4, { part0_nfc4, part0_str4, part0_nfc4, part0_str4 } },
7542 { part0_str5, { part0_nfc5, part0_nfc5, part0_nfc5, part0_nfc5 } },
7543 { part0_str6, { part0_nfc6, part0_nfc6, part0_nfc6, part0_nfc6 } },
7544 { part0_str8, { part0_str8, part0_nfd8, part0_str8, part0_nfd8 } },
7545 { part0_str9, { part0_nfc9, part0_nfd9, part0_nfc9, part0_nfd9 } },
7546 { part0_str10, { part0_str10, part0_nfd10, part0_str10, part0_nfd10 } },
7547 { part0_str11, { part0_str11, part0_nfd11, part0_str11, part0_nfd11 } },
7548 { part0_str12, { part0_nfc12, part0_nfd12, part0_nfc12, part0_nfd12 } },
7549 { part1_str1, { part1_str1, part1_str1, part1_nfkc1, part1_nfkc1 } },
7550 { part1_str2, { part1_str2, part1_str2, part1_nfkc2, part1_nfkc2 } },
7551 { part1_str3, { part1_str3, part1_nfd3, part1_str3, part1_nfd3 } },
7552 { part1_str4, { part1_str4, part1_str4, part1_nfkc4, part1_nfkc4 } },
7553 { part1_str5, { part1_str5, part1_nfd5, part1_str5, part1_nfd5 } },
7554 { part1_str6, { part1_str6, part1_nfd6, part1_str6, part1_nfd6 } },
7555 { part1_str7, { part1_str7, part1_str7, part1_nfkc7, part1_nfkc7 } },
7556 { part1_str8, { part1_str8, part1_nfd8, part1_str8, part1_nfd8 } },
7557 { part1_str9, { part1_str9, part1_str9, part1_nfkc9, part1_nfkc9 } },
7558 { part1_str10, { part1_str10, part1_str10, part1_nfkc10, part1_nfkc10 } },
7559 { part1_str11, { part1_nfc11, part1_nfd11, part1_nfc11, part1_nfd11 } },
7560 { 0 }
7561 };
7562 const struct test_data_normal *ptest = test_arr;
7563 const int norm_forms[] = { NormalizationC, NormalizationD, NormalizationKC, NormalizationKD };
7564 WCHAR dst[256];
7565 BOOLEAN ret;
7566 NTSTATUS status;
7567 int dstlen, str_cmp, i, j;
7568 FILE *f;
7569
7570 if (!pNormalizeString)
7571 {
7572 win_skip("NormalizeString is not available.\n");
7573 return;
7574 }
7575 if (!pRtlNormalizeString) win_skip("RtlNormalizeString is not available.\n");
7576
7577 /*
7578 * For each string, first test passing -1 as srclen to NormalizeString,
7579 * thereby assuming a null-terminating string in src, and then test passing
7580 * explicitly the string length.
7581 * Do that for all 4 normalization forms.
7582 */
7583 while (ptest->str)
7584 {
7585 for (i = 0; i < 4; i++)
7586 {
7587 SetLastError(0xdeadbeef);
7588 dstlen = pNormalizeString( norm_forms[i], ptest->str, -1, NULL, 0 );
7589 ok( dstlen > lstrlenW(ptest->str), "%s:%d: wrong len %d / %d\n",
7590 wine_dbgstr_w(ptest->str), i, dstlen, lstrlenW(ptest->str) );
7591 ok(GetLastError() == ERROR_SUCCESS, "%s:%d: got error %lu\n",
7592 wine_dbgstr_w(ptest->str), i, GetLastError());
7593 SetLastError(0xdeadbeef);
7594 dstlen = pNormalizeString( norm_forms[i], ptest->str, -1, dst, dstlen );
7595 ok(GetLastError() == ERROR_SUCCESS, "%s:%d: got error %lu\n",
7596 wine_dbgstr_w(ptest->str), i, GetLastError());
7597 ok(dstlen == lstrlenW( dst )+1, "%s:%d: Copied length differed: was %d, should be %d\n",
7598 wine_dbgstr_w(ptest->str), i, dstlen, lstrlenW( dst )+1);
7599 str_cmp = wcsncmp( ptest->expected[i], dst, dstlen+1 );
7600 ok( str_cmp == 0, "%s:%d: string incorrect got %s expect %s\n", wine_dbgstr_w(ptest->str), i,
7601 wine_dbgstr_w(dst), wine_dbgstr_w(ptest->expected[i]) );
7602
7603 dstlen = pNormalizeString( norm_forms[i], ptest->str, lstrlenW(ptest->str), NULL, 0 );
7604 memset(dst, 0xcc, sizeof(dst));
7605 dstlen = pNormalizeString( norm_forms[i], ptest->str, lstrlenW(ptest->str), dst, dstlen );
7606 ok(dstlen == lstrlenW( ptest->expected[i] ), "%s:%d: Copied length differed: was %d, should be %d\n",
7607 wine_dbgstr_w(ptest->str), i, dstlen, lstrlenW( dst ));
7608 str_cmp = wcsncmp( ptest->expected[i], dst, dstlen );
7609 ok( str_cmp == 0, "%s:%d: string incorrect got %s expect %s\n", wine_dbgstr_w(ptest->str), i,
7610 wine_dbgstr_w(dst), wine_dbgstr_w(ptest->expected[i]) );
7611
7612 if (pRtlNormalizeString)
7613 {
7614 dstlen = 0;
7615 status = pRtlNormalizeString( norm_forms[i], ptest->str, lstrlenW(ptest->str), NULL, &dstlen );
7616 ok( !status, "%s:%d: failed %lx\n", wine_dbgstr_w(ptest->str), i, status );
7617 ok( dstlen > lstrlenW(ptest->str), "%s:%d: wrong len %d / %d\n",
7618 wine_dbgstr_w(ptest->str), i, dstlen, lstrlenW(ptest->str) );
7619 memset(dst, 0, sizeof(dst));
7620 status = pRtlNormalizeString( norm_forms[i], ptest->str, lstrlenW(ptest->str), dst, &dstlen );
7621 ok( !status, "%s:%d: failed %lx\n", wine_dbgstr_w(ptest->str), i, status );
7622 ok(dstlen == lstrlenW( dst ), "%s:%d: Copied length differed: was %d, should be %d\n",
7623 wine_dbgstr_w(ptest->str), i, dstlen, lstrlenW( dst ));
7624 str_cmp = wcsncmp( ptest->expected[i], dst, dstlen );
7625 ok( str_cmp == 0, "%s:%d: string incorrect got %s expect %s\n", wine_dbgstr_w(ptest->str), i,
7626 wine_dbgstr_w(dst), wine_dbgstr_w(ptest->expected[i]) );
7627 ret = FALSE;
7628 status = pRtlIsNormalizedString( norm_forms[i], ptest->str, -1, &ret );
7629 ok( !status, "%s:%d: failed %lx\n", wine_dbgstr_w(ptest->str), i, status );
7630 if (!wcscmp( ptest->str, dst ))
7631 ok( ret, "%s:%d: not normalized\n", wine_dbgstr_w(ptest->str), i );
7632 else
7633 ok( !ret, "%s:%d: normalized (dst %s)\n", wine_dbgstr_w(ptest->str), i, wine_dbgstr_w(dst) );
7634 ret = FALSE;
7635 status = pRtlIsNormalizedString( norm_forms[i], dst, dstlen, &ret );
7636 ok( !status, "%s:%d: failed %lx\n", wine_dbgstr_w(ptest->str), i, status );
7637 ok( ret, "%s:%d: not normalized\n", wine_dbgstr_w(ptest->str), i );
7638 }
7639 }
7640 ptest++;
7641 }
7642
7643 /* buffer overflows */
7644
7645 SetLastError(0xdeadbeef);
7646 dstlen = pNormalizeString( NormalizationD, part0_str1, -1, dst, 1 );
7647 ok( dstlen <= 0, "wrong len %d\n", dstlen );
7648 ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER, "got error %lu\n", GetLastError());
7649
7650 SetLastError(0xdeadbeef);
7651 dstlen = pNormalizeString( NormalizationC, part0_str2, -1, dst, 1 );
7652 ok( dstlen <= 0, "wrong len %d\n", dstlen );
7653 ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER, "got error %lu\n", GetLastError());
7654
7655 SetLastError(0xdeadbeef);
7656 dstlen = pNormalizeString( NormalizationC, part0_str2, -1, NULL, 0 );
7657 ok( dstlen == 12, "wrong len %d\n", dstlen );
7658 ok(GetLastError() == ERROR_SUCCESS, "got error %lu\n", GetLastError());
7659
7660 SetLastError(0xdeadbeef);
7661 dstlen = pNormalizeString( NormalizationC, part0_str2, -1, dst, 3 );
7662 ok( dstlen == 3, "wrong len %d\n", dstlen );
7663 ok(GetLastError() == ERROR_SUCCESS, "got error %lu\n", GetLastError());
7664
7665 SetLastError(0xdeadbeef);
7666 dstlen = pNormalizeString( NormalizationC, part0_str2, 0, NULL, 0 );
7667 ok( dstlen == 0, "wrong len %d\n", dstlen );
7668 ok(GetLastError() == ERROR_SUCCESS, "got error %lu\n", GetLastError());
7669
7670 SetLastError(0xdeadbeef);
7671 dstlen = pNormalizeString( NormalizationC, part0_str2, 0, dst, 3 );
7672 ok( dstlen == 0, "wrong len %d\n", dstlen );
7673 ok(GetLastError() == ERROR_SUCCESS, "got error %lu\n", GetLastError());
7674
7675 /* size estimations */
7676
7677 memset( dst, 'A', sizeof(dst) );
7678 for (j = 1; j < ARRAY_SIZE(dst); j++)
7679 {
7680 for (i = 0; i < 4; i++)
7681 {
7682 int expect = (i < 2) ? j * 3 : j * 18;
7683 if (expect > 64) expect = max( 64, j + j / 8 );
7684 dstlen = pNormalizeString( norm_forms[i], dst, j, NULL, 0 );
7685 ok( dstlen == expect, "%d: %d -> wrong len %d\n", i, j, dstlen );
7686 if (pRtlNormalizeString)
7687 {
7688 dstlen = 0;
7689 status = pRtlNormalizeString( norm_forms[i], dst, j, NULL, &dstlen );
7690 ok( !status, "%d: failed %lx\n", i, status );
7691 ok( dstlen == expect, "%d: %d -> wrong len %d\n", i, j, dstlen );
7692 }
7693 }
7694 }
7695 for (i = 0; i < 4; i++)
7696 {
7697 int srclen = ARRAY_SIZE( composite_src );
7698 int expect = max( 64, srclen + srclen / 8 );
7699 dstlen = pNormalizeString( norm_forms[i], composite_src, srclen, NULL, 0 );
7700 ok( dstlen == expect, "%d: wrong len %d\n", i, dstlen );
7701 dstlen = pNormalizeString( norm_forms[i], composite_src, srclen, dst, dstlen );
7702 if (i == 0 || i == 2)
7703 {
7704 ok( dstlen == srclen, "%d: wrong len %d\n", i, dstlen );
7705 ok(GetLastError() == ERROR_SUCCESS, "got error %lu\n", GetLastError());
7706 }
7707 else
7708 {
7709 ok( dstlen < -expect, "%d: wrong len %d\n", i, dstlen );
7710 ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER, "got error %lu\n", GetLastError());
7711 }
7712 if (pRtlNormalizeString)
7713 {
7714 dstlen = 0;
7715 status = pRtlNormalizeString( norm_forms[i], composite_src, srclen, NULL, &dstlen );
7716 ok( !status, "%d: failed %lx\n", i, status );
7717 ok( dstlen == expect, "%d: wrong len %d\n", i, dstlen );
7718 status = pRtlNormalizeString( norm_forms[i], composite_src, srclen, dst, &dstlen );
7719 if (i == 0 || i == 2)
7720 {
7721 ok( !status, "%d: failed %lx\n", i, status );
7722 ok( dstlen == srclen, "%d: wrong len %d\n", i, dstlen );
7723 }
7724 else
7725 {
7726 ok( status == STATUS_BUFFER_TOO_SMALL, "%d: failed %lx\n", i, status );
7727 ok( dstlen > expect, "%d: wrong len %d\n", i, dstlen );
7728 }
7729 }
7730 }
7731
7732 /* invalid parameters */
7733
7734 for (i = 0; i < 32; i++)
7735 {
7736 SetLastError(0xdeadbeef);
7737 dstlen = pNormalizeString( i, L"ABC", -1, NULL, 0 );
7738 switch (i)
7739 {
7740 case NormalizationC:
7741 case NormalizationD:
7742 case NormalizationKC:
7743 case NormalizationKD:
7744 case 13: /* Idn */
7745 ok( dstlen > 0, "%d: wrong len %d\n", i, dstlen );
7746 ok( GetLastError() == ERROR_SUCCESS, "%d: got error %lu\n", i, GetLastError());
7747 break;
7748 default:
7749 ok( dstlen <= 0, "%d: wrong len %d\n", i, dstlen );
7750 ok( GetLastError() == ERROR_INVALID_PARAMETER, "%d: got error %lu\n", i, GetLastError());
7751 break;
7752 }
7753 if (pRtlNormalizeString)
7754 {
7755 dstlen = 0;
7756 status = pRtlNormalizeString( i, L"ABC", -1, NULL, &dstlen );
7757 switch (i)
7758 {
7759 case 0:
7760 ok( status == STATUS_INVALID_PARAMETER, "%d: failed %lx\n", i, status );
7761 break;
7762 case NormalizationC:
7763 case NormalizationD:
7764 case NormalizationKC:
7765 case NormalizationKD:
7766 case 13: /* Idn */
7767 ok( status == STATUS_SUCCESS, "%d: failed %lx\n", i, status );
7768 break;
7769 default:
7770 ok( status == STATUS_OBJECT_NAME_NOT_FOUND, "%d: failed %lx\n", i, status );
7771 break;
7772 }
7773 }
7774 }
7775
7776 /* invalid sequences */
7777
7778 for (i = 0; i < 4; i++)
7779 {
7780 dstlen = pNormalizeString( norm_forms[i], L"AB\xd800Z", -1, NULL, 0 );
7781 ok( dstlen == (i < 2 ? 15 : 64), "%d: wrong len %d\n", i, dstlen );
7782 SetLastError( 0xdeadbeef );
7783 dstlen = pNormalizeString( norm_forms[i], L"AB\xd800Z", -1, dst, ARRAY_SIZE(dst) );
7784 ok( dstlen == -3, "%d: wrong len %d\n", i, dstlen );
7785 ok( GetLastError() == ERROR_NO_UNICODE_TRANSLATION, "%d: wrong error %ld\n", i, GetLastError() );
7786 dstlen = pNormalizeString( norm_forms[i], L"ABCD\xdc12Z", -1, NULL, 0 );
7787 ok( dstlen == (i < 2 ? 21 : 64), "%d: wrong len %d\n", i, dstlen );
7788 SetLastError( 0xdeadbeef );
7789 dstlen = pNormalizeString( norm_forms[i], L"ABCD\xdc12Z", -1, dst, ARRAY_SIZE(dst) );
7790 ok( dstlen == -4, "%d: wrong len %d\n", i, dstlen );
7791 ok( GetLastError() == ERROR_NO_UNICODE_TRANSLATION, "%d: wrong error %ld\n", i, GetLastError() );
7792 SetLastError( 0xdeadbeef );
7793 dstlen = pNormalizeString( norm_forms[i], L"ABCD\xdc12Z", -1, dst, 2 );
7794 todo_wine
7795 ok( dstlen == (i < 2 ? -18 : -74), "%d: wrong len %d\n", i, dstlen );
7796 todo_wine_if (i == 0 || i == 2)
7797 ok( GetLastError() == ERROR_INSUFFICIENT_BUFFER, "%d: wrong error %ld\n", i, GetLastError() );
7798 if (pRtlNormalizeString)
7799 {
7800 dstlen = 0;
7801 status = pRtlNormalizeString( norm_forms[i], L"AB\xd800Z", -1, NULL, &dstlen );
7802 ok( !status, "%d: failed %lx\n", i, status );
7803 ok( dstlen == (i < 2 ? 15 : 64), "%d: wrong len %d\n", i, dstlen );
7804 dstlen = ARRAY_SIZE(dst);
7805 status = pRtlNormalizeString( norm_forms[i], L"AB\xd800Z", -1, dst, &dstlen );
7806 ok( status == STATUS_NO_UNICODE_TRANSLATION, "%d: failed %lx\n", i, status );
7807 ok( dstlen == 3, "%d: wrong len %d\n", i, dstlen );
7808 dstlen = 1;
7809 status = pRtlNormalizeString( norm_forms[i], L"AB\xd800Z", -1, dst, &dstlen );
7810 todo_wine_if( i == 0 || i == 2)
7811 ok( status == STATUS_BUFFER_TOO_SMALL, "%d: failed %lx\n", i, status );
7812 todo_wine_if( i != 3)
7813 ok( dstlen == (i < 2 ? 14 : 73), "%d: wrong len %d\n", i, dstlen );
7814 dstlen = 2;
7815 status = pRtlNormalizeString( norm_forms[i], L"AB\xd800Z", -1, dst, &dstlen );
7816 ok( status == STATUS_NO_UNICODE_TRANSLATION, "%d: failed %lx\n", i, status );
7817 ok( dstlen == 3, "%d: wrong len %d\n", i, dstlen );
7818 }
7819 }
7820
7821 /* optionally run the full test file from Unicode.org
7822 * available at http://www.unicode.org/Public/UCD/latest/ucd/NormalizationTest.txt
7823 */
7824 if ((f = fopen( "NormalizationTest.txt", "r" )))
7825 {
7826 char *p, buffer[1024];
7827 WCHAR str[3], srcW[32], dstW[32], resW[4][32];
7828 int line = 0, part = 0, ch;
7829 char tested[0x110000 / 8];
7830
7831 while (fgets( buffer, sizeof(buffer), f ))
7832 {
7833 line++;
7834 if ((p = strchr( buffer, '#' ))) *p = 0;
7835 if (!strncmp( buffer, "@Part", 5 ))
7836 {
7837 part = atoi( buffer + 5 );
7838 continue;
7839 }
7840 if (!(p = strtok( buffer, ";" ))) continue;
7841 read_str( p, srcW );
7842 for (i = 0; i < 4; i++)
7843 {
7844 p = strtok( NULL, ";" );
7845 read_str( p, &resW[i][0] );
7846 }
7847 if (part == 1)
7848 {
7849 ch = srcW[0];
7850 if (ch >= 0xd800 && ch <= 0xdbff)
7851 ch = 0x10000 + ((srcW[0] & 0x3ff) << 10) + (srcW[1] & 0x3ff);
7852 tested[ch / 8] |= 1 << (ch % 8);
7853 }
7854 for (i = 0; i < 4; i++)
7855 {
7856 memset( dstW, 0xcc, sizeof(dstW) );
7857 dstlen = pNormalizeString( norm_forms[i], srcW, -1, dstW, ARRAY_SIZE(dstW) );
7858 ok( !wcscmp( dstW, resW[i] ),
7859 "line %u form %u: wrong result %s for %s expected %s\n", line, i,
7860 wine_dbgstr_w( dstW ), wine_dbgstr_w( srcW ), wine_dbgstr_w( resW[i] ));
7861
7862 ret = FALSE;
7863 status = pRtlIsNormalizedString( norm_forms[i], srcW, -1, &ret );
7864 ok( !status, "line %u form %u: RtlIsNormalizedString failed %lx\n", line, i, status );
7865 if (!wcscmp( srcW, dstW ))
7866 ok( ret, "line %u form %u: source not normalized %s\n", line, i, wine_dbgstr_w(srcW) );
7867 else
7868 ok( !ret, "line %u form %u: source normalized %s\n", line, i, wine_dbgstr_w(srcW) );
7869 ret = FALSE;
7870 status = pRtlIsNormalizedString( norm_forms[i], dstW, -1, &ret );
7871 ok( !status, "line %u form %u: RtlIsNormalizedString failed %lx\n", line, i, status );
7872 ok( ret, "line %u form %u: dest not normalized %s\n", line, i, wine_dbgstr_w(dstW) );
7873
7874 for (j = 0; j < 4; j++)
7875 {
7876 int expect = i | (j & 2);
7877 memset( dstW, 0xcc, sizeof(dstW) );
7878 dstlen = pNormalizeString( norm_forms[i], resW[j], -1, dstW, ARRAY_SIZE(dstW) );
7879 ok( !wcscmp( dstW, resW[expect] ),
7880 "line %u form %u res %u: wrong result %s for %s expected %s\n", line, i, j,
7881 wine_dbgstr_w( dstW ), wine_dbgstr_w( resW[j] ), wine_dbgstr_w( resW[expect] ));
7882 }
7883 }
7884 }
7885 fclose( f );
7886
7887 /* test chars that are not in the @Part1 list */
7888 for (ch = 0; ch < 0x110000; ch++)
7889 {
7890 if (tested[ch / 8] & (1 << (ch % 8))) continue;
7891 str[put_utf16( str, ch )] = 0;
7892 for (i = 0; i < 4; i++)
7893 {
7894 memset( dstW, 0xcc, sizeof(dstW) );
7895 SetLastError( 0xdeadbeef );
7896 dstlen = pNormalizeString( norm_forms[i], str, -1, dstW, ARRAY_SIZE(dstW) );
7897 if ((ch >= 0xd800 && ch <= 0xdfff) ||
7898 (ch >= 0xfdd0 && ch <= 0xfdef) ||
7899 ((ch & 0xffff) >= 0xfffe))
7900 {
7901 ok( dstlen <= 0, "char %04x form %u: wrong result %d %s expected error\n",
7902 ch, i, dstlen, wine_dbgstr_w( dstW ));
7903 ok( GetLastError() == ERROR_NO_UNICODE_TRANSLATION,
7904 "char %04x form %u: error %lu\n", str[0], i, GetLastError() );
7905 status = pRtlIsNormalizedString( norm_forms[i], str, -1, &ret );
7906 ok( status == STATUS_NO_UNICODE_TRANSLATION,
7907 "char %04x form %u: failed %lx\n", ch, i, status );
7908 }
7909 else
7910 {
7911 ok( !wcscmp( dstW, str ),
7912 "char %04x form %u: wrong result %s expected unchanged\n",
7913 ch, i, wine_dbgstr_w( dstW ));
7914 ret = FALSE;
7915 status = pRtlIsNormalizedString( norm_forms[i], str, -1, &ret );
7916 ok( !status, "char %04x form %u: failed %lx\n", ch, i, status );
7917 ok( ret, "char %04x form %u: not normalized\n", ch, i );
7918 }
7919 }
7920 }
7921 }
7922}
7923
7924static void test_SpecialCasing(void)
7925{
7926 int ret, i, len;
7927 UINT val = 0, exp;
7928 WCHAR src[8], buffer[8];
7929 static const struct test {
7930 const WCHAR *lang;
7931 DWORD flags;
7932 UINT ch;
7933 UINT exp; /* 0 if self */
7934 UINT exp_ling; /* 0 if exp */
7935 BOOL broken;
7936 } tests[] = {
7937 {L"de-DE", LCMAP_UPPERCASE, 0x00DF}, /* LATIN SMALL LETTER SHARP S */
7938
7939 {L"en-US", LCMAP_UPPERCASE, 0xFB00}, /* LATIN SMALL LIGATURE FF */
7940 {L"en-US", LCMAP_UPPERCASE, 0xFB01}, /* LATIN SMALL LIGATURE FI */
7941 {L"en-US", LCMAP_UPPERCASE, 0xFB02}, /* LATIN SMALL LIGATURE FL */
7942 {L"en-US", LCMAP_UPPERCASE, 0xFB03}, /* LATIN SMALL LIGATURE FFI */
7943 {L"en-US", LCMAP_UPPERCASE, 0xFB04}, /* LATIN SMALL LIGATURE FFL */
7944 {L"en-US", LCMAP_UPPERCASE, 0xFB05}, /* LATIN SMALL LIGATURE LONG S T */
7945 {L"en-US", LCMAP_UPPERCASE, 0xFB06}, /* LATIN SMALL LIGATURE ST */
7946
7947 {L"hy-AM", LCMAP_UPPERCASE, 0x0587}, /* ARMENIAN SMALL LIGATURE ECH YIWN */
7948 {L"hy-AM", LCMAP_UPPERCASE, 0xFB13}, /* ARMENIAN SMALL LIGATURE MEN NOW */
7949 {L"hy-AM", LCMAP_UPPERCASE, 0xFB14}, /* ARMENIAN SMALL LIGATURE MEN ECH */
7950 {L"hy-AM", LCMAP_UPPERCASE, 0xFB15}, /* ARMENIAN SMALL LIGATURE MEN INI */
7951 {L"hy-AM", LCMAP_UPPERCASE, 0xFB16}, /* ARMENIAN SMALL LIGATURE VEW NOW */
7952 {L"hy-AM", LCMAP_UPPERCASE, 0xFB17}, /* ARMENIAN SMALL LIGATURE MEN XEH */
7953
7954 {L"en-US", LCMAP_UPPERCASE, 0x0149}, /* LATIN SMALL LETTER N PRECEDED BY APOSTROPHE */
7955 {L"el-GR", LCMAP_UPPERCASE, 0x0390,0,0,TRUE /*win7*/ }, /* GREEK SMALL LETTER IOTA WITH DIALYTIKA AND TONOS */
7956 {L"el-GR", LCMAP_UPPERCASE, 0x03B0,0,0,TRUE /*win7*/ }, /* GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND TONOS */
7957 {L"en-US", LCMAP_UPPERCASE, 0x01F0}, /* LATIN SMALL LETTER J WITH CARON */
7958 {L"en-US", LCMAP_UPPERCASE, 0x1E96}, /* LATIN SMALL LETTER H WITH LINE BELOW */
7959 {L"en-US", LCMAP_UPPERCASE, 0x1E97}, /* LATIN SMALL LETTER T WITH DIAERESIS */
7960 {L"en-US", LCMAP_UPPERCASE, 0x1E98}, /* LATIN SMALL LETTER W WITH RING ABOVE */
7961 {L"en-US", LCMAP_UPPERCASE, 0x1E99}, /* LATIN SMALL LETTER Y WITH RING ABOVE */
7962 {L"en-US", LCMAP_UPPERCASE, 0x1E9A}, /* LATIN SMALL LETTER A WITH RIGHT HALF RING */
7963 {L"el-GR", LCMAP_UPPERCASE, 0x1F50}, /* GREEK SMALL LETTER UPSILON WITH PSILI */
7964 {L"el-GR", LCMAP_UPPERCASE, 0x1F52}, /* GREEK SMALL LETTER UPSILON WITH PSILI AND VARIA */
7965 {L"el-GR", LCMAP_UPPERCASE, 0x1F54}, /* GREEK SMALL LETTER UPSILON WITH PSILI AND OXIA */
7966 {L"el-GR", LCMAP_UPPERCASE, 0x1F56}, /* GREEK SMALL LETTER UPSILON WITH PSILI AND PERISPOMENI */
7967 {L"el-GR", LCMAP_UPPERCASE, 0x1FB6}, /* GREEK SMALL LETTER ALPHA WITH PERISPOMENI */
7968 {L"el-GR", LCMAP_UPPERCASE, 0x1FC6}, /* GREEK SMALL LETTER ETA WITH PERISPOMENI */
7969 {L"el-GR", LCMAP_UPPERCASE, 0x1FD2}, /* GREEK SMALL LETTER IOTA WITH DIALYTIKA AND VARIA */
7970 {L"el-GR", LCMAP_UPPERCASE, 0x1FD3}, /* GREEK SMALL LETTER IOTA WITH DIALYTIKA AND OXIA */
7971 {L"el-GR", LCMAP_UPPERCASE, 0x1FD6}, /* GREEK SMALL LETTER IOTA WITH PERISPOMENI */
7972 {L"el-GR", LCMAP_UPPERCASE, 0x1FD7}, /* GREEK SMALL LETTER IOTA WITH DIALYTIKA AND PERISPOMENI */
7973 {L"el-GR", LCMAP_UPPERCASE, 0x1FE2}, /* GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND VARIA */
7974 {L"el-GR", LCMAP_UPPERCASE, 0x1FE3}, /* GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND OXIA */
7975 {L"el-GR", LCMAP_UPPERCASE, 0x1FE4}, /* GREEK SMALL LETTER RHO WITH PSILI */
7976 {L"el-GR", LCMAP_UPPERCASE, 0x1FE6}, /* GREEK SMALL LETTER UPSILON WITH PERISPOMENI */
7977 {L"el-GR", LCMAP_UPPERCASE, 0x1FE7}, /* GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND PERISPOMENI */
7978 {L"el-GR", LCMAP_UPPERCASE, 0x1FF6}, /* GREEK SMALL LETTER OMEGA WITH PERISPOMENI */
7979
7980 {L"el-GR", LCMAP_UPPERCASE, 0x1F80,0x1F88}, /* GREEK SMALL LETTER ALPHA WITH PSILI AND YPOGEGRAMMENI */
7981 {L"el-GR", LCMAP_UPPERCASE, 0x1F81,0x1F89}, /* GREEK SMALL LETTER ALPHA WITH DASIA AND YPOGEGRAMMENI */
7982 {L"el-GR", LCMAP_UPPERCASE, 0x1F82,0x1F8A}, /* GREEK SMALL LETTER ALPHA WITH PSILI AND VARIA AND YPOGEGRAMMENI */
7983 {L"el-GR", LCMAP_UPPERCASE, 0x1F83,0x1F8B}, /* GREEK SMALL LETTER ALPHA WITH DASIA AND VARIA AND YPOGEGRAMMENI */
7984 {L"el-GR", LCMAP_UPPERCASE, 0x1F84,0x1F8C}, /* GREEK SMALL LETTER ALPHA WITH PSILI AND OXIA AND YPOGEGRAMMENI */
7985 {L"el-GR", LCMAP_UPPERCASE, 0x1F85,0x1F8D}, /* GREEK SMALL LETTER ALPHA WITH DASIA AND OXIA AND YPOGEGRAMMENI */
7986 {L"el-GR", LCMAP_UPPERCASE, 0x1F86,0x1F8E}, /* GREEK SMALL LETTER ALPHA WITH PSILI AND PERISPOMENI AND YPOGEGRAMMENI */
7987 {L"el-GR", LCMAP_UPPERCASE, 0x1F87,0x1F8F}, /* GREEK SMALL LETTER ALPHA WITH DASIA AND PERISPOMENI AND YPOGEGRAMMENI */
7988
7989 {L"el-GR", LCMAP_LOWERCASE, 0x1F88,0x1F80}, /* GREEK CAPITAL LETTER ALPHA WITH PSILI AND PROSGEGRAMMENI */
7990 {L"el-GR", LCMAP_LOWERCASE, 0x1F89,0x1F81}, /* GREEK CAPITAL LETTER ALPHA WITH DASIA AND PROSGEGRAMMENI */
7991 {L"el-GR", LCMAP_LOWERCASE, 0x1F8A,0x1F82}, /* GREEK CAPITAL LETTER ALPHA WITH PSILI AND VARIA AND PROSGEGRAMMENI */
7992 {L"el-GR", LCMAP_LOWERCASE, 0x1F8B,0x1F83}, /* GREEK CAPITAL LETTER ALPHA WITH DASIA AND VARIA AND PROSGEGRAMMENI */
7993 {L"el-GR", LCMAP_LOWERCASE, 0x1F8C,0x1F84}, /* GREEK CAPITAL LETTER ALPHA WITH PSILI AND OXIA AND PROSGEGRAMMENI */
7994 {L"el-GR", LCMAP_LOWERCASE, 0x1F8D,0x1F85}, /* GREEK CAPITAL LETTER ALPHA WITH DASIA AND OXIA AND PROSGEGRAMMENI */
7995 {L"el-GR", LCMAP_LOWERCASE, 0x1F8E,0x1F86}, /* GREEK CAPITAL LETTER ALPHA WITH PSILI AND PERISPOMENI AND PROSGEGRAMMENI */
7996 {L"el-GR", LCMAP_LOWERCASE, 0x1F8F,0x1F87}, /* GREEK CAPITAL LETTER ALPHA WITH DASIA AND PERISPOMENI AND PROSGEGRAMMENI */
7997
7998 {L"el-GR", LCMAP_UPPERCASE, 0x1F90,0x1F98}, /* GREEK SMALL LETTER ETA WITH PSILI AND YPOGEGRAMMENI */
7999 {L"el-GR", LCMAP_UPPERCASE, 0x1F91,0x1F99}, /* GREEK SMALL LETTER ETA WITH DASIA AND YPOGEGRAMMENI */
8000 {L"el-GR", LCMAP_UPPERCASE, 0x1F92,0x1F9A}, /* GREEK SMALL LETTER ETA WITH PSILI AND VARIA AND YPOGEGRAMMENI */
8001 {L"el-GR", LCMAP_UPPERCASE, 0x1F93,0x1F9B}, /* GREEK SMALL LETTER ETA WITH DASIA AND VARIA AND YPOGEGRAMMENI */
8002 {L"el-GR", LCMAP_UPPERCASE, 0x1F94,0x1F9C}, /* GREEK SMALL LETTER ETA WITH PSILI AND OXIA AND YPOGEGRAMMENI */
8003 {L"el-GR", LCMAP_UPPERCASE, 0x1F95,0x1F9D}, /* GREEK SMALL LETTER ETA WITH DASIA AND OXIA AND YPOGEGRAMMENI */
8004 {L"el-GR", LCMAP_UPPERCASE, 0x1F96,0x1F9E}, /* GREEK SMALL LETTER ETA WITH PSILI AND PERISPOMENI AND YPOGEGRAMMENI */
8005 {L"el-GR", LCMAP_UPPERCASE, 0x1F97,0x1F9F}, /* GREEK SMALL LETTER ETA WITH DASIA AND PERISPOMENI AND YPOGEGRAMMENI */
8006
8007 {L"el-GR", LCMAP_LOWERCASE, 0x1FA8,0x1FA0}, /* GREEK CAPITAL LETTER OMEGA WITH PSILI AND PROSGEGRAMMENI */
8008 {L"el-GR", LCMAP_LOWERCASE, 0x1FA9,0x1FA1}, /* GREEK CAPITAL LETTER OMEGA WITH DASIA AND PROSGEGRAMMENI */
8009 {L"el-GR", LCMAP_LOWERCASE, 0x1FAA,0x1FA2}, /* GREEK CAPITAL LETTER OMEGA WITH PSILI AND VARIA AND PROSGEGRAMMENI */
8010 {L"el-GR", LCMAP_LOWERCASE, 0x1FAB,0x1FA3}, /* GREEK CAPITAL LETTER OMEGA WITH DASIA AND VARIA AND PROSGEGRAMMENI */
8011 {L"el-GR", LCMAP_LOWERCASE, 0x1FAC,0x1FA4}, /* GREEK CAPITAL LETTER OMEGA WITH PSILI AND OXIA AND PROSGEGRAMMENI */
8012 {L"el-GR", LCMAP_LOWERCASE, 0x1FAD,0x1FA5}, /* GREEK CAPITAL LETTER OMEGA WITH DASIA AND OXIA AND PROSGEGRAMMENI */
8013 {L"el-GR", LCMAP_LOWERCASE, 0x1FAE,0x1FA6}, /* GREEK CAPITAL LETTER OMEGA WITH PSILI AND PERISPOMENI AND PROSGEGRAMMENI */
8014 {L"el-GR", LCMAP_LOWERCASE, 0x1FAF,0x1FA7}, /* GREEK CAPITAL LETTER OMEGA WITH DASIA AND PERISPOMENI AND PROSGEGRAMMENI */
8015
8016 {L"el-GR", LCMAP_UPPERCASE, 0x1FB3,0x1FBC}, /* GREEK SMALL LETTER ALPHA WITH YPOGEGRAMMENI */
8017 {L"el-GR", LCMAP_LOWERCASE, 0x1FBC,0x1FB3}, /* GREEK CAPITAL LETTER ALPHA WITH PROSGEGRAMMENI */
8018#ifdef __REACTOS__
8019 {L"el-GR", LCMAP_UPPERCASE, 0x1FC3,0x1FCC,0, TRUE /* Vista */}, /* GREEK SMALL LETTER ETA WITH YPOGEGRAMMENI */
8020 {L"el-GR", LCMAP_LOWERCASE, 0x1FCC,0x1FC3,0, TRUE /* Vista */}, /* GREEK CAPITAL LETTER ETA WITH PROSGEGRAMMENI */
8021 {L"el-GR", LCMAP_UPPERCASE, 0x1FF3,0x1FFC,0, TRUE /* Vista */}, /* GREEK SMALL LETTER OMEGA WITH YPOGEGRAMMENI */
8022 {L"el-GR", LCMAP_LOWERCASE, 0x1FFC,0x1FF3,0, TRUE /* Vista */}, /* GREEK CAPITAL LETTER OMEGA WITH PROSGEGRAMMENI */
8023#else
8024 {L"el-GR", LCMAP_UPPERCASE, 0x1FC3,0x1FCC}, /* GREEK SMALL LETTER ETA WITH YPOGEGRAMMENI */
8025 {L"el-GR", LCMAP_LOWERCASE, 0x1FCC,0x1FC3}, /* GREEK CAPITAL LETTER ETA WITH PROSGEGRAMMENI */
8026 {L"el-GR", LCMAP_UPPERCASE, 0x1FF3,0x1FFC}, /* GREEK SMALL LETTER OMEGA WITH YPOGEGRAMMENI */
8027 {L"el-GR", LCMAP_LOWERCASE, 0x1FFC,0x1FF3}, /* GREEK CAPITAL LETTER OMEGA WITH PROSGEGRAMMENI */
8028#endif
8029
8030 {L"el-GR", LCMAP_UPPERCASE, 0x1FB2}, /* GREEK SMALL LETTER ALPHA WITH VARIA AND YPOGEGRAMMENI */
8031 {L"el-GR", LCMAP_UPPERCASE, 0x1FB4}, /* GREEK SMALL LETTER ALPHA WITH OXIA AND YPOGEGRAMMENI */
8032 {L"el-GR", LCMAP_UPPERCASE, 0x1FC2}, /* GREEK SMALL LETTER ETA WITH VARIA AND YPOGEGRAMMENI */
8033 {L"el-GR", LCMAP_UPPERCASE, 0x1FC4}, /* GREEK SMALL LETTER ETA WITH OXIA AND YPOGEGRAMMENI */
8034 {L"el-GR", LCMAP_UPPERCASE, 0x1FF2}, /* GREEK SMALL LETTER OMEGA WITH VARIA AND YPOGEGRAMMENI */
8035 {L"el-GR", LCMAP_UPPERCASE, 0x1FF4}, /* GREEK SMALL LETTER OMEGA WITH OXIA AND YPOGEGRAMMENI */
8036
8037 {L"el-GR", LCMAP_UPPERCASE, 0x1FB7}, /* GREEK SMALL LETTER ALPHA WITH PERISPOMENI AND YPOGEGRAMMENI */
8038 {L"el-GR", LCMAP_UPPERCASE, 0x1FC7}, /* GREEK SMALL LETTER ETA WITH PERISPOMENI AND YPOGEGRAMMENI */
8039 {L"el-GR", LCMAP_UPPERCASE, 0x1FF7}, /* GREEK SMALL LETTER OMEGA WITH PERISPOMENI AND YPOGEGRAMMENI */
8040
8041 {L"el-GR", LCMAP_LOWERCASE, 0x03A3,0x03C3}, /* GREEK CAPITAL LETTER SIGMA */
8042
8043 {L"lt-LT", LCMAP_LOWERCASE, 'J','j'}, /* LATIN CAPITAL LETTER J */
8044 {L"lt-LT", LCMAP_LOWERCASE, 0x012E,0x012F}, /* LATIN CAPITAL LETTER I WITH OGONEK */
8045 {L"lt-LT", LCMAP_LOWERCASE, 0x00CC,0x00EC}, /* LATIN CAPITAL LETTER I WITH GRAVE */
8046 {L"lt-LT", LCMAP_LOWERCASE, 0x00CD,0x00ED}, /* LATIN CAPITAL LETTER I WITH ACUTE */
8047 {L"lt-LT", LCMAP_LOWERCASE, 0x0128,0x0129}, /* LATIN CAPITAL LETTER I WITH TILDE */
8048
8049 {L"en-US", LCMAP_UPPERCASE, 'i', 'I'}, /* LATIN SMALL LETTER I */
8050 {L"lt-LT", LCMAP_UPPERCASE, 'i', 'I'}, /* LATIN SMALL LETTER I */
8051 {L"tr-TR", LCMAP_UPPERCASE, 'i', 'I', 0x0130}, /* LATIN SMALL LETTER I */
8052 {L"TR-TR", LCMAP_UPPERCASE, 'i', 'I', 0x0130}, /* LATIN SMALL LETTER I */
8053 {L"az-Cyrl-az", LCMAP_UPPERCASE, 'i', 'I', 0x0130, TRUE /*win7*/}, /* LATIN SMALL LETTER I */
8054 {L"az-Latn-az", LCMAP_UPPERCASE, 'i', 'I', 0x0130}, /* LATIN SMALL LETTER I */
8055
8056 {L"en-US", LCMAP_LOWERCASE, 'I', 'i'}, /* LATIN CAPITAL LETTER I */
8057 {L"lt-LT", LCMAP_LOWERCASE, 'I', 'i'}, /* LATIN CAPITAL LETTER I */
8058 {L"tr-TR", LCMAP_LOWERCASE, 'I', 'i', 0x0131}, /* LATIN CAPITAL LETTER I */
8059 {L"TR-TR", LCMAP_LOWERCASE, 'I', 'i', 0x0131}, /* LATIN CAPITAL LETTER I */
8060 {L"az-Cyrl-az", LCMAP_LOWERCASE, 'I', 'i', 0x0131, TRUE /*win7*/}, /* LATIN CAPITAL LETTER I */
8061 {L"az-Latn-az", LCMAP_LOWERCASE, 'I', 'i', 0x0131}, /* LATIN CAPITAL LETTER I */
8062
8063 {L"en-US", LCMAP_LOWERCASE, 0x0130,0,'i'}, /* LATIN CAPITAL LETTER I WITH DOT ABOVE */
8064 {L"tr-TR", LCMAP_LOWERCASE, 0x0130,0,'i'}, /* LATIN CAPITAL LETTER I WITH DOT ABOVE */
8065 {L"TR-TR", LCMAP_LOWERCASE, 0x0130,0,'i'}, /* LATIN CAPITAL LETTER I WITH DOT ABOVE */
8066 {L"az-Cyrl-az", LCMAP_LOWERCASE, 0x0130,0,'i'}, /* LATIN CAPITAL LETTER I WITH DOT ABOVE */
8067 {L"az-Latn-az", LCMAP_LOWERCASE, 0x0130,0,'i'}, /* LATIN CAPITAL LETTER I WITH DOT ABOVE */
8068
8069 {L"en-US", LCMAP_UPPERCASE, 0x0131,0,'I'}, /* LATIN SMALL LETTER DOTLESS I */
8070 {L"tr-TR", LCMAP_UPPERCASE, 0x0131,0,'I'}, /* LATIN SMALL LETTER DOTLESS I */
8071 {L"TR-TR", LCMAP_UPPERCASE, 0x0131,0,'I'}, /* LATIN SMALL LETTER DOTLESS I */
8072 {L"az-Cyrl-az", LCMAP_UPPERCASE, 0x0131,0,'I'}, /* LATIN SMALL LETTER DOTLESS I */
8073 {L"az-Latn-az", LCMAP_UPPERCASE, 0x0131,0,'I'}, /* LATIN SMALL LETTER DOTLESS I */
8074
8075 {L"en-US", LCMAP_LOWERCASE, 0x10418,0x10440,0,TRUE /*win7*/}, /* DESERET CAPITAL LETTER GAY */
8076 {L"en-US", LCMAP_UPPERCASE, 0x10431,0x10409,0,TRUE /*win7*/}, /* DESERET SMALL LETTER SHORT AH */
8077 };
8078
8079 if (!pLCMapStringEx)
8080 {
8081 win_skip("LCMapStringEx not available\n");
8082 return;
8083 }
8084
8085 for (i = 0; i < ARRAY_SIZE(tests); i++)
8086 {
8087 memset(buffer, 0, sizeof(buffer));
8088 len = put_utf16( src, tests[i].ch );
8089 ret = pLCMapStringEx(tests[i].lang, tests[i].flags,
8090 src, len, buffer, ARRAY_SIZE(buffer), NULL, NULL, 0);
8091 len = get_utf16( buffer, ret, &val );
8092 ok(ret == len, "got %d for %04x for %s\n", ret, tests[i].ch, wine_dbgstr_w(tests[i].lang));
8093 exp = tests[i].exp ? tests[i].exp : tests[i].ch;
8094 ok(val == exp || broken(tests[i].broken),
8095 "expected %04x, got %04x for %04x for %s\n",
8096 exp, val, tests[i].ch, wine_dbgstr_w(tests[i].lang));
8097
8098 memset(buffer, 0, sizeof(buffer));
8099 len = put_utf16( src, tests[i].ch );
8100 ret = pLCMapStringEx(tests[i].lang, tests[i].flags|LCMAP_LINGUISTIC_CASING,
8101 src, len, buffer, ARRAY_SIZE(buffer), NULL, NULL, 0);
8102 len = get_utf16( buffer, ret, &val );
8103 ok(ret == len, "got %d for %04x for %s\n", ret, tests[i].ch, wine_dbgstr_w(tests[i].lang));
8104 exp = tests[i].exp_ling ? tests[i].exp_ling : exp;
8105 ok(val == exp || broken(tests[i].broken),
8106 "expected %04x, got %04x for %04x for %s\n",
8107 exp, val, tests[i].ch, wine_dbgstr_w(tests[i].lang));
8108 }
8109}
8110
8111static void test_NLSVersion(void)
8112{
8113 static const GUID guid_null = { 0 };
8114 static const GUID guid_def = { 0x000000001, 0x57ee, 0x1e5c, {0x00,0xb4,0xd0,0x00,0x0b,0xb1,0xe1,0x1e}};
8115 static const GUID guid_fr = { 0x000000003, 0x57ee, 0x1e5c, {0x00,0xb4,0xd0,0x00,0x0b,0xb1,0xe1,0x1e}};
8116 static const GUID guid_ja = { 0x000000046, 0x57ee, 0x1e5c, {0x00,0xb4,0xd0,0x00,0x0b,0xb1,0xe1,0x1e}};
8117 BOOL ret;
8118 NLSVERSIONINFOEX info;
8119
8120 if (!pGetNLSVersion)
8121 {
8122 win_skip( "GetNLSVersion not available\n" );
8123 return;
8124 }
8125
8126 SetLastError( 0xdeadbeef );
8127 memset( &info, 0xcc, sizeof(info) );
8128 info.dwNLSVersionInfoSize = offsetof( NLSVERSIONINFO, dwEffectiveId );
8129 ret = pGetNLSVersion( COMPARE_STRING, MAKELANGID( LANG_FRENCH, SUBLANG_FRENCH_CANADIAN ),
8130 (NLSVERSIONINFO *)&info );
8131 ok( ret, "GetNLSVersion failed err %lu\n", GetLastError() );
8132
8133 SetLastError( 0xdeadbeef );
8134 memset( &info, 0xcc, sizeof(info) );
8135 info.dwNLSVersionInfoSize = sizeof(info);
8136 ret = pGetNLSVersion( COMPARE_STRING, MAKELANGID( LANG_FRENCH, SUBLANG_FRENCH_CANADIAN ),
8137 (NLSVERSIONINFO *)&info );
8138 ok( ret || GetLastError() == ERROR_INSUFFICIENT_BUFFER /* < Vista */,
8139 "GetNLSVersion failed err %lu\n", GetLastError() );
8140 if (ret)
8141 {
8142 ok( info.dwEffectiveId == MAKELANGID( LANG_FRENCH, SUBLANG_FRENCH_CANADIAN ),
8143 "wrong id %lx\n", info.dwEffectiveId );
8144 ok( IsEqualIID( &info.guidCustomVersion, &guid_fr ) ||
8145 broken( IsEqualIID( &info.guidCustomVersion, &guid_null )), /* <= win7 */
8146 "wrong guid %s\n", debugstr_guid(&info.guidCustomVersion) );
8147 }
8148
8149 SetLastError( 0xdeadbeef );
8150 info.dwNLSVersionInfoSize = 8;
8151 ret = pGetNLSVersion( COMPARE_STRING, LOCALE_USER_DEFAULT, (NLSVERSIONINFO *)&info );
8152 ok( !ret, "GetNLSVersion succeeded\n" );
8153 ok( GetLastError() == ERROR_INSUFFICIENT_BUFFER, "wrong error %lu\n", GetLastError() );
8154
8155 SetLastError( 0xdeadbeef );
8156 info.dwNLSVersionInfoSize = sizeof(info);
8157 ret = pGetNLSVersion( 2, LOCALE_USER_DEFAULT, (NLSVERSIONINFO *)&info );
8158 ok( !ret, "GetNLSVersion succeeded\n" );
8159 ok( GetLastError() == ERROR_INVALID_FLAGS ||
8160 broken( GetLastError() == ERROR_INSUFFICIENT_BUFFER ), /* win2003 */
8161 "wrong error %lu\n", GetLastError() );
8162
8163 SetLastError( 0xdeadbeef );
8164 info.dwNLSVersionInfoSize = sizeof(info);
8165 ret = pGetNLSVersion( COMPARE_STRING, 0xdeadbeef, (NLSVERSIONINFO *)&info );
8166 ok( !ret, "GetNLSVersion succeeded\n" );
8167 ok( GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %lu\n", GetLastError() );
8168
8169#ifdef __REACTOS__
8170 /* HACK: ReactOS's implementation for GetNLSVersionEx is a STUB! */
8171 if (pGetNLSVersionEx && !is_reactos())
8172#else
8173 if (pGetNLSVersionEx)
8174#endif
8175 {
8176 SetLastError( 0xdeadbeef );
8177 memset( &info, 0xcc, sizeof(info) );
8178 info.dwNLSVersionInfoSize = sizeof(info);
8179 ret = pGetNLSVersionEx( COMPARE_STRING, L"ja-JP", &info );
8180 ok( ret, "GetNLSVersionEx failed err %lu\n", GetLastError() );
8182 "wrong id %lx\n", info.dwEffectiveId );
8183 ok( IsEqualIID( &info.guidCustomVersion, &guid_ja ) ||
8184 broken( IsEqualIID( &info.guidCustomVersion, &guid_null )), /* <= win7 */
8185 "wrong guid %s\n", debugstr_guid(&info.guidCustomVersion) );
8186 trace( "version %08lx %08lx %08lx %s\n", info.dwNLSVersion, info.dwDefinedVersion, info.dwEffectiveId,
8187 debugstr_guid(&info.guidCustomVersion) );
8188
8189 SetLastError( 0xdeadbeef );
8190 memset( &info, 0xcc, sizeof(info) );
8191 info.dwNLSVersionInfoSize = sizeof(info);
8192 ret = pGetNLSVersionEx( COMPARE_STRING, L"fr", &info );
8193 ok( !ret == !pIsValidLocaleName(L"fr"), "GetNLSVersionEx doesn't match IsValidLocaleName\n" );
8194 if (ret)
8195 {
8196 ok( info.dwEffectiveId == MAKELANGID( LANG_FRENCH, SUBLANG_DEFAULT ),
8197 "wrong id %lx\n", info.dwEffectiveId );
8198 ok( IsEqualIID( &info.guidCustomVersion, &guid_fr ) ||
8199 broken( IsEqualIID( &info.guidCustomVersion, &guid_null )), /* <= win7 */
8200 "wrong guid %s\n", debugstr_guid(&info.guidCustomVersion) );
8201 }
8202
8203 SetLastError( 0xdeadbeef );
8204 info.dwNLSVersionInfoSize = sizeof(info) - 1;
8205 ret = pGetNLSVersionEx( COMPARE_STRING, L"en-US", &info );
8206 ok( !ret, "GetNLSVersionEx succeeded\n" );
8207 ok( GetLastError() == ERROR_INSUFFICIENT_BUFFER, "wrong error %lu\n", GetLastError() );
8208
8209 SetLastError( 0xdeadbeef );
8210 memset( &info, 0xcc, sizeof(info) );
8211 info.dwNLSVersionInfoSize = offsetof( NLSVERSIONINFO, dwEffectiveId );
8212 ret = pGetNLSVersionEx( COMPARE_STRING, L"en-US", &info );
8213 ok( ret, "GetNLSVersionEx failed err %lu\n", GetLastError() );
8214 ok( info.dwEffectiveId == 0xcccccccc, "wrong id %lx\n", info.dwEffectiveId );
8215
8216 SetLastError( 0xdeadbeef );
8217 info.dwNLSVersionInfoSize = sizeof(info);
8218 ret = pGetNLSVersionEx( 2, L"en-US", &info );
8219 ok( !ret, "GetNLSVersionEx succeeded\n" );
8220 ok( GetLastError() == ERROR_INVALID_FLAGS, "wrong error %lu\n", GetLastError() );
8221
8222 SetLastError( 0xdeadbeef );
8223 info.dwNLSVersionInfoSize = sizeof(info);
8224 ret = pGetNLSVersionEx( COMPARE_STRING, L"foobar", &info );
8225 ok( !ret, "GetNLSVersionEx succeeded\n" );
8226 ok( GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %lu\n", GetLastError() );
8227
8228 SetLastError( 0xdeadbeef );
8229 memset( &info, 0xcc, sizeof(info) );
8230 info.dwNLSVersionInfoSize = sizeof(info);
8231 ret = pGetNLSVersionEx( COMPARE_STRING, L"zz-XX", &info );
8232 if (!ret) ok( GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %lu\n", GetLastError() );
8233 ok( !ret == !pIsValidLocaleName(L"zz-XX"), "GetNLSVersionEx doesn't match IsValidLocaleName\n" );
8234 if (ret)
8235 {
8236 ok( info.dwEffectiveId == LOCALE_CUSTOM_UNSPECIFIED, "wrong id %lx\n", info.dwEffectiveId );
8237 ok( IsEqualIID( &info.guidCustomVersion, &guid_def ),
8238 "wrong guid %s\n", debugstr_guid(&info.guidCustomVersion) );
8239 }
8240
8241 SetLastError( 0xdeadbeef );
8242 memset( &info, 0xcc, sizeof(info) );
8243 info.dwNLSVersionInfoSize = sizeof(info);
8244 ret = pGetNLSVersionEx( COMPARE_STRING, LOCALE_NAME_INVARIANT, &info );
8245 ok( ret, "GetNLSVersionEx failed err %lu\n", GetLastError() );
8246 if (ret)
8247 {
8248 ok( info.dwEffectiveId == LOCALE_INVARIANT, "wrong id %lx\n", info.dwEffectiveId );
8249 ok( IsEqualIID( &info.guidCustomVersion, &guid_def ) ||
8250 broken( IsEqualIID( &info.guidCustomVersion, &guid_null )), /* <= win7 */
8251 "wrong guid %s\n", debugstr_guid(&info.guidCustomVersion) );
8252 }
8253 else ok( GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %lu\n", GetLastError() );
8254 }
8255 else win_skip( "GetNLSVersionEx not available\n" );
8256
8257 if (pIsValidNLSVersion)
8258 {
8259 info.dwNLSVersionInfoSize = sizeof(info);
8260 pGetNLSVersion( COMPARE_STRING, LOCALE_USER_DEFAULT, (NLSVERSIONINFO *)&info );
8261
8262 SetLastError( 0xdeadbeef );
8263 info.dwNLSVersionInfoSize = sizeof(info);
8264 ret = pIsValidNLSVersion( COMPARE_STRING, L"ja-JP", &info );
8265 ok( ret, "IsValidNLSVersion failed err %lu\n", GetLastError() );
8266 ok( GetLastError() == 0xdeadbeef, "wrong error %lu\n", GetLastError() );
8267
8268 SetLastError( 0xdeadbeef );
8269 info.dwNLSVersionInfoSize = offsetof( NLSVERSIONINFO, dwEffectiveId );
8270 ret = pIsValidNLSVersion( COMPARE_STRING, L"en-US", &info );
8271 ok( ret, "IsValidNLSVersion failed err %lu\n", GetLastError() );
8272 ok( GetLastError() == 0xdeadbeef, "wrong error %lu\n", GetLastError() );
8273
8274 SetLastError( 0xdeadbeef );
8275 info.dwNLSVersionInfoSize = sizeof(info);
8276 ret = pIsValidNLSVersion( 2, L"en-US", &info );
8277 ok( !ret, "IsValidNLSVersion succeeded\n" );
8278 ok( GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %lu\n", GetLastError() );
8279
8280 SetLastError( 0xdeadbeef );
8281 info.dwNLSVersionInfoSize = sizeof(info);
8282 ret = pIsValidNLSVersion( COMPARE_STRING, L"foobar", &info );
8283 ok( !ret, "IsValidNLSVersion succeeded\n" );
8284 ok( GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %lu\n", GetLastError() );
8285
8286 SetLastError( 0xdeadbeef );
8287 memset( &info, 0xcc, sizeof(info) );
8288 info.dwNLSVersionInfoSize = sizeof(info);
8289 ret = pIsValidNLSVersion( COMPARE_STRING, L"en-US", &info );
8290 ok( !ret, "IsValidNLSVersion succeeded\n" );
8291 ok( GetLastError() == ERROR_SUCCESS, "wrong error %lu\n", GetLastError() );
8292
8293 info.dwNLSVersionInfoSize = sizeof(info);
8294 pGetNLSVersion( COMPARE_STRING, LOCALE_USER_DEFAULT, (NLSVERSIONINFO *)&info );
8295 info.dwNLSVersion++;
8296 SetLastError( 0xdeadbeef );
8297 ret = pIsValidNLSVersion( COMPARE_STRING, L"en-US", &info );
8298 ok( ret, "IsValidNLSVersion failed err %lu\n", GetLastError() );
8299 ok( GetLastError() == 0xdeadbeef, "wrong error %lu\n", GetLastError() );
8300
8301 info.dwNLSVersion += 0x700; /* much higher ver -> surely invalid */
8302 SetLastError( 0xdeadbeef );
8303 ret = pIsValidNLSVersion( COMPARE_STRING, L"en-US", &info );
8304 ok( !ret, "IsValidNLSVersion succeeded\n" );
8305 ok( GetLastError() == 0, "wrong error %lu\n", GetLastError() );
8306
8307 info.dwNLSVersion -= 2 * 0x700; /* much lower ver -> surely invalid */
8308 SetLastError( 0xdeadbeef );
8309 ret = pIsValidNLSVersion( COMPARE_STRING, L"en-US", &info );
8310 ok( !ret, "IsValidNLSVersion succeeded\n" );
8311 ok( GetLastError() == 0, "wrong error %lu\n", GetLastError() );
8312
8313 info.dwNLSVersion += 0x700;
8314 info.dwDefinedVersion += 0x100;
8315 SetLastError( 0xdeadbeef );
8316 ret = pIsValidNLSVersion( COMPARE_STRING, L"en-US", &info );
8317 ok( ret, "IsValidNLSVersion failed err %lu\n", GetLastError() );
8318 ok( GetLastError() == 0xdeadbeef, "wrong error %lu\n", GetLastError() );
8319
8320 info.dwDefinedVersion -= 0x100;
8321 info.guidCustomVersion.Data1 = 0x123;
8322 SetLastError( 0xdeadbeef );
8323 ret = pIsValidNLSVersion( COMPARE_STRING, L"en-US", &info );
8324 ok( !ret, "IsValidNLSVersion succeeded\n" );
8325 ok( GetLastError() == 0, "wrong error %lu\n", GetLastError() );
8326
8327 info.guidCustomVersion = guid_null;
8328 SetLastError( 0xdeadbeef );
8329 ret = pIsValidNLSVersion( COMPARE_STRING, L"en-US", &info );
8330 ok( ret, "IsValidNLSVersion failed err %lu\n", GetLastError() );
8331 ok( GetLastError() == 0xdeadbeef, "wrong error %lu\n", GetLastError() );
8332 }
8333 else win_skip( "IsValidNLSVersion not available\n" );
8334
8335 if (pIsNLSDefinedString)
8336 {
8337 SetLastError( 0xdeadbeef );
8338 info.dwNLSVersionInfoSize = sizeof(info);
8339 ret = pIsNLSDefinedString( COMPARE_STRING, 0, (NLSVERSIONINFO *)&info, L"A", 1 );
8340 if (ret)
8341 ok( GetLastError() == 0xdeadbeef, "wrong error %lu\n", GetLastError() );
8342 else
8343 ok( broken( GetLastError() == ERROR_INSUFFICIENT_BUFFER ), /* win7 */
8344 "wrong error %lu\n", GetLastError() );
8345
8346 SetLastError( 0xdeadbeef );
8347 info.dwNLSVersionInfoSize = sizeof(info) + 1;
8348 ret = pIsNLSDefinedString( COMPARE_STRING, 0, (NLSVERSIONINFO *)&info, L"A", 1 );
8349 ok( !ret, "IsNLSDefinedString succeeded\n" );
8350 ok( GetLastError() == ERROR_INSUFFICIENT_BUFFER, "wrong error %lu\n", GetLastError() );
8351
8352#ifdef __REACTOS__
8354#endif
8355 SetLastError( 0xdeadbeef );
8356 info.dwNLSVersionInfoSize = offsetof( NLSVERSIONINFO, dwEffectiveId );
8357 ret = pIsNLSDefinedString( COMPARE_STRING, 0, (NLSVERSIONINFO *)&info, L"A", 1 );
8358 ok( ret, "IsNLSDefinedString failed err %lu\n", GetLastError() );
8359 ok( GetLastError() == 0xdeadbeef, "wrong error %lu\n", GetLastError() );
8360#ifdef __REACTOS__
8361 }
8362#endif
8363
8364 SetLastError( 0xdeadbeef );
8365 ret = pIsNLSDefinedString( 2, 0, (NLSVERSIONINFO *)&info, L"A", 1 );
8366 ok( !ret, "IsNLSDefinedString succeeded\n" );
8367 ok( GetLastError() == ERROR_INVALID_FLAGS, "wrong error %lu\n", GetLastError() );
8368
8369#ifdef __REACTOS__
8371#endif
8372 SetLastError( 0xdeadbeef );
8373 ret = pIsNLSDefinedString( COMPARE_STRING, 0, (NLSVERSIONINFO *)&info, L"ABC", -10 );
8374 ok( ret, "IsNLSDefinedString failed err %lu\n", GetLastError() );
8375 ok( GetLastError() == 0xdeadbeef, "wrong error %lu\n", GetLastError() );
8376
8377 SetLastError( 0xdeadbeef );
8378 ret = pIsNLSDefinedString( COMPARE_STRING, 0, (NLSVERSIONINFO *)&info, L"ABC", -1 );
8379 ok( ret, "IsNLSDefinedString failed err %lu\n", GetLastError() );
8380 ok( GetLastError() == 0xdeadbeef, "wrong error %lu\n", GetLastError() );
8381
8382 SetLastError( 0xdeadbeef );
8383 ret = pIsNLSDefinedString( COMPARE_STRING, 0, (NLSVERSIONINFO *)&info, L"\xd800", 1 );
8384 ok( !ret, "IsNLSDefinedString failed err %lu\n", GetLastError() );
8385 ok( GetLastError() == 0xdeadbeef, "wrong error %lu\n", GetLastError() );
8386
8387 SetLastError( 0xdeadbeef );
8388 ret = pIsNLSDefinedString( COMPARE_STRING, 0, (NLSVERSIONINFO *)&info, L"\xd800", -20 );
8389 ok( !ret, "IsNLSDefinedString failed err %lu\n", GetLastError() );
8390 ok( GetLastError() == 0xdeadbeef, "wrong error %lu\n", GetLastError() );
8391#ifdef __REACTOS__
8392 }
8393#endif
8394 }
8395 else win_skip( "IsNLSDefinedString not available\n" );
8396}
8397
8398static void test_locale_nls(void)
8399{
8401 void *addr, *addr2;
8402 UINT *ptr;
8403 LCID lcid;
8405
8406 if (!pNtInitializeNlsFiles || !pRtlGetLocaleFileMappingAddress)
8407 {
8408 win_skip( "locale.nls functions not supported\n" );
8409 return;
8410 }
8411 size.QuadPart = 0xdeadbeef;
8412 status = pNtInitializeNlsFiles( &addr, &lcid, &size );
8413 ok( !status, "NtInitializeNlsFiles failed %lx\n", status );
8414 trace( "locale %04lx size %I64x\n", lcid, size.QuadPart );
8415 ptr = addr;
8416 ok( size.QuadPart == 0xdeadbeef || size.QuadPart == ptr[4] || size.QuadPart == ptr[4] + 8,
8417 "wrong offset %x / %I64x\n", ptr[4], size.QuadPart );
8418 ptr = (UINT *)((char *)addr + ptr[4]);
8419 ok( ptr[0] == 8, "wrong offset %u\n", ptr[0] );
8420 ok( ptr[3] == 0x5344534e, "wrong magic %x\n", ptr[3] );
8421
8422 status = pNtInitializeNlsFiles( &addr2, &lcid, &size );
8423 ok( !status, "NtInitializeNlsFiles failed %lx\n", status );
8424 ok( addr != addr2, "got same address %p\n", addr );
8425 ok( !memcmp( addr, addr2, ptr[4] ), "contents differ\n" );
8427 ok( !status, "NtUnmapViewOfSection failed %lx\n", status );
8429 ok( !status, "NtUnmapViewOfSection failed %lx\n", status );
8430
8431 size.QuadPart = 0xdeadbeef;
8432 status = pRtlGetLocaleFileMappingAddress( &addr, &lcid, &size );
8433 ok( !status, "NtInitializeNlsFiles failed %lx\n", status );
8434 ptr = addr;
8435 ok( size.QuadPart == 0xdeadbeef || size.QuadPart == ptr[4] || size.QuadPart == ptr[4] + 8,
8436 "wrong offset %x / %I64x\n", ptr[4], size.QuadPart );
8437 ptr = (UINT *)((char *)addr + ptr[4]);
8438 ok( ptr[0] == 8, "wrong offset %u\n", ptr[0] );
8439 ok( ptr[3] == 0x5344534e, "wrong magic %x\n", ptr[3] );
8440
8441 /* RtlGetLocaleFileMappingAddress caches the pointer */
8442 status = pRtlGetLocaleFileMappingAddress( &addr2, &lcid, &size );
8443 ok( !status, "NtInitializeNlsFiles failed %lx\n", status );
8444 ok( addr == addr2, "got different address %p / %p\n", addr, addr2 );
8445}
8446
8447static void test_geo_name(void)
8448{
8449 WCHAR reg_name[32], buf[32], set_name[32], nation[32], region[32];
8450 BOOL have_name = FALSE, have_region = FALSE, have_nation = FALSE;
8451 DWORD size, type, name_size;
8453 GEOID geoid;
8454 BOOL bret;
8455 HKEY key;
8456 int ret;
8457
8458 if (!pSetUserGeoName || !pGetUserDefaultGeoName)
8459 {
8460 win_skip("GetUserDefaultGeoName / SetUserGeoName is not available, skipping test.\n");
8461 return;
8462 }
8463
8464 status = RegOpenKeyExA(HKEY_CURRENT_USER, "Control Panel\\International\\Geo", 0, KEY_READ | KEY_WRITE, &key);
8465 ok(status == ERROR_SUCCESS, "Got unexpected status %#lx.\n", status);
8466
8467 size = sizeof(reg_name);
8468 if (!RegQueryValueExW(key, L"Name", NULL, &type, (BYTE *)reg_name, &size))
8469 have_name = TRUE;
8470
8471 lstrcpyW(buf, L"QQ");
8472 RegSetValueExW(key, L"Name", 0, REG_SZ, (BYTE *)buf, (lstrlenW(buf) + 1) * sizeof(WCHAR));
8473
8474 size = sizeof(reg_name);
8475 if ((ret = pGetUserDefaultGeoName(NULL, 0)) == 1)
8476 {
8477 if (have_name)
8478 {
8479 status = RegSetValueExW(key, L"Name", 0, REG_SZ, (BYTE *)reg_name, (lstrlenW(reg_name) + 1) * sizeof(*reg_name));
8480 ok(status == ERROR_SUCCESS, "Got unexpected status %#lx.\n", status);
8481 }
8482 else
8483 {
8484 RegDeleteValueW(key, L"Name");
8485 }
8486 win_skip("Geo names are not available, skipping test.\n");
8487 return;
8488 }
8489
8490 size = sizeof(nation);
8491 if (!RegQueryValueExW(key, L"Nation", NULL, &type, (BYTE *)nation, &size))
8492 have_nation = TRUE;
8493 size = sizeof(region);
8494 if (!RegQueryValueExW(key, L"Region", NULL, &type, (BYTE *)region, &size))
8495 have_region = TRUE;
8496
8497 SetLastError(0xdeadbeef);
8498 ret = pGetUserDefaultGeoName(NULL, 0);
8499 ok((ret == 3 || ret == 4) && GetLastError() == 0xdeadbeef, "Got unexpected ret %u, GetLastError() %lu.\n", ret, GetLastError());
8500 name_size = ret;
8501
8502 SetLastError(0xdeadbeef);
8503 ret = pGetUserDefaultGeoName(buf, 0);
8504 ok(ret >= 3 && GetLastError() == 0xdeadbeef, "Got unexpected ret %u, GetLastError() %lu.\n", ret, GetLastError());
8505
8506 SetLastError(0xdeadbeef);
8507 ret = pGetUserDefaultGeoName(buf, 2);
8508 ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER, "Got unexpected ret %u, GetLastError() %lu.\n", ret, GetLastError());
8509
8510 SetLastError(0xdeadbeef);
8511 ret = pGetUserDefaultGeoName(NULL, 1);
8512 ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER, "Got unexpected ret %u, GetLastError() %lu.\n", ret, GetLastError());
8513
8514 SetLastError(0xdeadbeef);
8515 ret = pGetUserDefaultGeoName(NULL, name_size);
8516 ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER, "Got unexpected ret %u, GetLastError() %lu.\n", ret, GetLastError());
8517
8518 SetLastError(0xdeadbeef);
8519 ret = pGetUserDefaultGeoName(buf, name_size);
8520 ok(ret == name_size && GetLastError() == 0xdeadbeef, "Got unexpected ret %u, GetLastError() %lu.\n", ret, GetLastError());
8521 ok(!lstrcmpW(buf, L"QQ"), "Got unexpected name %s.\n", wine_dbgstr_w(buf));
8522
8523 SetLastError(0xdeadbeef);
8524 bret = pSetUserGeoName(NULL);
8525 ok(!bret && GetLastError() == ERROR_INVALID_PARAMETER, "Got unexpected bret %#x, GetLastError() %lu.\n", bret, GetLastError());
8526
8527 lstrcpyW(set_name, L"QQ");
8528 SetLastError(0xdeadbeef);
8529 bret = pSetUserGeoName(set_name);
8530 ok(!bret && GetLastError() == ERROR_INVALID_PARAMETER, "Got unexpected bret %#x, GetLastError() %lu.\n", bret, GetLastError());
8531
8532 lstrcpyW(set_name, L"Xx");
8533 SetLastError(0xdeadbeef);
8534 bret = pSetUserGeoName(set_name);
8535 ok((bret && GetLastError() == 0xdeadbeef) || broken(bret && GetLastError() == 0),
8536 "Got unexpected bret %#x, GetLastError() %lu.\n", bret, GetLastError());
8537
8538 SetLastError(0xdeadbeef);
8539 ret = pGetUserDefaultGeoName(buf, ARRAY_SIZE(buf));
8540 ok(ret == 4 && GetLastError() == 0xdeadbeef, "Got unexpected ret %u, GetLastError() %lu.\n", ret, GetLastError());
8541 ok(!lstrcmpW(buf, L"001"), "Got unexpected name %s.\n", wine_dbgstr_w(buf));
8543 ok(geoid == 39070, "Got unexpected geoid %lu.\n", geoid);
8544 size = sizeof(buf);
8545 status = RegQueryValueExW(key, L"Name", NULL, &type, (BYTE *)buf, &size);
8546 ok(status == ERROR_SUCCESS, "Got unexpected status %#lx.\n", status);
8547 ok(type == REG_SZ, "Got unexpected type %#lx.\n", type);
8548 ok(!lstrcmpW(buf, L"001"), "Got unexpected name %s.\n", wine_dbgstr_w(buf));
8549
8550 lstrcpyW(set_name, L"ar");
8551 SetLastError(0xdeadbeef);
8552 bret = pSetUserGeoName(set_name);
8553 ok((bret && GetLastError() == 0xdeadbeef) || broken(bret && GetLastError() == 0),
8554 "Got unexpected bret %#x, GetLastError() %lu.\n", bret, GetLastError());
8555 ret = pGetUserDefaultGeoName(buf, ARRAY_SIZE(buf));
8556 ok((ret == 3 && GetLastError() == 0xdeadbeef) || broken(ret == 3 && GetLastError() == 0),
8557 "Got unexpected ret %u, GetLastError() %lu.\n", ret, GetLastError());
8558 ok(!lstrcmpW(buf, L"AR"), "Got unexpected name %s.\n", wine_dbgstr_w(buf));
8560 ok(geoid == 11, "Got unexpected geoid %lu.\n", geoid);
8561
8562 lstrcpyW(set_name, L"150");
8563 SetLastError(0xdeadbeef);
8564 bret = pSetUserGeoName(set_name);
8565 ok((bret && GetLastError() == 0xdeadbeef) || broken(bret && GetLastError() == 0),
8566 "Got unexpected bret %#x, GetLastError() %lu.\n", bret, GetLastError());
8567 ret = pGetUserDefaultGeoName(buf, ARRAY_SIZE(buf));
8568 ok((ret == 4 && GetLastError() == 0xdeadbeef) || broken(ret == 4 && GetLastError() == 0),
8569 "Got unexpected ret %u, GetLastError() %lu.\n", ret, GetLastError());
8570 ok(!lstrcmpW(buf, L"150"), "Got unexpected name %s.\n", wine_dbgstr_w(buf));
8572 ok(geoid == 11, "Got unexpected geoid %lu.\n", geoid);
8573
8574 lstrcpyW(set_name, L"150a");
8575 SetLastError(0xdeadbeef);
8576 bret = pSetUserGeoName(set_name);
8577 ok(!bret && GetLastError() == ERROR_INVALID_PARAMETER, "Got unexpected bret %#x, GetLastError() %lu.\n", bret, GetLastError());
8578
8579 bret = SetUserGeoID(21242);
8580 ok(bret, "Got unexpected bret %#x, GetLastError() %lu.\n", bret, GetLastError());
8581 SetLastError(0xdeadbeef);
8582 ret = pGetUserDefaultGeoName(buf, ARRAY_SIZE(buf));
8583 ok(ret == 3 && GetLastError() == 0xdeadbeef, "Got unexpected ret %u, GetLastError() %lu.\n", ret, GetLastError());
8584 ok(!lstrcmpW(buf, L"XX"), "Got unexpected name %s.\n", wine_dbgstr_w(buf));
8585
8586 bret = SetUserGeoID(42483);
8587 ok(bret, "Got unexpected bret %#x, GetLastError() %lu.\n", bret, GetLastError());
8588 SetLastError(0xdeadbeef);
8589 ret = pGetUserDefaultGeoName(buf, ARRAY_SIZE(buf));
8590 ok(ret == 4 && GetLastError() == 0xdeadbeef, "Got unexpected ret %u, GetLastError() %lu.\n", ret, GetLastError());
8591 ok(!lstrcmpW(buf, L"011"), "Got unexpected name %s.\n", wine_dbgstr_w(buf));
8592
8593 bret = SetUserGeoID(333);
8594 ok(bret, "Got unexpected bret %#x, GetLastError() %lu.\n", bret, GetLastError());
8595 SetLastError(0xdeadbeef);
8596 ret = pGetUserDefaultGeoName(buf, ARRAY_SIZE(buf));
8597 ok(ret == 3 && GetLastError() == 0xdeadbeef, "Got unexpected ret %u, GetLastError() %lu.\n", ret, GetLastError());
8598 ok(!lstrcmpW(buf, L"AN"), "Got unexpected name %s.\n", wine_dbgstr_w(buf));
8599
8600 RegDeleteValueW(key, L"Name");
8601 RegDeleteValueW(key, L"Region");
8602 lstrcpyW(buf, L"124");
8603 status = RegSetValueExW(key, L"Nation", 0, REG_SZ, (BYTE *)buf, (lstrlenW(buf) + 1) * sizeof(*buf));
8604 ok(status == ERROR_SUCCESS, "Got unexpected status %#lx.\n", status);
8605 SetLastError(0xdeadbeef);
8606 ret = pGetUserDefaultGeoName(buf, ARRAY_SIZE(buf));
8607 ok(ret == 3 && GetLastError() == 0xdeadbeef, "Got unexpected ret %u, GetLastError() %lu.\n", ret, GetLastError());
8608 ok(!lstrcmpW(buf, L"JM"), "Got unexpected name %s.\n", wine_dbgstr_w(buf));
8609
8610 lstrcpyW(buf, L"333");
8611 status = RegSetValueExW(key, L"Region", 0, REG_SZ, (BYTE *)buf, (lstrlenW(buf) + 1) * sizeof(*buf));
8612 ok(status == ERROR_SUCCESS, "Got unexpected status %#lx.\n", status);
8613 SetLastError(0xdeadbeef);
8614 ret = pGetUserDefaultGeoName(buf, ARRAY_SIZE(buf));
8615 ok(ret == 3 && GetLastError() == 0xdeadbeef, "Got unexpected ret %u, GetLastError() %lu.\n", ret, GetLastError());
8616 ok(!lstrcmpW(buf, L"JM"), "Got unexpected name %s.\n", wine_dbgstr_w(buf));
8617
8618 RegDeleteValueW(key, L"Nation");
8619 SetLastError(0xdeadbeef);
8620 ret = pGetUserDefaultGeoName(buf, ARRAY_SIZE(buf));
8621 ok(ret == 4 && GetLastError() == 0xdeadbeef, "Got unexpected ret %u, GetLastError() %lu.\n", ret, GetLastError());
8622 ok(!lstrcmpW(buf, L"001"), "Got unexpected name %s.\n", wine_dbgstr_w(buf));
8623
8624 /* Restore user geo data. */
8625 if (have_name)
8626 {
8627 status = RegSetValueExW(key, L"Name", 0, REG_SZ, (BYTE *)reg_name, (lstrlenW(reg_name) + 1) * sizeof(*reg_name));
8628 ok(status == ERROR_SUCCESS, "Got unexpected status %#lx.\n", status);
8629 }
8630 else
8631 {
8632 RegDeleteValueW(key, L"Name");
8633 }
8634 if (have_nation)
8635 {
8636 status = RegSetValueExW(key, L"Nation", 0, REG_SZ, (BYTE *)nation, (lstrlenW(nation) + 1) * sizeof(*nation));
8637 ok(status == ERROR_SUCCESS, "Got unexpected status %#lx.\n", status);
8638 }
8639 else
8640 {
8641 RegDeleteValueW(key, L"Nation");
8642 }
8643 if (have_region)
8644 {
8645 status = RegSetValueExW(key, L"Region", 0, REG_SZ, (BYTE *)region, (lstrlenW(region) + 1) * sizeof(*region));
8646 ok(status == ERROR_SUCCESS, "Got unexpected status %#lx.\n", status);
8647 }
8648 else
8649 {
8650 RegDeleteValueW(key, L"Region");
8651 }
8652
8654}
8655
8681};
8682
8684{
8685 char *end;
8686 int val = strtoul( calinfo, &end, 10 );
8687 ok( !*end, "wrong value %s\n", debugstr_a(calinfo) );
8688 ok(val >= CAL_GREGORIAN && val <= CAL_UMALQURA, "got %d\n", val);
8689 return TRUE;
8690}
8691
8692static void test_EnumCalendarInfoA(void)
8693{
8694 BOOL ret;
8695 INT i;
8696
8698 ok( ret, "EnumCalendarInfoA for user default locale failed: %lu\n", GetLastError() );
8699
8701 CAL_RETURN_NUMBER | CAL_ICALINTVALUE );
8702 ok( ret, "EnumCalendarInfoA for user default locale failed: %lu\n", GetLastError() );
8703
8705 {
8708 CAL_RETURN_NUMBER | CAL_ICALINTVALUE );
8709 ok( ret || broken( GetLastError() == ERROR_INVALID_FLAGS ) /* no locale */,
8710 "EnumCalendarInfoA for LCID %#06lx failed: %lu\n", lcid, GetLastError() );
8711 }
8712}
8713
8715{
8716 WCHAR *end;
8717 int val = wcstoul( calinfo, &end, 10 );
8718 ok( !*end, "wrong value %s\n", debugstr_w(calinfo) );
8719 ok(val >= CAL_GREGORIAN && val <= CAL_UMALQURA, "got %d\n", val);
8720 return TRUE;
8721}
8722
8723static void test_EnumCalendarInfoW(void)
8724{
8725 BOOL ret;
8726 INT i;
8727
8729 ok( ret, "EnumCalendarInfoW for user default locale failed: %lu\n", GetLastError() );
8730
8732 CAL_RETURN_NUMBER | CAL_ICALINTVALUE );
8733 ok( ret, "EnumCalendarInfoW for user default locale failed: %lu\n", GetLastError() );
8734
8736 {
8739 CAL_RETURN_NUMBER | CAL_ICALINTVALUE );
8740 ok( ret || broken( GetLastError() == ERROR_INVALID_FLAGS ) /* no locale */,
8741 "EnumCalendarInfoW for LCID %#06lx failed: %lu\n", lcid, GetLastError() );
8742 }
8743}
8744
8746{
8747 char *end;
8748 int val = strtoul( calinfo, &end, 10 );
8749 ok( !*end, "wrong value %s\n", debugstr_a(calinfo) );
8750 ok(val >= CAL_GREGORIAN && val <= CAL_UMALQURA, "got %d\n", val);
8751 return TRUE;
8752}
8753
8755{
8756 BOOL ret;
8757 INT i;
8758
8760 ok( ret, "EnumCalendarInfoExA for user default locale failed: %lu\n", GetLastError() );
8761
8763 CAL_RETURN_NUMBER | CAL_ICALINTVALUE );
8764 ok( ret, "EnumCalendarInfoExA for user default locale failed: %lu\n", GetLastError() );
8765
8767 {
8770 CAL_RETURN_NUMBER | CAL_ICALINTVALUE );
8771 ok( ret || broken( GetLastError() == ERROR_INVALID_FLAGS ) /* no locale */,
8772 "EnumCalendarInfoExA for LCID %#06lx failed: %lu\n", lcid, GetLastError() );
8773 }
8774}
8775
8777{
8778 WCHAR *end;
8779 int val = wcstoul( calinfo, &end, 10 );
8780 ok( !*end, "wrong value %s\n", debugstr_w(calinfo) );
8781 ok(val >= CAL_GREGORIAN && val <= CAL_UMALQURA, "got %d\n", val);
8782 return TRUE;
8783}
8784
8786{
8787 BOOL ret;
8788 INT i;
8789
8791 ok( ret, "EnumCalendarInfoExW for user default locale failed: %lu\n", GetLastError() );
8792
8794 CAL_RETURN_NUMBER | CAL_ICALINTVALUE );
8795 ok( ret, "EnumCalendarInfoExW for user default locale failed: %lu\n", GetLastError() );
8796
8798 {
8801 CAL_RETURN_NUMBER | CAL_ICALINTVALUE );
8802 ok( ret || broken( GetLastError() == ERROR_INVALID_FLAGS ) /* no locale */,
8803 "EnumCalendarInfoExW for LCID %#06lx failed: %lu\n", lcid, GetLastError() );
8804 }
8805}
8806
8807/* Generate sort keys for a list of Unicode code points.
8808 * Possible source files:
8809 * The Unicode collation test suite: https://www.unicode.org/Public/UCA/latest/CollationTest.zip
8810 * The list of supported char compressions: winedump nls/sortdefault.nls | grep \\->
8811 */
8812static void dump_sortkeys( char *argv[] )
8813{
8814 WCHAR data[128];
8816 BYTE key[256];
8817 unsigned int i, val, pos, res, flags = 0;
8818 char *p, *end, buffer[1024];
8819 FILE *f = fopen( argv[1], "r" );
8820
8821 locale[0] = 0;
8822 if (argv[2])
8823 {
8825 if (argv[3]) flags = strtoul( argv[3], NULL, 0 );
8826 }
8827
8828 if (!f)
8829 {
8830 fprintf( stderr, "cannot open %s\n", argv[1] );
8831 return;
8832 }
8833 while (fgets( buffer, sizeof(buffer), f ))
8834 {
8835 if (buffer[0] && buffer[strlen(buffer)-1] == '\n') buffer[strlen(buffer)-1] = 0;
8836 p = buffer;
8837 while (*p == ' ' || *p == '\t') p++;
8838 if (*p == '#') continue;
8839 pos = 0;
8840 while (*p && *p != ';' && *p != '-')
8841 {
8842 val = strtoul( p, &end, 16 );
8843 if (end == p) break;
8844 if (val >= 0x10000)
8845 {
8846 data[pos++] = 0xd800 | (val >> 10);
8847 data[pos++] = 0xdc00 | (val & 0x3ff);
8848 }
8849 else data[pos++] = val;
8850 p = end;
8851 while (*p == ' ' || *p == '\t') p++;
8852 }
8853 *p = 0;
8854#if !defined(__REACTOS__) || DLL_EXPORT_VERSION >= 0x600
8856 (WCHAR *)key, sizeof(key), NULL, NULL, 0 );
8857 printf( "%s:", buffer );
8858 for (i = 0; i < res; i++) printf( " %02x", key[i] );
8859 printf( "\n" );
8860#endif
8861 }
8862 fclose( f );
8863}
8864
8865static BOOL CALLBACK EnumDateFormatsExEx_proc(LPWSTR date_format_string, CALID calendar_id, LPARAM lp)
8866{
8867 return TRUE;
8868}
8869
8871{
8872#if defined(__REACTOS__) && DLL_EXPORT_VERSION < 0x600
8873 skip("Cannot build test_EnumDateFormatsExEx() unless DLL_EXPORT_VERSION >= 0x600.\n");
8874#else
8875 DWORD error;
8876 BOOL ret;
8877
8878 /* Invalid locale name */
8880 error = GetLastError();
8881 ok(!ret, "EnumDateFormatsExEx succeeded.\n");
8882 ok(error == ERROR_INVALID_PARAMETER, "Got unexpected error %#lx.\n", error);
8883
8884 /* yi-Hebr is missing on versions < Win10 */
8885 /* Running the following tests will cause other tests that use LOCALE_CUSTOM_UNSPECIFIED to
8886 * report yi-Hebr instead the default locale on Windows 10. So run them at the end */
8888 error = GetLastError();
8889 ok(ret || (!ret && error == ERROR_INVALID_PARAMETER), /* < Win10 */
8890 "EnumDateFormatsExEx failed, error %#lx.\n", error);
8891
8893 error = GetLastError();
8894 ok(ret || (!ret && error == ERROR_INVALID_PARAMETER), /* < Win10 */
8895 "EnumDateFormatsExEx failed, error %#lx.\n", error);
8896#endif
8897}
8898
8900{
8901 char **argv;
8903
8905
8906 if (argc >= 4)
8907 {
8908 if (!strcmp( argv[2], "sortkeys" ))
8909 {
8910 dump_sortkeys( argv + 2 );
8911 return;
8912 }
8913 }
8914
8926 test_GetCurrencyFormatA(); /* Also tests the W version */
8927 test_GetNumberFormatA(); /* Also tests the W version */
8948 test_Idn();
8965 test_geo_name();
8966 test_sorting();
8972
8973 /* Run this test at the end */
8975}
NTSTATUS NTAPI NtUnmapViewOfSection(IN HANDLE ProcessHandle, IN PVOID BaseAddress)
Definition: section.c:3483
BOOL WINAPI EnumSystemLocalesEx(LOCALE_ENUMPROCEX proc, DWORD flags, LPARAM lparam, LPVOID reserved)
BOOLEAN Expected
INT WINAPI GetLocaleInfoEx(LPCWSTR locale, LCTYPE info, LPWSTR buffer, INT len)
FN_GetLocaleInfoEx * pGetLocaleInfoEx
Definition: GetLocaleInfo.c:19
int WINAPI LCIDToLocaleName(_In_ LCID Locale, _Out_writes_opt_(cchName) LPWSTR lpName, _In_ int cchName, _In_ DWORD dwFlags)
std::map< E_MODULE, HMODULE > mod
Definition: LocaleTests.cpp:66
unsigned char BOOLEAN
FN_RtlLocaleNameToLcid * pRtlLocaleNameToLcid
Definition: RtlLocale.c:56
FN_RtlLcidToLocaleName * pRtlLcidToLocaleName
Definition: RtlLocale.c:55
static int argc
Definition: ServiceArgs.c:12
@ lparam
Definition: SystemMenu.c:31
#define expect(EXPECTED, GOT)
Definition: SystemMenu.c:483
ios_base &_STLP_CALL dec(ios_base &__s)
Definition: _ios_base.h:321
#define VOID
Definition: acefi.h:82
reg_name
Definition: amd64_sup.c:11
#define GetNTVersion()
Definition: apitest.h:17
#define trace
Definition: atltest.h:70
#define ok(value,...)
Definition: atltest.h:57
#define skip(...)
Definition: atltest.h:64
#define broken(x)
Definition: atltest.h:178
#define START_TEST(x)
Definition: atltest.h:75
#define ok_(x1, x2)
Definition: atltest.h:61
LONG NTSTATUS
Definition: precomp.h:26
#define ARRAY_SIZE(A)
Definition: main.h:20
#define RegCloseKey(hKey)
Definition: registry.h:49
Definition: ehthrow.cxx:93
Definition: _locale.h:75
LPARAM lParam
Definition: combotst.c:139
#define ERROR_INSUFFICIENT_BUFFER
Definition: dderror.h:10
#define ERROR_SUCCESS
Definition: deptool.c:10
static LSTATUS(WINAPI *pRegDeleteTreeW)(HKEY
#define NULL
Definition: types.h:112
#define TRUE
Definition: types.h:120
#define FALSE
Definition: types.h:117
UINT op
Definition: effect.c:236
#define ARRAYSIZE(array)
Definition: filtermapper.c:47
#define frac(x)
Definition: texture.c:364
#define NTSTATUS
Definition: precomp.h:19
LONG WINAPI RegOpenKeyExA(_In_ HKEY hKey, _In_ LPCSTR lpSubKey, _In_ DWORD ulOptions, _In_ REGSAM samDesired, _Out_ PHKEY phkResult)
Definition: reg.c:3298
LONG WINAPI RegSetValueExW(_In_ HKEY hKey, _In_ LPCWSTR lpValueName, _In_ DWORD Reserved, _In_ DWORD dwType, _In_ CONST BYTE *lpData, _In_ DWORD cbData)
Definition: reg.c:4882
LONG WINAPI RegDeleteValueW(HKEY hKey, LPCWSTR lpValueName)
Definition: reg.c:2330
LONG WINAPI RegQueryValueExW(_In_ HKEY hkeyorg, _In_ LPCWSTR name, _In_ LPDWORD reserved, _In_ LPDWORD type, _In_ LPBYTE data, _In_ LPDWORD count)
Definition: reg.c:4103
static WCHAR available[MAX_STRING_RESOURCE_LEN]
Definition: object.c:2336
#define wcschr
Definition: compat.h:17
#define GetProcessHeap()
Definition: compat.h:736
#define ERROR_CALL_NOT_IMPLEMENTED
Definition: compat.h:102
#define ERROR_INVALID_PARAMETER
Definition: compat.h:101
#define wcsnicmp
Definition: compat.h:14
#define UnmapViewOfFile
Definition: compat.h:746
#define CP_ACP
Definition: compat.h:109
#define SetLastError(x)
Definition: compat.h:752
#define HeapAlloc
Definition: compat.h:733
#define GetCurrentProcess()
Definition: compat.h:759
#define HeapFree(x, y, z)
Definition: compat.h:735
#define CALLBACK
Definition: compat.h:35
#define lstrcpyW
Definition: compat.h:749
#define MultiByteToWideChar
Definition: compat.h:110
#define ERROR_INVALID_NAME
Definition: compat.h:103
#define HEAP_ZERO_MEMORY
Definition: compat.h:134
#define lstrlenW
Definition: compat.h:750
HMODULE WINAPI DECLSPEC_HOTPATCH GetModuleHandleA(LPCSTR lpModuleName)
Definition: loader.c:812
VOID WINAPI GetSystemInfo(IN LPSYSTEM_INFO lpSystemInfo)
Definition: sysinfo.c:143
LCID WINAPI LocaleNameToLCID(_In_ LPCWSTR lpName, _In_ DWORD dwFlags)
GEOID WINAPI GetUserGeoID(GEOCLASS GeoClass)
Definition: locale.c:4841
#define LOCALE_NAME_USER_DEFAULT
Definition: locale.c:43
LCID WINAPI GetThreadLocale(void)
Definition: locale.c:2803
BOOL WINAPI EnumSystemLocalesW(LOCALE_ENUMPROCW lpfnLocaleEnum, DWORD dwFlags)
Definition: locale.c:3001
LANGID WINAPI SetThreadUILanguage(LANGID langid)
Definition: locale.c:2857
INT WINAPI LCMapStringA(LCID lcid, DWORD flags, LPCSTR src, INT srclen, LPSTR dst, INT dstlen)
Definition: locale.c:3834
INT WINAPI ResolveLocaleName(LPCWSTR name, LPWSTR localename, INT len)
Definition: locale.c:6243
UINT WINAPI GetACP(void)
Definition: locale.c:2023
BOOL WINAPI IsValidLanguageGroup(LGRPID lgrpid, DWORD dwFlags)
Definition: locale.c:4627
INT WINAPI FoldStringA(DWORD dwFlags, LPCSTR src, INT srclen, LPSTR dst, INT dstlen)
Definition: locale.c:3924
INT WINAPI NormalizeString(NORM_FORM NormForm, LPCWSTR lpSrcString, INT cwSrcLength, LPWSTR lpDstString, INT cwDstLength)
Definition: locale.c:5662
INT WINAPI CompareStringA(LCID lcid, DWORD flags, LPCSTR str1, INT len1, LPCSTR str2, INT len2)
Definition: locale.c:4086
INT WINAPI IdnToUnicode(DWORD dwFlags, LPCWSTR lpASCIICharStr, INT cchASCIIChar, LPWSTR lpUnicodeCharStr, INT cchUnicodeChar)
Definition: locale.c:6059
int WINAPI lstrcmpW(LPCWSTR str1, LPCWSTR str2)
Definition: locale.c:4246
INT WINAPI CompareStringW(LCID lcid, DWORD flags, LPCWSTR str1, INT len1, LPCWSTR str2, INT len2)
Definition: locale.c:4017
BOOL WINAPI SetUserGeoID(GEOID GeoID)
Definition: locale.c:4878
LANGID WINAPI GetUserDefaultUILanguage(void)
Definition: locale.c:1380
BOOL WINAPI GetSystemPreferredUILanguages(DWORD flags, ULONG *count, WCHAR *buffer, ULONG *size)
Definition: locale.c:1301
BOOL WINAPI GetCPInfoExW(UINT codepage, DWORD dwFlags, LPCPINFOEXW cpinfo)
Definition: locale.c:2222
INT WINAPI GetLocaleInfoA(LCID lcid, LCTYPE lctype, LPSTR buffer, INT len)
Definition: locale.c:1609
BOOL WINAPI GetCPInfo(UINT codepage, LPCPINFO cpinfo)
Definition: locale.c:2146
INT WINAPI GetGeoInfoW(GEOID geoid, GEOTYPE geotype, LPWSTR data, int data_len, LANGID lang)
Definition: locale.c:5495
BOOL WINAPI IsValidLocaleName(LPCWSTR locale)
Definition: locale.c:2936
INT WINAPI IdnToAscii(DWORD dwFlags, LPCWSTR lpUnicodeCharStr, INT cchUnicodeChar, LPWSTR lpASCIICharStr, INT cchASCIIChar)
Definition: locale.c:5706
int WINAPI lstrcmpA(LPCSTR str1, LPCSTR str2)
Definition: locale.c:4198
BOOL WINAPI EnumSystemLocalesA(LOCALE_ENUMPROCA lpfnLocaleEnum, DWORD dwFlags)
Definition: locale.c:2986
INT WINAPI LCMapStringEx(LPCWSTR locale, DWORD flags, LPCWSTR src, INT srclen, LPWSTR dst, INT dstlen, LPNLSVERSIONINFO version, LPVOID reserved, LPARAM handle)
Definition: locale.c:3746
int WINAPI lstrcmpiA(LPCSTR str1, LPCSTR str2)
Definition: locale.c:4227
BOOL WINAPI GetStringTypeW(DWORD type, LPCWSTR src, INT count, LPWORD chartype)
Definition: locale.c:3098
BOOL WINAPI IsValidLocale(LCID lcid, DWORD flags)
Definition: locale.c:2925
INT WINAPI GetSystemDefaultLocaleName(LPWSTR localename, INT len)
Definition: locale.c:1246
INT WINAPI FoldStringW(DWORD dwFlags, LPCWSTR src, INT srclen, LPWSTR dst, INT dstlen)
Definition: locale.c:3982
BOOL WINAPI GetThreadPreferredUILanguages(DWORD flags, ULONG *count, WCHAR *buf, ULONG *size)
Definition: locale.c:1334
LCID WINAPI GetUserDefaultLCID(void)
Definition: locale.c:1216
INT WINAPI CompareStringEx(LPCWSTR locale, DWORD flags, LPCWSTR str1, INT len1, LPCWSTR str2, INT len2, LPNLSVERSIONINFO version, LPVOID reserved, LPARAM lParam)
Definition: locale.c:4026
LCID WINAPI GetSystemDefaultLCID(void)
Definition: locale.c:1235
BOOL WINAPI EnumUILanguagesA(UILANGUAGE_ENUMPROCA pUILangEnumProc, DWORD dwFlags, LONG_PTR lParam)
Definition: locale.c:4948
INT WINAPI LCMapStringW(LCID lcid, DWORD flags, LPCWSTR src, INT srclen, LPWSTR dst, INT dstlen)
Definition: locale.c:3808
BOOL WINAPI EnumSystemGeoID(GEOCLASS geoclass, GEOID parent, GEO_ENUMPROC enumproc)
Definition: locale.c:5613
BOOL WINAPI GetCPInfoExA(UINT codepage, DWORD dwFlags, LPCPINFOEXA cpinfo)
Definition: locale.c:2204
BOOL WINAPI EnumLanguageGroupLocalesA(LANGGROUPLOCALE_ENUMPROCA pLangGrpLcEnumProc, LGRPID lgrpid, DWORD dwFlags, LONG_PTR lParam)
Definition: locale.c:4778
BOOL WINAPI EnumSystemLanguageGroupsA(LANGUAGEGROUP_ENUMPROCA pLangGrpEnumProc, DWORD dwFlags, LONG_PTR lParam)
Definition: locale.c:4579
INT WINAPI GetLocaleInfoW(LCID lcid, LCTYPE lctype, LPWSTR buffer, INT len)
Definition: locale.c:1675
BOOL WINAPI SetLocaleInfoA(LCID lcid, LCTYPE lctype, LPCSTR data)
Definition: locale.c:1891
#define REG_SZ
Definition: locale.c:45
INT WINAPI GetGeoInfoA(GEOID geoid, GEOTYPE geotype, LPSTR data, int data_len, LANGID lang)
Definition: locale.c:5569
LCID WINAPI ConvertDefaultLocale(LCID lcid)
Definition: locale.c:2879
BOOL WINAPI SetLocaleInfoW(LCID lcid, LCTYPE lctype, LPCWSTR data)
Definition: locale.c:1923
INT WINAPI IdnToNameprepUnicode(DWORD dwFlags, LPCWSTR lpUnicodeCharStr, INT cchUnicodeChar, LPWSTR lpNameprepCharStr, INT cchNameprepChar)
Definition: locale.c:5844
BOOL WINAPI DECLSPEC_HOTPATCH EnumDateFormatsExEx(DATEFMT_ENUMPROCEXEX proc, const WCHAR *locale, DWORD flags, LPARAM lparam)
Definition: locale.c:4973
BOOL WINAPI DECLSPEC_HOTPATCH IsNLSDefinedString(NLS_FUNCTION func, DWORD flags, NLSVERSIONINFO *info, const WCHAR *str, int len)
Definition: locale.c:6745
static int put_utf16(WCHAR *dst, int pos, int dstlen, unsigned int ch)
Definition: locale.c:2017
BOOL WINAPI DECLSPEC_HOTPATCH EnumCalendarInfoExW(CALINFO_ENUMPROCEXW proc, LCID lcid, CALID id, CALTYPE type)
Definition: locale.c:4931
INT WINAPI DECLSPEC_HOTPATCH GetGeoInfoEx(WCHAR *location, GEOTYPE type, WCHAR *data, int data_count)
Definition: locale.c:5985
int WINAPI GetNumberFormatEx(const WCHAR *name, DWORD flags, const WCHAR *value, const NUMBERFMTW *format, WCHAR *buffer, int len)
Definition: locale.c:8187
LCID lcid
Definition: locale.c:5656
int WINAPI GetDateFormatEx(const WCHAR *name, DWORD flags, const SYSTEMTIME *systime, const WCHAR *format, WCHAR *buffer, int len, const WCHAR *calendar)
Definition: locale.c:8294
INT WINAPI GetUserDefaultGeoName(LPWSTR geo_name, int count)
Definition: locale.c:7421
INT WINAPI DECLSPEC_HOTPATCH FindStringOrdinal(DWORD flag, const WCHAR *src, INT src_size, const WCHAR *val, INT val_size, BOOL ignore_case)
Definition: locale.c:5254
BOOL WINAPI DECLSPEC_HOTPATCH GetNLSVersion(NLS_FUNCTION func, LCID lcid, NLSVERSIONINFO *info)
Definition: locale.c:6100
const NLS_LOCALE_DATA *WINAPI NlsValidateLocale(LCID *lcid, ULONG flags)
Definition: locale.c:723
BOOL WINAPI DECLSPEC_HOTPATCH GetNLSVersionEx(NLS_FUNCTION func, const WCHAR *locale, NLSVERSIONINFOEX *info)
Definition: locale.c:6121
BOOL WINAPI DECLSPEC_HOTPATCH EnumCalendarInfoW(CALINFO_ENUMPROCW proc, LCID lcid, CALID id, CALTYPE type)
Definition: locale.c:4920
int WINAPI GetTimeFormatEx(const WCHAR *name, DWORD flags, const SYSTEMTIME *systime, const WCHAR *format, WCHAR *buffer, int len)
Definition: locale.c:8362
BOOL WINAPI SetUserGeoName(PWSTR geo_name)
Definition: locale.c:7465
INT WINAPI DECLSPEC_HOTPATCH CompareStringOrdinal(const WCHAR *str1, INT len1, const WCHAR *str2, INT len2, BOOL ignore_case)
Definition: locale.c:4886
INT WINAPI DECLSPEC_HOTPATCH FindNLSStringEx(const WCHAR *locale, DWORD flags, const WCHAR *src, int srclen, const WCHAR *value, int valuelen, int *found, NLSVERSIONINFO *version, void *reserved, LPARAM handle)
Definition: locale.c:5223
int WINAPI GetDateFormatW(LCID lcid, DWORD flags, const SYSTEMTIME *systime, const WCHAR *format, WCHAR *buffer, int len)
Definition: locale.c:8275
int WINAPI GetDateFormatA(LCID lcid, DWORD flags, const SYSTEMTIME *time, const char *format, char *buffer, int len)
Definition: locale.c:8246
DWORD WINAPI DECLSPEC_HOTPATCH IsValidNLSVersion(NLS_FUNCTION func, const WCHAR *locale, NLSVERSIONINFOEX *info)
Definition: locale.c:6786
int WINAPI GetTimeFormatA(LCID lcid, DWORD flags, const SYSTEMTIME *time, const char *format, char *buffer, int len)
Definition: locale.c:8314
BOOL WINAPI DECLSPEC_HOTPATCH EnumTimeFormatsW(TIMEFMT_ENUMPROCW proc, LCID lcid, DWORD flags)
Definition: locale.c:5168
LANGID WINAPI DECLSPEC_HOTPATCH GetThreadUILanguage(void)
Definition: thread.c:328
unsigned char ch[4][2]
Definition: console.c:118
int CDECL fclose(FILE *file)
Definition: file.c:3757
int WINAPIV fprintf(FILE *file, const char *format,...)
Definition: file.c:5549
char *CDECL fgets(char *s, int size, FILE *file)
Definition: file.c:3903
FILE *CDECL fopen(const char *path, const char *mode)
Definition: file.c:4310
#define assert(_expr)
Definition: assert.h:32
#define stderr
_ACRTIMP int __cdecl swscanf(const wchar_t *, const wchar_t *,...)
Definition: scanf.c:438
_ACRTIMP __msvcrt_ulong __cdecl wcstoul(const wchar_t *, wchar_t **, int)
Definition: wcs.c:2912
_ACRTIMP size_t __cdecl wcslen(const wchar_t *)
Definition: wcs.c:2983
_ACRTIMP int __cdecl wcscmp(const wchar_t *, const wchar_t *)
Definition: wcs.c:1972
_ACRTIMP int __cdecl memcmp(const void *, const void *, size_t)
Definition: string.c:2802
_ACRTIMP wchar_t *__cdecl wcstok(wchar_t *, const wchar_t *)
Definition: wcs.c:2065
_ACRTIMP int __cdecl wcsncmp(const wchar_t *, const wchar_t *, size_t)
Definition: wcs.c:518
_ACRTIMP int __cdecl system(const char *)
Definition: process.c:1297
_ACRTIMP void __cdecl qsort(void *, size_t, size_t, int(__cdecl *)(const void *, const void *))
_ACRTIMP int __cdecl _ACRTIMP int __cdecl _ACRTIMP int __cdecl _ACRTIMP int __cdecl _ACRTIMP int __cdecl _ACRTIMP int __cdecl _ACRTIMP int __cdecl sscanf(const char *, const char *,...) __WINE_CRT_SCANF_ATTR(2
_ACRTIMP __msvcrt_ulong __cdecl strtoul(const char *, char **, int)
Definition: string.c:1859
_ACRTIMP char *__cdecl strchr(const char *, int)
Definition: string.c:3286
_ACRTIMP size_t __cdecl strlen(const char *)
Definition: string.c:1592
_ACRTIMP int __cdecl strcmp(const char *, const char *)
Definition: string.c:3319
_ACRTIMP char *__cdecl strtok(char *, const char *)
Definition: string.c:285
static char empty[]
Definition: locale.c:157
unsigned int(__cdecl typeof(jpeg_read_scanlines))(struct jpeg_decompress_struct *
Definition: typeof.h:31
static const WCHAR month[12][4]
Definition: session.c:2150
return ret
Definition: mutex.c:146
#define L(x)
Definition: resources.c:13
int Simple(int arg)
Definition: ehframes.cpp:45
void test2()
Definition: ehthrow.cxx:284
void test1()
Definition: ehthrow.cxx:277
void test3()
Definition: ehthrow.cxx:291
unsigned short WORD
Definition: ntddk_ex.h:93
unsigned int BOOL
Definition: ntddk_ex.h:94
unsigned long DWORD
Definition: ntddk_ex.h:95
#define printf
Definition: freeldr.h:104
BOOLEAN valid
void(* func_ptr)(void)
Definition: gccmain.c:11
GLint GLint GLint GLint GLint x
Definition: gl.h:1548
GLuint GLuint GLsizei count
Definition: gl.h:1545
GLuint GLuint GLsizei GLenum type
Definition: gl.h:1545
GLclampf GLclampf GLclampf alpha
Definition: gl.h:1740
GLdouble s
Definition: gl.h:2039
GLuint GLuint end
Definition: gl.h:1545
GLint GLenum GLsizei GLsizei GLsizei GLint GLsizei const GLvoid * data
Definition: gl.h:1950
GLdouble n
Definition: glext.h:7729
GLuint res
Definition: glext.h:9613
GLenum src
Definition: glext.h:6340
GLsizei const GLchar *const * strings
Definition: glext.h:7622
GLuint buffer
Definition: glext.h:5915
GLsizeiptr size
Definition: glext.h:5919
const GLubyte * c
Definition: glext.h:8905
GLfloat f
Definition: glext.h:7540
GLenum GLuint GLenum GLsizei const GLchar * buf
Definition: glext.h:7751
GLuint in
Definition: glext.h:9616
GLenum GLenum dst
Definition: glext.h:6340
GLbitfield flags
Definition: glext.h:7161
const GLint * first
Definition: glext.h:5794
GLenum const GLvoid * addr
Definition: glext.h:9621
GLuint GLfloat * val
Definition: glext.h:7180
GLuint64EXT * result
Definition: glext.h:11304
GLfloat GLfloat p
Definition: glext.h:8902
GLuint64EXT GLuint GLuint GLenum GLenum GLuint GLuint GLenum GLuint GLuint key1
Definition: glext.h:10608
GLenum GLsizei len
Definition: glext.h:6722
GLboolean GLboolean GLboolean GLboolean a
Definition: glext.h:6204
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
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 * u
Definition: glfuncs.h:240
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 GLint GLint j
Definition: glfuncs.h:250
#define C1_CNTRL
Definition: unicode.h:36
#define C1_DIGIT
Definition: unicode.h:33
#define C1_PUNCT
Definition: unicode.h:35
#define C1_SPACE
Definition: unicode.h:34
#define C1_ALPHA
Definition: unicode.h:39
#define C1_BLANK
Definition: unicode.h:37
#define C1_LOWER
Definition: unicode.h:32
#define C1_UPPER
Definition: unicode.h:31
static int is_utf8(const char *src)
Definition: icy2utf8.c:336
static double two
Definition: jn_yn.c:52
static const WCHAR emptyW[]
Definition: navigate.c:40
NTSYSAPI NTSTATUS WINAPI RtlGetLocaleFileMappingAddress(void **, LCID *, LARGE_INTEGER *)
NTSYSAPI void WINAPI RtlInitCodePageTable(USHORT *, CPTABLEINFO *)
NTSYSAPI NTSTATUS WINAPI RtlLocaleNameToLcid(const WCHAR *, LCID *, ULONG)
NTSYSAPI NTSTATUS WINAPI RtlNormalizeString(ULONG, const WCHAR *, INT, WCHAR *, INT *)
NTSYSAPI BOOLEAN WINAPI RtlIsValidLocaleName(const WCHAR *, ULONG)
NTSYSAPI NTSTATUS WINAPI RtlGetThreadPreferredUILanguages(DWORD, ULONG *, WCHAR *, ULONG *)
NTSYSAPI NTSTATUS WINAPI RtlLcidToLocaleName(LCID, UNICODE_STRING *, ULONG, BOOLEAN)
NTSYSAPI NTSTATUS WINAPI RtlGetUserPreferredUILanguages(DWORD, ULONG, ULONG *, WCHAR *, ULONG *)
NTSYSAPI NTSTATUS WINAPI NtGetNlsSectionPtr(ULONG, ULONG, void *, void **, SIZE_T *)
NTSYSAPI NTSTATUS WINAPI RtlIsNormalizedString(ULONG, const WCHAR *, INT, BOOLEAN *)
NTSYSAPI NTSTATUS WINAPI NtInitializeNlsFiles(void **, LCID *, LARGE_INTEGER *)
NTSYSAPI NTSTATUS WINAPI RtlCustomCPToUnicodeN(CPTABLEINFO *, WCHAR *, DWORD, DWORD *, const char *, DWORD)
NTSYSAPI NTSTATUS WINAPI RtlGetSystemPreferredUILanguages(DWORD, ULONG, ULONG *, WCHAR *, ULONG *)
#define I(s)
uint32_t entry
Definition: isohybrid.c:63
#define d
Definition: ke_i.h:81
#define e
Definition: ke_i.h:82
#define f
Definition: ke_i.h:83
#define c
Definition: ke_i.h:80
BOOL WINAPI GetUserPreferredUILanguages(DWORD dwFlags, PULONG pulNumLanguages, PZZWSTR pwszLanguagesBuffer, PULONG pcchLanguagesBuffer)
Definition: vista.c:702
#define STUB
Definition: kernel32.h:27
#define debugstr_guid
Definition: kernel32.h:35
#define debugstr_a
Definition: kernel32.h:31
#define debugstr_w
Definition: kernel32.h:32
#define wine_dbgstr_w
Definition: kernel32.h:34
BOOL WINAPI EnumTimeFormatsA(TIMEFMT_ENUMPROCA proc, LCID lcid, DWORD flags)
Definition: lcformat.c:2130
BOOL WINAPI EnumCalendarInfoA(CALINFO_ENUMPROCA calinfoproc, LCID locale, CALID calendar, CALTYPE caltype)
Definition: lcformat.c:2337
INT WINAPI GetCurrencyFormatA(LCID lcid, DWORD dwFlags, LPCSTR lpszValue, const CURRENCYFMTA *lpFormat, LPSTR lpCurrencyStr, int cchOut)
Definition: lcformat.c:1492
BOOL WINAPI EnumCalendarInfoExA(CALINFO_ENUMPROCEXA calinfoproc, LCID locale, CALID calendar, CALTYPE caltype)
Definition: lcformat.c:2377
INT WINAPI GetNumberFormatA(LCID lcid, DWORD dwFlags, LPCSTR lpszValue, const NUMBERFMTA *lpFormat, LPSTR lpNumberStr, int cchOut)
Definition: lcformat.c:1126
BOOL WINAPI EnumDateFormatsA(DATEFMT_ENUMPROCA proc, LCID lcid, DWORD flags)
Definition: lcformat.c:2013
USHORT LANGID
Definition: mui.h:9
ULONG GEOID
Definition: mui.h:28
if(dx< 0)
Definition: linetemp.h:194
LPSTR WINAPI lstrcpyA(LPSTR lpString1, LPCSTR lpString2)
Definition: lstring.c:100
LPWSTR WINAPI lstrcatW(LPWSTR lpString1, LPCWSTR lpString2)
Definition: lstring.c:274
LPSTR WINAPI lstrcatA(LPSTR lpString1, LPCSTR lpString2)
Definition: lstring.c:123
int WINAPI lstrlenA(LPCSTR lpString)
Definition: lstring.c:145
struct S1 s1
int winetest_debug
void __cdecl void __cdecl void __cdecl void __cdecl void __cdecl winetest_push_context(const char *fmt,...) __WINE_PRINTF_ATTR(1
#define win_skip
Definition: minitest.h:67
void __cdecl void __cdecl void __cdecl void __cdecl void __cdecl void winetest_pop_context(void)
#define todo_wine
Definition: minitest.h:80
LONG_PTR LPARAM
Definition: minwindef.h:175
#define error(str)
Definition: mkdosfs.c:1605
#define memcpy(s1, s2, n)
Definition: mkisofs.h:878
#define memchr(s, c, n)
Definition: mkisofs.h:875
static PVOID ptr
Definition: dispmode.c:27
static struct test_info tests[]
#define sprintf
Definition: sprintf.c:45
FN_LocaleNameToLCID * pLocaleNameToLCID
BOOL expected
Definition: store.c:2000
static UINT UINT last
Definition: font.c:45
static void test_EnumDateFormatsExEx(void)
Definition: locale.c:8870
static LONG alternate_seen
Definition: locale.c:4626
static LPNLSVERSIONINFO
Definition: locale.c:65
static void test_FindStringOrdinal(void)
Definition: locale.c:7311
static BOOL is_idn_error(const WCHAR *str)
Definition: locale.c:5875
static int compare_string1(const void *e1, const void *e2)
Definition: locale.c:3468
static LPINT
Definition: locale.c:92
static const SYSTEMTIME INT
Definition: locale.c:57
static void *WINAPI * pNlsValidateLocale(LCID *, ULONG)
static void test_EnumSystemLanguageGroupsA(void)
Definition: locale.c:4590
static void test_SpecialCasing(void)
Definition: locale.c:7924
static void test_LCMapStringW(void)
Definition: locale.c:2882
static BOOL CALLBACK calinfoex_procA(LPSTR calinfo, LCID calid)
Definition: locale.c:8745
static void test_ConvertDefaultLocale(void)
Definition: locale.c:4477
static void test_IsValidLocaleName(void)
Definition: locale.c:6086
static const struct sorting_test_entry unicode_sorting_tests[]
Definition: locale.c:3540
#define expect_err(r, s, e)
Definition: locale.c:199
static LPSTR
Definition: locale.c:81
static void test_CompareStringOrdinal(void)
Definition: locale.c:6265
static LANGID
Definition: locale.c:81
static void test_sorting(void)
Definition: locale.c:3497
static const WCHAR title_case[]
Definition: locale.c:47
static void expect_werr_(int line, int ret, const WCHAR *str, DWORD err, const char *err_name)
Definition: locale.c:223
static BOOL CALLBACK EnumDateFormatsExEx_proc(LPWSTR date_format_string, CALID calendar_id, LPARAM lp)
Definition: locale.c:8865
#define CY_POS_LEFT_SPACE
Definition: locale.c:1215
static BOOL CALLBACK lgrplocale_procA(LGRPID lgrpid, LCID lcid, LPSTR lpszNum, LONG_PTR lParam)
Definition: locale.c:4827
static const WCHAR lower_case[]
Definition: locale.c:46
static void test_GetTimeFormatA(void)
Definition: locale.c:537
static BOOL CALLBACK enum_datetime_procW(WCHAR *fmt)
Definition: locale.c:5049
static BOOL CALLBACK test_geoid_enumproc2(GEOID geoid)
Definition: locale.c:6509
static void test_GetThreadPreferredUILanguages(void)
Definition: locale.c:6993
static void test_EnumSystemGeoID(void)
Definition: locale.c:6515
static UNICODE_STRING BYTE
Definition: locale.c:69
static void test_IdnToUnicode(void)
Definition: locale.c:5827
#define expect_werr(r, s, e)
Definition: locale.c:222
#define NEG_LEFT_SPACE
Definition: locale.c:1406
static WORD enumCount
Definition: locale.c:55
static GEOTYPE
Definition: locale.c:81
#define X(f)
Definition: locale.c:6584
static BOOL CALLBACK test_EnumSystemLocalesW_callback(LPWSTR str)
Definition: locale.c:4652
static BOOL CALLBACK test_EnumSystemLocalesA_callback(LPSTR str)
Definition: locale.c:4628
static const WCHAR invalidW[]
Definition: locale.c:52
static void dump_sortkeys(char *argv[])
Definition: locale.c:8812
static void test_EnumUILanguageA(void)
Definition: locale.c:4983
static void test_LCMapStringA(void)
Definition: locale.c:2359
static void test_Idn(void)
Definition: locale.c:5889
INT(* lcmapstring_wrapper)(DWORD, LPCWSTR, INT, LPWSTR, INT)
Definition: locale.c:2526
static void test_unicode_sorting(void)
Definition: locale.c:3863
static void test_CompareStringEx(void)
Definition: locale.c:2306
#define CY_POS_LEFT
Definition: locale.c:1213
#define LCID_RES(src, res)
Definition: locale.c:4473
static BOOL CALLBACK enum_func(LPWSTR name, DWORD flags, LPARAM lparam)
Definition: locale.c:4802
static void test_GetCPInfo(void)
Definition: locale.c:5214
static void test_GetTimeFormatEx(void)
Definition: locale.c:725
static ULONG WCHAR ULONG *static ULONG WCHAR ULONG *static ULONG WCHAR ULONG *static void InitFunctionPointers(void)
Definition: locale.c:113
static LPARAM
Definition: locale.c:64
static void test_GetDateFormatW(void)
Definition: locale.c:1130
static void test_GetLocaleInfoW(void)
Definition: locale.c:394
static void test_GetCurrencyFormatA(void)
Definition: locale.c:1218
static void test_EnumCalendarInfoExW(void)
Definition: locale.c:8785
static char date_fmt_buf[1024]
Definition: locale.c:5039
static const WCHAR localeW[]
Definition: locale.c:49
static void test_EnumDateFormatsA(void)
Definition: locale.c:5055
static void test_GetDateFormatA(void)
Definition: locale.c:897
static void test_GetUserPreferredUILanguages(void)
Definition: locale.c:7069
static const struct comparestringa_entry comparestringa_data[]
Definition: locale.c:1853
static void test_NLSVersion(void)
Definition: locale.c:8111
static const DWORD lcmap_invalid_flags[]
Definition: locale.c:2331
static const SYSTEMTIME LPWSTR
Definition: locale.c:57
#define BUFFER_SIZE
Definition: locale.c:183
static void expect_wstr_(int line, int ret, const WCHAR *str, const WCHAR *expected)
Definition: locale.c:209
static int geoidenum_count
Definition: locale.c:6498
static BOOL CALLBACK enum_datetime_procA(LPSTR fmt)
Definition: locale.c:5042
static void expect_str_(int line, int ret, const char *str, const char *expected)
Definition: locale.c:186
static void test_invariant(void)
Definition: locale.c:6698
static const WCHAR upper_case[]
Definition: locale.c:45
#define MKLCID(x, y, z)
Definition: locale.c:4472
static void test_GetGeoInfo(void)
Definition: locale.c:6353
static void test_GetLocaleInfoEx(void)
Definition: locale.c:5984
static void test_geo_name(void)
Definition: locale.c:8447
static LONG default_seen
Definition: locale.c:4625
static INT LCMapStringW_wrapper(DWORD flags, LPCWSTR src, INT srclen, LPWSTR dst, INT dstlen)
Definition: locale.c:2877
static void test_lcmapstring_unicode(lcmapstring_wrapper func_ptr, const char *func_name)
Definition: locale.c:2528
static LCID
Definition: locale.c:98
static void test_GetNumberFormatEx(void)
Definition: locale.c:1660
static void test_IdnToAscii(void)
Definition: locale.c:5782
static void test_GetStringTypeW(void)
Definition: locale.c:5482
static BOOL CALLBACK langgrp_procA(LGRPID lgrpid, LPSTR lpszNum, LPSTR lpszName, DWORD dwFlags, LONG_PTR lParam)
Definition: locale.c:4573
static void test_EnumCalendarInfoA(void)
Definition: locale.c:8692
static void test_GetDateFormatEx(void)
Definition: locale.c:1042
static const LCID locales_with_optional_calendars[]
Definition: locale.c:8656
static BOOL CALLBACK luilocale_proc2A(LPSTR value, LONG_PTR lParam)
Definition: locale.c:4970
static void test_EnumLanguageGroupLocalesA(void)
Definition: locale.c:4844
static void test_SetThreadUILanguage(void)
Definition: locale.c:7378
static const struct comparestringex_test comparestringex_tests[]
Definition: locale.c:2153
static LPCWSTR lpStringSource
Definition: locale.c:97
static const struct neutralsublang_name2_t neutralsublang_names2[]
Definition: locale.c:360
static void test_IdnToNameprepUnicode(void)
Definition: locale.c:5662
static void test_LCMapStringEx(void)
Definition: locale.c:2907
static int compare_string2(const void *e1, const void *e2)
Definition: locale.c:3476
static BOOL CALLBACK calinfo_procW(LPWSTR calinfo)
Definition: locale.c:8714
static void test_EnumTimeFormatsA(void)
Definition: locale.c:5135
#define NEG_PARENS
Definition: locale.c:1404
static const char *const strings_sorted[]
Definition: locale.c:3404
#define NEG_RIGHT
Definition: locale.c:1407
static LCTYPE
Definition: locale.c:75
static void expect_err_(int line, int ret, const char *str, DWORD err, const char *err_name)
Definition: locale.c:200
#define expect_wstr(r, s, e)
Definition: locale.c:208
static void test_FindNLSStringEx(void)
Definition: locale.c:7209
#define NEG_LEFT
Definition: locale.c:1405
static const WCHAR fooW[]
Definition: locale.c:50
static LPVOID
Definition: locale.c:64
static PWSTR
Definition: locale.c:83
static void test_FoldStringA(void)
Definition: locale.c:3916
static INT LCMapStringEx_wrapper(DWORD flags, LPCWSTR src, INT srclen, LPWSTR dst, INT dstlen)
Definition: locale.c:2902
static void test_SetLocaleInfo(void)
Definition: locale.c:4886
#define CY_POS_RIGHT
Definition: locale.c:1214
static void test_CompareStringW(void)
Definition: locale.c:2063
static void test_EnumSystemLocalesEx(void)
Definition: locale.c:4809
static WCHAR date_fmt_bufW[1024]
Definition: locale.c:5040
static const WCHAR symbols_stripped[]
Definition: locale.c:48
static void test_EnumSystemLocalesA(void)
Definition: locale.c:4676
static void test_EnumTimeFormatsW(void)
Definition: locale.c:5162
static int get_utf16(const WCHAR *src, unsigned int srclen, unsigned int *ch)
Definition: locale.c:231
static BOOL CALLBACK calinfoex_procW(LPWSTR calinfo, LCID calid)
Definition: locale.c:8776
static void test_EnumSystemLocalesW(void)
Definition: locale.c:4739
static void test_locale_nls(void)
Definition: locale.c:8398
static BOOL CALLBACK luilocale_proc1A(LPSTR value, LONG_PTR lParam)
Definition: locale.c:4963
static const struct neutralsublang_name_t neutralsublang_names[]
Definition: locale.c:2962
static void test_NormalizeString(void)
Definition: locale.c:7417
static LGRPID
Definition: locale.c:60
static void test_GetNumberFormatA(void)
Definition: locale.c:1410
#define TEST_LCIDLANG(a, b)
Definition: locale.c:4474
#define expect_str(r, s, e)
Definition: locale.c:185
static void test_GetSystemPreferredUILanguages(void)
Definition: locale.c:6760
#define TEST_LCID(a, b, c)
Definition: locale.c:4475
static BOOL CALLBACK luilocale_proc3A(LPSTR value, LONG_PTR lParam)
Definition: locale.c:4977
static const struct invariant_entry invariant_list[]
Definition: locale.c:6585
static void test_CompareStringA(void)
Definition: locale.c:1909
static BOOL CALLBACK calinfo_procA(LPSTR calinfo)
Definition: locale.c:8683
#define NUO
Definition: locale.c:258
static void test_GetLocaleInfoA(void)
Definition: locale.c:260
static int compare_string3(const void *e1, const void *e2)
Definition: locale.c:3484
static void test_ResolveLocaleName(void)
Definition: locale.c:6175
static ULONG
Definition: locale.c:68
static void test_EnumCalendarInfoExA(void)
Definition: locale.c:8754
#define CY_POS_RIGHT_SPACE
Definition: locale.c:1216
static void test_LocaleNameToLCID(void)
Definition: locale.c:2980
static void test_EnumCalendarInfoW(void)
Definition: locale.c:8723
static GEOID
Definition: locale.c:86
static BOOL CALLBACK test_geoid_enumproc(GEOID geoid)
Definition: locale.c:6499
static void test_FoldStringW(void)
Definition: locale.c:4126
static LONG_PTR
Definition: locale.c:59
#define NEG_RIGHT_SPACE
Definition: locale.c:1408
static SYSTEM_INFO si
Definition: virtual.c:39
static DWORD LPDWORD LPCSTR DWORD srclen
Definition: directory.c:52
static DWORD LPDWORD reslen
Definition: directory.c:51
static const WCHAR dummyW[]
Definition: directory.c:79
static const WCHAR dotW[]
Definition: directory.c:80
static DWORD dstlen
Definition: directory.c:51
DWORD exp
Definition: msg.c:16058
#define min(a, b)
Definition: monoChain.cc:55
#define argv
Definition: mplay32.c:18
LANGID langid
Definition: msctf.idl:626
__int3264 LONG_PTR
Definition: mstsclib_h.h:276
unsigned int UINT
Definition: ndis.h:50
_In_ LPWSTR _In_ DWORD _In_ DWORD _In_ DWORD dwFlags
Definition: netsh.h:141
WCHAR NTAPI RtlUpcaseUnicodeChar(_In_ WCHAR Source)
Definition: nlsboot.c:176
#define PAGE_READWRITE
Definition: nt_native.h:1307
#define KEY_READ
Definition: nt_native.h:1026
#define BOOL
Definition: nt_native.h:43
NTSYSAPI VOID NTAPI RtlFreeUnicodeString(PUNICODE_STRING UnicodeString)
#define KEY_WRITE
Definition: nt_native.h:1034
#define MEM_RELEASE
Definition: nt_native.h:1319
#define DWORD
Definition: nt_native.h:44
#define MEM_COMMIT
Definition: nt_native.h:1316
#define PAGE_NOACCESS
Definition: nt_native.h:1305
#define LOCALE_NEUTRAL
#define LOCALE_NAME_MAX_LENGTH
#define SORT_JAPANESE_UNICODE
#define LANG_FULAH
#define LOCALE_CUSTOM_UNSPECIFIED
#define LANG_SYSTEM_DEFAULT
#define LOCALE_USER_DEFAULT
#define SUBLANG_FULAH_SENEGAL
#define LOCALE_INVARIANT
#define LOCALE_CUSTOM_DEFAULT
#define SORTIDFROMLCID(lcid)
#define SUBLANG_SERBIAN_SERBIA_CYRILLIC
#define LOCALE_SYSTEM_DEFAULT
#define LANG_TIGRINYA
#define SORT_DEFAULT
#define SUBLANG_TIGRINYA_ERITREA
#define MAKELCID(lgid, srtid)
#define SORT_GERMAN_PHONE_BOOK
#define SUBLANG_SERBIAN_SERBIA_LATIN
#define LOCALE_CUSTOM_UI_DEFAULT
#define STATUS_NO_UNICODE_TRANSLATION
Definition: ntstatus.h:1320
#define STATUS_INVALID_PARAMETER_2
Definition: ntstatus.h:570
#define STATUS_INVALID_PARAMETER_1
Definition: ntstatus.h:569
#define STATUS_INVALID_PARAMETER_3
Definition: ntstatus.h:571
#define BOOLEAN
Definition: pedump.c:73
long LONG
Definition: pedump.c:60
unsigned short USHORT
Definition: pedump.c:61
#define IsEqualIID(riid1, riid2)
Definition: guiddef.h:95
#define err(...)
#define wine_dbgstr_wn
Definition: testlist.c:2
void func_name(void)
const WCHAR * str
#define offsetof(TYPE, MEMBER)
return succeed
Definition: scsi.h:3782
#define SUBLANG_SPANISH
Definition: nls.h:336
#define SUBLANG_ARABIC_KUWAIT
Definition: nls.h:190
#define SUBLANG_ITALIAN
Definition: nls.h:269
#define SUBLANG_DUTCH
Definition: nls.h:220
#define SUBLANG_JAPANESE_JAPAN
Definition: nls.h:271
#define LANG_THAI
Definition: nls.h:132
#define SUBLANG_SERBIAN_LATIN
Definition: nls.h:329
#define SUBLANG_TAMAZIGHT_ALGERIA_LATIN
Definition: nls.h:362
#define MAKELANGID(p, s)
Definition: nls.h:15
#define SUBLANG_SERBIAN_CROATIA
Definition: nls.h:328
#define LANG_CHINESE_SIMPLIFIED
Definition: nls.h:43
#define LANG_INUKTITUT
Definition: nls.h:73
#define LANG_SPANISH
Definition: nls.h:123
#define LANG_POLISH
Definition: nls.h:107
#define LANG_AZERI
Definition: nls.h:32
#define LANG_GERMAN
Definition: nls.h:62
#define SUBLANG_ARABIC_UAE
Definition: nls.h:191
#define LANG_HEBREW
Definition: nls.h:67
#define LANG_CHINESE_TRADITIONAL
Definition: nls.h:44
#define SUBLANG_ENGLISH_UK
Definition: nls.h:223
#define SUBLANG_ARABIC_SYRIA
Definition: nls.h:187
#define SUBLANG_PORTUGUESE_BRAZILIAN
Definition: nls.h:308
#define SUBLANG_ARABIC_SAUDI_ARABIA
Definition: nls.h:178
#define LANG_PERSIAN
Definition: nls.h:106
#define SUBLANG_SWEDISH
Definition: nls.h:358
#define SUBLANG_MALAY_MALAYSIA
Definition: nls.h:288
#define SUBLANG_SINDHI_AFGHANISTAN
Definition: nls.h:331
#define LANG_URDU
Definition: nls.h:141
#define SUBLANG_ARABIC_IRAQ
Definition: nls.h:179
#define SUBLANG_GERMAN
Definition: nls.h:251
#define LANG_ENGLISH
Definition: nls.h:52
#define LANGIDFROMLCID(l)
Definition: nls.h:18
#define SUBLANG_CHINESE_TRADITIONAL
Definition: nls.h:208
#define SUBLANG_NEUTRAL
Definition: nls.h:167
#define LANG_MALAY
Definition: nls.h:92
#define LANG_BENGALI
Definition: nls.h:36
#define LANG_DUTCH
Definition: nls.h:51
#define SUBLANG_CHINESE_SIMPLIFIED
Definition: nls.h:209
#define SUBLANG_DEFAULT
Definition: nls.h:168
#define SUBLANG_ARABIC_QATAR
Definition: nls.h:193
#define SUBLANG_ARABIC_OMAN
Definition: nls.h:185
#define LANG_RUSSIAN
Definition: nls.h:113
#define SUBLANG_ARABIC_LEBANON
Definition: nls.h:189
#define SUBLANG_ARABIC_LIBYA
Definition: nls.h:181
#define SUBLANG_ARABIC_JORDAN
Definition: nls.h:188
#define LANG_SWEDISH
Definition: nls.h:125
#define SUBLANG_URDU_PAKISTAN
Definition: nls.h:376
#define LANG_ARABIC
Definition: nls.h:29
#define SUBLANG_CHINESE_HONGKONG
Definition: nls.h:210
#define LANG_CHINESE
Definition: nls.h:42
#define LANG_SERBIAN
Definition: nls.h:116
DWORD LCID
Definition: nls.h:13
#define CP_UTF8
Definition: nls.h:20
#define LANG_JAPANESE
Definition: nls.h:76
#define SUBLANG_ARABIC_MOROCCO
Definition: nls.h:183
#define SUBLANG_ARABIC_TUNISIA
Definition: nls.h:184
#define PRIMARYLANGID(l)
Definition: nls.h:16
#define LANG_DIVEHI
Definition: nls.h:50
#define SUBLANG_SPANISH_MODERN
Definition: nls.h:338
#define LANG_SINDHI
Definition: nls.h:118
#define LANG_INVARIANT
Definition: nls.h:23
#define SUBLANG_ARABIC_EGYPT
Definition: nls.h:180
#define SUBLANG_ARABIC_YEMEN
Definition: nls.h:186
#define LANG_KOREAN
Definition: nls.h:84
#define LANG_TAMAZIGHT
Definition: nls.h:128
#define LANG_FRENCH
Definition: nls.h:58
#define LANG_UZBEK
Definition: nls.h:142
#define SUBLANG_ARABIC_ALGERIA
Definition: nls.h:182
#define SUBLANG_INUKTITUT_CANADA_LATIN
Definition: nls.h:267
#define SUBLANG_ENGLISH_US
Definition: nls.h:222
#define LANG_ITALIAN
Definition: nls.h:75
#define LANG_PORTUGUESE
Definition: nls.h:108
#define SUBLANG_KOREAN
Definition: nls.h:280
#define SUBLANG_ARABIC_BAHRAIN
Definition: nls.h:192
#define SUBLANG_IRISH_IRELAND
Definition: nls.h:268
#define SUBLANG_UZBEK_LATIN
Definition: nls.h:378
#define LANG_IRISH
Definition: nls.h:74
#define SUBLANG_BENGALI_BANGLADESH
Definition: nls.h:202
#define SUBLANG_AZERI_LATIN
Definition: nls.h:196
#define LANG_SERBIAN_NEUTRAL
Definition: nls.h:117
wcscpy
strcpy
Definition: string.h:131
#define is_reactos()
Definition: test.h:1041
int winetest_get_mainargs(char ***pargv)
XML_HIDDEN void xmlParserErrors const char const xmlChar const xmlChar * str2
Definition: parser.h:35
XML_HIDDEN void xmlParserErrors const char const xmlChar * str1
Definition: parser.h:35
#define memset(x, y, z)
Definition: compat.h:39
#define _WIN32_WINNT_VISTA
Definition: sdkddkver.h:25
PCWSTR s2
Definition: shell32_main.h:38
#define STATUS_SUCCESS
Definition: shellext.h:65
#define STATUS_BUFFER_TOO_SMALL
Definition: shellext.h:69
TCHAR str_buf[MAX_LOADSTRING]
Definition: sndrec32.cpp:60
WORD wMilliseconds
Definition: minwinbase.h:263
WORD wSecond
Definition: minwinbase.h:262
WORD wMinute
Definition: minwinbase.h:261
WORD wDayOfWeek
Definition: minwinbase.h:258
DWORD dwPageSize
Definition: winbase.h:898
BYTE LeadByte[MAX_LEADBYTES]
Definition: winnls.h:652
BYTE DefaultChar[MAX_DEFAULTCHAR]
Definition: winnls.h:651
UINT MaxCharSize
Definition: winnls.h:650
UINT CodePage
Definition: winnls.h:659
WCHAR UnicodeDefaultChar
Definition: winnls.h:666
BYTE DefaultChar[MAX_DEFAULTCHAR]
Definition: winnls.h:664
WCHAR CodePageName[MAX_PATH]
Definition: winnls.h:668
UINT MaxCharSize
Definition: winnls.h:663
BYTE LeadByte[MAX_LEADBYTES]
Definition: winnls.h:665
UINT CodePage
Definition: winnls.h:667
Definition: locale.c:1842
int second_len
Definition: locale.c:1848
const char * second
Definition: locale.c:1847
int first_len
Definition: locale.c:1846
LCID lcid
Definition: locale.c:1843
int ret
Definition: locale.c:1849
const char * first
Definition: locale.c:1845
DWORD flags
Definition: locale.c:1844
DWORD le
Definition: locale.c:1850
const char * locale
Definition: locale.c:2145
const WCHAR second[2]
Definition: locale.c:2148
Definition: dsound.c:943
Definition: format.c:58
Definition: locale.c:6578
const char * expect
Definition: locale.c:6581
const char * name
Definition: locale.c:6579
int id
Definition: locale.c:6580
const char * expect2
Definition: locale.c:6581
Definition: copy.c:22
Definition: parser.c:49
Definition: name.c:39
WCHAR sname_broken[15]
Definition: locale.c:357
Definition: locale.c:3531
const WCHAR * second
Definition: locale.c:3537
int result_compare
Definition: locale.c:3534
DWORD flags
Definition: locale.c:3535
const WCHAR * locale
Definition: locale.c:3532
const WCHAR * first
Definition: locale.c:3536
int result_sortkey
Definition: locale.c:3533
Definition: ps.c:97
Definition: cmds.c:130
#define max(a, b)
Definition: svc.c:63
#define LANG_USER_DEFAULT
Definition: tnerror.cpp:50
ULONG_PTR SIZE_T
Definition: typedefs.h:80
int32_t INT
Definition: typedefs.h:58
uint32_t ULONG
Definition: typedefs.h:59
#define STATUS_UNSUCCESSFUL
Definition: udferr_usr.h:132
#define STATUS_OBJECT_NAME_NOT_FOUND
Definition: udferr_usr.h:149
Definition: pdh_main.c:96
static struct WINE_WAVEMAP * oss
Definition: wavemap.c:1190
static const WCHAR lang[]
Definition: wbemdisp.c:287
wchar_t tm const _CrtWcstime_Writes_and_advances_ptr_ count wchar_t ** out
Definition: wcsftime.cpp:383
_In_ WDFCOLLECTION _In_ WDFOBJECT Item
_Must_inspect_result_ _In_ WDFKEY _In_ PCUNICODE_STRING _Out_opt_ PUSHORT _Inout_opt_ PUNICODE_STRING Value
Definition: wdfregistry.h:413
@ undefined
Definition: whoami.c:26
LPVOID NTAPI VirtualAlloc(IN LPVOID lpAddress, IN SIZE_T dwSize, IN DWORD flAllocationType, IN DWORD flProtect)
Definition: virtmem.c:65
BOOL NTAPI VirtualProtect(IN LPVOID lpAddress, IN SIZE_T dwSize, IN DWORD flNewProtect, OUT PDWORD lpflOldProtect)
Definition: virtmem.c:135
BOOL NTAPI VirtualFree(IN LPVOID lpAddress, IN SIZE_T dwSize, IN DWORD dwFreeType)
Definition: virtmem.c:119
#define success(from, fromstr, to, tostr)
DWORD WINAPI GetLastError(void)
Definition: except.c:1042
#define WINAPI
Definition: msvc.h:6
#define ERROR_INVALID_FLAGS
Definition: winerror.h:907
#define LGRPID_INSTALLED
Definition: winnls.h:502
#define LOCALE_USE_CP_ACP
Definition: winnls.h:20
#define LOCALE_SABBREVMONTHNAME10
Definition: winnls.h:120
#define LOCALE_SMONTHNAME12
Definition: winnls.h:109
#define LOCALE_ICURRDIGITS
Definition: winnls.h:61
#define LOCALE_IDEFAULTCODEPAGE
Definition: winnls.h:44
#define LCID_ALTERNATE_SORTS
Definition: winnls.h:216
#define NORM_IGNORECASE
Definition: winnls.h:187
#define LOCALE_ALLOW_NEUTRAL_NAMES
Definition: winnls.h:25
#define LOCALE_SMONTHNAME5
Definition: winnls.h:102
#define LOCALE_SCOUNTRY
Definition: winnls.h:37
#define LOCALE_SDATE
Definition: winnls.h:65
#define LOCALE_SDAYNAME5
Definition: winnls.h:88
@ NormalizationKC
Definition: winnls.h:727
@ NormalizationKD
Definition: winnls.h:728
@ NormalizationD
Definition: winnls.h:726
@ NormalizationC
Definition: winnls.h:725
#define C3_NOTAPPLICABLE
Definition: winnls.h:292
DWORD LGRPID
Definition: winnls.h:584
#define LOCALE_SABBREVMONTHNAME9
Definition: winnls.h:119
BOOL(CALLBACK * LOCALE_ENUMPROCEX)(LPWSTR, DWORD, LPARAM)
Definition: winnls.h:603
BOOL(CALLBACK * LANGGROUPLOCALE_ENUMPROCA)(LGRPID, LCID, LPSTR, LONG_PTR)
Definition: winnls.h:597
enum _NORM_FORM NORM_FORM
#define LOCALE_SABBREVMONTHNAME11
Definition: winnls.h:121
DWORD CALID
Definition: winnls.h:583
#define LOCALE_SABBREVDAYNAME5
Definition: winnls.h:95
#define LOCALE_SABBREVDAYNAME2
Definition: winnls.h:92
#define LOCALE_INEGSEPBYSPACE
Definition: winnls.h:131
#define LOCALE_SABBREVMONTHNAME2
Definition: winnls.h:112
#define LOCALE_INEGSIGNPOSN
Definition: winnls.h:127
#define MAP_FOLDDIGITS
Definition: winnls.h:232
#define LOCALE_SMONTHNAME13
Definition: winnls.h:110
#define LCID_INSTALLED
Definition: winnls.h:214
#define LOCALE_SGROUPING
Definition: winnls.h:51
#define LOCALE_SMONTHNAME3
Definition: winnls.h:100
#define SORT_STRINGSORT
Definition: winnls.h:195
#define LOCALE_SSHORTTIME
Definition: winnls.h:170
#define LOCALE_ICOUNTRY
Definition: winnls.h:36
#define CAL_UMALQURA
Definition: winnls.h:498
#define LINGUISTIC_IGNORECASE
Definition: winnls.h:192
#define LCMAP_SIMPLIFIED_CHINESE
Definition: winnls.h:206
#define CP_SYMBOL
Definition: winnls.h:252
#define LOCALE_SDECIMAL
Definition: winnls.h:49
#define LOCALE_SMONTHNAME11
Definition: winnls.h:108
#define LOCALE_SMONTHNAME8
Definition: winnls.h:105
@ GEO_ISO3
Definition: winnls.h:631
@ GEO_ISO_UN_NUMBER
Definition: winnls.h:638
@ GEO_PARENT
Definition: winnls.h:639
@ GEO_ISO2
Definition: winnls.h:630
@ GEO_ID
Definition: winnls.h:645
@ GEO_NATION
Definition: winnls.h:627
@ GEO_LCID
Definition: winnls.h:633
#define LCMAP_TRADITIONAL_CHINESE
Definition: winnls.h:207
#define LGRPID_ARMENIAN
Definition: winnls.h:520
#define CT_CTYPE3
Definition: winnls.h:257
#define CT_CTYPE1
Definition: winnls.h:255
#define IS_HIGH_SURROGATE(ch)
Definition: winnls.h:752
#define LOCALE_IDATE
Definition: winnls.h:70
#define LOCALE_SMONTHNAME4
Definition: winnls.h:101
#define LOCALE_SNATIVECTRYNAME
Definition: winnls.h:41
#define LOCALE_SENGLANGUAGE
Definition: winnls.h:32
#define MAP_PRECOMPOSED
Definition: winnls.h:233
#define LOCALE_SABBREVMONTHNAME13
Definition: winnls.h:123
#define LOCALE_IFIRSTWEEKOFYEAR
Definition: winnls.h:83
#define LCMAP_HALFWIDTH
Definition: winnls.h:203
#define LOCALE_SDAYNAME1
Definition: winnls.h:84
#define LOCALE_IMEASURE
Definition: winnls.h:48
#define LCMAP_HIRAGANA
Definition: winnls.h:201
#define LOCALE_ILANGUAGE
Definition: winnls.h:30
#define LOCALE_SNAME
Definition: winnls.h:137
#define LCMAP_UPPERCASE
Definition: winnls.h:198
#define LOCALE_SNATIVELANGNAME
Definition: winnls.h:35
#define LOCALE_SLONGDATE
Definition: winnls.h:68
#define LOCALE_SMONTHNAME7
Definition: winnls.h:104
#define CAL_ICALINTVALUE
Definition: winnls.h:415
#define C3_LOWSURROGATE
Definition: winnls.h:294
#define NORM_IGNOREKANATYPE
Definition: winnls.h:188
#define NORM_LINGUISTIC_CASING
Definition: winnls.h:194
#define LOCALE_IINTLCURRDIGITS
Definition: winnls.h:62
#define LOCALE_S1159
Definition: winnls.h:78
#define LOCALE_SSHORTDATE
Definition: winnls.h:67
#define CSTR_EQUAL
Definition: winnls.h:500
BOOL(CALLBACK * GEO_ENUMPROC)(GEOID)
Definition: winnls.h:612
#define NORM_IGNORENONSPACE
Definition: winnls.h:189
#define TIME_NOTIMEMARKER
Definition: winnls.h:297
#define TIME_NOMINUTESORSECONDS
Definition: winnls.h:295
#define LOCALE_IPOSSYMPRECEDES
Definition: winnls.h:128
#define LOCALE_IDAYLZERO
Definition: winnls.h:76
#define CP_UTF7
Definition: winnls.h:253
#define LOCALE_SABBREVMONTHNAME4
Definition: winnls.h:114
#define C1_DEFINED
Definition: winnls.h:267
#define LOCALE_SPOSITIVESIGN
Definition: winnls.h:124
#define NORM_IGNORESYMBOLS
Definition: winnls.h:190
#define LOCALE_IDEFAULTLANGUAGE
Definition: winnls.h:42
#define CAL_GREGORIAN
Definition: winnls.h:485
#define LOCALE_SABBREVDAYNAME4
Definition: winnls.h:94
#define LOCALE_SMONDECIMALSEP
Definition: winnls.h:58
#define LGRPID_WESTERN_EUROPE
Definition: winnls.h:504
#define LOCALE_SISO639LANGNAME
Definition: winnls.h:133
#define LCMAP_SORTKEY
Definition: winnls.h:199
#define LINGUISTIC_IGNOREDIACRITIC
Definition: winnls.h:193
#define MAP_COMPOSITE
Definition: winnls.h:234
#define LCMAP_LOWERCASE
Definition: winnls.h:197
#define LOCALE_ITIME
Definition: winnls.h:72
#define LOCALE_ICURRENCY
Definition: winnls.h:63
#define C3_KASHIDA
Definition: winnls.h:289
#define LOCALE_SMONTHNAME1
Definition: winnls.h:98
#define LOCALE_SABBREVMONTHNAME3
Definition: winnls.h:113
#define LOCALE_ITLZERO
Definition: winnls.h:75
#define LOCALE_INEGSYMPRECEDES
Definition: winnls.h:130
BOOL(CALLBACK * LOCALE_ENUMPROCA)(LPSTR)
Definition: winnls.h:601
#define LOCALE_SLANGUAGE
Definition: winnls.h:31
#define LOCALE_SMONTHOUSANDSEP
Definition: winnls.h:59
#define LOCALE_SDAYNAME7
Definition: winnls.h:90
#define LOCALE_IPOSSIGNPOSN
Definition: winnls.h:126
#define LOCALE_SDAYNAME2
Definition: winnls.h:85
#define LOCALE_SABBREVMONTHNAME1
Definition: winnls.h:111
DWORD GEOCLASS
Definition: winnls.h:587
#define LOCALE_NOUSEROVERRIDE
Definition: winnls.h:19
#define LOCALE_IOPTIONALCALENDAR
Definition: winnls.h:81
#define LOCALE_IDIGITS
Definition: winnls.h:52
#define MAP_FOLDCZONE
Definition: winnls.h:231
#define LCID_SUPPORTED
Definition: winnls.h:215
#define LOCALE_STHOUSAND
Definition: winnls.h:50
#define LOCALE_IDEFAULTANSICODEPAGE
Definition: winnls.h:45
#define LOCALE_SISO3166CTRYNAME
Definition: winnls.h:134
#define LOCALE_SABBREVDAYNAME6
Definition: winnls.h:96
#define LOCALE_SMONTHNAME2
Definition: winnls.h:99
#define LOCALE_ALL
Definition: winnls.h:223
#define LOCALE_STIMEFORMAT
Definition: winnls.h:69
#define IS_LOW_SURROGATE(ch)
Definition: winnls.h:753
BOOL(CALLBACK * LANGUAGEGROUP_ENUMPROCA)(LGRPID, LPSTR, LPSTR, DWORD, LONG_PTR)
Definition: winnls.h:595
#define LOCALE_SABBREVDAYNAME1
Definition: winnls.h:91
#define ENUM_ALL_CALENDARS
Definition: winnls.h:208
#define LOCALE_IFIRSTDAYOFWEEK
Definition: winnls.h:82
#define LOCALE_SABBREVMONTHNAME6
Definition: winnls.h:116
#define LOCALE_SMONTHNAME6
Definition: winnls.h:103
#define LOCALE_STIME
Definition: winnls.h:66
#define SORT_DIGITSASNUMBERS
Definition: winnls.h:196
#define NORM_IGNOREWIDTH
Definition: winnls.h:191
#define LOCALE_SABBREVLANGNAME
Definition: winnls.h:34
#define LOCALE_SENGCOUNTRY
Definition: winnls.h:38
#define C3_HIGHSURROGATE
Definition: winnls.h:293
BOOL(CALLBACK * UILANGUAGE_ENUMPROCA)(LPSTR, LONG_PTR)
Definition: winnls.h:600
#define LOCALE_SABBREVCTRYNAME
Definition: winnls.h:40
#define LOCALE_INEGNUMBER
Definition: winnls.h:54
#define LOCALE_SNEGATIVESIGN
Definition: winnls.h:125
#define LOCALE_IDEFAULTCOUNTRY
Definition: winnls.h:43
#define TIME_FORCE24HOURFORMAT
Definition: winnls.h:298
#define LOCALE_SDAYNAME3
Definition: winnls.h:86
#define CSTR_LESS_THAN
Definition: winnls.h:499
#define LOCALE_S2359
Definition: winnls.h:79
#define LOCALE_SNATIVEDIGITS
Definition: winnls.h:55
#define LOCALE_SLIST
Definition: winnls.h:47
#define LOCALE_SABBREVDAYNAME3
Definition: winnls.h:93
#define LOCALE_ILZERO
Definition: winnls.h:53
#define LOCALE_SABBREVMONTHNAME5
Definition: winnls.h:115
#define LOCALE_SABBREVMONTHNAME7
Definition: winnls.h:117
#define LOCALE_ICALENDARTYPE
Definition: winnls.h:80
#define LOCALE_SINTLSYMBOL
Definition: winnls.h:57
BOOL(CALLBACK * LOCALE_ENUMPROCW)(LPWSTR)
Definition: winnls.h:602
#define LOCALE_SABBREVMONTHNAME8
Definition: winnls.h:118
#define LCMAP_KATAKANA
Definition: winnls.h:202
#define CSTR_GREATER_THAN
Definition: winnls.h:501
#define LOCALE_SMONGROUPING
Definition: winnls.h:60
#define LOCALE_SDAYNAME4
Definition: winnls.h:87
#define TIME_NOSECONDS
Definition: winnls.h:296
#define LOCALE_SCURRENCY
Definition: winnls.h:56
#define LOCALE_SMONTHNAME10
Definition: winnls.h:107
#define LOCALE_INEGCURR
Definition: winnls.h:64
#define LOCALE_ILDATE
Definition: winnls.h:71
#define LCMAP_FULLWIDTH
Definition: winnls.h:204
#define LOCALE_SMONTHNAME9
Definition: winnls.h:106
#define DATE_LONGDATE
Definition: winnls.h:210
#define LOCALE_IPOSSEPBYSPACE
Definition: winnls.h:129
#define LOCALE_ICENTURY
Definition: winnls.h:74
#define LOCALE_IMONLZERO
Definition: winnls.h:77
@ GEOCLASS_REGION
Definition: winnls.h:620
@ GEOCLASS_NATION
Definition: winnls.h:621
@ GEOCLASS_ALL
Definition: winnls.h:619
#define LOCALE_SABBREVMONTHNAME12
Definition: winnls.h:122
#define LOCALE_IDEFAULTMACCODEPAGE
Definition: winnls.h:46
#define LGRPID_SUPPORTED
Definition: winnls.h:503
NLS_FUNCTION
Definition: winnls.h:614
@ COMPARE_STRING
Definition: winnls.h:615
#define LOCALE_SDAYNAME6
Definition: winnls.h:89
#define LOCALE_ITIMEMARKPOSN
Definition: winnls.h:73
#define LOCALE_RETURN_GENITIVE_NAMES
Definition: winnls.h:24
#define DATE_SHORTDATE
Definition: winnls.h:209
#define LOCALE_SABBREVDAYNAME7
Definition: winnls.h:97
#define HKEY_CURRENT_USER
Definition: winreg.h:11
static void set_name(msft_typelib_t *typelib)
Definition: write_msft.c:2498
DWORD Returned
Definition: ws2tcpip.h:624
const WCHAR * LPCWSTR
Definition: xmlstorage.h:185
__wchar_t WCHAR
Definition: xmlstorage.h:180
WCHAR * LPWSTR
Definition: xmlstorage.h:184
char * LPSTR
Definition: xmlstorage.h:182
char CHAR
Definition: xmlstorage.h:175
unsigned char BYTE
Definition: xxhash.c:193