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