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