[BASESRV]
[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 PBASE_NLS_CREATE_SECTION NlsMsg = &((PBASE_API_MESSAGE)ApiMessage)->Data.NlsCreateSection;
155
156 /* Load kernel32 first and import the NLS routines */
157 Status = BaseSrvDelayLoadKernel32();
158 if (!NT_SUCCESS(Status)) return Status;
159
160 /* Assume failure */
161 NlsMsg->SectionHandle = NULL;
162
163 /* Check and validate the locale ID, if one is present */
164 LocaleId = NlsMsg->LocaleId;
165 DPRINT1("NLS: Create Section with LCID: %lx for Type: %d\n", LocaleId, NlsMsg->Type);
166 if (LocaleId)
167 {
168 if (!pValidateLocale(LocaleId)) return STATUS_INVALID_PARAMETER;
169 }
170
171 /* Check which NLS section is being created */
172 switch (NlsMsg->Type)
173 {
174 /* For each one, set the correct filename and object name */
175 case 1:
176 RtlInitUnicodeString(&NlsSectionName, L"\\NLS\\NlsSectionUnicode");
177 NlsFileName = L"unicode.nls";
178 break;
179 case 2:
180 RtlInitUnicodeString(&NlsSectionName, L"\\NLS\\NlsSectionLocale");
181 NlsFileName = L"locale.nls";
182 break;
183 case 3:
184 RtlInitUnicodeString(&NlsSectionName, L"\\NLS\\NlsSectionCType");
185 NlsFileName = L"ctype.nls";
186 break;
187 case 4:
188 RtlInitUnicodeString(&NlsSectionName, L"\\NLS\\NlsSectionSortkey");
189 NlsFileName = L"sortkey.nls";
190 break;
191 case 5:
192 RtlInitUnicodeString(&NlsSectionName, L"\\NLS\\NlsSectionSortTbls");
193 NlsFileName = L"sorttbls.nls";
194 break;
195 case 6:
196 RtlInitUnicodeString(&NlsSectionName, L"\\NLS\\NlsSectionCP437");
197 NlsFileName = L"c_437.nls";
198 break;
199 case 7:
200 RtlInitUnicodeString(&NlsSectionName, L"\\NLS\\NlsSectionCP1252");
201 NlsFileName = L"c_1252.nls";
202 break;
203 case 8:
204 RtlInitUnicodeString(&NlsSectionName, L"\\NLS\\NlsSectionLANG_EXCEPT");
205 NlsFileName = L"l_except.nls";
206 break;
207 case 9:
208 DPRINT1("This type not yet supported\n");
209 return STATUS_NOT_IMPLEMENTED;
210 case 10:
211 DPRINT1("This type not yet supported\n");
212 return STATUS_NOT_IMPLEMENTED;
213 case 11:
214 DPRINT1("This type not yet supported\n");
215 return STATUS_NOT_IMPLEMENTED;
216 case 12:
217 RtlInitUnicodeString(&NlsSectionName, L"\\NLS\\NlsSectionGeo");
218 NlsFileName = L"geo.nls";
219 break;
220 default:
221 DPRINT1("NLS: Invalid NLS type!\n");
222 return STATUS_INVALID_PARAMETER;
223 }
224
225 /* Open the specified NLS file */
226 Status = pOpenDataFile(&FileHandle, NlsFileName);
227 if (Status != STATUS_SUCCESS)
228 {
229 DPRINT1("NLS: Failed to open file: %lx\n", Status);
230 return Status;
231 }
232
233 /* Create an SD for the section object */
234 Status = pCreateNlsSecurityDescriptor(&SecurityDescriptor,
235 sizeof(SecurityDescriptor),
236 0x80000000);
237 if (!NT_SUCCESS(Status))
238 {
239 DPRINT1("NLS: CreateNlsSecurityDescriptor FAILED!: %lx\n", Status);
240 NtClose(FileHandle);
241 return Status;
242 }
243
244 /* Create the section object proper */
245 InitializeObjectAttributes(&ObjectAttributes,
246 &NlsSectionName,
247 OBJ_CASE_INSENSITIVE | OBJ_PERMANENT | OBJ_OPENIF,
248 NULL,
249 &SecurityDescriptor);
250 Status = NtCreateSection(&SectionHandle,
251 SECTION_MAP_READ,
252 &ObjectAttributes,
253 0,
254 PAGE_READONLY,
255 SEC_COMMIT,
256 FileHandle);
257 NtClose(FileHandle);
258 if (!NT_SUCCESS(Status))
259 {
260 DPRINT1("NLS: Failed to create section! %lx\n", Status);
261 return Status;
262 }
263
264 /* Open a handle to the calling process */
265 InitializeObjectAttributes(&ObjectAttributes, NULL, 0, NULL, NULL);
266 Status = NtOpenProcess(&ProcessHandle,
267 PROCESS_DUP_HANDLE,
268 &ObjectAttributes,
269 &ApiMessage->Header.ClientId);
270 if (!NT_SUCCESS(Status))
271 {
272 DPRINT1("NLS: Failed to open process! %lx\n", Status);
273 NtClose(SectionHandle);
274 return Status;
275 }
276
277 /* Duplicate the handle to the section object into it */
278 Status = NtDuplicateObject(NtCurrentProcess(),
279 SectionHandle,
280 ProcessHandle,
281 &NlsMsg->SectionHandle,
282 0,
283 0,
284 3);
285 NtClose(ProcessHandle);
286 return Status;
287 }
288
289 CSR_API(BaseSrvNlsUpdateCacheCount)
290 {
291 DPRINT1("%s not yet implemented\n", __FUNCTION__);
292 return STATUS_NOT_IMPLEMENTED;
293 }
294
295 CSR_API(BaseSrvNlsGetUserInfo)
296 {
297 NTSTATUS Status;
298 PBASE_NLS_GET_USER_INFO NlsMsg = &((PBASE_API_MESSAGE)ApiMessage)->Data.NlsGetUserInfo;
299
300 /* Make sure the buffer is valid and of the right size */
301 if ((CsrValidateMessageBuffer(ApiMessage, &NlsMsg->NlsUserInfo, NlsMsg->Size, TRUE)) &&
302 (NlsMsg->Size == sizeof(NLS_USER_INFO)))
303 {
304 /* Acquire the lock to prevent updates while we copy */
305 Status = RtlEnterCriticalSection(&NlsCacheCriticalSection);
306 if (NT_SUCCESS(Status))
307 {
308 /* Do the copy now, then drop the lock */
309 RtlCopyMemory(&NlsMsg->NlsUserInfo, pNlsRegUserInfo, NlsMsg->Size);
310 DPRINT1("NLS Data copy complete\n");
311 RtlLeaveCriticalSection(&NlsCacheCriticalSection);
312 }
313 }
314 else
315 {
316 /* The data was invalid, bail out */
317 DPRINT1("NLS: Size of info is invalid: %lx vs %lx\n", NlsMsg->Size, sizeof(NLS_USER_INFO));
318 Status = STATUS_INVALID_PARAMETER;
319 }
320
321 /* All done */
322 return Status;
323 }
324
325 /* EOF */