4a40d211f0d37c385d0f352a0a43d78f0b6f6ef3
[reactos.git] / reactos / subsystems / win / basesrv / nls.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS Base API Server DLL
4 * FILE: subsystems/win/basesrv/nls.c
5 * PURPOSE: National Language Support (NLS)
6 * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
7 */
8
9 /* INCLUDES *******************************************************************/
10
11 #include "basesrv.h"
12
13 #define NDEBUG
14 #include <debug.h>
15
16 /* GLOBALS ********************************************************************/
17
18 RTL_CRITICAL_SECTION NlsCacheCriticalSection;
19 PNLS_USER_INFO pNlsRegUserInfo;
20
21 BOOLEAN BaseSrvKernel32DelayLoadComplete;
22 HANDLE BaseSrvKernel32DllHandle;
23 UNICODE_STRING BaseSrvKernel32DllPath;
24
25 POPEN_DATA_FILE pOpenDataFile;
26 PVOID /*PGET_DEFAULT_SORTKEY_SIZE */ pGetDefaultSortkeySize;
27 PVOID /*PGET_LINGUIST_LANG_SIZE*/ pGetLinguistLangSize;
28 PVOID /*PNLS_CONVERT_INTEGER_TO_STRING*/ pNlsConvertIntegerToString;
29 PVOID /*PVALIDATE_LCTYPE*/ pValidateLCType;
30 PVALIDATE_LOCALE pValidateLocale;
31 PGET_NLS_SECTION_NAME pGetNlsSectionName;
32 PVOID /*PGET_USER_DEFAULT_LANGID*/ pGetUserDefaultLangID;
33 PGET_CP_FILE_NAME_FROM_REGISTRY pGetCPFileNameFromRegistry;
34 PCREATE_NLS_SECURTY_DESCRIPTOR pCreateNlsSecurityDescriptor;
35
36 BASESRV_KERNEL_IMPORTS BaseSrvKernel32Imports[10] =
37 {
38 { "OpenDataFile", (PVOID*) &pOpenDataFile },
39 { "GetDefaultSortkeySize", (PVOID*) &pGetDefaultSortkeySize },
40 { "GetLinguistLangSize", (PVOID*) &pGetLinguistLangSize },
41 { "NlsConvertIntegerToString", (PVOID*) &pNlsConvertIntegerToString },
42 { "ValidateLCType", (PVOID*) &pValidateLCType },
43 { "ValidateLocale", (PVOID*) &pValidateLocale },
44 { "GetNlsSectionName", (PVOID*) &pGetNlsSectionName },
45 { "GetUserDefaultLangID", (PVOID*) &pGetUserDefaultLangID },
46 { "GetCPFileNameFromRegistry", (PVOID*) &pGetCPFileNameFromRegistry },
47 { "CreateNlsSecurityDescriptor", (PVOID*) &pCreateNlsSecurityDescriptor },
48 };
49
50 /* FUNCTIONS *****************************************************************/
51
52 NTSTATUS
53 NTAPI
54 BaseSrvDelayLoadKernel32(VOID)
55 {
56 NTSTATUS Status;
57 ULONG i;
58 ANSI_STRING ProcedureName;
59
60 /* Only do this once */
61 if (BaseSrvKernel32DelayLoadComplete) return STATUS_SUCCESS;
62
63 /* Loop all imports */
64 for (i = 0; i < RTL_NUMBER_OF(BaseSrvKernel32Imports); i++)
65 {
66 /* Only look them up once */
67 if (!*BaseSrvKernel32Imports[i].FunctionPointer)
68 {
69 /* If we haven't loaded the DLL yet, do it now */
70 if (!BaseSrvKernel32DllHandle)
71 {
72 Status = LdrLoadDll(0,
73 0,
74 &BaseSrvKernel32DllPath,
75 &BaseSrvKernel32DllHandle);
76 if (!NT_SUCCESS(Status))
77 {
78 DPRINT1("Failed to load %wZ\n", &BaseSrvKernel32DllPath);
79 return Status;
80 }
81 }
82
83 /* Get the address of the routine being looked up*/
84 RtlInitAnsiString(&ProcedureName, BaseSrvKernel32Imports[i].FunctionName);
85 Status = LdrGetProcedureAddress(BaseSrvKernel32DllHandle,
86 &ProcedureName,
87 0,
88 BaseSrvKernel32Imports[i].FunctionPointer);
89 DPRINT1("NLS: Found %Z at 0x%p\n",
90 &ProcedureName,
91 BaseSrvKernel32Imports[i].FunctionPointer);
92 if (!NT_SUCCESS(Status)) break;
93 }
94 }
95
96 /* Did we find them all? */
97 if (i == RTL_NUMBER_OF(BaseSrvKernel32Imports))
98 {
99 /* Excellent */
100 BaseSrvKernel32DelayLoadComplete = TRUE;
101 return STATUS_SUCCESS;
102 }
103
104 /* Nope, fail */
105 return Status;
106 }
107
108 VOID
109 WINAPI
110 BaseSrvNLSInit(IN PBASE_STATIC_SERVER_DATA StaticData)
111 {
112 /* Initialize the lock */
113 RtlInitializeCriticalSection(&NlsCacheCriticalSection);
114
115 /* Initialize the data with all F's */
116 pNlsRegUserInfo = &StaticData->NlsUserInfo;
117 RtlFillMemory(&StaticData->NlsUserInfo, 0xFF, sizeof(StaticData->NlsUserInfo));
118
119 /* Set empty LCID */
120 pNlsRegUserInfo->UserLocaleId = 0;
121
122 /* Reset the cache update counter */
123 RtlEnterCriticalSection(&NlsCacheCriticalSection);
124 pNlsRegUserInfo->ulCacheUpdateCount = 0;
125 RtlLeaveCriticalSection(&NlsCacheCriticalSection);
126
127 /* Get the LCID */
128 NtQueryDefaultLocale(0, &pNlsRegUserInfo->UserLocaleId);
129 }
130
131 /* PUBLIC SERVER APIS *********************************************************/
132
133 CSR_API(BaseSrvNlsSetUserInfo)
134 {
135 DPRINT1("%s not yet implemented\n", __FUNCTION__);
136 return STATUS_NOT_IMPLEMENTED;
137 }
138
139 CSR_API(BaseSrvNlsSetMultipleUserInfo)
140 {
141 DPRINT1("%s not yet implemented\n", __FUNCTION__);
142 return STATUS_NOT_IMPLEMENTED;
143 }
144
145 CSR_API(BaseSrvNlsCreateSection)
146 {
147 NTSTATUS Status;
148 HANDLE SectionHandle, ProcessHandle, FileHandle;
149 ULONG LocaleId;
150 UNICODE_STRING NlsSectionName;
151 PWCHAR NlsFileName;
152 UCHAR SecurityDescriptor[52];
153 OBJECT_ATTRIBUTES ObjectAttributes;
154 WCHAR FileNameBuffer[32];
155 WCHAR NlsSectionNameBuffer[32];
156 PBASE_NLS_CREATE_SECTION NlsMsg = &((PBASE_API_MESSAGE)ApiMessage)->Data.NlsCreateSection;
157
158 /* Load kernel32 first and import the NLS routines */
159 Status = BaseSrvDelayLoadKernel32();
160 if (!NT_SUCCESS(Status)) return Status;
161
162 /* Assume failure */
163 NlsMsg->SectionHandle = NULL;
164
165 /* Check and validate the locale ID, if one is present */
166 LocaleId = NlsMsg->LocaleId;
167 DPRINT1("NLS: Create Section with LCID: %lx for Type: %d\n", LocaleId, NlsMsg->Type);
168 if (LocaleId)
169 {
170 if (!pValidateLocale(LocaleId)) return STATUS_INVALID_PARAMETER;
171 }
172
173 /* Check which NLS section is being created */
174 switch (NlsMsg->Type)
175 {
176 /* For each one, set the correct filename and object name */
177 case 1:
178 RtlInitUnicodeString(&NlsSectionName, L"\\NLS\\NlsSectionUnicode");
179 NlsFileName = L"unicode.nls";
180 break;
181 case 2:
182 RtlInitUnicodeString(&NlsSectionName, L"\\NLS\\NlsSectionLocale");
183 NlsFileName = L"locale.nls";
184 break;
185 case 3:
186 RtlInitUnicodeString(&NlsSectionName, L"\\NLS\\NlsSectionCType");
187 NlsFileName = L"ctype.nls";
188 break;
189 case 4:
190 RtlInitUnicodeString(&NlsSectionName, L"\\NLS\\NlsSectionSortkey");
191 NlsFileName = L"sortkey.nls";
192 break;
193 case 5:
194 RtlInitUnicodeString(&NlsSectionName, L"\\NLS\\NlsSectionSortTbls");
195 NlsFileName = L"sorttbls.nls";
196 break;
197 case 6:
198 RtlInitUnicodeString(&NlsSectionName, L"\\NLS\\NlsSectionCP437");
199 NlsFileName = L"c_437.nls";
200 break;
201 case 7:
202 RtlInitUnicodeString(&NlsSectionName, L"\\NLS\\NlsSectionCP1252");
203 NlsFileName = L"c_1252.nls";
204 break;
205 case 8:
206 RtlInitUnicodeString(&NlsSectionName, L"\\NLS\\NlsSectionLANG_EXCEPT");
207 NlsFileName = L"l_except.nls";
208 break;
209 case 9:
210 DPRINT1("This type not yet supported\n");
211 return STATUS_NOT_IMPLEMENTED;
212 case 10:
213 DPRINT1("This type not yet supported\n");
214 return STATUS_NOT_IMPLEMENTED;
215 case 11:
216 /* Get the filename for this locale */
217 if (!pGetCPFileNameFromRegistry(NlsMsg->LocaleId,
218 FileNameBuffer,
219 RTL_NUMBER_OF(FileNameBuffer)))
220 {
221 DPRINT1("File name query failed\n");
222 return STATUS_INVALID_PARAMETER;
223 }
224
225 /* Get the name of the section for this locale */
226 DPRINT1("File name: %S\n", FileNameBuffer);
227 Status = pGetNlsSectionName(NlsMsg->LocaleId,
228 10,
229 0,
230 L"\\NLS\\NlsSectionCP",
231 NlsSectionNameBuffer,
232 RTL_NUMBER_OF(NlsSectionNameBuffer));
233 if (!NT_SUCCESS(Status))
234 {
235 DPRINT1("Section name query failed: %lx\n", Status);
236 return Status;
237 }
238
239 /* Setup the name and go open it */
240 NlsFileName = FileNameBuffer;
241 DPRINT1("Section name: %S\n", NlsSectionNameBuffer);
242 RtlInitUnicodeString(&NlsSectionName, NlsSectionNameBuffer);
243 break;
244 case 12:
245 RtlInitUnicodeString(&NlsSectionName, L"\\NLS\\NlsSectionGeo");
246 NlsFileName = L"geo.nls";
247 break;
248 default:
249 DPRINT1("NLS: Invalid NLS type!\n");
250 return STATUS_INVALID_PARAMETER;
251 }
252
253 /* Open the specified NLS file */
254 Status = pOpenDataFile(&FileHandle, NlsFileName);
255 if (Status != STATUS_SUCCESS)
256 {
257 DPRINT1("NLS: Failed to open file: %lx\n", Status);
258 return Status;
259 }
260
261 /* Create an SD for the section object */
262 Status = pCreateNlsSecurityDescriptor(&SecurityDescriptor,
263 sizeof(SecurityDescriptor),
264 0x80000000);
265 if (!NT_SUCCESS(Status))
266 {
267 DPRINT1("NLS: CreateNlsSecurityDescriptor FAILED!: %lx\n", Status);
268 NtClose(FileHandle);
269 return Status;
270 }
271
272 /* Create the section object proper */
273 InitializeObjectAttributes(&ObjectAttributes,
274 &NlsSectionName,
275 OBJ_CASE_INSENSITIVE | OBJ_PERMANENT | OBJ_OPENIF,
276 NULL,
277 &SecurityDescriptor);
278 Status = NtCreateSection(&SectionHandle,
279 SECTION_MAP_READ,
280 &ObjectAttributes,
281 0,
282 PAGE_READONLY,
283 SEC_COMMIT,
284 FileHandle);
285 NtClose(FileHandle);
286 if (!NT_SUCCESS(Status))
287 {
288 DPRINT1("NLS: Failed to create section! %lx\n", Status);
289 return Status;
290 }
291
292 /* Open a handle to the calling process */
293 InitializeObjectAttributes(&ObjectAttributes, NULL, 0, NULL, NULL);
294 Status = NtOpenProcess(&ProcessHandle,
295 PROCESS_DUP_HANDLE,
296 &ObjectAttributes,
297 &ApiMessage->Header.ClientId);
298 if (!NT_SUCCESS(Status))
299 {
300 DPRINT1("NLS: Failed to open process! %lx\n", Status);
301 NtClose(SectionHandle);
302 return Status;
303 }
304
305 /* Duplicate the handle to the section object into it */
306 Status = NtDuplicateObject(NtCurrentProcess(),
307 SectionHandle,
308 ProcessHandle,
309 &NlsMsg->SectionHandle,
310 0,
311 0,
312 3);
313 NtClose(ProcessHandle);
314 return Status;
315 }
316
317 CSR_API(BaseSrvNlsUpdateCacheCount)
318 {
319 DPRINT1("%s not yet implemented\n", __FUNCTION__);
320 return STATUS_NOT_IMPLEMENTED;
321 }
322
323 CSR_API(BaseSrvNlsGetUserInfo)
324 {
325 NTSTATUS Status;
326 PBASE_NLS_GET_USER_INFO NlsMsg = &((PBASE_API_MESSAGE)ApiMessage)->Data.NlsGetUserInfo;
327
328 /* Make sure the buffer is valid and of the right size */
329 if ((CsrValidateMessageBuffer(ApiMessage, &NlsMsg->NlsUserInfo, NlsMsg->Size, TRUE)) &&
330 (NlsMsg->Size == sizeof(NLS_USER_INFO)))
331 {
332 /* Acquire the lock to prevent updates while we copy */
333 Status = RtlEnterCriticalSection(&NlsCacheCriticalSection);
334 if (NT_SUCCESS(Status))
335 {
336 /* Do the copy now, then drop the lock */
337 RtlCopyMemory(NlsMsg->NlsUserInfo, pNlsRegUserInfo, NlsMsg->Size);
338 DPRINT1("NLS Data copy complete\n");
339 RtlLeaveCriticalSection(&NlsCacheCriticalSection);
340 }
341 }
342 else
343 {
344 /* The data was invalid, bail out */
345 DPRINT1("NLS: Size of info is invalid: %lx vs %lx\n", NlsMsg->Size, sizeof(NLS_USER_INFO));
346 Status = STATUS_INVALID_PARAMETER;
347 }
348
349 /* All done */
350 return Status;
351 }
352
353 /* PUBLIC APIS ****************************************************************/
354
355 NTSTATUS
356 NTAPI
357 BaseSrvNlsLogon(DWORD Unknown)
358 {
359 DPRINT1("%s(%lu) not yet implemented\n", __FUNCTION__, Unknown);
360 return STATUS_NOT_IMPLEMENTED;
361 }
362
363 NTSTATUS
364 NTAPI
365 BaseSrvNlsUpdateRegistryCache(DWORD Unknown1,
366 DWORD Unknown2)
367 {
368 DPRINT1("%s(%lu, %lu) not yet implemented\n", __FUNCTION__, Unknown1, Unknown2);
369 return STATUS_NOT_IMPLEMENTED;
370 }
371
372 /* EOF */