[MMIXER] Fix additional data size initialization for different audio formats (#6753)
[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 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 PSECURITY_DESCRIPTOR NlsSd;
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(&NlsSd,
275 sizeof(SECURITY_DESCRIPTOR),
276 SECTION_MAP_READ);
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 NlsSd);
290 Status = NtCreateSection(&SectionHandle,
291 SECTION_MAP_READ,
292 &ObjectAttributes,
293 0,
294 PAGE_READONLY,
295 SEC_COMMIT,
296 FileHandle);
297 NtClose(FileHandle);
298 RtlFreeHeap(RtlGetProcessHeap(), 0, NlsSd);
299 if (!NT_SUCCESS(Status))
300 {
301 DPRINT1("NLS: Failed to create section! %lx\n", Status);
302 return Status;
303 }
304
305 /* Open a handle to the calling process */
306 InitializeObjectAttributes(&ObjectAttributes, NULL, 0, NULL, NULL);
307 Status = NtOpenProcess(&ProcessHandle,
308 PROCESS_DUP_HANDLE,
309 &ObjectAttributes,
310 &ApiMessage->Header.ClientId);
311 if (!NT_SUCCESS(Status))
312 {
313 DPRINT1("NLS: Failed to open process! %lx\n", Status);
314 NtClose(SectionHandle);
315 return Status;
316 }
317
318 /* Duplicate the handle to the section object into it */
319 Status = NtDuplicateObject(NtCurrentProcess(),
320 SectionHandle,
321 ProcessHandle,
322 &NlsMsg->SectionHandle,
323 0,
324 0,
325 3);
326 NtClose(ProcessHandle);
327 return Status;
328 }
329
330 CSR_API(BaseSrvNlsUpdateCacheCount)
331 {
332 DPRINT1("%s not yet implemented\n", __FUNCTION__);
333 return STATUS_NOT_IMPLEMENTED;
334 }
335
336 CSR_API(BaseSrvNlsGetUserInfo)
337 {
338 NTSTATUS Status;
339 PBASE_NLS_GET_USER_INFO NlsMsg = &((PBASE_API_MESSAGE)ApiMessage)->Data.NlsGetUserInfo;
340
341 /* Make sure the buffer is valid and of the right size */
342 if ((CsrValidateMessageBuffer(ApiMessage, &NlsMsg->NlsUserInfo, NlsMsg->Size, sizeof(BYTE))) &&
343 (NlsMsg->Size == sizeof(NLS_USER_INFO)))
344 {
345 /* Acquire the lock to prevent updates while we copy */
346 Status = RtlEnterCriticalSection(&NlsCacheCriticalSection);
347 if (NT_SUCCESS(Status))
348 {
349 /* Do the copy now, then drop the lock */
350 RtlCopyMemory(NlsMsg->NlsUserInfo, pNlsRegUserInfo, NlsMsg->Size);
351 DPRINT1("NLS Data copy complete\n");
352 RtlLeaveCriticalSection(&NlsCacheCriticalSection);
353 }
354 }
355 else
356 {
357 /* The data was invalid, bail out */
358 DPRINT1("NLS: Size of info is invalid: %lx vs %lx\n", NlsMsg->Size, sizeof(NLS_USER_INFO));
359 Status = STATUS_INVALID_PARAMETER;
360 }
361
362 /* All done */
363 return Status;
364 }
365
366 /* PUBLIC APIS ****************************************************************/
367
368 NTSTATUS
369 NTAPI
370 BaseSrvNlsLogon(DWORD Unknown)
371 {
372 DPRINT1("%s(%lu) not yet implemented\n", __FUNCTION__, Unknown);
373 return STATUS_NOT_IMPLEMENTED;
374 }
375
376 NTSTATUS
377 NTAPI
378 BaseSrvNlsUpdateRegistryCache(DWORD Unknown1,
379 DWORD Unknown2)
380 {
381 DPRINT1("%s(%lu, %lu) not yet implemented\n", __FUNCTION__, Unknown1, Unknown2);
382 return STATUS_NOT_IMPLEMENTED;
383 }
384
385 /* EOF */