[CMAKE]
[reactos.git] / dll / win32 / kernel32 / misc / lang.c
1 /*
2 *
3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS system libraries
5 * FILE: dll/win32/kernel32/file/lang.c
6 * PURPOSE: National Laguage Support related funcs
7 * PROGRAMMER: Thomas Weidenmueller
8 * Gunnar Andre Dalsnes
9 * Aleksey Bragin
10 * Eric Kohl
11 * Alex Ionescu
12 * Richard Campbell
13 * James Tabor
14 * Dmitry Chapyshev
15 * UPDATE HISTORY:
16 * Created 21/09/2003
17 */
18
19 #include <k32.h>
20 #include <winnls.h>
21
22 #define NDEBUG
23 #include <debug.h>
24
25 #include "lcformat_private.h"
26
27 #define LOCALE_LOCALEINFOFLAGSMASK (LOCALE_NOUSEROVERRIDE|LOCALE_USE_CP_ACP|\
28 LOCALE_RETURN_NUMBER|LOCALE_RETURN_GENITIVE_NAMES)
29 #define CALINFO_MAX_YEAR 2029
30
31 //static LCID SystemLocale = MAKELCID(LANG_ENGLISH, SORT_DEFAULT);
32
33 //static RTL_CRITICAL_SECTION LocalesListLock;
34
35 extern int wine_fold_string(int flags, const WCHAR *src, int srclen, WCHAR *dst, int dstlen);
36 extern int wine_get_sortkey(int flags, const WCHAR *src, int srclen, char *dst, int dstlen);
37 extern int wine_compare_string(int flags, const WCHAR *str1, int len1, const WCHAR *str2, int len2);
38
39 typedef struct
40 {
41 union
42 {
43 UILANGUAGE_ENUMPROCA procA;
44 UILANGUAGE_ENUMPROCW procW;
45 } u;
46 DWORD flags;
47 LONG_PTR param;
48 } ENUM_UILANG_CALLBACK;
49
50 static const WCHAR szLocaleKeyName[] = L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\NLS\\Locale";
51 static const WCHAR szLangGroupsKeyName[] = L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\NLS\\Language Groups";
52
53 /***********************************************************************
54 * is_genitive_name_supported
55 *
56 * Determine could LCTYPE basically support genitive name form or not.
57 */
58 static BOOL is_genitive_name_supported( LCTYPE lctype )
59 {
60 switch(lctype & 0xffff)
61 {
62 case LOCALE_SMONTHNAME1:
63 case LOCALE_SMONTHNAME2:
64 case LOCALE_SMONTHNAME3:
65 case LOCALE_SMONTHNAME4:
66 case LOCALE_SMONTHNAME5:
67 case LOCALE_SMONTHNAME6:
68 case LOCALE_SMONTHNAME7:
69 case LOCALE_SMONTHNAME8:
70 case LOCALE_SMONTHNAME9:
71 case LOCALE_SMONTHNAME10:
72 case LOCALE_SMONTHNAME11:
73 case LOCALE_SMONTHNAME12:
74 case LOCALE_SMONTHNAME13:
75 return TRUE;
76 default:
77 return FALSE;
78 }
79 }
80
81 /***********************************************************************
82 * create_registry_key
83 *
84 * Create the Control Panel\\International registry key.
85 */
86 static inline HANDLE create_registry_key(void)
87 {
88 static const WCHAR intlW[] = {'C','o','n','t','r','o','l',' ','P','a','n','e','l','\\',
89 'I','n','t','e','r','n','a','t','i','o','n','a','l',0};
90 OBJECT_ATTRIBUTES attr;
91 UNICODE_STRING nameW;
92 HANDLE hkey;
93
94 if (RtlOpenCurrentUser( KEY_ALL_ACCESS, &hkey ) != STATUS_SUCCESS) return 0;
95
96 attr.Length = sizeof(attr);
97 attr.RootDirectory = hkey;
98 attr.ObjectName = &nameW;
99 attr.Attributes = 0;
100 attr.SecurityDescriptor = NULL;
101 attr.SecurityQualityOfService = NULL;
102 RtlInitUnicodeString( &nameW, intlW );
103
104 if (NtCreateKey( &hkey, KEY_ALL_ACCESS, &attr, 0, NULL, 0, NULL ) != STATUS_SUCCESS) hkey = 0;
105 NtClose( attr.RootDirectory );
106 return hkey;
107 }
108
109 /******************************************************************************
110 * @implemented
111 * RIPPED FROM WINE's dlls\kernel\locale.c rev 1.42
112 *
113 * ConvertDefaultLocale (KERNEL32.@)
114 *
115 * Convert a default locale identifier into a real identifier.
116 *
117 * PARAMS
118 * lcid [I] LCID identifier of the locale to convert
119 *
120 * RETURNS
121 * lcid unchanged, if not a default locale or its sublanguage is
122 * not SUBLANG_NEUTRAL.
123 * GetSystemDefaultLCID(), if lcid == LOCALE_SYSTEM_DEFAULT.
124 * GetUserDefaultLCID(), if lcid == LOCALE_USER_DEFAULT or LOCALE_NEUTRAL.
125 * Otherwise, lcid with sublanguage changed to SUBLANG_DEFAULT.
126 */
127 LCID WINAPI
128 ConvertDefaultLocale(LCID lcid)
129 {
130 LANGID langid;
131
132 switch (lcid)
133 {
134 case LOCALE_SYSTEM_DEFAULT:
135 lcid = GetSystemDefaultLCID();
136 break;
137
138 case LOCALE_USER_DEFAULT:
139 case LOCALE_NEUTRAL:
140 lcid = GetUserDefaultLCID();
141 break;
142
143 default:
144 /* Replace SUBLANG_NEUTRAL with SUBLANG_DEFAULT */
145 langid = LANGIDFROMLCID(lcid);
146 if (SUBLANGID(langid) == SUBLANG_NEUTRAL)
147 {
148 langid = MAKELANGID(PRIMARYLANGID(langid), SUBLANG_DEFAULT);
149 lcid = MAKELCID(langid, SORTIDFROMLCID(lcid));
150 }
151 }
152
153 return lcid;
154 }
155
156
157 static BOOL NLS_RegEnumValue(HANDLE hKey, UINT ulIndex,
158 LPWSTR szValueName, ULONG valueNameSize,
159 LPWSTR szValueData, ULONG valueDataSize)
160 {
161 BYTE buffer[80];
162 KEY_VALUE_FULL_INFORMATION *info = (KEY_VALUE_FULL_INFORMATION *)buffer;
163 DWORD dwLen;
164
165 if (NtEnumerateValueKey( hKey, ulIndex, KeyValueFullInformation,
166 buffer, sizeof(buffer), &dwLen ) != STATUS_SUCCESS ||
167 info->NameLength > valueNameSize ||
168 info->DataLength > valueDataSize)
169 {
170 return FALSE;
171 }
172
173 DPRINT("info->Name %s info->DataLength %d\n", info->Name, info->DataLength);
174
175 memcpy( szValueName, info->Name, info->NameLength);
176 szValueName[info->NameLength / sizeof(WCHAR)] = '\0';
177 memcpy( szValueData, buffer + info->DataOffset, info->DataLength );
178 szValueData[info->DataLength / sizeof(WCHAR)] = '\0';
179
180 DPRINT("returning %s %s\n", szValueName, szValueData);
181 return TRUE;
182 }
183
184
185 static HANDLE NLS_RegOpenKey(HANDLE hRootKey, LPCWSTR szKeyName)
186 {
187 UNICODE_STRING keyName;
188 OBJECT_ATTRIBUTES attr;
189 HANDLE hkey;
190
191 RtlInitUnicodeString( &keyName, szKeyName );
192 InitializeObjectAttributes(&attr, &keyName, OBJ_CASE_INSENSITIVE, hRootKey, NULL);
193
194 if (NtOpenKey( &hkey, KEY_ALL_ACCESS, &attr ) != STATUS_SUCCESS)
195 {
196 SetLastError( ERROR_BADDB );
197 hkey = 0;
198 }
199
200 return hkey;
201 }
202
203 static BOOL NLS_RegEnumSubKey(HANDLE hKey, UINT ulIndex, LPWSTR szKeyName,
204 ULONG keyNameSize)
205 {
206 BYTE buffer[80];
207 KEY_BASIC_INFORMATION *info = (KEY_BASIC_INFORMATION *)buffer;
208 DWORD dwLen;
209
210 if (NtEnumerateKey( hKey, ulIndex, KeyBasicInformation, buffer,
211 sizeof(buffer), &dwLen) != STATUS_SUCCESS ||
212 info->NameLength > keyNameSize)
213 {
214 return FALSE;
215 }
216
217 DPRINT("info->Name %s info->NameLength %d\n", info->Name, info->NameLength);
218
219 memcpy( szKeyName, info->Name, info->NameLength);
220 szKeyName[info->NameLength / sizeof(WCHAR)] = '\0';
221
222 DPRINT("returning %s\n", szKeyName);
223 return TRUE;
224 }
225
226 static BOOL NLS_RegGetDword(HANDLE hKey, LPCWSTR szValueName, DWORD *lpVal)
227 {
228 BYTE buffer[128];
229 const KEY_VALUE_PARTIAL_INFORMATION *info = (KEY_VALUE_PARTIAL_INFORMATION *)buffer;
230 DWORD dwSize = sizeof(buffer);
231 UNICODE_STRING valueName;
232
233 RtlInitUnicodeString( &valueName, szValueName );
234
235 DPRINT("%p, %s\n", hKey, szValueName);
236 if (NtQueryValueKey( hKey, &valueName, KeyValuePartialInformation,
237 buffer, dwSize, &dwSize ) == STATUS_SUCCESS &&
238 info->DataLength == sizeof(DWORD))
239 {
240 memcpy(lpVal, info->Data, sizeof(DWORD));
241 return TRUE;
242 }
243
244 return FALSE;
245 }
246
247 static BOOL NLS_GetLanguageGroupName(LGRPID lgrpid, LPWSTR szName, ULONG nameSize)
248 {
249 LANGID langId;
250 LPCWSTR szResourceName = MAKEINTRESOURCEW(((lgrpid + 0x2000) >> 4) + 1);
251 HRSRC hResource;
252 BOOL bRet = FALSE;
253
254 /* FIXME: Is it correct to use the system default langid? */
255 langId = GetSystemDefaultLangID();
256
257 if (SUBLANGID(langId) == SUBLANG_NEUTRAL)
258 langId = MAKELANGID( PRIMARYLANGID(langId), SUBLANG_DEFAULT );
259
260 hResource = FindResourceExW( hCurrentModule, (LPWSTR)RT_STRING, szResourceName, langId );
261
262 if (hResource)
263 {
264 HGLOBAL hResDir = LoadResource( hCurrentModule, hResource );
265
266 if (hResDir)
267 {
268 ULONG iResourceIndex = lgrpid & 0xf;
269 LPCWSTR lpResEntry = LockResource( hResDir );
270 ULONG i;
271
272 for (i = 0; i < iResourceIndex; i++)
273 lpResEntry += *lpResEntry + 1;
274
275 if (*lpResEntry < nameSize)
276 {
277 memcpy( szName, lpResEntry + 1, *lpResEntry * sizeof(WCHAR) );
278 szName[*lpResEntry] = '\0';
279 bRet = TRUE;
280 }
281
282 }
283 FreeResource( hResource );
284 }
285 else DPRINT1("FindResourceExW() failed\n");
286
287 return bRet;
288 }
289
290
291 /* Callback function ptrs for EnumLanguageGrouplocalesA/W */
292 typedef struct
293 {
294 LANGGROUPLOCALE_ENUMPROCA procA;
295 LANGGROUPLOCALE_ENUMPROCW procW;
296 DWORD dwFlags;
297 LGRPID lgrpid;
298 LONG_PTR lParam;
299 } ENUMLANGUAGEGROUPLOCALE_CALLBACKS;
300
301 /* Internal implementation of EnumLanguageGrouplocalesA/W */
302 static BOOL NLS_EnumLanguageGroupLocales(ENUMLANGUAGEGROUPLOCALE_CALLBACKS *lpProcs)
303 {
304 static const WCHAR szAlternateSortsKeyName[] = {
305 'A','l','t','e','r','n','a','t','e',' ','S','o','r','t','s','\0'
306 };
307 WCHAR szNumber[10], szValue[4];
308 HANDLE hKey;
309 BOOL bContinue = TRUE, bAlternate = FALSE;
310 LGRPID lgrpid;
311 ULONG ulIndex = 1; /* Ignore default entry of 1st key */
312
313 if (!lpProcs || !lpProcs->lgrpid || lpProcs->lgrpid > LGRPID_ARMENIAN)
314 {
315 SetLastError(ERROR_INVALID_PARAMETER);
316 return FALSE;
317 }
318
319 if (lpProcs->dwFlags)
320 {
321 SetLastError(ERROR_INVALID_FLAGS);
322 return FALSE;
323 }
324
325 hKey = NLS_RegOpenKey( 0, szLocaleKeyName );
326
327 if (!hKey)
328 {
329 DPRINT1("NLS_RegOpenKey() failed\n");
330 return FALSE;
331 }
332
333 while (bContinue)
334 {
335 if (NLS_RegEnumValue( hKey, ulIndex, szNumber, sizeof(szNumber),
336 szValue, sizeof(szValue) ))
337 {
338 lgrpid = wcstoul( szValue, NULL, 16 );
339
340 DPRINT("lcid %s, grpid %d (%smatched)\n", szNumber,
341 lgrpid, lgrpid == lpProcs->lgrpid ? "" : "not ");
342
343 if (lgrpid == lpProcs->lgrpid)
344 {
345 LCID lcid;
346
347 lcid = wcstoul( szNumber, NULL, 16 );
348
349 /* FIXME: native returns extra text for a few (17/150) locales, e.g:
350 * '00000437 ;Georgian'
351 * At present we only pass the LCID string.
352 */
353
354 if (lpProcs->procW)
355 bContinue = lpProcs->procW( lgrpid, lcid, szNumber, lpProcs->lParam );
356 else
357 {
358 char szNumberA[sizeof(szNumber)/sizeof(WCHAR)];
359
360 WideCharToMultiByte(CP_ACP, 0, szNumber, -1, szNumberA, sizeof(szNumberA), 0, 0);
361
362 bContinue = lpProcs->procA( lgrpid, lcid, szNumberA, lpProcs->lParam );
363 }
364 }
365
366 ulIndex++;
367 }
368 else
369 {
370 /* Finished enumerating this key */
371 if (!bAlternate)
372 {
373 /* Enumerate alternate sorts also */
374 hKey = NLS_RegOpenKey( hKey, szAlternateSortsKeyName );
375 bAlternate = TRUE;
376 ulIndex = 0;
377 }
378 else
379 bContinue = FALSE; /* Finished both keys */
380 }
381
382 if (!bContinue)
383 break;
384 }
385
386 if (hKey)
387 NtClose( hKey );
388
389 return TRUE;
390 }
391
392
393 /*
394 * @implemented
395 */
396 BOOL
397 WINAPI
398 EnumLanguageGroupLocalesA(
399 LANGGROUPLOCALE_ENUMPROCA lpLangGroupLocaleEnumProc,
400 LGRPID LanguageGroup,
401 DWORD dwFlags,
402 LONG_PTR lParam)
403 {
404 ENUMLANGUAGEGROUPLOCALE_CALLBACKS callbacks;
405
406 DPRINT("(%p,0x%08X,0x%08X,0x%08lX)\n", lpLangGroupLocaleEnumProc, LanguageGroup, dwFlags, lParam);
407
408 callbacks.procA = lpLangGroupLocaleEnumProc;
409 callbacks.procW = NULL;
410 callbacks.dwFlags = dwFlags;
411 callbacks.lgrpid = LanguageGroup;
412 callbacks.lParam = lParam;
413
414 return NLS_EnumLanguageGroupLocales( lpLangGroupLocaleEnumProc ? &callbacks : NULL );
415 }
416
417
418 /*
419 * @implemented
420 */
421 BOOL
422 WINAPI
423 EnumLanguageGroupLocalesW(
424 LANGGROUPLOCALE_ENUMPROCW lpLangGroupLocaleEnumProc,
425 LGRPID LanguageGroup,
426 DWORD dwFlags,
427 LONG_PTR lParam)
428 {
429 ENUMLANGUAGEGROUPLOCALE_CALLBACKS callbacks;
430
431 DPRINT("(%p,0x%08X,0x%08X,0x%08lX)\n", lpLangGroupLocaleEnumProc, LanguageGroup, dwFlags, lParam);
432
433 callbacks.procA = NULL;
434 callbacks.procW = lpLangGroupLocaleEnumProc;
435 callbacks.dwFlags = dwFlags;
436 callbacks.lgrpid = LanguageGroup;
437 callbacks.lParam = lParam;
438
439 return NLS_EnumLanguageGroupLocales( lpLangGroupLocaleEnumProc ? &callbacks : NULL );
440 }
441
442
443 /* Callback function ptrs for EnumSystemCodePagesA/W */
444 typedef struct
445 {
446 CODEPAGE_ENUMPROCA procA;
447 CODEPAGE_ENUMPROCW procW;
448 DWORD dwFlags;
449 } ENUMSYSTEMCODEPAGES_CALLBACKS;
450
451 /* Internal implementation of EnumSystemCodePagesA/W */
452 static BOOL NLS_EnumSystemCodePages(ENUMSYSTEMCODEPAGES_CALLBACKS *lpProcs)
453 {
454 WCHAR szNumber[5 + 1], szValue[MAX_PATH];
455 HANDLE hKey;
456 BOOL bContinue = TRUE;
457 ULONG ulIndex = 0;
458
459 if (!lpProcs)
460 {
461 SetLastError(ERROR_INVALID_PARAMETER);
462 return FALSE;
463 }
464
465 switch (lpProcs->dwFlags)
466 {
467 case CP_INSTALLED:
468 case CP_SUPPORTED:
469 break;
470 default:
471 SetLastError(ERROR_INVALID_FLAGS);
472 return FALSE;
473 }
474
475 hKey = NLS_RegOpenKey(0, L"\\Registry\\Machine\\SYSTEM\\CurrentControlSet\\Control\\NLS\\CodePage");
476 if (!hKey)
477 {
478 DPRINT1("NLS_RegOpenKey() failed\n");
479 return FALSE;
480 }
481
482 while (bContinue)
483 {
484 if (NLS_RegEnumValue(hKey, ulIndex, szNumber, sizeof(szNumber),
485 szValue, sizeof(szValue)))
486 {
487 if ((lpProcs->dwFlags == CP_SUPPORTED)||
488 ((lpProcs->dwFlags == CP_INSTALLED)&&(wcslen(szValue) > 2)))
489 {
490 if (lpProcs->procW)
491 {
492 bContinue = lpProcs->procW(szNumber);
493 }
494 else
495 {
496 char szNumberA[sizeof(szNumber)/sizeof(WCHAR)];
497
498 WideCharToMultiByte(CP_ACP, 0, szNumber, -1, szNumberA, sizeof(szNumberA), 0, 0);
499 bContinue = lpProcs->procA(szNumberA);
500 }
501 }
502
503 ulIndex++;
504
505 } else bContinue = FALSE;
506
507 if (!bContinue)
508 break;
509 }
510
511 if (hKey)
512 NtClose(hKey);
513
514 return TRUE;
515 }
516
517 /*
518 * @implemented
519 */
520 BOOL
521 WINAPI
522 EnumSystemCodePagesW (
523 CODEPAGE_ENUMPROCW lpCodePageEnumProc,
524 DWORD dwFlags
525 )
526 {
527 ENUMSYSTEMCODEPAGES_CALLBACKS procs;
528
529 DPRINT("(%p,0x%08X,0x%08lX)\n", lpCodePageEnumProc, dwFlags);
530
531 procs.procA = NULL;
532 procs.procW = lpCodePageEnumProc;
533 procs.dwFlags = dwFlags;
534
535 return NLS_EnumSystemCodePages(lpCodePageEnumProc ? &procs : NULL);
536 }
537
538
539 /*
540 * @implemented
541 */
542 BOOL
543 WINAPI
544 EnumSystemCodePagesA (
545 CODEPAGE_ENUMPROCA lpCodePageEnumProc,
546 DWORD dwFlags
547 )
548 {
549 ENUMSYSTEMCODEPAGES_CALLBACKS procs;
550
551 DPRINT("(%p,0x%08X,0x%08lX)\n", lpCodePageEnumProc, dwFlags);
552
553 procs.procA = lpCodePageEnumProc;
554 procs.procW = NULL;
555 procs.dwFlags = dwFlags;
556
557 return NLS_EnumSystemCodePages(lpCodePageEnumProc ? &procs : NULL);
558 }
559
560
561 /*
562 * @implemented
563 */
564 BOOL
565 WINAPI
566 EnumSystemGeoID(
567 GEOCLASS GeoClass,
568 GEOID ParentGeoId, // reserved
569 GEO_ENUMPROC lpGeoEnumProc)
570 {
571 WCHAR szNumber[5 + 1];
572 ULONG ulIndex = 0;
573 HANDLE hKey;
574
575 DPRINT("(0x%08X,0x%08X,%p)\n", GeoClass, ParentGeoId, lpGeoEnumProc);
576
577 if(!lpGeoEnumProc || GeoClass != GEOCLASS_NATION)
578 {
579 SetLastError(ERROR_INVALID_PARAMETER);
580 return FALSE;
581 }
582
583 hKey = NLS_RegOpenKey(0, L"\\REGISTRY\\Machine\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Telephony\\Country List");
584 if (!hKey)
585 {
586 DPRINT1("NLS_RegOpenKey() failed\n");
587 return FALSE;
588 }
589
590 while (NLS_RegEnumSubKey(hKey, ulIndex, szNumber, sizeof(szNumber)))
591 {
592 BOOL bContinue = TRUE;
593 DWORD dwGeoId;
594 HANDLE hSubKey = NLS_RegOpenKey(hKey, szNumber);
595
596 if (hSubKey)
597 {
598 if (NLS_RegGetDword(hSubKey, L"CountryCode", &dwGeoId))
599 {
600 if (!lpGeoEnumProc(dwGeoId))
601 bContinue = FALSE;
602 }
603
604 NtClose(hSubKey);
605 }
606
607 if (!bContinue)
608 break;
609
610 ulIndex++;
611 }
612
613 if (hKey)
614 NtClose(hKey);
615
616 return TRUE;
617 }
618
619
620 /* Callback function ptrs for EnumSystemLanguageGroupsA/W */
621 typedef struct
622 {
623 LANGUAGEGROUP_ENUMPROCA procA;
624 LANGUAGEGROUP_ENUMPROCW procW;
625 DWORD dwFlags;
626 LONG_PTR lParam;
627 } ENUMLANGUAGEGROUP_CALLBACKS;
628
629
630 /* Internal implementation of EnumSystemLanguageGroupsA/W */
631 static BOOL NLS_EnumSystemLanguageGroups(ENUMLANGUAGEGROUP_CALLBACKS *lpProcs)
632 {
633 WCHAR szNumber[10], szValue[4];
634 HANDLE hKey;
635 BOOL bContinue = TRUE;
636 ULONG ulIndex = 0;
637
638 if (!lpProcs)
639 {
640 SetLastError(ERROR_INVALID_PARAMETER);
641 return FALSE;
642 }
643
644 switch (lpProcs->dwFlags)
645 {
646 case 0:
647 /* Default to LGRPID_INSTALLED */
648 lpProcs->dwFlags = LGRPID_INSTALLED;
649 /* Fall through... */
650 case LGRPID_INSTALLED:
651 case LGRPID_SUPPORTED:
652 break;
653 default:
654 SetLastError(ERROR_INVALID_FLAGS);
655 return FALSE;
656 }
657
658 hKey = NLS_RegOpenKey( 0, szLangGroupsKeyName );
659
660 if (!hKey)
661 {
662 DPRINT1("NLS_RegOpenKey() failed, KeyName='%S'\n", szLangGroupsKeyName);
663 return FALSE;
664 }
665
666 while (bContinue)
667 {
668 if (NLS_RegEnumValue( hKey, ulIndex, szNumber, sizeof(szNumber),
669 szValue, sizeof(szValue) ))
670 {
671 BOOL bInstalled = szValue[0] == '1' ? TRUE : FALSE;
672 LGRPID lgrpid = wcstoul( szNumber, NULL, 16 );
673
674 DPRINT("grpid %s (%sinstalled)\n", szNumber,
675 bInstalled ? "" : "not ");
676
677 if (lpProcs->dwFlags == LGRPID_SUPPORTED || bInstalled)
678 {
679 WCHAR szGrpName[48];
680
681 if (!NLS_GetLanguageGroupName( lgrpid, szGrpName, sizeof(szGrpName) / sizeof(WCHAR) ))
682 szGrpName[0] = '\0';
683
684 if (lpProcs->procW)
685 bContinue = lpProcs->procW( lgrpid, szNumber, szGrpName, lpProcs->dwFlags,
686 lpProcs->lParam );
687 else
688 {
689 char szNumberA[sizeof(szNumber)/sizeof(WCHAR)];
690 char szGrpNameA[48];
691
692 /* FIXME: MSDN doesn't say which code page the W->A translation uses,
693 * or whether the language names are ever localised. Assume CP_ACP.
694 */
695
696 WideCharToMultiByte(CP_ACP, 0, szNumber, -1, szNumberA, sizeof(szNumberA), 0, 0);
697 WideCharToMultiByte(CP_ACP, 0, szGrpName, -1, szGrpNameA, sizeof(szGrpNameA), 0, 0);
698
699 bContinue = lpProcs->procA( lgrpid, szNumberA, szGrpNameA, lpProcs->dwFlags,
700 lpProcs->lParam );
701 }
702 }
703
704 ulIndex++;
705 }
706 else
707 bContinue = FALSE;
708
709 if (!bContinue)
710 break;
711 }
712
713 if (hKey)
714 NtClose( hKey );
715
716 return TRUE;
717 }
718
719
720 /*
721 * @implemented
722 */
723 BOOL
724 WINAPI
725 EnumSystemLanguageGroupsA(
726 LANGUAGEGROUP_ENUMPROCA pLangGroupEnumProc,
727 DWORD dwFlags,
728 LONG_PTR lParam)
729 {
730 ENUMLANGUAGEGROUP_CALLBACKS procs;
731
732 DPRINT("(%p,0x%08X,0x%08lX)\n", pLangGroupEnumProc, dwFlags, lParam);
733
734 procs.procA = pLangGroupEnumProc;
735 procs.procW = NULL;
736 procs.dwFlags = dwFlags;
737 procs.lParam = lParam;
738
739 return NLS_EnumSystemLanguageGroups( pLangGroupEnumProc ? &procs : NULL);
740 }
741
742
743 /*
744 * @implemented
745 */
746 BOOL
747 WINAPI
748 EnumSystemLanguageGroupsW(
749 LANGUAGEGROUP_ENUMPROCW pLangGroupEnumProc,
750 DWORD dwFlags,
751 LONG_PTR lParam)
752 {
753 ENUMLANGUAGEGROUP_CALLBACKS procs;
754
755 DPRINT("(%p,0x%08X,0x%08lX)\n", pLangGroupEnumProc, dwFlags, lParam);
756
757 procs.procA = NULL;
758 procs.procW = pLangGroupEnumProc;
759 procs.dwFlags = dwFlags;
760 procs.lParam = lParam;
761
762 return NLS_EnumSystemLanguageGroups( pLangGroupEnumProc ? &procs : NULL);
763 }
764
765
766 /* Callback function ptrs for EnumSystemLocalesA/W */
767 typedef struct
768 {
769 LOCALE_ENUMPROCA procA;
770 LOCALE_ENUMPROCW procW;
771 DWORD dwFlags;
772 } ENUMSYSTEMLOCALES_CALLBACKS;
773
774
775 /* Internal implementation of EnumSystemLocalesA/W */
776 static BOOL NLS_EnumSystemLocales(ENUMSYSTEMLOCALES_CALLBACKS *lpProcs)
777 {
778 WCHAR szNumber[10], szValue[4];
779 HANDLE hKey;
780 BOOL bContinue = TRUE;
781 ULONG ulIndex = 0;
782
783 if (!lpProcs)
784 {
785 SetLastError(ERROR_INVALID_PARAMETER);
786 return FALSE;
787 }
788
789 /* Passing 0 flags behaves like LCID_SUPPORTED */
790 if (lpProcs->dwFlags == 0)
791 {
792 lpProcs->dwFlags = LCID_SUPPORTED;
793 }
794
795 switch (lpProcs->dwFlags)
796 {
797 case LCID_ALTERNATE_SORTS:
798 case LCID_INSTALLED:
799 case LCID_SUPPORTED:
800 break;
801 default:
802 SetLastError(ERROR_INVALID_FLAGS);
803 return FALSE;
804 }
805
806 hKey = NLS_RegOpenKey(0, L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\Nls\\Locale");
807
808 if (!hKey)
809 {
810 DPRINT1("NLS_RegOpenKey() failed\n");
811 return FALSE;
812 }
813
814 while (bContinue)
815 {
816 if (NLS_RegEnumValue( hKey, ulIndex, szNumber, sizeof(szNumber),
817 szValue, sizeof(szValue)))
818 {
819 if ((lpProcs->dwFlags == LCID_SUPPORTED)||
820 ((lpProcs->dwFlags == LCID_INSTALLED)&&(wcslen(szValue) > 0)))
821 {
822 if (lpProcs->procW)
823 {
824 bContinue = lpProcs->procW(szNumber);
825 }
826 else
827 {
828 char szNumberA[sizeof(szNumber)/sizeof(WCHAR)];
829
830 WideCharToMultiByte(CP_ACP, 0, szNumber, -1, szNumberA, sizeof(szNumberA), 0, 0);
831 bContinue = lpProcs->procA(szNumberA);
832 }
833 }
834
835 ulIndex++;
836 }
837 else
838 bContinue = FALSE;
839
840 if (!bContinue)
841 break;
842 }
843
844 if (hKey)
845 NtClose(hKey);
846
847 return TRUE;
848 }
849
850 /*
851 * @implemented
852 */
853 BOOL
854 WINAPI
855 EnumSystemLocalesA (
856 LOCALE_ENUMPROCA lpLocaleEnumProc,
857 DWORD dwFlags
858 )
859 {
860 ENUMSYSTEMLOCALES_CALLBACKS procs;
861
862 DPRINT("(%p,0x%08X)\n", lpLocaleEnumProc, dwFlags);
863
864 procs.procA = lpLocaleEnumProc;
865 procs.procW = NULL;
866 procs.dwFlags = dwFlags;
867
868 return NLS_EnumSystemLocales(lpLocaleEnumProc ? &procs : NULL);
869 }
870
871
872 /*
873 * @implemented
874 */
875 BOOL
876 WINAPI
877 EnumSystemLocalesW (
878 LOCALE_ENUMPROCW lpLocaleEnumProc,
879 DWORD dwFlags
880 )
881 {
882 ENUMSYSTEMLOCALES_CALLBACKS procs;
883
884 DPRINT("(%p,0x%08X)\n", lpLocaleEnumProc, dwFlags);
885
886 procs.procA = NULL;
887 procs.procW = lpLocaleEnumProc;
888 procs.dwFlags = dwFlags;
889
890 return NLS_EnumSystemLocales(lpLocaleEnumProc ? &procs : NULL);
891 }
892
893
894 static BOOL CALLBACK enum_uilang_proc_a( HMODULE hModule, LPCSTR type,
895 LPCSTR name, WORD LangID, LONG_PTR lParam )
896 {
897 ENUM_UILANG_CALLBACK *enum_uilang = (ENUM_UILANG_CALLBACK *)lParam;
898 char buf[20];
899
900 sprintf(buf, "%08x", (UINT)LangID);
901 return enum_uilang->u.procA( buf, enum_uilang->param );
902 }
903
904
905 /*
906 * @implemented
907 */
908 BOOL
909 WINAPI
910 EnumUILanguagesA(
911 UILANGUAGE_ENUMPROCA lpUILanguageEnumProc,
912 DWORD dwFlags,
913 LONG_PTR lParam)
914 {
915 ENUM_UILANG_CALLBACK enum_uilang;
916
917 DPRINT("%p, %x, %lx\n", lpUILanguageEnumProc, dwFlags, lParam);
918
919 if(!lpUILanguageEnumProc) {
920 SetLastError(ERROR_INVALID_PARAMETER);
921 return FALSE;
922 }
923 if(dwFlags) {
924 SetLastError(ERROR_INVALID_FLAGS);
925 return FALSE;
926 }
927
928 enum_uilang.u.procA = lpUILanguageEnumProc;
929 enum_uilang.flags = dwFlags;
930 enum_uilang.param = lParam;
931
932 EnumResourceLanguagesA( hCurrentModule, (LPCSTR)RT_STRING,
933 (LPCSTR)LOCALE_ILANGUAGE, enum_uilang_proc_a,
934 (LONG_PTR)&enum_uilang);
935 return TRUE;
936 }
937
938 static BOOL CALLBACK enum_uilang_proc_w( HMODULE hModule, LPCWSTR type,
939 LPCWSTR name, WORD LangID, LONG_PTR lParam )
940 {
941 static const WCHAR formatW[] = {'%','0','8','x',0};
942 ENUM_UILANG_CALLBACK *enum_uilang = (ENUM_UILANG_CALLBACK *)lParam;
943 WCHAR buf[20];
944
945 swprintf( buf, formatW, (UINT)LangID );
946 return enum_uilang->u.procW( buf, enum_uilang->param );
947 }
948
949 /*
950 * @implemented
951 */
952 BOOL
953 WINAPI
954 EnumUILanguagesW(
955 UILANGUAGE_ENUMPROCW lpUILanguageEnumProc,
956 DWORD dwFlags,
957 LONG_PTR lParam)
958 {
959 ENUM_UILANG_CALLBACK enum_uilang;
960
961 DPRINT("%p, %x, %lx\n", lpUILanguageEnumProc, dwFlags, lParam);
962
963
964 if(!lpUILanguageEnumProc) {
965 SetLastError(ERROR_INVALID_PARAMETER);
966 return FALSE;
967 }
968 if(dwFlags) {
969 SetLastError(ERROR_INVALID_FLAGS);
970 return FALSE;
971 }
972
973 enum_uilang.u.procW = lpUILanguageEnumProc;
974 enum_uilang.flags = dwFlags;
975 enum_uilang.param = lParam;
976
977 EnumResourceLanguagesW( hCurrentModule, (LPCWSTR)RT_STRING,
978 (LPCWSTR)LOCALE_ILANGUAGE, enum_uilang_proc_w,
979 (LONG_PTR)&enum_uilang);
980 return TRUE;
981 }
982
983 /*
984 * @implemented
985 */
986 int
987 WINAPI
988 GetCalendarInfoA(
989 LCID lcid,
990 CALID Calendar,
991 CALTYPE CalType,
992 LPSTR lpCalData,
993 int cchData,
994 LPDWORD lpValue
995 )
996 {
997 int ret;
998 LPWSTR lpCalDataW = NULL;
999
1000 if (NLS_IsUnicodeOnlyLcid(lcid))
1001 {
1002 SetLastError(ERROR_INVALID_PARAMETER);
1003 return 0;
1004 }
1005
1006 if (cchData &&
1007 !(lpCalDataW = HeapAlloc(GetProcessHeap(), 0, cchData*sizeof(WCHAR))))
1008 return 0;
1009
1010 ret = GetCalendarInfoW(lcid, Calendar, CalType, lpCalDataW, cchData, lpValue);
1011 if(ret && lpCalDataW && lpCalData)
1012 WideCharToMultiByte(CP_ACP, 0, lpCalDataW, cchData, lpCalData, cchData, NULL, NULL);
1013 HeapFree(GetProcessHeap(), 0, lpCalDataW);
1014
1015 return ret;
1016 }
1017
1018
1019 /*
1020 * @unimplemented
1021 */
1022 int
1023 WINAPI
1024 GetCalendarInfoW(
1025 LCID Locale,
1026 CALID Calendar,
1027 CALTYPE CalType,
1028 LPWSTR lpCalData,
1029 int cchData,
1030 LPDWORD lpValue)
1031 {
1032 if (CalType & CAL_NOUSEROVERRIDE)
1033 DPRINT("FIXME: flag CAL_NOUSEROVERRIDE used, not fully implemented\n");
1034 if (CalType & CAL_USE_CP_ACP)
1035 DPRINT("FIXME: flag CAL_USE_CP_ACP used, not fully implemented\n");
1036
1037 if (CalType & CAL_RETURN_NUMBER) {
1038 if (lpCalData != NULL)
1039 DPRINT("WARNING: lpCalData not NULL (%p) when it should!\n", lpCalData);
1040 if (cchData != 0)
1041 DPRINT("WARNING: cchData not 0 (%d) when it should!\n", cchData);
1042 } else {
1043 if (lpValue != NULL)
1044 DPRINT("WARNING: lpValue not NULL (%p) when it should!\n", lpValue);
1045 }
1046
1047 /* FIXME: No verification is made yet wrt Locale
1048 * for the CALTYPES not requiring GetLocaleInfoA */
1049 switch (CalType & ~(CAL_NOUSEROVERRIDE|CAL_RETURN_NUMBER|CAL_USE_CP_ACP)) {
1050 case CAL_ICALINTVALUE:
1051 DPRINT("FIXME: Unimplemented caltype %d\n", CalType & 0xffff);
1052 return E_FAIL;
1053 case CAL_SCALNAME:
1054 DPRINT("FIXME: Unimplemented caltype %d\n", CalType & 0xffff);
1055 return E_FAIL;
1056 case CAL_IYEAROFFSETRANGE:
1057 DPRINT("FIXME: Unimplemented caltype %d\n", CalType & 0xffff);
1058 return E_FAIL;
1059 case CAL_SERASTRING:
1060 DPRINT("FIXME: Unimplemented caltype %d\n", CalType & 0xffff);
1061 return E_FAIL;
1062 case CAL_SSHORTDATE:
1063 return GetLocaleInfoW(Locale, LOCALE_SSHORTDATE, lpCalData, cchData);
1064 case CAL_SLONGDATE:
1065 return GetLocaleInfoW(Locale, LOCALE_SLONGDATE, lpCalData, cchData);
1066 case CAL_SDAYNAME1:
1067 return GetLocaleInfoW(Locale, LOCALE_SDAYNAME1, lpCalData, cchData);
1068 case CAL_SDAYNAME2:
1069 return GetLocaleInfoW(Locale, LOCALE_SDAYNAME2, lpCalData, cchData);
1070 case CAL_SDAYNAME3:
1071 return GetLocaleInfoW(Locale, LOCALE_SDAYNAME3, lpCalData, cchData);
1072 case CAL_SDAYNAME4:
1073 return GetLocaleInfoW(Locale, LOCALE_SDAYNAME4, lpCalData, cchData);
1074 case CAL_SDAYNAME5:
1075 return GetLocaleInfoW(Locale, LOCALE_SDAYNAME5, lpCalData, cchData);
1076 case CAL_SDAYNAME6:
1077 return GetLocaleInfoW(Locale, LOCALE_SDAYNAME6, lpCalData, cchData);
1078 case CAL_SDAYNAME7:
1079 return GetLocaleInfoW(Locale, LOCALE_SDAYNAME7, lpCalData, cchData);
1080 case CAL_SABBREVDAYNAME1:
1081 return GetLocaleInfoW(Locale, LOCALE_SABBREVDAYNAME1, lpCalData, cchData);
1082 case CAL_SABBREVDAYNAME2:
1083 return GetLocaleInfoW(Locale, LOCALE_SABBREVDAYNAME2, lpCalData, cchData);
1084 case CAL_SABBREVDAYNAME3:
1085 return GetLocaleInfoW(Locale, LOCALE_SABBREVDAYNAME3, lpCalData, cchData);
1086 case CAL_SABBREVDAYNAME4:
1087 return GetLocaleInfoW(Locale, LOCALE_SABBREVDAYNAME4, lpCalData, cchData);
1088 case CAL_SABBREVDAYNAME5:
1089 return GetLocaleInfoW(Locale, LOCALE_SABBREVDAYNAME5, lpCalData, cchData);
1090 case CAL_SABBREVDAYNAME6:
1091 return GetLocaleInfoW(Locale, LOCALE_SABBREVDAYNAME6, lpCalData, cchData);
1092 case CAL_SABBREVDAYNAME7:
1093 return GetLocaleInfoW(Locale, LOCALE_SABBREVDAYNAME7, lpCalData, cchData);
1094 case CAL_SMONTHNAME1:
1095 return GetLocaleInfoW(Locale, LOCALE_SMONTHNAME1, lpCalData, cchData);
1096 case CAL_SMONTHNAME2:
1097 return GetLocaleInfoW(Locale, LOCALE_SMONTHNAME2, lpCalData, cchData);
1098 case CAL_SMONTHNAME3:
1099 return GetLocaleInfoW(Locale, LOCALE_SMONTHNAME3, lpCalData, cchData);
1100 case CAL_SMONTHNAME4:
1101 return GetLocaleInfoW(Locale, LOCALE_SMONTHNAME4, lpCalData, cchData);
1102 case CAL_SMONTHNAME5:
1103 return GetLocaleInfoW(Locale, LOCALE_SMONTHNAME5, lpCalData, cchData);
1104 case CAL_SMONTHNAME6:
1105 return GetLocaleInfoW(Locale, LOCALE_SMONTHNAME6, lpCalData, cchData);
1106 case CAL_SMONTHNAME7:
1107 return GetLocaleInfoW(Locale, LOCALE_SMONTHNAME7, lpCalData, cchData);
1108 case CAL_SMONTHNAME8:
1109 return GetLocaleInfoW(Locale, LOCALE_SMONTHNAME8, lpCalData, cchData);
1110 case CAL_SMONTHNAME9:
1111 return GetLocaleInfoW(Locale, LOCALE_SMONTHNAME9, lpCalData, cchData);
1112 case CAL_SMONTHNAME10:
1113 return GetLocaleInfoW(Locale, LOCALE_SMONTHNAME10, lpCalData, cchData);
1114 case CAL_SMONTHNAME11:
1115 return GetLocaleInfoW(Locale, LOCALE_SMONTHNAME11, lpCalData, cchData);
1116 case CAL_SMONTHNAME12:
1117 return GetLocaleInfoW(Locale, LOCALE_SMONTHNAME12, lpCalData, cchData);
1118 case CAL_SMONTHNAME13:
1119 return GetLocaleInfoW(Locale, LOCALE_SMONTHNAME13, lpCalData, cchData);
1120 case CAL_SABBREVMONTHNAME1:
1121 return GetLocaleInfoW(Locale, LOCALE_SABBREVMONTHNAME1, lpCalData, cchData);
1122 case CAL_SABBREVMONTHNAME2:
1123 return GetLocaleInfoW(Locale, LOCALE_SABBREVMONTHNAME2, lpCalData, cchData);
1124 case CAL_SABBREVMONTHNAME3:
1125 return GetLocaleInfoW(Locale, LOCALE_SABBREVMONTHNAME3, lpCalData, cchData);
1126 case CAL_SABBREVMONTHNAME4:
1127 return GetLocaleInfoW(Locale, LOCALE_SABBREVMONTHNAME4, lpCalData, cchData);
1128 case CAL_SABBREVMONTHNAME5:
1129 return GetLocaleInfoW(Locale, LOCALE_SABBREVMONTHNAME5, lpCalData, cchData);
1130 case CAL_SABBREVMONTHNAME6:
1131 return GetLocaleInfoW(Locale, LOCALE_SABBREVMONTHNAME6, lpCalData, cchData);
1132 case CAL_SABBREVMONTHNAME7:
1133 return GetLocaleInfoW(Locale, LOCALE_SABBREVMONTHNAME7, lpCalData, cchData);
1134 case CAL_SABBREVMONTHNAME8:
1135 return GetLocaleInfoW(Locale, LOCALE_SABBREVMONTHNAME8, lpCalData, cchData);
1136 case CAL_SABBREVMONTHNAME9:
1137 return GetLocaleInfoW(Locale, LOCALE_SABBREVMONTHNAME9, lpCalData, cchData);
1138 case CAL_SABBREVMONTHNAME10:
1139 return GetLocaleInfoW(Locale, LOCALE_SABBREVMONTHNAME10, lpCalData, cchData);
1140 case CAL_SABBREVMONTHNAME11:
1141 return GetLocaleInfoW(Locale, LOCALE_SABBREVMONTHNAME11, lpCalData, cchData);
1142 case CAL_SABBREVMONTHNAME12:
1143 return GetLocaleInfoW(Locale, LOCALE_SABBREVMONTHNAME12, lpCalData, cchData);
1144 case CAL_SABBREVMONTHNAME13:
1145 return GetLocaleInfoW(Locale, LOCALE_SABBREVMONTHNAME13, lpCalData, cchData);
1146 case CAL_SYEARMONTH:
1147 return GetLocaleInfoW(Locale, LOCALE_SYEARMONTH, lpCalData, cchData);
1148 case CAL_ITWODIGITYEARMAX:
1149 if (lpValue) *lpValue = CALINFO_MAX_YEAR;
1150 break;
1151 default: DPRINT("Unknown caltype %d\n",CalType & 0xffff);
1152 return E_FAIL;
1153 }
1154 return 0;
1155 }
1156
1157
1158 /*
1159 * @implemented
1160 */
1161 BOOL
1162 WINAPI
1163 GetCPInfo(UINT CodePage,
1164 LPCPINFO CodePageInfo)
1165 {
1166 PCODEPAGE_ENTRY CodePageEntry;
1167
1168 if (!CodePageInfo)
1169 {
1170 SetLastError(ERROR_INVALID_PARAMETER);
1171 return FALSE;
1172 }
1173
1174 CodePageEntry = IntGetCodePageEntry(CodePage);
1175 if (CodePageEntry == NULL)
1176 {
1177 switch(CodePage)
1178 {
1179 case CP_UTF7:
1180 case CP_UTF8:
1181 CodePageInfo->DefaultChar[0] = 0x3f;
1182 CodePageInfo->DefaultChar[1] = 0;
1183 CodePageInfo->LeadByte[0] = CodePageInfo->LeadByte[1] = 0;
1184 CodePageInfo->MaxCharSize = (CodePage == CP_UTF7) ? 5 : 4;
1185 return TRUE;
1186 }
1187
1188 SetLastError( ERROR_INVALID_PARAMETER );
1189 return FALSE;
1190 }
1191
1192 if (CodePageEntry->CodePageTable.DefaultChar & 0xff00)
1193 {
1194 CodePageInfo->DefaultChar[0] = (CodePageEntry->CodePageTable.DefaultChar & 0xff00) >> 8;
1195 CodePageInfo->DefaultChar[1] = CodePageEntry->CodePageTable.DefaultChar & 0x00ff;
1196 }
1197 else
1198 {
1199 CodePageInfo->DefaultChar[0] = CodePageEntry->CodePageTable.DefaultChar & 0xff;
1200 CodePageInfo->DefaultChar[1] = 0;
1201 }
1202
1203 if ((CodePageInfo->MaxCharSize = CodePageEntry->CodePageTable.MaximumCharacterSize) == 2)
1204 memcpy(CodePageInfo->LeadByte, CodePageEntry->CodePageTable.LeadByte, sizeof(CodePageInfo->LeadByte));
1205 else
1206 CodePageInfo->LeadByte[0] = CodePageInfo->LeadByte[1] = 0;
1207
1208 return TRUE;
1209 }
1210
1211 static BOOL
1212 GetLocalisedText(DWORD dwResId, WCHAR *lpszDest)
1213 {
1214 HRSRC hrsrc;
1215 LCID lcid;
1216 LANGID langId;
1217 DWORD dwId;
1218
1219 if (dwResId == 37)
1220 dwId = dwResId * 100;
1221 else
1222 dwId = dwResId;
1223
1224 lcid = GetUserDefaultLCID();
1225 lcid = ConvertDefaultLocale(lcid);
1226
1227 langId = LANGIDFROMLCID(lcid);
1228
1229 if (PRIMARYLANGID(langId) == LANG_NEUTRAL)
1230 langId = MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US);
1231
1232 hrsrc = FindResourceExW(hCurrentModule,
1233 (LPWSTR)RT_STRING,
1234 MAKEINTRESOURCEW((dwId >> 4) + 1),
1235 langId);
1236 if (hrsrc)
1237 {
1238 HGLOBAL hmem = LoadResource(hCurrentModule, hrsrc);
1239
1240 if (hmem)
1241 {
1242 const WCHAR *p;
1243 unsigned int i;
1244
1245 p = LockResource(hmem);
1246 for (i = 0; i < (dwId & 0x0f); i++) p += *p + 1;
1247
1248 memcpy(lpszDest, p + 1, *p * sizeof(WCHAR));
1249 lpszDest[*p] = '\0';
1250
1251 return TRUE;
1252 }
1253 }
1254
1255 DPRINT1("Could not get codepage name. dwResId = %ld\n", dwResId);
1256 return FALSE;
1257 }
1258
1259 /*
1260 * @implemented
1261 */
1262 BOOL
1263 WINAPI
1264 GetCPInfoExW(UINT CodePage,
1265 DWORD dwFlags,
1266 LPCPINFOEXW lpCPInfoEx)
1267 {
1268 if (!GetCPInfo(CodePage, (LPCPINFO) lpCPInfoEx))
1269 return FALSE;
1270
1271 switch(CodePage)
1272 {
1273 case CP_UTF7:
1274 {
1275 lpCPInfoEx->CodePage = CP_UTF7;
1276 lpCPInfoEx->UnicodeDefaultChar = 0x3f;
1277 return GetLocalisedText((DWORD)CodePage, lpCPInfoEx->CodePageName);
1278 }
1279 break;
1280
1281 case CP_UTF8:
1282 {
1283 lpCPInfoEx->CodePage = CP_UTF8;
1284 lpCPInfoEx->UnicodeDefaultChar = 0x3f;
1285 return GetLocalisedText((DWORD)CodePage, lpCPInfoEx->CodePageName);
1286 }
1287
1288 default:
1289 {
1290 PCODEPAGE_ENTRY CodePageEntry;
1291
1292 CodePageEntry = IntGetCodePageEntry(CodePage);
1293 if (CodePageEntry == NULL)
1294 {
1295 DPRINT1("Could not get CodePage Entry! CodePageEntry = 0\n");
1296 SetLastError(ERROR_INVALID_PARAMETER);
1297 return FALSE;
1298 }
1299
1300 lpCPInfoEx->CodePage = CodePageEntry->CodePageTable.CodePage;
1301 lpCPInfoEx->UnicodeDefaultChar = CodePageEntry->CodePageTable.UniDefaultChar;
1302 return GetLocalisedText((DWORD)CodePage, lpCPInfoEx->CodePageName);
1303 }
1304 break;
1305 }
1306 }
1307
1308
1309 /*
1310 * @implemented
1311 */
1312 BOOL
1313 WINAPI
1314 GetCPInfoExA(UINT CodePage,
1315 DWORD dwFlags,
1316 LPCPINFOEXA lpCPInfoEx)
1317 {
1318 CPINFOEXW CPInfo;
1319
1320 if (!GetCPInfoExW(CodePage, dwFlags, &CPInfo))
1321 return FALSE;
1322
1323 /* the layout is the same except for CodePageName */
1324 memcpy(lpCPInfoEx, &CPInfo, sizeof(CPINFOEXA));
1325
1326 WideCharToMultiByte(CP_ACP,
1327 0,
1328 CPInfo.CodePageName,
1329 -1,
1330 lpCPInfoEx->CodePageName,
1331 sizeof(lpCPInfoEx->CodePageName),
1332 NULL,
1333 NULL);
1334 return TRUE;
1335 }
1336
1337 static int
1338 NLS_GetGeoFriendlyName(GEOID Location, LPWSTR szFriendlyName, int cchData)
1339 {
1340 HANDLE hKey;
1341 WCHAR szPath[MAX_PATH];
1342 UNICODE_STRING ValueName;
1343 KEY_VALUE_PARTIAL_INFORMATION *info;
1344 static const int info_size = FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data);
1345 DWORD dwSize;
1346 NTSTATUS Status;
1347 int Ret;
1348
1349 swprintf(szPath, L"\\REGISTRY\\Machine\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Telephony\\Country List\\%d", Location);
1350
1351 hKey = NLS_RegOpenKey(0, szPath);
1352 if (!hKey)
1353 {
1354 DPRINT1("NLS_RegOpenKey() failed\n");
1355 return 0;
1356 }
1357
1358 dwSize = info_size + cchData * sizeof(WCHAR);
1359
1360 if (!(info = HeapAlloc(GetProcessHeap(), 0, dwSize)))
1361 {
1362 NtClose(hKey);
1363 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1364 return 0;
1365 }
1366
1367 RtlInitUnicodeString(&ValueName, L"Name");
1368
1369 Status = NtQueryValueKey(hKey, &ValueName, KeyValuePartialInformation,
1370 (LPBYTE)info, dwSize, &dwSize);
1371
1372 if (!Status)
1373 {
1374 Ret = (dwSize - info_size) / sizeof(WCHAR);
1375
1376 if (!Ret || ((WCHAR *)info->Data)[Ret-1])
1377 {
1378 if (Ret < cchData || !szFriendlyName) Ret++;
1379 else
1380 {
1381 SetLastError(ERROR_INSUFFICIENT_BUFFER);
1382 Ret = 0;
1383 }
1384 }
1385
1386 if (Ret && szFriendlyName)
1387 {
1388 memcpy(szFriendlyName, info->Data, (Ret-1) * sizeof(WCHAR));
1389 szFriendlyName[Ret-1] = 0;
1390 }
1391 }
1392 else if (Status == STATUS_BUFFER_OVERFLOW && !szFriendlyName)
1393 {
1394 Ret = (dwSize - info_size) / sizeof(WCHAR) + 1;
1395 }
1396 else if (Status == STATUS_OBJECT_NAME_NOT_FOUND)
1397 {
1398 Ret = -1;
1399 }
1400 else
1401 {
1402 SetLastError(RtlNtStatusToDosError(Status));
1403 Ret = 0;
1404 }
1405
1406 NtClose(hKey);
1407 HeapFree(GetProcessHeap(), 0, info);
1408
1409 return Ret;
1410 }
1411
1412 /*
1413 * @unimplemented
1414 */
1415 int
1416 WINAPI
1417 GetGeoInfoW(
1418 GEOID Location,
1419 GEOTYPE GeoType,
1420 LPWSTR lpGeoData,
1421 int cchData,
1422 LANGID LangId)
1423 {
1424 DPRINT("%d %d %p %d %d\n", Location, GeoType, lpGeoData, cchData, LangId);
1425
1426 if ((GeoType == GEO_TIMEZONES)||(GeoType == GEO_OFFICIALLANGUAGES))
1427 {
1428 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1429 }
1430
1431 switch (GeoType)
1432 {
1433 case GEO_FRIENDLYNAME:
1434 {
1435 return NLS_GetGeoFriendlyName(Location, lpGeoData, cchData);
1436 }
1437 case GEO_NATION:
1438 case GEO_LATITUDE:
1439 case GEO_LONGITUDE:
1440 case GEO_ISO2:
1441 case GEO_ISO3:
1442 case GEO_RFC1766:
1443 case GEO_LCID:
1444 case GEO_OFFICIALNAME:
1445 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1446 break;
1447 }
1448
1449 return 0;
1450 }
1451
1452
1453 /*
1454 * @unimplemented
1455 */
1456 int
1457 WINAPI
1458 GetGeoInfoA(
1459 GEOID Location,
1460 GEOTYPE GeoType,
1461 LPSTR lpGeoData,
1462 int cchData,
1463 LANGID LangId)
1464 {
1465 DPRINT("%d %d %p %d %d\n", Location, GeoType, lpGeoData, cchData, LangId);
1466
1467 if ((GeoType == GEO_TIMEZONES)||(GeoType == GEO_OFFICIALLANGUAGES))
1468 {
1469 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1470 }
1471
1472 switch (GeoType)
1473 {
1474 case GEO_FRIENDLYNAME:
1475 {
1476 WCHAR szBuffer[MAX_PATH];
1477 char szBufferA[sizeof(szBuffer)/sizeof(WCHAR)];
1478 int Ret;
1479
1480 Ret = NLS_GetGeoFriendlyName(Location, szBuffer, cchData);
1481
1482 WideCharToMultiByte(CP_ACP, 0, szBuffer, -1, szBufferA, sizeof(szBufferA), 0, 0);
1483 strcpy(lpGeoData, szBufferA);
1484
1485 return Ret;
1486 }
1487 case GEO_NATION:
1488 case GEO_LATITUDE:
1489 case GEO_LONGITUDE:
1490 case GEO_ISO2:
1491 case GEO_ISO3:
1492 case GEO_RFC1766:
1493 case GEO_LCID:
1494 case GEO_OFFICIALNAME:
1495 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1496 break;
1497 }
1498
1499 return 0;
1500 }
1501
1502 const WCHAR *RosGetLocaleValueName( DWORD lctype )
1503 {
1504 switch (lctype & ~LOCALE_LOCALEINFOFLAGSMASK)
1505 {
1506 /* These values are used by SetLocaleInfo and GetLocaleInfo, and
1507 * the values are stored in the registry, confirmed under Windows.
1508 */
1509 case LOCALE_ICALENDARTYPE: return L"iCalendarType";
1510 case LOCALE_ICURRDIGITS: return L"iCurrDigits";
1511 case LOCALE_ICURRENCY: return L"iCurrency";
1512 case LOCALE_IDIGITS: return L"iDigits";
1513 case LOCALE_IFIRSTDAYOFWEEK: return L"iFirstDayOfWeek";
1514 case LOCALE_IFIRSTWEEKOFYEAR: return L"iFirstWeekOfYear";
1515 case LOCALE_ILZERO: return L"iLZero";
1516 case LOCALE_IMEASURE: return L"iMeasure";
1517 case LOCALE_INEGCURR: return L"iNegCurr";
1518 case LOCALE_INEGNUMBER: return L"iNegNumber";
1519 case LOCALE_IPAPERSIZE: return L"iPaperSize";
1520 case LOCALE_ITIME: return L"iTime";
1521 case LOCALE_S1159: return L"s1159";
1522 case LOCALE_S2359: return L"s2359";
1523 case LOCALE_SCURRENCY: return L"sCurrency";
1524 case LOCALE_SDATE: return L"sDate";
1525 case LOCALE_SDECIMAL: return L"sDecimal";
1526 case LOCALE_SGROUPING: return L"sGrouping";
1527 case LOCALE_SLIST: return L"sList";
1528 case LOCALE_SLONGDATE: return L"sLongDate";
1529 case LOCALE_SMONDECIMALSEP: return L"sMonDecimalSep";
1530 case LOCALE_SMONGROUPING: return L"sMonGrouping";
1531 case LOCALE_SMONTHOUSANDSEP: return L"sMonThousandSep";
1532 case LOCALE_SNEGATIVESIGN: return L"sNegativeSign";
1533 case LOCALE_SPOSITIVESIGN: return L"sPositiveSign";
1534 case LOCALE_SSHORTDATE: return L"sShortDate";
1535 case LOCALE_STHOUSAND: return L"sThousand";
1536 case LOCALE_STIME: return L"sTime";
1537 case LOCALE_STIMEFORMAT: return L"sTimeFormat";
1538 case LOCALE_SYEARMONTH: return L"sYearMonth";
1539
1540 /* The following are not listed under MSDN as supported,
1541 * but seem to be used and also stored in the registry.
1542 */
1543 case LOCALE_ICOUNTRY: return L"iCountry";
1544 case LOCALE_IDATE: return L"iDate";
1545 case LOCALE_ILDATE: return L"iLDate";
1546 case LOCALE_ITLZERO: return L"iTLZero";
1547 case LOCALE_SCOUNTRY: return L"sCountry";
1548 case LOCALE_SLANGUAGE: return L"sLanguage";
1549
1550 /* The following are used in XP and later */
1551 case LOCALE_IDIGITSUBSTITUTION: return L"NumShape";
1552 case LOCALE_SNATIVEDIGITS: return L"sNativeDigits";
1553 case LOCALE_ITIMEMARKPOSN: return L"iTimePrefix";
1554 }
1555 return NULL;
1556 }
1557
1558 HKEY RosCreateRegistryKey(void)
1559 {
1560 OBJECT_ATTRIBUTES objAttr;
1561 UNICODE_STRING nameW;
1562 HANDLE hKey;
1563
1564 if (RtlOpenCurrentUser( KEY_ALL_ACCESS, &hKey ) != STATUS_SUCCESS) return 0;
1565
1566 objAttr.Length = sizeof(objAttr);
1567 objAttr.RootDirectory = hKey;
1568 objAttr.ObjectName = &nameW;
1569 objAttr.Attributes = 0;
1570 objAttr.SecurityDescriptor = NULL;
1571 objAttr.SecurityQualityOfService = NULL;
1572 RtlInitUnicodeString( &nameW, L"Control Panel\\International");
1573
1574 if (NtCreateKey( &hKey, KEY_ALL_ACCESS, &objAttr, 0, NULL, 0, NULL ) != STATUS_SUCCESS) hKey = 0;
1575 NtClose( objAttr.RootDirectory );
1576 return hKey;
1577 }
1578
1579 INT RosGetRegistryLocaleInfo( LPCWSTR lpValue, LPWSTR lpBuffer, INT nLen )
1580 {
1581 DWORD dwSize;
1582 HKEY hKey;
1583 INT nRet;
1584 NTSTATUS ntStatus;
1585 UNICODE_STRING usNameW;
1586 KEY_VALUE_PARTIAL_INFORMATION *kvpiInfo;
1587 const int nInfoSize = FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data);
1588
1589 if (!(hKey = RosCreateRegistryKey())) return -1;
1590
1591 RtlInitUnicodeString( &usNameW, lpValue );
1592 dwSize = nInfoSize + nLen * sizeof(WCHAR);
1593
1594 if (!(kvpiInfo = HeapAlloc( GetProcessHeap(), 0, dwSize )))
1595 {
1596 NtClose( hKey );
1597 SetLastError( ERROR_NOT_ENOUGH_MEMORY );
1598 return 0;
1599 }
1600
1601 ntStatus = NtQueryValueKey( hKey, &usNameW, KeyValuePartialInformation, kvpiInfo, dwSize, &dwSize );
1602
1603 if (!ntStatus)
1604 {
1605 nRet = (dwSize - nInfoSize) / sizeof(WCHAR);
1606
1607 if (!nRet || ((WCHAR *)kvpiInfo->Data)[nRet - 1])
1608 {
1609 if (nRet < nLen || !lpBuffer) nRet++;
1610 else
1611 {
1612 SetLastError( ERROR_INSUFFICIENT_BUFFER );
1613 nRet = 0;
1614 }
1615 }
1616 if (nRet && lpBuffer)
1617 {
1618 memcpy( lpBuffer, kvpiInfo->Data, (nRet - 1) * sizeof(WCHAR) );
1619 lpBuffer[nRet - 1] = 0;
1620 }
1621 }
1622 else if (ntStatus == STATUS_BUFFER_OVERFLOW && !lpBuffer)
1623 {
1624 nRet = (dwSize - nInfoSize) / sizeof(WCHAR) + 1;
1625 }
1626 else if (ntStatus == STATUS_OBJECT_NAME_NOT_FOUND)
1627 {
1628 nRet = -1;
1629 }
1630 else
1631 {
1632 SetLastError( RtlNtStatusToDosError(ntStatus) );
1633 nRet = 0;
1634 }
1635 NtClose( hKey );
1636 HeapFree( GetProcessHeap(), 0, kvpiInfo );
1637 return nRet;
1638 }
1639
1640 int
1641 WINAPI
1642 GetLocaleInfoEx (
1643 LPCWSTR lpLocaleName,
1644 LCTYPE LCType,
1645 LPWSTR lpLCData,
1646 int cchData
1647 )
1648 {
1649 return -1;
1650 }
1651
1652 /*
1653 * @implemented
1654 */
1655 int
1656 WINAPI
1657 GetLocaleInfoW (
1658 LCID Locale,
1659 LCTYPE LCType,
1660 LPWSTR lpLCData,
1661 int cchData
1662 )
1663 {
1664 LANGID liLangID;
1665 HRSRC hRsrc;
1666 HGLOBAL hMem;
1667 HMODULE hModule;
1668 INT nRet;
1669 UINT uiFlags;
1670 const WCHAR *ch;
1671 int i;
1672
1673 if (cchData < 0 || (cchData && !lpLCData))
1674 {
1675 SetLastError( ERROR_INVALID_PARAMETER );
1676 return 0;
1677 }
1678 if (LCType & LOCALE_RETURN_GENITIVE_NAMES &&
1679 !is_genitive_name_supported( LCType ))
1680 {
1681 SetLastError( ERROR_INVALID_FLAGS );
1682 return 0;
1683 }
1684
1685 if (!cchData) lpLCData = NULL;
1686
1687 if (Locale == LOCALE_NEUTRAL || Locale == LOCALE_SYSTEM_DEFAULT) Locale = GetSystemDefaultLCID();
1688 else if (Locale == LOCALE_USER_DEFAULT) Locale = GetUserDefaultLCID();
1689
1690 uiFlags = LCType & LOCALE_LOCALEINFOFLAGSMASK;
1691 LCType &= ~LOCALE_LOCALEINFOFLAGSMASK;
1692
1693 if (!(uiFlags & LOCALE_NOUSEROVERRIDE) && Locale == GetUserDefaultLCID())
1694 {
1695 const WCHAR *value = RosGetLocaleValueName(LCType);
1696
1697 if (value && ((nRet = RosGetRegistryLocaleInfo( value, lpLCData, cchData )) != -1)) return nRet;
1698 }
1699
1700 liLangID = LANGIDFROMLCID( Locale );
1701
1702 if (SUBLANGID(liLangID) == SUBLANG_NEUTRAL)
1703 liLangID = MAKELANGID(PRIMARYLANGID(liLangID), SUBLANG_DEFAULT);
1704
1705 hModule = GetModuleHandleW( L"kernel32.dll" );
1706 if (!(hRsrc = FindResourceExW( hModule, (LPWSTR)RT_STRING, (LPCWSTR)((LCType >> 4) + 1), liLangID )))
1707 {
1708 SetLastError( ERROR_INVALID_FLAGS );
1709 return 0;
1710 }
1711 if (!(hMem = LoadResource( hModule, hRsrc )))
1712 return 0;
1713
1714 ch = LockResource( hMem );
1715 for (i = 0; i < (LCType & 0x0f); i++) ch += *ch + 1;
1716
1717 if (uiFlags & LOCALE_RETURN_NUMBER) nRet = sizeof(UINT) / sizeof(WCHAR);
1718 else if (is_genitive_name_supported( LCType ) && *ch)
1719 {
1720 /* genitive form's stored after a null separator from a nominative */
1721 for (i = 1; i <= *ch; i++) if (!ch[i]) break;
1722
1723 if (i <= *ch && (uiFlags & LOCALE_RETURN_GENITIVE_NAMES))
1724 {
1725 nRet = *ch - i + 1;
1726 ch += i;
1727 }
1728 else nRet = i;
1729 }
1730 else
1731 nRet = (LCType == LOCALE_FONTSIGNATURE) ? *ch : *ch + 1;
1732
1733 if (!lpLCData) return nRet;
1734
1735 if (nRet > cchData)
1736 {
1737 SetLastError( ERROR_INSUFFICIENT_BUFFER );
1738 return 0;
1739 }
1740
1741 if (uiFlags & LOCALE_RETURN_NUMBER)
1742 {
1743 UINT uiNum;
1744 WCHAR *chEnd, *chTmp = HeapAlloc( GetProcessHeap(), 0, (*ch + 1) * sizeof(WCHAR) );
1745
1746 if (!chTmp)
1747 return 0;
1748
1749 memcpy( chTmp, ch + 1, *ch * sizeof(WCHAR) );
1750 chTmp[*ch] = L'\0';
1751 uiNum = wcstol( chTmp, &chEnd, 10 );
1752
1753 if (!*chEnd)
1754 memcpy( lpLCData, &uiNum, sizeof(uiNum) );
1755 else
1756 {
1757 SetLastError( ERROR_INVALID_FLAGS );
1758 nRet = 0;
1759 }
1760 HeapFree( GetProcessHeap(), 0, chTmp );
1761 }
1762 else
1763 {
1764 memcpy( lpLCData, ch + 1, nRet * sizeof(WCHAR) );
1765 if (LCType != LOCALE_FONTSIGNATURE) lpLCData[nRet-1] = 0;
1766 }
1767 return nRet;
1768 }
1769
1770
1771
1772 /***********************************************************************
1773 * get_lcid_codepage
1774 *
1775 * Retrieve the ANSI codepage for a given locale.
1776 */
1777 __inline static UINT get_lcid_codepage( LCID lcid )
1778 {
1779 UINT ret;
1780 if (!GetLocaleInfoW( lcid, LOCALE_IDEFAULTANSICODEPAGE|LOCALE_RETURN_NUMBER, (WCHAR *)&ret,
1781 sizeof(ret)/sizeof(WCHAR) )) ret = 0;
1782 return ret;
1783 }
1784
1785
1786 /*************************************************************************
1787 * FoldStringA (KERNEL32.@)
1788 *
1789 * Map characters in a string.
1790 *
1791 * PARAMS
1792 * dwFlags [I] Flags controlling chars to map (MAP_ constants from "winnls.h")
1793 * src [I] String to map
1794 * srclen [I] Length of src, or -1 if src is NUL terminated
1795 * dst [O] Destination for mapped string
1796 * dstlen [I] Length of dst, or 0 to find the required length for the mapped string
1797 *
1798 * RETURNS
1799 * Success: The length of the string written to dst, including the terminating NUL. If
1800 * dstlen is 0, the value returned is the same, but nothing is written to dst,
1801 * and dst may be NULL.
1802 * Failure: 0. Use GetLastError() to determine the cause.
1803 */
1804 INT WINAPI FoldStringA(DWORD dwFlags, LPCSTR src, INT srclen,
1805 LPSTR dst, INT dstlen)
1806 {
1807 INT ret = 0, srclenW = 0;
1808 WCHAR *srcW = NULL, *dstW = NULL;
1809
1810 if (!src || !srclen || dstlen < 0 || (dstlen && !dst) || src == dst)
1811 {
1812 SetLastError(ERROR_INVALID_PARAMETER);
1813 return 0;
1814 }
1815
1816 srclenW = MultiByteToWideChar(CP_ACP, dwFlags & MAP_COMPOSITE ? MB_COMPOSITE : 0,
1817 src, srclen, NULL, 0);
1818 srcW = HeapAlloc(GetProcessHeap(), 0, srclenW * sizeof(WCHAR));
1819
1820 if (!srcW)
1821 {
1822 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1823 goto FoldStringA_exit;
1824 }
1825
1826 MultiByteToWideChar(CP_ACP, dwFlags & MAP_COMPOSITE ? MB_COMPOSITE : 0,
1827 src, srclen, srcW, srclenW);
1828
1829 dwFlags = (dwFlags & ~MAP_PRECOMPOSED) | MAP_FOLDCZONE;
1830
1831 ret = FoldStringW(dwFlags, srcW, srclenW, NULL, 0);
1832 if (ret && dstlen)
1833 {
1834 dstW = HeapAlloc(GetProcessHeap(), 0, ret * sizeof(WCHAR));
1835
1836 if (!dstW)
1837 {
1838 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1839 goto FoldStringA_exit;
1840 }
1841
1842 ret = FoldStringW(dwFlags, srcW, srclenW, dstW, ret);
1843 if (!WideCharToMultiByte(CP_ACP, 0, dstW, ret, dst, dstlen, NULL, NULL))
1844 {
1845 ret = 0;
1846 SetLastError(ERROR_INSUFFICIENT_BUFFER);
1847 }
1848 }
1849
1850 HeapFree(GetProcessHeap(), 0, dstW);
1851
1852 FoldStringA_exit:
1853 HeapFree(GetProcessHeap(), 0, srcW);
1854 return ret;
1855 }
1856
1857 /*************************************************************************
1858 * FoldStringW (KERNEL32.@)
1859 *
1860 * See FoldStringA.
1861 */
1862 INT WINAPI FoldStringW(DWORD dwFlags, LPCWSTR src, INT srclen,
1863 LPWSTR dst, INT dstlen)
1864 {
1865 int ret;
1866
1867 switch (dwFlags & (MAP_COMPOSITE|MAP_PRECOMPOSED|MAP_EXPAND_LIGATURES))
1868 {
1869 case 0:
1870 if (dwFlags)
1871 break;
1872 /* Fall through for dwFlags == 0 */
1873 case MAP_PRECOMPOSED|MAP_COMPOSITE:
1874 case MAP_PRECOMPOSED|MAP_EXPAND_LIGATURES:
1875 case MAP_COMPOSITE|MAP_EXPAND_LIGATURES:
1876 SetLastError(ERROR_INVALID_FLAGS);
1877 return 0;
1878 }
1879
1880 if (!src || !srclen || dstlen < 0 || (dstlen && !dst) || src == dst)
1881 {
1882 SetLastError(ERROR_INVALID_PARAMETER);
1883 return 0;
1884 }
1885
1886 ret = wine_fold_string(dwFlags, src, srclen, dst, dstlen);
1887 if (!ret)
1888 SetLastError(ERROR_INSUFFICIENT_BUFFER);
1889 return ret;
1890 }
1891
1892
1893 /*
1894 * @implemented (Synced to Wine-22112008)
1895 */
1896 int
1897 WINAPI
1898 CompareStringA (
1899 LCID Locale,
1900 DWORD dwCmpFlags,
1901 LPCSTR lpString1,
1902 int cchCount1,
1903 LPCSTR lpString2,
1904 int cchCount2
1905 )
1906 {
1907 WCHAR *buf1W = NtCurrentTeb()->StaticUnicodeBuffer;
1908 WCHAR *buf2W = buf1W + 130;
1909 LPWSTR str1W, str2W;
1910 INT len1W, len2W, ret;
1911 UINT locale_cp = CP_ACP;
1912
1913 if (!lpString1 || !lpString2)
1914 {
1915 SetLastError(ERROR_INVALID_PARAMETER);
1916 return 0;
1917 }
1918 if (cchCount1 < 0) cchCount1 = strlen(lpString1);
1919 if (cchCount2 < 0) cchCount2 = strlen(lpString2);
1920
1921 if (!(dwCmpFlags & LOCALE_USE_CP_ACP)) locale_cp = get_lcid_codepage(Locale);
1922
1923 len1W = MultiByteToWideChar(locale_cp, 0, lpString1, cchCount1, buf1W, 130);
1924 if (len1W)
1925 str1W = buf1W;
1926 else
1927 {
1928 len1W = MultiByteToWideChar(locale_cp, 0, lpString1, cchCount1, NULL, 0);
1929 str1W = HeapAlloc(GetProcessHeap(), 0, len1W * sizeof(WCHAR));
1930 if (!str1W)
1931 {
1932 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1933 return 0;
1934 }
1935 MultiByteToWideChar(locale_cp, 0, lpString1, cchCount1, str1W, len1W);
1936 }
1937 len2W = MultiByteToWideChar(locale_cp, 0, lpString2, cchCount2, buf2W, 130);
1938 if (len2W)
1939 str2W = buf2W;
1940 else
1941 {
1942 len2W = MultiByteToWideChar(locale_cp, 0, lpString2, cchCount2, NULL, 0);
1943 str2W = HeapAlloc(GetProcessHeap(), 0, len2W * sizeof(WCHAR));
1944 if (!str2W)
1945 {
1946 if (str1W != buf1W) HeapFree(GetProcessHeap(), 0, str1W);
1947 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1948 return 0;
1949 }
1950 MultiByteToWideChar(locale_cp, 0, lpString2, cchCount2, str2W, len2W);
1951 }
1952
1953 ret = CompareStringW(Locale, dwCmpFlags, str1W, len1W, str2W, len2W);
1954
1955 if (str1W != buf1W) HeapFree(GetProcessHeap(), 0, str1W);
1956 if (str2W != buf2W) HeapFree(GetProcessHeap(), 0, str2W);
1957 return ret;
1958 }
1959
1960 /*
1961 * @implemented (Synced to Wine-22/11/2008)
1962 */
1963 int
1964 WINAPI
1965 CompareStringW (
1966 LCID Locale,
1967 DWORD dwCmpFlags,
1968 LPCWSTR lpString1,
1969 int cchCount1,
1970 LPCWSTR lpString2,
1971 int cchCount2
1972 )
1973 {
1974 INT Result;
1975
1976 if (!lpString1 || !lpString2)
1977 {
1978 SetLastError(ERROR_INVALID_PARAMETER);
1979 return 0;
1980 }
1981
1982 if (dwCmpFlags & ~(NORM_IGNORECASE | NORM_IGNORENONSPACE |
1983 NORM_IGNORESYMBOLS | SORT_STRINGSORT | NORM_IGNOREKANATYPE |
1984 NORM_IGNOREWIDTH | LOCALE_USE_CP_ACP | 0x10000000))
1985 {
1986 SetLastError(ERROR_INVALID_FLAGS);
1987 return 0;
1988 }
1989
1990 /* this style is related to diacritics in Arabic, Japanese, and Hebrew */
1991 if (dwCmpFlags & 0x10000000)
1992 DPRINT1("Ignoring unknown style 0x10000000\n");
1993
1994 if (cchCount1 < 0) cchCount1 = wcslen(lpString1);
1995 if (cchCount2 < 0) cchCount2 = wcslen(lpString2);
1996
1997 Result = wine_compare_string(dwCmpFlags, lpString1, cchCount1, lpString2, cchCount2);
1998
1999 if (Result) /* need to translate result */
2000 return (Result < 0) ? CSTR_LESS_THAN : CSTR_GREATER_THAN;
2001
2002 return CSTR_EQUAL;
2003 }
2004
2005
2006
2007
2008 /*
2009 * @implemented
2010 *
2011 * Get information about an aspect of a locale.
2012 *
2013 * PARAMS
2014 * lcid [I] LCID of the locale
2015 * lctype [I] LCTYPE_ flags from "winnls.h"
2016 * buffer [O] Destination for the information
2017 * len [I] Length of buffer in characters
2018 *
2019 * RETURNS
2020 * Success: The size of the data requested. If buffer is non-NULL, it is filled
2021 * with the information.
2022 * Failure: 0. Use GetLastError() to determine the cause.
2023 *
2024 * NOTES
2025 * - LOCALE_NEUTRAL is equal to LOCALE_SYSTEM_DEFAULT
2026 * - The string returned is NUL terminated, except for LOCALE_FONTSIGNATURE,
2027 * which is a bit string.
2028 */
2029 INT WINAPI GetLocaleInfoA( LCID lcid, LCTYPE lctype, LPSTR buffer, INT len )
2030 {
2031 WCHAR *bufferW;
2032 INT lenW, ret;
2033
2034 if (len < 0 || (len && !buffer))
2035 {
2036 SetLastError( ERROR_INVALID_PARAMETER );
2037 return 0;
2038 }
2039 if (lctype & LOCALE_RETURN_GENITIVE_NAMES )
2040 {
2041 SetLastError( ERROR_INVALID_FLAGS );
2042 return 0;
2043 }
2044
2045 if (!len) buffer = NULL;
2046
2047 if (!(lenW = GetLocaleInfoW( lcid, lctype, NULL, 0 ))) return 0;
2048
2049 if (!(bufferW = HeapAlloc( GetProcessHeap(), 0, lenW * sizeof(WCHAR) )))
2050 {
2051 SetLastError( ERROR_NOT_ENOUGH_MEMORY );
2052 return 0;
2053 }
2054 if ((ret = GetLocaleInfoW( lcid, lctype, bufferW, lenW )))
2055 {
2056 if ((lctype & LOCALE_RETURN_NUMBER) ||
2057 ((lctype & ~LOCALE_LOCALEINFOFLAGSMASK) == LOCALE_FONTSIGNATURE))
2058 {
2059 /* it's not an ASCII string, just bytes */
2060 ret *= sizeof(WCHAR);
2061 if (buffer)
2062 {
2063 if (ret <= len) memcpy( buffer, bufferW, ret );
2064 else
2065 {
2066 SetLastError( ERROR_INSUFFICIENT_BUFFER );
2067 ret = 0;
2068 }
2069 }
2070 }
2071 else
2072 {
2073 UINT codepage = CP_ACP;
2074 if (!(lctype & LOCALE_USE_CP_ACP)) codepage = get_lcid_codepage( lcid );
2075 ret = WideCharToMultiByte( codepage, 0, bufferW, ret, buffer, len, NULL, NULL );
2076 }
2077 }
2078 HeapFree( GetProcessHeap(), 0, bufferW );
2079 return ret;
2080 }
2081
2082
2083 /*
2084 * @implemented
2085 */
2086 LANGID WINAPI
2087 GetSystemDefaultLangID(VOID)
2088 {
2089 return LANGIDFROMLCID(GetSystemDefaultLCID());
2090 }
2091
2092
2093 /*
2094 * @implemented
2095 */
2096 LCID WINAPI
2097 GetSystemDefaultLCID(VOID)
2098 {
2099 LCID lcid;
2100
2101 NtQueryDefaultLocale(FALSE, &lcid);
2102
2103 return lcid;
2104 }
2105
2106
2107 /*
2108 * @implemented
2109 */
2110 LANGID WINAPI
2111 GetSystemDefaultUILanguage(VOID)
2112 {
2113 LANGID LanguageId;
2114 NTSTATUS Status;
2115
2116 Status = NtQueryInstallUILanguage(&LanguageId);
2117 if (!NT_SUCCESS(Status))
2118 {
2119 SetLastErrorByStatus(Status);
2120 return 0;
2121 }
2122
2123 return LanguageId;
2124 }
2125
2126
2127 /*
2128 * @implemented
2129 */
2130 LCID WINAPI
2131 GetThreadLocale(VOID)
2132 {
2133 return NtCurrentTeb()->CurrentLocale;
2134 }
2135
2136
2137 /*
2138 * @implemented
2139 */
2140 LANGID WINAPI
2141 GetUserDefaultLangID(VOID)
2142 {
2143 return LANGIDFROMLCID(GetUserDefaultLCID());
2144 }
2145
2146
2147 /*
2148 * @implemented
2149 */
2150 LCID WINAPI
2151 GetUserDefaultLCID(VOID)
2152 {
2153 LCID lcid;
2154 NTSTATUS Status;
2155
2156 Status = NtQueryDefaultLocale(TRUE, &lcid);
2157 if (!NT_SUCCESS(Status))
2158 {
2159 SetLastErrorByStatus(Status);
2160 return 0;
2161 }
2162
2163 return lcid;
2164 }
2165
2166
2167 /*
2168 * @implemented
2169 */
2170 LANGID WINAPI
2171 GetUserDefaultUILanguage(VOID)
2172 {
2173 LANGID LangId;
2174 NTSTATUS Status;
2175
2176 Status = NtQueryDefaultUILanguage(&LangId);
2177 if (!NT_SUCCESS(Status))
2178 {
2179 SetLastErrorByStatus(Status);
2180 return 0;
2181 }
2182
2183 return LangId;
2184 }
2185
2186
2187 /*
2188 * @unimplemented
2189 */
2190 GEOID
2191 WINAPI
2192 GetUserGeoID(
2193 GEOCLASS GeoClass)
2194 {
2195 GEOID ret = GEOID_NOT_AVAILABLE;
2196 static const WCHAR geoW[] = {'G','e','o',0};
2197 static const WCHAR nationW[] = {'N','a','t','i','o','n',0};
2198 WCHAR bufferW[40], *end;
2199 DWORD count;
2200 HANDLE hkey, hSubkey = 0;
2201 UNICODE_STRING keyW;
2202 const KEY_VALUE_PARTIAL_INFORMATION *info = (KEY_VALUE_PARTIAL_INFORMATION *)bufferW;
2203 RtlInitUnicodeString( &keyW, nationW );
2204 count = sizeof(bufferW);
2205
2206 if(!(hkey = create_registry_key())) return ret;
2207
2208 switch( GeoClass ){
2209 case GEOCLASS_NATION:
2210 if ((hSubkey = NLS_RegOpenKey(hkey, geoW)))
2211 {
2212 if((NtQueryValueKey(hSubkey, &keyW, KeyValuePartialInformation,
2213 (LPBYTE)bufferW, count, &count) == STATUS_SUCCESS ) && info->DataLength)
2214 ret = wcstol((LPCWSTR)info->Data, &end, 10);
2215 }
2216 break;
2217 case GEOCLASS_REGION:
2218 DPRINT("GEOCLASS_REGION not handled yet\n");
2219 break;
2220 }
2221
2222 NtClose(hkey);
2223 if (hSubkey) NtClose(hSubkey);
2224 return ret;
2225 }
2226
2227
2228 /******************************************************************************
2229 * IsValidLanguageGroup
2230 *
2231 * Determine if a language group is supported and/or installed.
2232 *
2233 * PARAMS
2234 * LanguageGroup [I] Language Group Id (LGRPID_ values from "winnls.h")
2235 * dwFlags [I] LGRPID_SUPPORTED=Supported, LGRPID_INSTALLED=Installed
2236 *
2237 * RETURNS
2238 * TRUE, if lgrpid is supported and/or installed, according to dwFlags.
2239 * FALSE otherwise.
2240 *
2241 * @implemented
2242 */
2243 BOOL
2244 WINAPI
2245 IsValidLanguageGroup(
2246 LGRPID LanguageGroup,
2247 DWORD dwFlags)
2248 {
2249 static const WCHAR szFormat[] = { '%','x','\0' };
2250 WCHAR szValueName[16], szValue[2];
2251 BOOL bSupported = FALSE, bInstalled = FALSE;
2252 HANDLE hKey;
2253
2254
2255 switch (dwFlags)
2256 {
2257 case LGRPID_INSTALLED:
2258 case LGRPID_SUPPORTED:
2259
2260 hKey = NLS_RegOpenKey( 0, szLangGroupsKeyName );
2261 if (!hKey)
2262 break;
2263
2264 swprintf( szValueName, szFormat, LanguageGroup );
2265
2266 if (NLS_RegGetDword( hKey, szValueName, (LPDWORD)szValue ))
2267 {
2268 bSupported = TRUE;
2269
2270 if (szValue[0] == '1')
2271 bInstalled = TRUE;
2272 }
2273
2274 NtClose( hKey );
2275
2276 break;
2277
2278 default:
2279 DPRINT("Invalid flags: %lx\n", dwFlags);
2280 return FALSE;
2281 }
2282
2283 if ((dwFlags == LGRPID_SUPPORTED && bSupported) ||
2284 (dwFlags == LGRPID_INSTALLED && bInstalled))
2285 return TRUE;
2286
2287 return FALSE;
2288 }
2289
2290
2291 /******************************************************************************
2292 * IsValidLocale
2293 *
2294 * Determine if a locale is valid.
2295 *
2296 * PARAMS
2297 * Locale [I] LCID of the locale to check
2298 * dwFlags [I] LCID_SUPPORTED = Valid
2299 * LCID_INSTALLED = Valid and installed on the system
2300 *
2301 * RETURN
2302 * TRUE, if Locale is valid,
2303 * FALSE, otherwise.
2304 *
2305 * @implemented
2306 */
2307 BOOL WINAPI
2308 IsValidLocale(LCID Locale,
2309 DWORD dwFlags)
2310 {
2311 OBJECT_ATTRIBUTES ObjectAttributes;
2312 PKEY_VALUE_PARTIAL_INFORMATION KeyInfo;
2313 WCHAR ValueNameBuffer[9];
2314 UNICODE_STRING KeyName;
2315 UNICODE_STRING ValueName;
2316 ULONG KeyInfoSize;
2317 ULONG ReturnedSize;
2318 HANDLE KeyHandle;
2319 PWSTR ValueData;
2320 NTSTATUS Status;
2321 BOOL Installed = FALSE;
2322
2323 DPRINT("IsValidLocale() called\n");
2324
2325 if ((dwFlags & ~(LCID_SUPPORTED | LCID_INSTALLED)) ||
2326 (dwFlags == (LCID_SUPPORTED | LCID_INSTALLED)))
2327 {
2328 DPRINT("Invalid flags: %lx\n", dwFlags);
2329 return FALSE;
2330 }
2331
2332 if (Locale & 0xFFFF0000)
2333 {
2334 RtlInitUnicodeString(&KeyName,
2335 L"\\REGISTRY\\Machine\\SYSTEM\\CurrentControlSet\\Control\\Nls\\Locale\\Alternate Sorts");
2336 }
2337 else
2338 {
2339 RtlInitUnicodeString(&KeyName,
2340 L"\\REGISTRY\\Machine\\SYSTEM\\CurrentControlSet\\Control\\Nls\\Locale");
2341 }
2342
2343 InitializeObjectAttributes(&ObjectAttributes,
2344 &KeyName,
2345 OBJ_CASE_INSENSITIVE,
2346 NULL,
2347 NULL);
2348
2349 Status = NtOpenKey(&KeyHandle,
2350 KEY_QUERY_VALUE,
2351 &ObjectAttributes);
2352 if (!NT_SUCCESS(Status))
2353 {
2354 DPRINT("NtOpenKey() failed (Status %lx)\n", Status);
2355 SetLastError(ERROR_BADDB);
2356 return FALSE;
2357 }
2358
2359 swprintf(ValueNameBuffer, L"%08lx", (ULONG)Locale);
2360 RtlInitUnicodeString(&ValueName, ValueNameBuffer);
2361
2362 KeyInfoSize = sizeof(KEY_VALUE_PARTIAL_INFORMATION) + 4 * sizeof(WCHAR);
2363 KeyInfo = RtlAllocateHeap(RtlGetProcessHeap(),
2364 HEAP_ZERO_MEMORY,
2365 KeyInfoSize);
2366 if (KeyInfo == NULL)
2367 {
2368 DPRINT("RtlAllocateHeap() failed (Status %lx)\n", Status);
2369 NtClose(KeyHandle);
2370 return FALSE;
2371 }
2372
2373 Status = NtQueryValueKey(KeyHandle,
2374 &ValueName,
2375 KeyValuePartialInformation,
2376 KeyInfo,
2377 KeyInfoSize,
2378 &ReturnedSize);
2379 NtClose(KeyHandle);
2380
2381 if (!NT_SUCCESS(Status))
2382 {
2383 DPRINT("NtQueryValueKey() failed (Status %lx)\n", Status);
2384 RtlFreeHeap(RtlGetProcessHeap(), 0, KeyInfo);
2385 return FALSE;
2386 }
2387
2388 if (dwFlags & LCID_SUPPORTED)
2389 {
2390 DPRINT("Locale is supported\n");
2391 RtlFreeHeap(RtlGetProcessHeap(), 0, KeyInfo);
2392 return TRUE;
2393 }
2394
2395 ValueData = (PWSTR)&KeyInfo->Data[0];
2396 if ((KeyInfo->Type == REG_SZ) &&
2397 (KeyInfo->DataLength == 2 * sizeof(WCHAR)))
2398 {
2399 /* Find out if there is support for the language group
2400 * installed, to which this language belongs */
2401 KeyHandle = NLS_RegOpenKey(0, szLangGroupsKeyName);
2402 if (KeyHandle)
2403 {
2404 WCHAR Value[2];
2405 if (NLS_RegGetDword(KeyHandle, ValueData, (LPDWORD) Value) &&
2406 Value[0] == L'1')
2407 {
2408 Installed = TRUE;
2409 DPRINT("Locale is supported and installed\n");
2410 }
2411
2412 NtClose(KeyHandle);
2413 }
2414 }
2415
2416 RtlFreeHeap(RtlGetProcessHeap(), 0, KeyInfo);
2417
2418 DPRINT("IsValidLocale() called\n");
2419
2420 return Installed;
2421 }
2422
2423 /*
2424 * @implemented
2425 */
2426 int
2427 WINAPI
2428 LCMapStringA (
2429 LCID Locale,
2430 DWORD dwMapFlags,
2431 LPCSTR lpSrcStr,
2432 int cchSrc,
2433 LPSTR lpDestStr,
2434 int cchDest
2435 )
2436 {
2437 WCHAR *bufW = NtCurrentTeb()->StaticUnicodeBuffer;
2438 LPWSTR srcW, dstW;
2439 INT ret = 0, srclenW, dstlenW;
2440 UINT locale_cp = CP_ACP;
2441
2442 if (!lpSrcStr || !cchSrc || cchDest < 0)
2443 {
2444 SetLastError(ERROR_INVALID_PARAMETER);
2445 return 0;
2446 }
2447
2448 if (!(dwMapFlags & LOCALE_USE_CP_ACP)) locale_cp = get_lcid_codepage(Locale);
2449
2450 srclenW = MultiByteToWideChar(locale_cp, 0, lpSrcStr, cchSrc, bufW, 260);
2451 if (srclenW)
2452 srcW = bufW;
2453 else
2454 {
2455 srclenW = MultiByteToWideChar(locale_cp, 0, lpSrcStr, cchSrc, NULL, 0);
2456 srcW = HeapAlloc(GetProcessHeap(), 0, srclenW * sizeof(WCHAR));
2457 if (!srcW)
2458 {
2459 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
2460 return 0;
2461 }
2462 MultiByteToWideChar(locale_cp, 0, lpSrcStr, cchSrc, srcW, srclenW);
2463 }
2464
2465 if (dwMapFlags & LCMAP_SORTKEY)
2466 {
2467 if (lpSrcStr == lpDestStr)
2468 {
2469 SetLastError(ERROR_INVALID_FLAGS);
2470 goto map_string_exit;
2471 }
2472 ret = wine_get_sortkey(dwMapFlags, srcW, srclenW, lpDestStr, cchDest);
2473 if (ret == 0)
2474 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2475 else
2476 ret++;
2477 goto map_string_exit;
2478 }
2479
2480 if (dwMapFlags & SORT_STRINGSORT)
2481 {
2482 SetLastError(ERROR_INVALID_FLAGS);
2483 goto map_string_exit;
2484 }
2485
2486 dstlenW = LCMapStringW(Locale, dwMapFlags, srcW, srclenW, NULL, 0);
2487 if (!dstlenW)
2488 goto map_string_exit;
2489
2490 dstW = HeapAlloc(GetProcessHeap(), 0, dstlenW * sizeof(WCHAR));
2491 if (!dstW)
2492 {
2493 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
2494 goto map_string_exit;
2495 }
2496
2497 LCMapStringW(Locale, dwMapFlags, srcW, srclenW, dstW, dstlenW);
2498 ret = WideCharToMultiByte(locale_cp, 0, dstW, dstlenW, lpDestStr, cchDest, NULL, NULL);
2499 HeapFree(GetProcessHeap(), 0, dstW);
2500
2501 map_string_exit:
2502 if (srcW != bufW) HeapFree(GetProcessHeap(), 0, srcW);
2503 return ret;
2504 }
2505
2506
2507 /*
2508 * @implemented
2509 */
2510 int
2511 WINAPI
2512 LCMapStringW (
2513 LCID Locale,
2514 DWORD dwMapFlags,
2515 LPCWSTR lpSrcStr,
2516 int cchSrc,
2517 LPWSTR lpDestStr,
2518 int cchDest
2519 )
2520 {
2521 LPWSTR dst_ptr;
2522
2523 if (!lpSrcStr || !cchSrc || cchDest < 0)
2524 {
2525 SetLastError(ERROR_INVALID_PARAMETER);
2526 return 0;
2527 }
2528
2529 /* mutually exclusive flags */
2530 if ((dwMapFlags & (LCMAP_LOWERCASE | LCMAP_UPPERCASE)) == (LCMAP_LOWERCASE | LCMAP_UPPERCASE) ||
2531 (dwMapFlags & (LCMAP_HIRAGANA | LCMAP_KATAKANA)) == (LCMAP_HIRAGANA | LCMAP_KATAKANA) ||
2532 (dwMapFlags & (LCMAP_HALFWIDTH | LCMAP_FULLWIDTH)) == (LCMAP_HALFWIDTH | LCMAP_FULLWIDTH) ||
2533 (dwMapFlags & (LCMAP_TRADITIONAL_CHINESE | LCMAP_SIMPLIFIED_CHINESE)) == (LCMAP_TRADITIONAL_CHINESE | LCMAP_SIMPLIFIED_CHINESE))
2534 {
2535 SetLastError(ERROR_INVALID_FLAGS);
2536 return 0;
2537 }
2538
2539 if (!cchDest) lpDestStr = NULL;
2540
2541 Locale = ConvertDefaultLocale(Locale);
2542
2543 if (dwMapFlags & LCMAP_SORTKEY)
2544 {
2545 INT ret;
2546 if (lpSrcStr == lpDestStr)
2547 {
2548 SetLastError(ERROR_INVALID_FLAGS);
2549 return 0;
2550 }
2551
2552 if (cchSrc < 0) cchSrc = wcslen(lpSrcStr);
2553
2554 ret = wine_get_sortkey(dwMapFlags, lpSrcStr, cchSrc, (char *)lpDestStr, cchDest);
2555 if (ret == 0)
2556 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2557 return ret;
2558 }
2559
2560 /* SORT_STRINGSORT must be used exclusively with LCMAP_SORTKEY */
2561 if (dwMapFlags & SORT_STRINGSORT)
2562 {
2563 SetLastError(ERROR_INVALID_FLAGS);
2564 return 0;
2565 }
2566
2567 if (cchSrc < 0) cchSrc = wcslen(lpSrcStr) + 1;
2568
2569 if (!lpDestStr) /* return required string length */
2570 {
2571 INT len;
2572
2573 for (len = 0; cchSrc; lpSrcStr++, cchSrc--)
2574 {
2575 WCHAR wch = *lpSrcStr;
2576 /* tests show that win2k just ignores NORM_IGNORENONSPACE,
2577 * and skips white space and punctuation characters for
2578 * NORM_IGNORESYMBOLS.
2579 */
2580 if ((dwMapFlags & NORM_IGNORESYMBOLS) && (iswctype(wch, _SPACE | _PUNCT)))
2581 continue;
2582 len++;
2583 }
2584 return len;
2585 }
2586
2587 if (dwMapFlags & LCMAP_UPPERCASE)
2588 {
2589 for (dst_ptr = lpDestStr; cchSrc && cchDest; lpSrcStr++, cchSrc--)
2590 {
2591 WCHAR wch = *lpSrcStr;
2592 if ((dwMapFlags & NORM_IGNORESYMBOLS) && (iswctype(wch, _SPACE | _PUNCT)))
2593 continue;
2594 *dst_ptr++ = towupper(wch);
2595 cchDest--;
2596 }
2597 }
2598 else if (dwMapFlags & LCMAP_LOWERCASE)
2599 {
2600 for (dst_ptr = lpDestStr; cchSrc && cchDest; lpSrcStr++, cchSrc--)
2601 {
2602 WCHAR wch = *lpSrcStr;
2603 if ((dwMapFlags & NORM_IGNORESYMBOLS) && (iswctype(wch, _SPACE | _PUNCT)))
2604 continue;
2605 *dst_ptr++ = towlower(wch);
2606 cchDest--;
2607 }
2608 }
2609 else
2610 {
2611 if (lpSrcStr == lpDestStr)
2612 {
2613 SetLastError(ERROR_INVALID_FLAGS);
2614 return 0;
2615 }
2616 for (dst_ptr = lpDestStr; cchSrc && cchDest; lpSrcStr++, cchSrc--)
2617 {
2618 WCHAR wch = *lpSrcStr;
2619 if ((dwMapFlags & NORM_IGNORESYMBOLS) && (iswctype(wch, _SPACE | _PUNCT)))
2620 continue;
2621 *dst_ptr++ = wch;
2622 cchDest--;
2623 }
2624 }
2625
2626 if (cchSrc)
2627 {
2628 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2629 return 0;
2630 }
2631
2632 return dst_ptr - lpDestStr;
2633 }
2634
2635
2636 /*
2637 * @unimplemented
2638 */
2639 BOOL
2640 WINAPI
2641 SetCalendarInfoA(
2642 LCID Locale,
2643 CALID Calendar,
2644 CALTYPE CalType,
2645 LPCSTR lpCalData)
2646 {
2647 if (!Locale || !lpCalData)
2648 {
2649 SetLastError(ERROR_INVALID_PARAMETER);
2650 return FALSE;
2651 }
2652
2653 switch (CalType)
2654 {
2655 case CAL_NOUSEROVERRIDE:
2656 case CAL_RETURN_NUMBER:
2657 case CAL_USE_CP_ACP:
2658 break;
2659 default:
2660 SetLastError(ERROR_INVALID_FLAGS);
2661 return FALSE;
2662 }
2663
2664 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
2665 return FALSE;
2666 }
2667
2668 /*
2669 * @unimplemented
2670 */
2671 BOOL
2672 WINAPI
2673 SetCalendarInfoW(
2674 LCID Locale,
2675 CALID Calendar,
2676 CALTYPE CalType,
2677 LPCWSTR lpCalData)
2678 {
2679 if (!Locale || !lpCalData)
2680 {
2681 SetLastError(ERROR_INVALID_PARAMETER);
2682 return FALSE;
2683 }
2684
2685 switch (CalType)
2686 {
2687 case CAL_NOUSEROVERRIDE:
2688 case CAL_RETURN_NUMBER:
2689 case CAL_USE_CP_ACP:
2690 break;
2691 default:
2692 SetLastError(ERROR_INVALID_FLAGS);
2693 return FALSE;
2694 }
2695
2696 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
2697 return FALSE;
2698 }
2699
2700
2701 /**********************************************************************
2702 * @implemented
2703 * RIPPED FROM WINE's dlls\kernel\locale.c ver 0.9.29
2704 *
2705 * SetLocaleInfoA (KERNEL32.@)
2706 *
2707 * Set the current locale info.
2708 *
2709 * PARAMS
2710 * Locale [I] LCID of the locale
2711 * LCType [I] LCTYPE_ flags from "winnls.h"
2712 * lpLCData [I] Information to set
2713 *
2714 * RETURNS
2715 * Success: TRUE. The information given will be returned by GetLocaleInfoA()
2716 * whenever it is called without LOCALE_NOUSEROVERRIDE.
2717 * Failure: FALSE. Use GetLastError() to determine the cause.
2718 */
2719 BOOL
2720 WINAPI
2721 SetLocaleInfoA (
2722 LCID Locale,
2723 LCTYPE LCType,
2724 LPCSTR lpLCData
2725 )
2726 {
2727 UINT codepage = CP_ACP;
2728 WCHAR *strW;
2729 DWORD len;
2730 BOOL ret;
2731
2732 if (!(LCType & LOCALE_USE_CP_ACP)) codepage = get_lcid_codepage( Locale );
2733
2734 if (!lpLCData)
2735 {
2736 SetLastError( ERROR_INVALID_PARAMETER );
2737 return FALSE;
2738 }
2739 len = MultiByteToWideChar( codepage, 0, lpLCData, -1, NULL, 0 );
2740 if (!(strW = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) )))
2741 {
2742 SetLastError( ERROR_NOT_ENOUGH_MEMORY );
2743 return FALSE;
2744 }
2745 MultiByteToWideChar( codepage, 0, lpLCData, -1, strW, len );
2746 ret = SetLocaleInfoW( Locale, LCType, strW );
2747 HeapFree( GetProcessHeap(), 0, strW );
2748 return ret;
2749 }
2750
2751
2752 /**********************************************************************
2753 * @implemented
2754 * RIPPED FROM WINE's dlls\kernel\locale.c ver 0.9.29
2755 *
2756 * SetLocaleInfoW (KERNEL32.@)
2757 *
2758 * See SetLocaleInfoA.
2759 *
2760 */
2761 BOOL
2762 WINAPI
2763 SetLocaleInfoW (
2764 LCID Locale,
2765 LCTYPE LCType,
2766 LPCWSTR lpLCData
2767 )
2768 {
2769 const WCHAR *value;
2770 UNICODE_STRING valueW;
2771 NTSTATUS status;
2772 HANDLE hkey;
2773
2774 LCType &= 0xffff;
2775 value = RosGetLocaleValueName( LCType );
2776
2777 if (!lpLCData || !value)
2778 {
2779 SetLastError( ERROR_INVALID_PARAMETER );
2780 return FALSE;
2781 }
2782
2783 if (LCType == LOCALE_IDATE || LCType == LOCALE_ILDATE)
2784 {
2785 SetLastError( ERROR_INVALID_FLAGS );
2786 return FALSE;
2787 }
2788
2789 if (!(hkey = RosCreateRegistryKey())) return FALSE;
2790 RtlInitUnicodeString( &valueW, value );
2791 status = NtSetValueKey( hkey, &valueW, 0, REG_SZ, (PVOID)lpLCData, (lstrlenW(lpLCData)+1)*sizeof(WCHAR) );
2792
2793 if (LCType == LOCALE_SSHORTDATE || LCType == LOCALE_SLONGDATE)
2794 {
2795 /* Set I-value from S value */
2796 WCHAR *lpD, *lpM, *lpY;
2797 WCHAR szBuff[2];
2798
2799 lpD = wcschr(lpLCData, 'd');
2800 lpM = wcschr(lpLCData, 'M');
2801 lpY = wcschr(lpLCData, 'y');
2802
2803 if (lpD <= lpM)
2804 {
2805 szBuff[0] = '1'; /* D-M-Y */
2806 }
2807 else
2808 {
2809 if (lpY <= lpM)
2810 szBuff[0] = '2'; /* Y-M-D */
2811 else
2812 szBuff[0] = '0'; /* M-D-Y */
2813 }
2814
2815 szBuff[1] = '\0';
2816
2817 if (LCType == LOCALE_SSHORTDATE)
2818 LCType = LOCALE_IDATE;
2819 else
2820 LCType = LOCALE_ILDATE;
2821
2822 value = RosGetLocaleValueName( LCType );
2823
2824 RtlInitUnicodeString( &valueW, value );
2825 status = NtSetValueKey( hkey, &valueW, 0, REG_SZ, szBuff, sizeof(szBuff) );
2826 }
2827
2828 NtClose( hkey );
2829
2830 if (status) SetLastError( RtlNtStatusToDosError(status) );
2831 return !status;
2832 }
2833
2834
2835 /**********************************************************************
2836 * @implemented
2837 * RIPPED FROM WINE's dlls\kernel\locale.c rev 1.42
2838 *
2839 * SetThreadLocale (KERNEL32.@)
2840 *
2841 * Set the current threads locale.
2842 *
2843 * PARAMS
2844 * lcid [I] LCID of the locale to set
2845 *
2846 * RETURNS
2847 * Success: TRUE. The threads locale is set to lcid.
2848 * Failure: FALSE. Use GetLastError() to determine the cause.
2849 *
2850 */
2851 BOOL WINAPI SetThreadLocale( LCID lcid )
2852 {
2853 DPRINT("SetThreadLocale(0x%04lX)\n", lcid);
2854
2855 lcid = ConvertDefaultLocale(lcid);
2856
2857 if (lcid != GetThreadLocale())
2858 {
2859 if (!IsValidLocale(lcid, LCID_SUPPORTED))
2860 {
2861 SetLastError(ERROR_INVALID_PARAMETER);
2862 return FALSE;
2863 }
2864
2865 NtCurrentTeb()->CurrentLocale = lcid;
2866 /* FIXME: NtCurrentTeb()->code_page = get_lcid_codepage( lcid );
2867 * Wine save the acp for easy/fast access, but ROS has no such Teb member.
2868 * Maybe add this member to ros as well?
2869 */
2870
2871 /*
2872 Lag test app for å se om locale etc, endres i en app. etter at prosessen er
2873 startet, eller om bare nye prosesser blir berørt.
2874 */
2875 }
2876 return TRUE;
2877 }
2878
2879
2880 /*
2881 * @implemented
2882 */
2883 BOOL WINAPI
2884 SetUserDefaultLCID(LCID lcid)
2885 {
2886 NTSTATUS Status;
2887
2888 Status = NtSetDefaultLocale(TRUE, lcid);
2889 if (!NT_SUCCESS(Status))
2890 {
2891 SetLastErrorByStatus(Status);
2892 return 0;
2893 }
2894 return 1;
2895 }
2896
2897
2898 /*
2899 * @implemented
2900 */
2901 BOOL WINAPI
2902 SetUserDefaultUILanguage(LANGID LangId)
2903 {
2904 NTSTATUS Status;
2905
2906 Status = NtSetDefaultUILanguage(LangId);
2907 if (!NT_SUCCESS(Status))
2908 {
2909 SetLastErrorByStatus(Status);
2910 return 0;
2911 }
2912 return 1;
2913 }
2914
2915
2916 /*
2917 * @implemented
2918 */
2919 BOOL
2920 WINAPI
2921 SetUserGeoID(
2922 GEOID GeoId)
2923 {
2924 static const WCHAR geoW[] = {'G','e','o',0};
2925 static const WCHAR nationW[] = {'N','a','t','i','o','n',0};
2926 static const WCHAR formatW[] = {'%','i',0};
2927 UNICODE_STRING nameW,keyW;
2928 WCHAR bufferW[10];
2929 OBJECT_ATTRIBUTES attr;
2930 HANDLE hkey;
2931
2932 if(!(hkey = create_registry_key())) return FALSE;
2933
2934 attr.Length = sizeof(attr);
2935 attr.RootDirectory = hkey;
2936 attr.ObjectName = &nameW;
2937 attr.Attributes = 0;
2938 attr.SecurityDescriptor = NULL;
2939 attr.SecurityQualityOfService = NULL;
2940 RtlInitUnicodeString( &nameW, geoW );
2941 RtlInitUnicodeString( &keyW, nationW );
2942
2943 if (NtCreateKey( &hkey, KEY_ALL_ACCESS, &attr, 0, NULL, 0, NULL ) != STATUS_SUCCESS)
2944
2945 {
2946 NtClose(attr.RootDirectory);
2947 return FALSE;
2948 }
2949
2950 swprintf(bufferW, formatW, GeoId);
2951 NtSetValueKey(hkey, &keyW, 0, REG_SZ, bufferW, (wcslen(bufferW) + 1) * sizeof(WCHAR));
2952 NtClose(attr.RootDirectory);
2953 NtClose(hkey);
2954 return TRUE;
2955 }
2956
2957
2958 /*
2959 * @implemented
2960 */
2961 DWORD
2962 WINAPI
2963 VerLanguageNameA (
2964 DWORD wLang,
2965 LPSTR szLang,
2966 DWORD nSize
2967 )
2968 {
2969 return GetLocaleInfoA( MAKELCID(wLang, SORT_DEFAULT), LOCALE_SENGLANGUAGE, szLang, nSize );
2970 }
2971
2972
2973 /*
2974 * @implemented
2975 */
2976 DWORD
2977 WINAPI
2978 VerLanguageNameW (
2979 DWORD wLang,
2980 LPWSTR szLang,
2981 DWORD nSize
2982 )
2983 {
2984 return GetLocaleInfoW( MAKELCID(wLang, SORT_DEFAULT), LOCALE_SENGLANGUAGE, szLang, nSize );
2985 }
2986
2987 /***********************************************************************
2988 * LCIDToLocaleName (KERNEL32.@) Wine 13.02.2009
2989 */
2990 INT WINAPI LCIDToLocaleName( LCID lcid, LPWSTR name, INT count, DWORD flags )
2991 {
2992 if (flags) DPRINT1( "unsupported flags %x\n", flags );
2993
2994 return GetLocaleInfoW( lcid, LOCALE_SNAME | LOCALE_NOUSEROVERRIDE, name, count );
2995 }