[INTRIN]
[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 #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 NTAPI
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 NTSTATUS
134 NTAPI
135 BaseSrvNlsConnect(IN PCSR_PROCESS CsrProcess,
136 IN OUT PVOID ConnectionInfo,
137 IN OUT PULONG ConnectionInfoLength)
138 {
139 /* Does nothing */
140 return STATUS_SUCCESS;
141 }
142
143 /* PUBLIC SERVER APIS *********************************************************/
144
145 CSR_API(BaseSrvNlsSetUserInfo)
146 {
147 DPRINT1("%s not yet implemented\n", __FUNCTION__);
148 return STATUS_NOT_IMPLEMENTED;
149 }
150
151 CSR_API(BaseSrvNlsSetMultipleUserInfo)
152 {
153 DPRINT1("%s not yet implemented\n", __FUNCTION__);
154 return STATUS_NOT_IMPLEMENTED;
155 }
156
157 CSR_API(BaseSrvNlsCreateSection)
158 {
159 NTSTATUS Status;
160 HANDLE SectionHandle, ProcessHandle, FileHandle;
161 ULONG LocaleId;
162 UNICODE_STRING NlsSectionName;
163 PWCHAR NlsFileName;
164 UCHAR SecurityDescriptor[52];
165 OBJECT_ATTRIBUTES ObjectAttributes;
166 WCHAR FileNameBuffer[32];
167 WCHAR NlsSectionNameBuffer[32];
168 PBASE_NLS_CREATE_SECTION NlsMsg = &((PBASE_API_MESSAGE)ApiMessage)->Data.NlsCreateSection;
169
170 /* Load kernel32 first and import the NLS routines */
171 Status = BaseSrvDelayLoadKernel32();
172 if (!NT_SUCCESS(Status)) return Status;
173
174 /* Assume failure */
175 NlsMsg->SectionHandle = NULL;
176
177 /* Check and validate the locale ID, if one is present */
178 LocaleId = NlsMsg->LocaleId;
179 DPRINT1("NLS: Create Section with LCID: %lx for Type: %d\n", LocaleId, NlsMsg->Type);
180 if (LocaleId)
181 {
182 if (!pValidateLocale(LocaleId)) return STATUS_INVALID_PARAMETER;
183 }
184
185 /* Check which NLS section is being created */
186 switch (NlsMsg->Type)
187 {
188 /* For each one, set the correct filename and object name */
189 case 1:
190 RtlInitUnicodeString(&NlsSectionName, L"\\NLS\\NlsSectionUnicode");
191 NlsFileName = L"unicode.nls";
192 break;
193 case 2:
194 RtlInitUnicodeString(&NlsSectionName, L"\\NLS\\NlsSectionLocale");
195 NlsFileName = L"locale.nls";
196 break;
197 case 3:
198 RtlInitUnicodeString(&NlsSectionName, L"\\NLS\\NlsSectionCType");
199 NlsFileName = L"ctype.nls";
200 break;
201 case 4:
202 RtlInitUnicodeString(&NlsSectionName, L"\\NLS\\NlsSectionSortkey");
203 NlsFileName = L"sortkey.nls";
204 break;
205 case 5:
206 RtlInitUnicodeString(&NlsSectionName, L"\\NLS\\NlsSectionSortTbls");
207 NlsFileName = L"sorttbls.nls";
208 break;
209 case 6:
210 RtlInitUnicodeString(&NlsSectionName, L"\\NLS\\NlsSectionCP437");
211 NlsFileName = L"c_437.nls";
212 break;
213 case 7:
214 RtlInitUnicodeString(&NlsSectionName, L"\\NLS\\NlsSectionCP1252");
215 NlsFileName = L"c_1252.nls";
216 break;
217 case 8:
218 RtlInitUnicodeString(&NlsSectionName, L"\\NLS\\NlsSectionLANG_EXCEPT");
219 NlsFileName = L"l_except.nls";
220 break;
221 case 9:
222 DPRINT1("This type not yet supported\n");
223 return STATUS_NOT_IMPLEMENTED;
224 case 10:
225 DPRINT1("This type not yet supported\n");
226 return STATUS_NOT_IMPLEMENTED;
227 case 11:
228 /* Get the filename for this locale */
229 if (!pGetCPFileNameFromRegistry(NlsMsg->LocaleId,
230 FileNameBuffer,
231 RTL_NUMBER_OF(FileNameBuffer)))
232 {
233 DPRINT1("File name query failed\n");
234 return STATUS_INVALID_PARAMETER;
235 }
236
237 /* Get the name of the section for this locale */
238 DPRINT1("File name: %S\n", FileNameBuffer);
239 Status = pGetNlsSectionName(NlsMsg->LocaleId,
240 10,
241 0,
242 L"\\NLS\\NlsSectionCP",
243 NlsSectionNameBuffer,
244 RTL_NUMBER_OF(NlsSectionNameBuffer));
245 if (!NT_SUCCESS(Status))
246 {
247 DPRINT1("Section name query failed: %lx\n", Status);
248 return Status;
249 }
250
251 /* Setup the name and go open it */
252 NlsFileName = FileNameBuffer;
253 DPRINT1("Section name: %S\n", NlsSectionNameBuffer);
254 RtlInitUnicodeString(&NlsSectionName, NlsSectionNameBuffer);
255 break;
256 case 12:
257 RtlInitUnicodeString(&NlsSectionName, L"\\NLS\\NlsSectionGeo");
258 NlsFileName = L"geo.nls";
259 break;
260 default:
261 DPRINT1("NLS: Invalid NLS type!\n");
262 return STATUS_INVALID_PARAMETER;
263 }
264
265 /* Open the specified NLS file */
266 Status = pOpenDataFile(&FileHandle, NlsFileName);
267 if (Status != STATUS_SUCCESS)
268 {
269 DPRINT1("NLS: Failed to open file: %lx\n", Status);
270 return Status;
271 }
272
273 /* Create an SD for the section object */
274 Status = pCreateNlsSecurityDescriptor(&SecurityDescriptor,
275 sizeof(SecurityDescriptor),
276 0x80000000);
277 if (!NT_SUCCESS(Status))
278 {
279 DPRINT1("NLS: CreateNlsSecurityDescriptor FAILED!: %lx\n", Status);
280 NtClose(FileHandle);
281 return Status;
282 }
283
284 /* Create the section object proper */
285 InitializeObjectAttributes(&ObjectAttributes,
286 &NlsSectionName,
287 OBJ_CASE_INSENSITIVE | OBJ_PERMANENT | OBJ_OPENIF,
288 NULL,
289 &SecurityDescriptor);
290 Status = NtCreateSection(&SectionHandle,
291 SECTION_MAP_READ,
292 &ObjectAttributes,
293 0,
294 PAGE_READONLY,
295 SEC_COMMIT,
296 FileHandle);
297 NtClose(FileHandle);
298 if (!NT_SUCCESS(Status))
299 {
300 DPRINT1("NLS: Failed to create section! %lx\n", Status);
301 return Status;
302 }
303
304 /* Open a handle to the calling process */
305 InitializeObjectAttributes(&ObjectAttributes, NULL, 0, NULL, NULL);
306 Status = NtOpenProcess(&ProcessHandle,
307 PROCESS_DUP_HANDLE,
308 &ObjectAttributes,
309 &ApiMessage->Header.ClientId);
310 if (!NT_SUCCESS(Status))
311 {
312 DPRINT1("NLS: Failed to open process! %lx\n", Status);
313 NtClose(SectionHandle);
314 return Status;
315 }
316
317 /* Duplicate the handle to the section object into it */
318 Status = NtDuplicateObject(NtCurrentProcess(),
319 SectionHandle,
320 ProcessHandle,
321 &NlsMsg->SectionHandle,
322 0,
323 0,
324 3);
325 NtClose(ProcessHandle);
326 return Status;
327 }
328
329 CSR_API(BaseSrvNlsUpdateCacheCount)
330 {
331 DPRINT1("%s not yet implemented\n", __FUNCTION__);
332 return STATUS_NOT_IMPLEMENTED;
333 }
334
335 CSR_API(BaseSrvNlsGetUserInfo)
336 {
337 NTSTATUS Status;
338 PBASE_NLS_GET_USER_INFO NlsMsg = &((PBASE_API_MESSAGE)ApiMessage)->Data.NlsGetUserInfo;
339
340 /* Make sure the buffer is valid and of the right size */
341 if ((CsrValidateMessageBuffer(ApiMessage, &NlsMsg->NlsUserInfo, NlsMsg->Size, TRUE)) &&
342 (NlsMsg->Size == sizeof(NLS_USER_INFO)))
343 {
344 /* Acquire the lock to prevent updates while we copy */
345 Status = RtlEnterCriticalSection(&NlsCacheCriticalSection);
346 if (NT_SUCCESS(Status))
347 {
348 /* Do the copy now, then drop the lock */
349 RtlCopyMemory(NlsMsg->NlsUserInfo, pNlsRegUserInfo, NlsMsg->Size);
350 DPRINT1("NLS Data copy complete\n");
351 RtlLeaveCriticalSection(&NlsCacheCriticalSection);
352 }
353 }
354 else
355 {
356 /* The data was invalid, bail out */
357 DPRINT1("NLS: Size of info is invalid: %lx vs %lx\n", NlsMsg->Size, sizeof(NLS_USER_INFO));
358 Status = STATUS_INVALID_PARAMETER;
359 }
360
361 /* All done */
362 return Status;
363 }
364
365 /* PUBLIC APIS ****************************************************************/
366
367 NTSTATUS
368 NTAPI
369 BaseSrvNlsLogon(DWORD Unknown)
370 {
371 DPRINT1("%s(%lu) not yet implemented\n", __FUNCTION__, Unknown);
372 return STATUS_NOT_IMPLEMENTED;
373 }
374
375 NTSTATUS
376 NTAPI
377 BaseSrvNlsUpdateRegistryCache(DWORD Unknown1,
378 DWORD Unknown2)
379 {
380 DPRINT1("%s(%lu, %lu) not yet implemented\n", __FUNCTION__, Unknown1, Unknown2);
381 return STATUS_NOT_IMPLEMENTED;
382 }
383
384 /* EOF */