3c4e01bba643d6a736ce0c9a47427f945befa774
[reactos.git] / reactos / dll / ntdll / rtl / libsupp.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS NT User-Mode DLL
4 * FILE: lib/ntdll/rtl/libsup.c
5 * PURPOSE: RTL Support Routines
6 * PROGRAMMERS: Alex Ionescu (alex@relsoft.net)
7 * Gunnar Dalsnes
8 */
9
10 /* INCLUDES *****************************************************************/
11
12 #include <ntdll.h>
13 #define NDEBUG
14 #include <debug.h>
15
16 SIZE_T RtlpAllocDeallocQueryBufferSize = PAGE_SIZE;
17 PTEB LdrpTopLevelDllBeingLoadedTeb = NULL;
18
19 /* FUNCTIONS ***************************************************************/
20
21 /*
22 * @implemented
23 */
24 ULONG
25 NTAPI
26 RtlWalkFrameChain(OUT PVOID *Callers,
27 IN ULONG Count,
28 IN ULONG Flags)
29 {
30 /* Not implemented for user-mode */
31 return 0;
32 }
33
34 BOOLEAN
35 NTAPI
36 RtlpCheckForActiveDebugger(VOID)
37 {
38 /* Return the flag in the PEB */
39 return NtCurrentPeb()->BeingDebugged;
40 }
41
42 BOOLEAN
43 NTAPI
44 RtlpSetInDbgPrint(IN BOOLEAN NewValue)
45 {
46 /* If we're setting it to false, do it and return */
47 if (NewValue == FALSE)
48 {
49 NtCurrentTeb()->InDbgPrint = FALSE;
50 return FALSE;
51 }
52
53 /* Setting to true; check if it's not already */
54 if (NtCurrentTeb()->InDbgPrint) return TRUE;
55
56 /* Set it and return */
57 NtCurrentTeb()->InDbgPrint = TRUE;
58 return FALSE;
59 }
60
61 KPROCESSOR_MODE
62 NTAPI
63 RtlpGetMode()
64 {
65 return UserMode;
66 }
67
68 /*
69 * @implemented
70 */
71 PPEB
72 NTAPI
73 RtlGetCurrentPeb(VOID)
74 {
75 return NtCurrentPeb();
76 }
77
78 /*
79 * @implemented
80 */
81 VOID NTAPI
82 RtlAcquirePebLock(VOID)
83 {
84 PPEB Peb = NtCurrentPeb ();
85 Peb->FastPebLockRoutine (Peb->FastPebLock);
86 }
87
88 /*
89 * @implemented
90 */
91 VOID NTAPI
92 RtlReleasePebLock(VOID)
93 {
94 PPEB Peb = NtCurrentPeb ();
95 Peb->FastPebUnlockRoutine (Peb->FastPebLock);
96 }
97
98 /*
99 * @implemented
100 */
101 ULONG
102 NTAPI
103 RtlGetNtGlobalFlags(VOID)
104 {
105 PPEB pPeb = NtCurrentPeb();
106 return pPeb->NtGlobalFlag;
107 }
108
109 NTSTATUS
110 NTAPI
111 RtlDeleteHeapLock(
112 PRTL_CRITICAL_SECTION CriticalSection)
113 {
114 return RtlDeleteCriticalSection(CriticalSection);
115 }
116
117 NTSTATUS
118 NTAPI
119 RtlEnterHeapLock(
120 PRTL_CRITICAL_SECTION CriticalSection)
121 {
122 return RtlEnterCriticalSection(CriticalSection);
123 }
124
125 NTSTATUS
126 NTAPI
127 RtlInitializeHeapLock(
128 PRTL_CRITICAL_SECTION CriticalSection)
129 {
130 return RtlInitializeCriticalSection(CriticalSection);
131 }
132
133 NTSTATUS
134 NTAPI
135 RtlLeaveHeapLock(
136 PRTL_CRITICAL_SECTION CriticalSection)
137 {
138 return RtlLeaveCriticalSection(CriticalSection );
139 }
140
141 PVOID
142 NTAPI
143 RtlpAllocateMemory(UINT Bytes,
144 ULONG Tag)
145 {
146 UNREFERENCED_PARAMETER(Tag);
147
148 return RtlAllocateHeap(RtlGetProcessHeap(),
149 0,
150 Bytes);
151 }
152
153
154 VOID
155 NTAPI
156 RtlpFreeMemory(PVOID Mem,
157 ULONG Tag)
158 {
159 UNREFERENCED_PARAMETER(Tag);
160
161 RtlFreeHeap(RtlGetProcessHeap(),
162 0,
163 Mem);
164 }
165
166
167 #if DBG
168 VOID FASTCALL
169 CHECK_PAGED_CODE_RTL(char *file, int line)
170 {
171 /* meaningless in user mode */
172 }
173 #endif
174
175 BOOLEAN
176 NTAPI
177 RtlpHandleDpcStackException(IN PEXCEPTION_REGISTRATION_RECORD RegistrationFrame,
178 IN ULONG_PTR RegistrationFrameEnd,
179 IN OUT PULONG_PTR StackLow,
180 IN OUT PULONG_PTR StackHigh)
181 {
182 /* There's no such thing as a DPC stack in user-mode */
183 return FALSE;
184 }
185
186 VOID
187 NTAPI
188 RtlpCheckLogException(IN PEXCEPTION_RECORD ExceptionRecord,
189 IN PCONTEXT ContextRecord,
190 IN PVOID ContextData,
191 IN ULONG Size)
192 {
193 /* Exception logging is not done in user-mode */
194 }
195
196 BOOLEAN
197 NTAPI
198 RtlpCaptureStackLimits(IN ULONG_PTR Ebp,
199 IN ULONG_PTR *StackBegin,
200 IN ULONG_PTR *StackEnd)
201 {
202 /* FIXME: Verify */
203 *StackBegin = (ULONG_PTR)NtCurrentTeb()->Tib.StackLimit;
204 *StackEnd = (ULONG_PTR)NtCurrentTeb()->Tib.StackBase;
205 return TRUE;
206 }
207
208 BOOLEAN
209 NTAPI
210 RtlIsThreadWithinLoaderCallout(VOID)
211 {
212 return LdrpTopLevelDllBeingLoadedTeb == NtCurrentTeb();
213 }
214
215 /* RTL Atom Tables ************************************************************/
216
217 typedef struct _RTL_ATOM_HANDLE
218 {
219 RTL_HANDLE_TABLE_ENTRY Handle;
220 PRTL_ATOM_TABLE_ENTRY AtomEntry;
221 } RTL_ATOM_HANDLE, *PRTL_ATOM_HANDLE;
222
223 NTSTATUS
224 RtlpInitAtomTableLock(PRTL_ATOM_TABLE AtomTable)
225 {
226 RtlInitializeCriticalSection(&AtomTable->CriticalSection);
227 return STATUS_SUCCESS;
228 }
229
230
231 VOID
232 RtlpDestroyAtomTableLock(PRTL_ATOM_TABLE AtomTable)
233 {
234 RtlDeleteCriticalSection(&AtomTable->CriticalSection);
235 }
236
237
238 BOOLEAN
239 RtlpLockAtomTable(PRTL_ATOM_TABLE AtomTable)
240 {
241 RtlEnterCriticalSection(&AtomTable->CriticalSection);
242 return TRUE;
243 }
244
245
246 VOID
247 RtlpUnlockAtomTable(PRTL_ATOM_TABLE AtomTable)
248 {
249 RtlLeaveCriticalSection(&AtomTable->CriticalSection);
250 }
251
252
253 /* handle functions */
254
255 BOOLEAN
256 RtlpCreateAtomHandleTable(PRTL_ATOM_TABLE AtomTable)
257 {
258 RtlInitializeHandleTable(0xCFFF,
259 sizeof(RTL_ATOM_HANDLE),
260 &AtomTable->RtlHandleTable);
261
262 return TRUE;
263 }
264
265 VOID
266 RtlpDestroyAtomHandleTable(PRTL_ATOM_TABLE AtomTable)
267 {
268 RtlDestroyHandleTable(&AtomTable->RtlHandleTable);
269 }
270
271 PRTL_ATOM_TABLE
272 RtlpAllocAtomTable(ULONG Size)
273 {
274 return (PRTL_ATOM_TABLE)RtlAllocateHeap(RtlGetProcessHeap(),
275 HEAP_ZERO_MEMORY,
276 Size);
277 }
278
279 VOID
280 RtlpFreeAtomTable(PRTL_ATOM_TABLE AtomTable)
281 {
282 RtlFreeHeap(RtlGetProcessHeap(),
283 0,
284 AtomTable);
285 }
286
287 PRTL_ATOM_TABLE_ENTRY
288 RtlpAllocAtomTableEntry(ULONG Size)
289 {
290 return (PRTL_ATOM_TABLE_ENTRY)RtlAllocateHeap(RtlGetProcessHeap(),
291 HEAP_ZERO_MEMORY,
292 Size);
293 }
294
295 VOID
296 RtlpFreeAtomTableEntry(PRTL_ATOM_TABLE_ENTRY Entry)
297 {
298 RtlFreeHeap(RtlGetProcessHeap(),
299 0,
300 Entry);
301 }
302
303 VOID
304 RtlpFreeAtomHandle(PRTL_ATOM_TABLE AtomTable, PRTL_ATOM_TABLE_ENTRY Entry)
305 {
306 PRTL_HANDLE_TABLE_ENTRY RtlHandleEntry;
307
308 if (RtlIsValidIndexHandle(&AtomTable->RtlHandleTable,
309 (ULONG)Entry->HandleIndex,
310 &RtlHandleEntry))
311 {
312 RtlFreeHandle(&AtomTable->RtlHandleTable,
313 RtlHandleEntry);
314 }
315 }
316
317 BOOLEAN
318 RtlpCreateAtomHandle(PRTL_ATOM_TABLE AtomTable, PRTL_ATOM_TABLE_ENTRY Entry)
319 {
320 ULONG HandleIndex;
321 PRTL_HANDLE_TABLE_ENTRY RtlHandle;
322
323 RtlHandle = RtlAllocateHandle(&AtomTable->RtlHandleTable,
324 &HandleIndex);
325 if (RtlHandle != NULL)
326 {
327 PRTL_ATOM_HANDLE AtomHandle = (PRTL_ATOM_HANDLE)RtlHandle;
328
329 /* FIXME - Handle Indexes >= 0xC000 ?! */
330 if (HandleIndex < 0xC000)
331 {
332 Entry->HandleIndex = (USHORT)HandleIndex;
333 Entry->Atom = 0xC000 + (USHORT)HandleIndex;
334
335 AtomHandle->AtomEntry = Entry;
336 AtomHandle->Handle.Flags = RTL_HANDLE_VALID;
337
338 return TRUE;
339 }
340 else
341 {
342 /* set the valid flag, otherwise RtlFreeHandle will fail! */
343 AtomHandle->Handle.Flags = RTL_HANDLE_VALID;
344
345 RtlFreeHandle(&AtomTable->RtlHandleTable,
346 RtlHandle);
347 }
348 }
349
350 return FALSE;
351 }
352
353 PRTL_ATOM_TABLE_ENTRY
354 RtlpGetAtomEntry(PRTL_ATOM_TABLE AtomTable, ULONG Index)
355 {
356 PRTL_HANDLE_TABLE_ENTRY RtlHandle;
357
358 if (RtlIsValidIndexHandle(&AtomTable->RtlHandleTable,
359 Index,
360 &RtlHandle))
361 {
362 PRTL_ATOM_HANDLE AtomHandle = (PRTL_ATOM_HANDLE)RtlHandle;
363
364 return AtomHandle->AtomEntry;
365 }
366
367 return NULL;
368 }
369
370
371 /*
372 * Ldr Resource support code
373 */
374
375 IMAGE_RESOURCE_DIRECTORY *find_entry_by_name( IMAGE_RESOURCE_DIRECTORY *dir,
376 LPCWSTR name, void *root,
377 int want_dir );
378 IMAGE_RESOURCE_DIRECTORY *find_entry_by_id( IMAGE_RESOURCE_DIRECTORY *dir,
379 WORD id, void *root, int want_dir );
380 IMAGE_RESOURCE_DIRECTORY *find_first_entry( IMAGE_RESOURCE_DIRECTORY *dir,
381 void *root, int want_dir );
382 int push_language( USHORT *list, ULONG pos, WORD lang );
383
384 /**********************************************************************
385 * find_entry
386 *
387 * Find a resource entry
388 */
389 NTSTATUS find_entry( PVOID BaseAddress, LDR_RESOURCE_INFO *info,
390 ULONG level, void **ret, int want_dir )
391 {
392 ULONG size;
393 void *root;
394 IMAGE_RESOURCE_DIRECTORY *resdirptr;
395 USHORT list[9]; /* list of languages to try */
396 int i, pos = 0;
397 LCID user_lcid, system_lcid;
398
399 root = RtlImageDirectoryEntryToData( BaseAddress, TRUE, IMAGE_DIRECTORY_ENTRY_RESOURCE, &size );
400 if (!root) return STATUS_RESOURCE_DATA_NOT_FOUND;
401 resdirptr = root;
402
403 if (!level--) goto done;
404 if (!(*ret = find_entry_by_name( resdirptr, (LPCWSTR)info->Type, root, want_dir || level )))
405 return STATUS_RESOURCE_TYPE_NOT_FOUND;
406 if (!level--) return STATUS_SUCCESS;
407
408 resdirptr = *ret;
409 if (!(*ret = find_entry_by_name( resdirptr, (LPCWSTR)info->Name, root, want_dir || level )))
410 return STATUS_RESOURCE_NAME_NOT_FOUND;
411 if (!level--) return STATUS_SUCCESS;
412 if (level) return STATUS_INVALID_PARAMETER; /* level > 3 */
413
414 /* 1. specified language */
415 pos = push_language( list, pos, info->Language );
416
417 /* 2. specified language with neutral sublanguage */
418 pos = push_language( list, pos, MAKELANGID( PRIMARYLANGID(info->Language), SUBLANG_NEUTRAL ) );
419
420 /* 3. neutral language with neutral sublanguage */
421 pos = push_language( list, pos, MAKELANGID( LANG_NEUTRAL, SUBLANG_NEUTRAL ) );
422
423 /* if no explicitly specified language, try some defaults */
424 if (PRIMARYLANGID(info->Language) == LANG_NEUTRAL)
425 {
426 /* user defaults, unless SYS_DEFAULT sublanguage specified */
427 if (SUBLANGID(info->Language) != SUBLANG_SYS_DEFAULT)
428 {
429 /* 4. current thread locale language */
430 pos = push_language( list, pos, LANGIDFROMLCID(NtCurrentTeb()->CurrentLocale) );
431
432 if (NT_SUCCESS(NtQueryDefaultLocale(TRUE, &user_lcid)))
433 {
434 /* 5. user locale language */
435 pos = push_language( list, pos, LANGIDFROMLCID(user_lcid) );
436
437 /* 6. user locale language with neutral sublanguage */
438 pos = push_language( list, pos, MAKELANGID( PRIMARYLANGID(user_lcid), SUBLANG_NEUTRAL ) );
439 }
440 }
441
442 /* now system defaults */
443
444 if (NT_SUCCESS(NtQueryDefaultLocale(FALSE, &system_lcid)))
445 {
446 /* 7. system locale language */
447 pos = push_language( list, pos, LANGIDFROMLCID( system_lcid ) );
448
449 /* 8. system locale language with neutral sublanguage */
450 pos = push_language( list, pos, MAKELANGID( PRIMARYLANGID(system_lcid), SUBLANG_NEUTRAL ) );
451 }
452
453 /* 9. English */
454 pos = push_language( list, pos, MAKELANGID( LANG_ENGLISH, SUBLANG_DEFAULT ) );
455 }
456
457 resdirptr = *ret;
458 for (i = 0; i < pos; i++)
459 if ((*ret = find_entry_by_id( resdirptr, list[i], root, want_dir ))) return STATUS_SUCCESS;
460
461 /* if no explicitly specified language, return the first entry */
462 if (PRIMARYLANGID(info->Language) == LANG_NEUTRAL)
463 {
464 if ((*ret = find_first_entry( resdirptr, root, want_dir ))) return STATUS_SUCCESS;
465 }
466 return STATUS_RESOURCE_LANG_NOT_FOUND;
467
468 done:
469 *ret = resdirptr;
470 return STATUS_SUCCESS;
471 }