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