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