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