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