fixed some signed/unsigned comparison warnings with -Wsign-compare
[reactos.git] / reactos / lib / kernel32 / misc / lang.c
1 /* $Id$
2 *
3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT : ReactOS user mode libraries
5 * MODULE : kernel32.dll
6 * FILE : reactos/lib/kernel32/misc/lang.c
7 * AUTHOR : ???
8 */
9
10 #include <k32.h>
11
12 #define NDEBUG
13 #include "../include/debug.h"
14
15 /* FIXME: these are included in winnls.h, however including this file causes alot of
16 conflicting type errors. */
17
18 #define LOCALE_SYEARMONTH 0x1006
19 #define LOCALE_IPAPERSIZE 0x100A
20 #define LOCALE_RETURN_NUMBER 0x20000000
21 #define LOCALE_USE_CP_ACP 0x40000000
22 #define LOCALE_LOCALEINFOFLAGSMASK (LOCALE_NOUSEROVERRIDE|LOCALE_USE_CP_ACP|LOCALE_RETURN_NUMBER)
23
24 //static LCID SystemLocale = MAKELCID(LANG_ENGLISH, SORT_DEFAULT);
25
26 //static RTL_CRITICAL_SECTION LocalesListLock;
27
28 /******************************************************************************
29 * @implemented
30 * RIPPED FROM WINE's dlls\kernel\locale.c rev 1.42
31 *
32 * ConvertDefaultLocale (KERNEL32.@)
33 *
34 * Convert a default locale identifier into a real identifier.
35 *
36 * PARAMS
37 * lcid [I] LCID identifier of the locale to convert
38 *
39 * RETURNS
40 * lcid unchanged, if not a default locale or its sublanguage is
41 * not SUBLANG_NEUTRAL.
42 * GetSystemDefaultLCID(), if lcid == LOCALE_SYSTEM_DEFAULT.
43 * GetUserDefaultLCID(), if lcid == LOCALE_USER_DEFAULT or LOCALE_NEUTRAL.
44 * Otherwise, lcid with sublanguage changed to SUBLANG_DEFAULT.
45 */
46 LCID WINAPI
47 ConvertDefaultLocale(LCID lcid)
48 {
49 LANGID langid;
50
51 switch (lcid)
52 {
53 case LOCALE_SYSTEM_DEFAULT:
54 lcid = GetSystemDefaultLCID();
55 break;
56
57 case LOCALE_USER_DEFAULT:
58 case LOCALE_NEUTRAL:
59 lcid = GetUserDefaultLCID();
60 break;
61
62 default:
63 /* Replace SUBLANG_NEUTRAL with SUBLANG_DEFAULT */
64 langid = LANGIDFROMLCID(lcid);
65 if (SUBLANGID(langid) == SUBLANG_NEUTRAL)
66 {
67 langid = MAKELANGID(PRIMARYLANGID(langid), SUBLANG_DEFAULT);
68 lcid = MAKELCID(langid, SORTIDFROMLCID(lcid));
69 }
70 }
71
72 return lcid;
73 }
74
75
76 /*
77 * @unimplemented
78 */
79 BOOL
80 STDCALL
81 EnumCalendarInfoExA(
82 CALINFO_ENUMPROCEXA lpCalInfoEnumProcEx,
83 LCID Locale,
84 CALID Calendar,
85 CALTYPE CalType)
86 {
87 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
88 return 0;
89 }
90
91
92 /*
93 * @unimplemented
94 */
95 BOOL
96 STDCALL
97 EnumCalendarInfoExW(
98 CALINFO_ENUMPROCEXW lpCalInfoEnumProcEx,
99 LCID Locale,
100 CALID Calendar,
101 CALTYPE CalType)
102 {
103 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
104 return 0;
105 }
106
107
108
109
110 /*
111 * @unimplemented
112 */
113 BOOL
114 STDCALL
115 EnumDateFormatsExA(
116 DATEFMT_ENUMPROCEXA lpDateFmtEnumProcEx,
117 LCID Locale,
118 DWORD dwFlags)
119 {
120 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
121 return 0;
122 }
123
124
125 /*
126 * @unimplemented
127 */
128 BOOL
129 STDCALL
130 EnumDateFormatsExW(
131 DATEFMT_ENUMPROCEXW lpDateFmtEnumProcEx,
132 LCID Locale,
133 DWORD dwFlags)
134 {
135 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
136 return 0;
137 }
138
139
140 /*
141 * @unimplemented
142 */
143 BOOL
144 STDCALL
145 EnumLanguageGroupLocalesA(
146 LANGGROUPLOCALE_ENUMPROCA lpLangGroupLocaleEnumProc,
147 LGRPID LanguageGroup,
148 DWORD dwFlags,
149 LONG_PTR lParam)
150 {
151 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
152 return 0;
153 }
154
155
156 /*
157 * @unimplemented
158 */
159 BOOL
160 STDCALL
161 EnumLanguageGroupLocalesW(
162 LANGGROUPLOCALE_ENUMPROCW lpLangGroupLocaleEnumProc,
163 LGRPID LanguageGroup,
164 DWORD dwFlags,
165 LONG_PTR lParam)
166 {
167 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
168 return 0;
169 }
170
171
172 /*
173 * @unimplemented
174 */
175 BOOL
176 STDCALL
177 EnumSystemCodePagesW (
178 CODEPAGE_ENUMPROCW lpCodePageEnumProc,
179 DWORD dwFlags
180 )
181 {
182 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
183 return FALSE;
184 }
185
186
187 /*
188 * @unimplemented
189 */
190 BOOL
191 STDCALL
192 EnumSystemCodePagesA (
193 CODEPAGE_ENUMPROCA lpCodePageEnumProc,
194 DWORD dwFlags
195 )
196 {
197 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
198 return FALSE;
199 }
200
201
202 /*
203 * @unimplemented
204 */
205 BOOL
206 STDCALL
207 EnumSystemGeoID(
208 GEOCLASS GeoClass,
209 GEOID ParentGeoId,
210 GEO_ENUMPROC lpGeoEnumProc)
211 {
212 if(!lpGeoEnumProc)
213 {
214 SetLastError(ERROR_INVALID_PARAMETER);
215 return FALSE;
216 }
217
218 switch(GeoClass)
219 {
220 case GEOCLASS_NATION:
221 /*RtlEnterCriticalSection(&DllLock);
222
223 FIXME - Get GEO IDs calling Csr
224
225 RtlLeaveCriticalSection(&DllLock);*/
226
227 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
228 break;
229
230 default:
231 SetLastError(ERROR_INVALID_FLAGS);
232 return FALSE;
233 }
234
235 return FALSE;
236 }
237
238
239 /*
240 * @unimplemented
241 */
242 BOOL
243 STDCALL
244 EnumSystemLanguageGroupsA(
245 LANGUAGEGROUP_ENUMPROCA pLangGroupEnumProc,
246 DWORD dwFlags,
247 LONG_PTR lParam)
248 {
249 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
250 return 0;
251 }
252
253
254 /*
255 * @unimplemented
256 */
257 BOOL
258 STDCALL
259 EnumSystemLanguageGroupsW(
260 LANGUAGEGROUP_ENUMPROCW pLangGroupEnumProc,
261 DWORD dwFlags,
262 LONG_PTR lParam)
263 {
264 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
265 return 0;
266 }
267
268
269 /*
270 * @unimplemented
271 */
272 BOOL
273 STDCALL
274 EnumSystemLocalesA (
275 LOCALE_ENUMPROCA lpLocaleEnumProc,
276 DWORD dwFlags
277 )
278 {
279 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
280 return FALSE;
281 }
282
283
284 /*
285 * @implemented
286 */
287 BOOL
288 STDCALL
289 EnumSystemLocalesW (
290 LOCALE_ENUMPROCW lpLocaleEnumProc,
291 DWORD dwFlags
292 )
293 {
294 NTSTATUS result;
295 HANDLE langKey;
296 UNICODE_STRING langKeyName = RTL_CONSTANT_STRING(
297 L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\Nls\\Locale");
298 OBJECT_ATTRIBUTES objectAttributes;
299 ULONG index, length;
300 unsigned char fullInfo[sizeof(KEY_VALUE_FULL_INFORMATION)+255*2]; //FIXME: MAX_PATH*2
301 PKEY_VALUE_FULL_INFORMATION pFullInfo;
302
303 //TODO: Combine with EnumSystemLocalesA - maybe by having one common part, driven by some
304 // unicode/non-unicode flag.
305
306 //FIXME: dwFlags is really not used, sorry
307
308 // Check if enum proc is a real one
309 if (lpLocaleEnumProc == NULL)
310 {
311 SetLastError(ERROR_INVALID_PARAMETER);
312 return FALSE;
313 }
314
315 // Open language registry key
316 //FIXME: Should we use critical section here?
317
318 InitializeObjectAttributes(&objectAttributes,
319 &langKeyName,
320 OBJ_CASE_INSENSITIVE,
321 NULL,
322 NULL);
323
324 result = NtOpenKey(&langKey,
325 KEY_READ,
326 &objectAttributes);
327
328 if (!NT_SUCCESS(result))
329 return result;
330
331 DPRINT1("Registry key succesfully opened\n");
332
333 length = sizeof(KEY_VALUE_FULL_INFORMATION) + 255*2;//MAX_PATH*sizeof(WCHAR);
334 pFullInfo = (PKEY_VALUE_FULL_INFORMATION)&fullInfo;
335 RtlZeroMemory(pFullInfo, length);
336
337 index = 0;
338
339 result = NtEnumerateValueKey(langKey,
340 index,
341 KeyValueFullInformation,
342 pFullInfo,
343 length,
344 &length);
345
346 DPRINT1("First enumerate call result=%x\n", result);
347 while (result != STATUS_NO_MORE_ENTRIES)
348 {
349 int i;
350 WCHAR lpLocale[9];
351
352 // TODO: Here we should check, in case dwFlags & LCID_INSTALLED is specified,
353 // if this locale is really installed
354 // but for now we skip it
355
356 for (i=0; i<8; i++)
357 lpLocale[i] = pFullInfo->Name[i];
358
359 lpLocale[8]=0;
360
361 DPRINT1("Locale=%S\n", lpLocale);
362
363 // Call Enum func
364 if (!lpLocaleEnumProc((LPWSTR)lpLocale))
365 break;
366
367 // Zero previous values
368 RtlZeroMemory(pFullInfo, length);
369
370 index++;
371 result = NtEnumerateValueKey(langKey, index,KeyValueFullInformation, pFullInfo, length, &length);
372 }
373
374 NtClose(langKey);
375
376 return STATUS_SUCCESS;
377 }
378
379
380 /*
381 * @unimplemented
382 */
383 BOOL
384 STDCALL
385 EnumUILanguagesA(
386 UILANGUAGE_ENUMPROCA lpUILanguageEnumProc,
387 DWORD dwFlags,
388 LONG_PTR lParam)
389 {
390 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
391 return 0;
392 }
393
394
395 /*
396 * @unimplemented
397 */
398 BOOL
399 STDCALL
400 EnumUILanguagesW(
401 UILANGUAGE_ENUMPROCW lpUILanguageEnumProc,
402 DWORD dwFlags,
403 LONG_PTR lParam)
404 {
405 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
406 return 0;
407 }
408
409 /*
410 * @unimplemented
411 */
412 int
413 STDCALL
414 GetCalendarInfoA(
415 LCID Locale,
416 CALID Calendar,
417 CALTYPE CalType,
418 LPSTR lpCalData,
419 int cchData,
420 LPDWORD lpValue)
421 {
422 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
423 return 0;
424 }
425
426
427 /*
428 * @unimplemented
429 */
430 int
431 STDCALL
432 GetCalendarInfoW(
433 LCID Locale,
434 CALID Calendar,
435 CALTYPE CalType,
436 LPWSTR lpCalData,
437 int cchData,
438 LPDWORD lpValue)
439 {
440 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
441 return 0;
442 }
443
444
445 /*
446 * @unimplemented
447 */
448 BOOL
449 STDCALL
450 GetCPInfo (
451 UINT CodePage,
452 LPCPINFO CodePageInfo
453 )
454 {
455 unsigned i;
456
457 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
458
459 CodePageInfo->MaxCharSize = 1;
460 CodePageInfo->DefaultChar[0] = '?';
461 for (i = 1; i < MAX_DEFAULTCHAR; i++)
462 {
463 CodePageInfo->DefaultChar[i] = 0;
464 }
465 for (i = 0; i < MAX_LEADBYTES; i++)
466 {
467 CodePageInfo->LeadByte[i] = 0;
468 }
469
470 return TRUE;
471 }
472
473
474 /*
475 * @unimplemented
476 */
477 BOOL
478 STDCALL
479 GetCPInfoExW(
480 UINT CodePage,
481 DWORD dwFlags,
482 LPCPINFOEXW lpCPInfoEx)
483 {
484 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
485 return 0;
486 }
487
488
489 /*
490 * @unimplemented
491 */
492 BOOL
493 STDCALL
494 GetCPInfoExA(
495 UINT CodePage,
496 DWORD dwFlags,
497 LPCPINFOEXA lpCPInfoEx)
498 {
499 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
500 return 0;
501 }
502
503
504 /*
505 * @unimplemented
506 */
507 int
508 STDCALL
509 GetGeoInfoW(
510 GEOID Location,
511 GEOTYPE GeoType,
512 LPWSTR lpGeoData,
513 int cchData,
514 LANGID LangId)
515 {
516 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
517 return 0;
518 }
519
520
521 /*
522 * @unimplemented
523 */
524 int
525 STDCALL
526 GetGeoInfoA(
527 GEOID Location,
528 GEOTYPE GeoType,
529 LPSTR lpGeoData,
530 int cchData,
531 LANGID LangId)
532 {
533 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
534 return 0;
535 }
536
537 const WCHAR *RosGetLocaleValueName( DWORD lctype )
538 {
539 switch (lctype & ~LOCALE_LOCALEINFOFLAGSMASK)
540 {
541 /* These values are used by SetLocaleInfo and GetLocaleInfo, and
542 * the values are stored in the registry, confirmed under Windows.
543 */
544 case LOCALE_ICALENDARTYPE: return L"iCalendarType";
545 case LOCALE_ICURRDIGITS: return L"iCurrDigits";
546 case LOCALE_ICURRENCY: return L"iCurrency";
547 case LOCALE_IDIGITS: return L"iDigits";
548 case LOCALE_IFIRSTDAYOFWEEK: return L"iFirstDayOfWeek";
549 case LOCALE_IFIRSTWEEKOFYEAR: return L"iFirstWeekOfYear";
550 case LOCALE_ILZERO: return L"iLZero";
551 case LOCALE_IMEASURE: return L"iMeasure";
552 case LOCALE_INEGCURR: return L"iNegCurr";
553 case LOCALE_INEGNUMBER: return L"iNegNumber";
554 case LOCALE_IPAPERSIZE: return L"iPaperSize";
555 case LOCALE_ITIME: return L"iTime";
556 case LOCALE_S1159: return L"s1159";
557 case LOCALE_S2359: return L"s2359";
558 case LOCALE_SCURRENCY: return L"sCurrency";
559 case LOCALE_SDATE: return L"sDate";
560 case LOCALE_SDECIMAL: return L"sDecimal";
561 case LOCALE_SGROUPING: return L"sGrouping";
562 case LOCALE_SLIST: return L"sList";
563 case LOCALE_SLONGDATE: return L"sLongDate";
564 case LOCALE_SMONDECIMALSEP: return L"sMonDecimalSep";
565 case LOCALE_SMONGROUPING: return L"sMonGrouping";
566 case LOCALE_SMONTHOUSANDSEP: return L"sMonThousandSep";
567 case LOCALE_SNEGATIVESIGN: return L"sNegativeSign";
568 case LOCALE_SPOSITIVESIGN: return L"sPositiveSign";
569 case LOCALE_SSHORTDATE: return L"sShortDate";
570 case LOCALE_STHOUSAND: return L"sThousand";
571 case LOCALE_STIME: return L"sTime";
572 case LOCALE_STIMEFORMAT: return L"sTimeFormat";
573 case LOCALE_SYEARMONTH: return L"sYearMonth";
574
575 /* The following are not listed under MSDN as supported,
576 * but seem to be used and also stored in the registry.
577 */
578 case LOCALE_ICOUNTRY: return L"iCountry";
579 case LOCALE_IDATE: return L"iDate";
580 case LOCALE_ILDATE: return L"iLDate";
581 case LOCALE_ITLZERO: return L"iTLZero";
582 case LOCALE_SCOUNTRY: return L"sCountry";
583 case LOCALE_SLANGUAGE: return L"sLanguage";
584 }
585 return NULL;
586 }
587
588 HKEY RosCreateRegistryKey(void)
589 {
590 OBJECT_ATTRIBUTES objAttr;
591 UNICODE_STRING nameW;
592 HANDLE hKey;
593
594 if (RtlOpenCurrentUser( KEY_ALL_ACCESS, &hKey ) != STATUS_SUCCESS) return 0;
595
596 objAttr.Length = sizeof(objAttr);
597 objAttr.RootDirectory = hKey;
598 objAttr.ObjectName = &nameW;
599 objAttr.Attributes = 0;
600 objAttr.SecurityDescriptor = NULL;
601 objAttr.SecurityQualityOfService = NULL;
602 RtlInitUnicodeString( &nameW, L"Control Panel\\International");
603
604 if (NtCreateKey( &hKey, KEY_ALL_ACCESS, &objAttr, 0, NULL, 0, NULL ) != STATUS_SUCCESS) hKey = 0;
605 NtClose( objAttr.RootDirectory );
606 return hKey;
607 }
608
609 INT RosGetRegistryLocaleInfo( LPCWSTR lpValue, LPWSTR lpBuffer, INT nLen )
610 {
611 DWORD dwSize;
612 HKEY hKey;
613 INT nRet;
614 NTSTATUS ntStatus;
615 UNICODE_STRING usNameW;
616 KEY_VALUE_PARTIAL_INFORMATION *kvpiInfo;
617 const int nInfoSize = FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data);
618
619 if (!(hKey = RosCreateRegistryKey())) return -1;
620
621 RtlInitUnicodeString( &usNameW, lpValue );
622 dwSize = nInfoSize + nLen * sizeof(WCHAR);
623
624 if (!(kvpiInfo = HeapAlloc( GetProcessHeap(), 0, dwSize )))
625 {
626 NtClose( hKey );
627 SetLastError( ERROR_NOT_ENOUGH_MEMORY );
628 return 0;
629 }
630
631 ntStatus = NtQueryValueKey( hKey, &usNameW, KeyValuePartialInformation, kvpiInfo, dwSize, &dwSize );
632 if (ntStatus == STATUS_BUFFER_OVERFLOW && !lpBuffer) ntStatus = 0;
633
634 if (!ntStatus)
635 {
636 nRet = (dwSize - nInfoSize) / sizeof(WCHAR);
637
638 if (!nRet || ((WCHAR *)kvpiInfo->Data)[nRet - 1])
639 {
640 if (nRet < nLen || !lpBuffer) nRet++;
641 else
642 {
643 SetLastError( ERROR_INSUFFICIENT_BUFFER );
644 nRet = 0;
645 }
646 }
647 if (nRet && lpBuffer)
648 {
649 memcpy( lpBuffer, kvpiInfo->Data, (nRet - 1) * sizeof(WCHAR) );
650 lpBuffer[nRet - 1] = 0;
651 }
652 }
653 else
654 {
655 if (ntStatus == STATUS_OBJECT_NAME_NOT_FOUND) nRet = -1;
656 else
657 {
658 SetLastError( RtlNtStatusToDosError(ntStatus) );
659 nRet = 0;
660 }
661 }
662 NtClose( hKey );
663 HeapFree( GetProcessHeap(), 0, kvpiInfo );
664 return nRet;
665 }
666
667 /*
668 * @implemented
669 */
670 int
671 STDCALL
672 GetLocaleInfoW (
673 LCID Locale,
674 LCTYPE LCType,
675 LPWSTR lpLCData,
676 int cchData
677 )
678 {
679 LANGID liLangID;
680 HRSRC hRsrc;
681 HGLOBAL hMem;
682 HMODULE hModule;
683 INT nRet;
684 UINT uiFlags;
685 const WCHAR *ch;
686 int i;
687
688 if (cchData < 0 || (cchData && !lpLCData))
689 {
690 SetLastError( ERROR_INVALID_PARAMETER );
691 return 0;
692 }
693 if (!cchData) lpLCData = NULL;
694
695 if (Locale == LOCALE_NEUTRAL || Locale == LOCALE_SYSTEM_DEFAULT) Locale = GetSystemDefaultLCID();
696 else if (Locale == LOCALE_USER_DEFAULT) Locale = GetUserDefaultLCID();
697
698 uiFlags = LCType & LOCALE_LOCALEINFOFLAGSMASK;
699 LCType &= ~LOCALE_LOCALEINFOFLAGSMASK;
700
701 if (!(uiFlags & LOCALE_NOUSEROVERRIDE) && Locale == GetUserDefaultLCID())
702 {
703 const WCHAR *value = RosGetLocaleValueName(LCType);
704
705 if (value && ((nRet = RosGetRegistryLocaleInfo( value, lpLCData, cchData )) != -1)) return nRet;
706 }
707
708 liLangID = LANGIDFROMLCID( Locale );
709
710 if (SUBLANGID(liLangID) == SUBLANG_NEUTRAL)
711 liLangID = MAKELANGID(PRIMARYLANGID(liLangID), SUBLANG_DEFAULT);
712
713 hModule = GetModuleHandleW( L"kernel32.dll" );
714 if (!(hRsrc = FindResourceExW( hModule, (LPWSTR)RT_STRING, (LPCWSTR)((LCType >> 4) + 1), liLangID )))
715 {
716 SetLastError( ERROR_INVALID_FLAGS );
717 return 0;
718 }
719 if (!(hMem = LoadResource( hModule, hRsrc )))
720 return 0;
721
722 ch = LockResource( hMem );
723 for (i = 0; i < (int)(LCType & 0x0f); i++) ch += *ch + 1;
724
725 if (uiFlags & LOCALE_RETURN_NUMBER) nRet = sizeof(UINT) / sizeof(WCHAR);
726 else nRet = (LCType == LOCALE_FONTSIGNATURE) ? *ch : *ch + 1;
727
728 if (!lpLCData) return nRet;
729
730 if (nRet > cchData)
731 {
732 SetLastError( ERROR_INSUFFICIENT_BUFFER );
733 return 0;
734 }
735
736 if (uiFlags & LOCALE_RETURN_NUMBER)
737 {
738 UINT uiNum;
739 WCHAR *chEnd, *chTmp = HeapAlloc( GetProcessHeap(), 0, (*ch + 1) * sizeof(WCHAR) );
740
741 if (!chTmp)
742 return 0;
743
744 memcpy( chTmp, ch + 1, *ch * sizeof(WCHAR) );
745 chTmp[*ch] = L'\0';
746 uiNum = wcstol( chTmp, &chEnd, 10 );
747
748 if (!*chEnd)
749 memcpy( lpLCData, &uiNum, sizeof(uiNum) );
750 else
751 {
752 SetLastError( ERROR_INVALID_FLAGS );
753 nRet = 0;
754 }
755 HeapFree( GetProcessHeap(), 0, chTmp );
756 }
757 else
758 {
759 memcpy( lpLCData, ch + 1, *ch * sizeof(WCHAR) );
760 if (LCType != LOCALE_FONTSIGNATURE) lpLCData[nRet-1] = 0;
761 }
762 return nRet;
763 }
764
765
766
767 /***********************************************************************
768 * get_lcid_codepage
769 *
770 * Retrieve the ANSI codepage for a given locale.
771 */
772 inline static UINT get_lcid_codepage( LCID lcid )
773 {
774 UINT ret;
775 if (!GetLocaleInfoW( lcid, LOCALE_IDEFAULTANSICODEPAGE|LOCALE_RETURN_NUMBER, (WCHAR *)&ret,
776 sizeof(ret)/sizeof(WCHAR) )) ret = 0;
777 return ret;
778 }
779
780
781 /*
782 * @implemented
783 */
784 int
785 STDCALL
786 CompareStringA (
787 LCID Locale,
788 DWORD dwCmpFlags,
789 LPCSTR lpString1,
790 int cchCount1,
791 LPCSTR lpString2,
792 int cchCount2
793 )
794 {
795 WCHAR *buf1W = NtCurrentTeb()->StaticUnicodeBuffer;
796 WCHAR *buf2W = buf1W + 130;
797 LPWSTR str1W, str2W;
798 INT len1W, len2W, ret;
799 UINT locale_cp;
800
801 if (!lpString1 || !lpString2)
802 {
803 SetLastError(ERROR_INVALID_PARAMETER);
804 return 0;
805 }
806 if (cchCount1 < 0) cchCount1 = strlen(lpString1);
807 if (cchCount2 < 0) cchCount2 = strlen(lpString2);
808
809 locale_cp = get_lcid_codepage(Locale);
810
811 len1W = MultiByteToWideChar(locale_cp, 0, lpString1, cchCount1, buf1W, 130);
812 if (len1W)
813 str1W = buf1W;
814 else
815 {
816 len1W = MultiByteToWideChar(locale_cp, 0, lpString1, cchCount1, NULL, 0);
817 str1W = HeapAlloc(GetProcessHeap(), 0, len1W * sizeof(WCHAR));
818 if (!str1W)
819 {
820 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
821 return 0;
822 }
823 MultiByteToWideChar(locale_cp, 0, lpString1, cchCount1, str1W, len1W);
824 }
825 len2W = MultiByteToWideChar(locale_cp, 0, lpString2, cchCount2, buf2W, 130);
826 if (len2W)
827 str2W = buf2W;
828 else
829 {
830 len2W = MultiByteToWideChar(locale_cp, 0, lpString2, cchCount2, NULL, 0);
831 str2W = HeapAlloc(GetProcessHeap(), 0, len2W * sizeof(WCHAR));
832 if (!str2W)
833 {
834 if (str1W != buf1W) HeapFree(GetProcessHeap(), 0, str1W);
835 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
836 return 0;
837 }
838 MultiByteToWideChar(locale_cp, 0, lpString2, cchCount2, str2W, len2W);
839 }
840
841 ret = CompareStringW(Locale, dwCmpFlags, str1W, len1W, str2W, len2W);
842
843 if (str1W != buf1W) HeapFree(GetProcessHeap(), 0, str1W);
844 if (str2W != buf2W) HeapFree(GetProcessHeap(), 0, str2W);
845 return ret;
846 }
847
848
849 static int compare_unicode_string(
850 PUNICODE_STRING String1,
851 PUNICODE_STRING String2,
852 DWORD Flags
853 )
854 {
855 ULONG len1, len2;
856 PWCHAR s1, s2;
857 WCHAR c1, c2;
858
859 if (String1 && String2)
860 {
861 len1 = String1->Length / sizeof(WCHAR);
862 len2 = String2->Length / sizeof(WCHAR);
863 s1 = String1->Buffer;
864 s2 = String2->Buffer;
865
866 while (len1 > 0 && len2 > 0)
867 {
868 if (Flags & NORM_IGNORESYMBOLS)
869 {
870 int skip = 0;
871 /* FIXME: not tested */
872 if (iswctype(*s1, _SPACE | _PUNCT))
873 {
874 s1++;
875 len1--;
876 skip = 1;
877 }
878 if (iswctype(*s2, _SPACE | _PUNCT))
879 {
880 s2++;
881 len2--;
882 skip = 1;
883 }
884 if (skip) continue;
885 }
886
887 /* hyphen and apostrophe are treated differently depending on
888 * whether SORT_STRINGSORT specified or not
889 */
890 if (!(Flags & SORT_STRINGSORT))
891 {
892 if (*s1 == '-' || *s1 == '\'')
893 {
894 if (*s2 != '-' && *s2 != '\'')
895 {
896 s1++;
897 len1--;
898 continue;
899 }
900 }
901 else if (*s2 == '-' || *s2 == '\'')
902 {
903 s2++;
904 len2--;
905 continue;
906 }
907 }
908 if (Flags & NORM_IGNORECASE)
909 {
910 c1 = len1-- ? RtlUpcaseUnicodeChar(*s1++) : 0;
911 c2 = len2-- ? RtlUpcaseUnicodeChar(*s2++) : 0;
912 if (!c1 || !c2 || c1 != c2)
913 return c1 - c2;
914 }
915 else
916 {
917 c1 = len1-- ? *s1++ : 0;
918 c2 = len2-- ? *s2++ : 0;
919 if (!c1 || !c2 || c1 != c2)
920 return c1 - c2;
921 }
922 }
923 }
924 return 0;
925 }
926
927
928 /*
929 * @unimplemented
930 */
931 int
932 STDCALL
933 CompareStringW (
934 LCID Locale,
935 DWORD dwCmpFlags,
936 LPCWSTR lpString1,
937 int cchCount1,
938 LPCWSTR lpString2,
939 int cchCount2
940 )
941 {
942 INT Result;
943 UNICODE_STRING String1, String2;
944
945 if (!lpString1 || !lpString2)
946 {
947 SetLastError(ERROR_INVALID_PARAMETER);
948 return 0;
949 }
950
951 if (dwCmpFlags & ~(NORM_IGNORECASE | NORM_IGNORENONSPACE |
952 NORM_IGNORESYMBOLS | SORT_STRINGSORT | NORM_IGNOREKANATYPE |
953 NORM_IGNOREWIDTH | 0x10000000))
954 {
955 SetLastError(ERROR_INVALID_FLAGS);
956 return 0;
957 }
958
959 if (cchCount1 < 0) cchCount1 = lstrlenW(lpString1);
960 if (cchCount2 < 0) cchCount2 = lstrlenW(lpString2);
961
962 String1.Length = String1.MaximumLength = cchCount1 * sizeof(WCHAR);
963 String1.Buffer = (LPWSTR)lpString1;
964 String2.Length = String2.MaximumLength = cchCount2 * sizeof(WCHAR);
965 String2.Buffer = (LPWSTR)lpString2;
966
967
968 if (dwCmpFlags & ~NORM_IGNORECASE)
969 {
970 DPRINT1("CompareString: STUB flags - 0x%x\n", dwCmpFlags);
971 Result = compare_unicode_string(&String1, &String2, dwCmpFlags);
972 }
973 else
974 Result = RtlCompareUnicodeString(
975 &String1, &String2, dwCmpFlags & NORM_IGNORECASE);
976
977
978 if (Result) /* need to translate result */
979 return (Result < 0) ? CSTR_LESS_THAN : CSTR_GREATER_THAN;
980
981 return CSTR_EQUAL;
982 }
983
984
985
986
987 /*
988 * @implemented
989 *
990 * Get information about an aspect of a locale.
991 *
992 * PARAMS
993 * lcid [I] LCID of the locale
994 * lctype [I] LCTYPE_ flags from "winnls.h"
995 * buffer [O] Destination for the information
996 * len [I] Length of buffer in characters
997 *
998 * RETURNS
999 * Success: The size of the data requested. If buffer is non-NULL, it is filled
1000 * with the information.
1001 * Failure: 0. Use GetLastError() to determine the cause.
1002 *
1003 * NOTES
1004 * - LOCALE_NEUTRAL is equal to LOCALE_SYSTEM_DEFAULT
1005 * - The string returned is NUL terminated, except for LOCALE_FONTSIGNATURE,
1006 * which is a bit string.
1007 */
1008 INT STDCALL GetLocaleInfoA( LCID lcid, LCTYPE lctype, LPSTR buffer, INT len )
1009 {
1010 WCHAR *bufferW;
1011 INT lenW, ret;
1012
1013 if (len < 0 || (len && !buffer))
1014 {
1015 SetLastError( ERROR_INVALID_PARAMETER );
1016 return 0;
1017 }
1018 if (!len) buffer = NULL;
1019
1020 if (!(lenW = GetLocaleInfoW( lcid, lctype, NULL, 0 ))) return 0;
1021
1022 if (!(bufferW = HeapAlloc( GetProcessHeap(), 0, lenW * sizeof(WCHAR) )))
1023 {
1024 SetLastError( ERROR_NOT_ENOUGH_MEMORY );
1025 return 0;
1026 }
1027 if ((ret = GetLocaleInfoW( lcid, lctype, bufferW, lenW )))
1028 {
1029 if ((lctype & LOCALE_RETURN_NUMBER) ||
1030 ((lctype & ~LOCALE_LOCALEINFOFLAGSMASK) == LOCALE_FONTSIGNATURE))
1031 {
1032 /* it's not an ASCII string, just bytes */
1033 ret *= sizeof(WCHAR);
1034 if (buffer)
1035 {
1036 if (ret <= len) memcpy( buffer, bufferW, ret );
1037 else
1038 {
1039 SetLastError( ERROR_INSUFFICIENT_BUFFER );
1040 ret = 0;
1041 }
1042 }
1043 }
1044 else
1045 {
1046 UINT codepage = CP_ACP;
1047 if (!(lctype & LOCALE_USE_CP_ACP)) codepage = get_lcid_codepage( lcid );
1048 ret = WideCharToMultiByte( codepage, 0, bufferW, ret, buffer, len, NULL, NULL );
1049 }
1050 }
1051 HeapFree( GetProcessHeap(), 0, bufferW );
1052 return ret;
1053 }
1054
1055
1056 /*
1057 * @implemented
1058 */
1059 LANGID STDCALL
1060 GetSystemDefaultLangID(VOID)
1061 {
1062 return LANGIDFROMLCID(GetSystemDefaultLCID());
1063 }
1064
1065
1066 /*
1067 * @implemented
1068 */
1069 LCID STDCALL
1070 GetSystemDefaultLCID(VOID)
1071 {
1072 LCID lcid;
1073
1074 NtQueryDefaultLocale(FALSE, &lcid);
1075
1076 return lcid;
1077 }
1078
1079
1080 /*
1081 * @implemented
1082 */
1083 LANGID STDCALL
1084 GetSystemDefaultUILanguage(VOID)
1085 {
1086 LANGID LanguageId;
1087 NTSTATUS Status;
1088
1089 Status = NtQueryInstallUILanguage(&LanguageId);
1090 if (!NT_SUCCESS(Status))
1091 {
1092 SetLastErrorByStatus(Status);
1093 return 0;
1094 }
1095
1096 return LanguageId;
1097 }
1098
1099
1100 /*
1101 * @implemented
1102 */
1103 LCID STDCALL
1104 GetThreadLocale(VOID)
1105 {
1106 return NtCurrentTeb()->CurrentLocale;
1107 }
1108
1109
1110 /*
1111 * @implemented
1112 */
1113 LANGID STDCALL
1114 GetUserDefaultLangID(VOID)
1115 {
1116 return LANGIDFROMLCID(GetUserDefaultLCID());
1117 }
1118
1119
1120 /*
1121 * @implemented
1122 */
1123 LCID STDCALL
1124 GetUserDefaultLCID(VOID)
1125 {
1126 LCID lcid;
1127 NTSTATUS Status;
1128
1129 Status = NtQueryDefaultLocale(TRUE, &lcid);
1130 if (!NT_SUCCESS(Status))
1131 {
1132 SetLastErrorByStatus(Status);
1133 return 0;
1134 }
1135
1136 return lcid;
1137 }
1138
1139
1140 /*
1141 * @implemented
1142 */
1143 LANGID STDCALL
1144 GetUserDefaultUILanguage(VOID)
1145 {
1146 LANGID LangId;
1147 NTSTATUS Status;
1148
1149 Status = NtQueryDefaultUILanguage(&LangId);
1150 if (!NT_SUCCESS(Status))
1151 {
1152 SetLastErrorByStatus(Status);
1153 return 0;
1154 }
1155
1156 return LangId;
1157 }
1158
1159
1160 /*
1161 * @unimplemented
1162 */
1163 GEOID
1164 STDCALL
1165 GetUserGeoID(
1166 GEOCLASS GeoClass)
1167 {
1168 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1169 return 0;
1170 }
1171
1172
1173 /*
1174 * @unimplemented
1175 */
1176 BOOL
1177 STDCALL
1178 IsValidLanguageGroup(
1179 LGRPID LanguageGroup,
1180 DWORD dwFlags)
1181 {
1182 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1183 return 0;
1184 }
1185
1186
1187 /******************************************************************************
1188 * IsValidLocale
1189 *
1190 * Determine if a locale is valid.
1191 *
1192 * PARAMS
1193 * Locale [I] LCID of the locale to check
1194 * dwFlags [I] LCID_SUPPORTED = Valid
1195 * LCID_INSTALLED = Valid and installed on the system
1196 *
1197 * RETURN
1198 * TRUE, if Locale is valid,
1199 * FALSE, otherwise.
1200 *
1201 * @implemented
1202 */
1203 BOOL STDCALL
1204 IsValidLocale(LCID Locale,
1205 DWORD dwFlags)
1206 {
1207 OBJECT_ATTRIBUTES ObjectAttributes;
1208 PKEY_VALUE_PARTIAL_INFORMATION KeyInfo;
1209 WCHAR ValueNameBuffer[9];
1210 UNICODE_STRING KeyName;
1211 UNICODE_STRING ValueName;
1212 ULONG KeyInfoSize;
1213 ULONG ReturnedSize;
1214 HANDLE KeyHandle;
1215 PWSTR ValueData;
1216 NTSTATUS Status;
1217
1218 DPRINT("IsValidLocale() called\n");
1219
1220 if ((dwFlags & ~(LCID_SUPPORTED | LCID_INSTALLED)) ||
1221 (dwFlags == (LCID_SUPPORTED | LCID_INSTALLED)))
1222 {
1223 DPRINT("Invalid flags: %lx\n", dwFlags);
1224 return FALSE;
1225 }
1226
1227 if (Locale & 0xFFFF0000)
1228 {
1229 RtlInitUnicodeString(&KeyName,
1230 L"\\Registry\\Machine\\SYSTEM\\CurrentControlSet\\Control\\Nls\\Locale\\Alternate Sorts");
1231 }
1232 else
1233 {
1234 RtlInitUnicodeString(&KeyName,
1235 L"\\Registry\\Machine\\SYSTEM\\CurrentControlSet\\Control\\Nls\\Locale");
1236 }
1237
1238 InitializeObjectAttributes(&ObjectAttributes,
1239 &KeyName,
1240 OBJ_CASE_INSENSITIVE,
1241 NULL,
1242 NULL);
1243
1244 Status = NtOpenKey(&KeyHandle,
1245 KEY_QUERY_VALUE,
1246 &ObjectAttributes);
1247 if (!NT_SUCCESS(Status))
1248 {
1249 DPRINT("NtOpenKey() failed (Status %lx)\n", Status);
1250 return FALSE;
1251 }
1252
1253 swprintf(ValueNameBuffer, L"%08lx", (ULONG)Locale);
1254 RtlInitUnicodeString(&ValueName, ValueNameBuffer);
1255
1256 KeyInfoSize = sizeof(KEY_VALUE_PARTIAL_INFORMATION) + 4 * sizeof(WCHAR);
1257 KeyInfo = RtlAllocateHeap(RtlGetProcessHeap(),
1258 HEAP_ZERO_MEMORY,
1259 KeyInfoSize);
1260 if (KeyInfo == NULL)
1261 {
1262 DPRINT("RtlAllocateHeap() failed (Status %lx)\n", Status);
1263 NtClose(KeyHandle);
1264 return FALSE;
1265 }
1266
1267 Status = NtQueryValueKey(KeyHandle,
1268 &ValueName,
1269 KeyValuePartialInformation,
1270 KeyInfo,
1271 KeyInfoSize,
1272 &ReturnedSize);
1273 NtClose(KeyHandle);
1274
1275 if (!NT_SUCCESS(Status))
1276 {
1277 DPRINT("NtQueryValueKey() failed (Status %lx)\n", Status);
1278 RtlFreeHeap(RtlGetProcessHeap(), 0, KeyInfo);
1279 return FALSE;
1280 }
1281
1282 if (dwFlags & LCID_SUPPORTED)
1283 {
1284 DPRINT("Locale is supported\n");
1285 RtlFreeHeap(RtlGetProcessHeap(), 0, KeyInfo);
1286 return TRUE;
1287 }
1288
1289 ValueData = (PWSTR)&KeyInfo->Data[0];
1290 if ((dwFlags & LCID_INSTALLED) &&
1291 (KeyInfo->Type == REG_SZ) &&
1292 (KeyInfo->DataLength == 2 * sizeof(WCHAR)) &&
1293 (ValueData[0] == L'1'))
1294 {
1295 DPRINT("Locale is supported and installed\n");
1296 RtlFreeHeap(RtlGetProcessHeap(), 0, KeyInfo);
1297 return TRUE;
1298 }
1299
1300 RtlFreeHeap(RtlGetProcessHeap(), 0, KeyInfo);
1301
1302 DPRINT("IsValidLocale() called\n");
1303
1304 return FALSE;
1305 }
1306
1307
1308 /*
1309 * @unimplemented
1310 */
1311 int
1312 STDCALL
1313 LCMapStringA (
1314 LCID Locale,
1315 DWORD dwMapFlags,
1316 LPCSTR lpSrcStr,
1317 int cchSrc,
1318 LPSTR lpDestStr,
1319 int cchDest
1320 )
1321 {
1322 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1323 return 0;
1324 }
1325
1326
1327 /*
1328 * @unimplemented
1329 */
1330 int
1331 STDCALL
1332 LCMapStringW (
1333 LCID Locale,
1334 DWORD dwMapFlags,
1335 LPCWSTR lpSrcStr,
1336 int cchSrc,
1337 LPWSTR lpDestStr,
1338 int cchDest
1339 )
1340 {
1341 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1342 return 0;
1343 }
1344
1345
1346 /*
1347 * @unimplemented
1348 */
1349 BOOL
1350 STDCALL
1351 SetCalendarInfoA(
1352 LCID Locale,
1353 CALID Calendar,
1354 CALTYPE CalType,
1355 LPCSTR lpCalData)
1356 {
1357 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1358 return 0;
1359 }
1360
1361 /*
1362 * @unimplemented
1363 */
1364 BOOL
1365 STDCALL
1366 SetCalendarInfoW(
1367 LCID Locale,
1368 CALID Calendar,
1369 CALTYPE CalType,
1370 LPCWSTR lpCalData)
1371 {
1372 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1373 return 0;
1374 }
1375
1376
1377 /*
1378 * @unimplemented
1379 */
1380 BOOL
1381 STDCALL
1382 SetLocaleInfoA (
1383 LCID Locale,
1384 LCTYPE LCType,
1385 LPCSTR lpLCData
1386 )
1387 {
1388 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1389 return FALSE;
1390 }
1391
1392
1393 /*
1394 * @unimplemented
1395 */
1396 BOOL
1397 STDCALL
1398 SetLocaleInfoW (
1399 LCID Locale,
1400 LCTYPE LCType,
1401 LPCWSTR lpLCData
1402 )
1403 {
1404 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1405 return FALSE;
1406 }
1407
1408
1409 /**********************************************************************
1410 * @implemented
1411 * RIPPED FROM WINE's dlls\kernel\locale.c rev 1.42
1412 *
1413 * SetThreadLocale (KERNEL32.@)
1414 *
1415 * Set the current threads locale.
1416 *
1417 * PARAMS
1418 * lcid [I] LCID of the locale to set
1419 *
1420 * RETURNS
1421 * Success: TRUE. The threads locale is set to lcid.
1422 * Failure: FALSE. Use GetLastError() to determine the cause.
1423 *
1424 */
1425 BOOL WINAPI SetThreadLocale( LCID lcid )
1426 {
1427 DPRINT("SetThreadLocale(0x%04lX)\n", lcid);
1428
1429 lcid = ConvertDefaultLocale(lcid);
1430
1431 if (lcid != GetThreadLocale())
1432 {
1433 if (!IsValidLocale(lcid, LCID_SUPPORTED))
1434 {
1435 SetLastError(ERROR_INVALID_PARAMETER);
1436 return FALSE;
1437 }
1438
1439 NtCurrentTeb()->CurrentLocale = lcid;
1440 /* FIXME: NtCurrentTeb()->code_page = get_lcid_codepage( lcid );
1441 * Wine save the acp for easy/fast access, but ROS has no such Teb member.
1442 * Maybe add this member to ros as well?
1443 */
1444
1445 /*
1446 Lag test app for å se om locale etc, endres i en app. etter at prosessen er
1447 startet, eller om bare nye prosesser blir berørt.
1448 */
1449 }
1450 return TRUE;
1451 }
1452
1453
1454 /*
1455 * @unimplemented
1456 */
1457 BOOL
1458 STDCALL
1459 SetUserGeoID(
1460 GEOID GeoId)
1461 {
1462 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1463 return 0;
1464 }