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