migrate substitution keywords to SVN
[reactos.git] / reactos / lib / ntdll / rtl / atom.c
1 /* $Id$
2 *
3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS kernel
5 * FILE: lib/ntdll/rtl/atom.c
6 * PURPOSE: Atom managment
7 * PROGRAMMER: Nobody
8 * UPDATE HISTORY:
9 * Created 22/05/98
10 */
11
12 /* INCLUDES *****************************************************************/
13
14 #include <ddk/ntddk.h>
15 #include <ntdll/rtl.h>
16 #include <ntos/heap.h>
17
18 #define NDEBUG
19 #include <ntdll/ntdll.h>
20
21
22 /* LOCAL TYPES ***************************************************************/
23
24 typedef struct _RTL_ATOM_ENTRY
25 {
26 LIST_ENTRY List;
27 UNICODE_STRING Name;
28 ULONG RefCount;
29 BOOLEAN Locked;
30 ULONG Index;
31 PRTL_HANDLE Handle;
32 } RTL_ATOM_ENTRY, *PRTL_ATOM_ENTRY;
33
34 typedef struct _RTL_ATOM_HANDLE
35 {
36 RTL_HANDLE Handle;
37 PRTL_ATOM_ENTRY Entry;
38 } RTL_ATOM_HANDLE, *PRTL_ATOM_HANDLE;
39
40
41 /* PROTOTYPES ****************************************************************/
42
43 static ULONG RtlpHashAtomName(ULONG TableSize, PWSTR AtomName);
44 static BOOLEAN RtlpCheckIntegerAtom(PWSTR AtomName, PUSHORT AtomValue);
45
46 static NTSTATUS RtlpInitAtomTableLock(PRTL_ATOM_TABLE AtomTable);
47 static VOID RtlpDestroyAtomTableLock(PRTL_ATOM_TABLE AtomTable);
48 static BOOLEAN RtlpLockAtomTable(PRTL_ATOM_TABLE AtomTable);
49 static VOID RtlpUnlockAtomTable(PRTL_ATOM_TABLE AtomTable);
50
51 static BOOLEAN RtlpCreateAtomHandleTable(PRTL_ATOM_TABLE AtomTable);
52 static VOID RtlpDestroyAtomHandleTable(PRTL_ATOM_TABLE AtomTable);
53
54
55 /* FUNCTIONS *****************************************************************/
56
57
58 /*
59 * @implemented
60 */
61 NTSTATUS STDCALL
62 RtlCreateAtomTable(ULONG TableSize,
63 PRTL_ATOM_TABLE *AtomTable)
64 {
65 PRTL_ATOM_TABLE Table;
66 ULONG i;
67 NTSTATUS Status;
68
69 DPRINT("RtlCreateAtomTable(TableSize %lu AtomTable %p)\n",
70 TableSize, AtomTable);
71
72 if (*AtomTable != NULL)
73 {
74 return STATUS_SUCCESS;
75 }
76
77 /* allocate atom table */
78 Table = RtlAllocateHeap(RtlGetProcessHeap(),
79 HEAP_ZERO_MEMORY,
80 TableSize * sizeof(LIST_ENTRY) +
81 sizeof(RTL_ATOM_TABLE));
82 if (Table == NULL)
83 {
84 return STATUS_NO_MEMORY;
85 }
86
87 /* initialize atom table */
88 Table->TableSize = TableSize;
89
90 for (i = 0; i < TableSize; i++)
91 {
92 InitializeListHead(&Table->Slot[i]);
93 }
94
95 Status = RtlpInitAtomTableLock(Table);
96 if (!NT_SUCCESS(Status))
97 {
98 RtlFreeHeap(RtlGetProcessHeap(),
99 0,
100 Table);
101 return Status;
102 }
103
104 if (RtlpCreateAtomHandleTable(Table) == FALSE)
105 {
106 RtlpDestroyAtomTableLock(Table);
107 RtlFreeHeap(RtlGetProcessHeap(),
108 0,
109 Table);
110 return STATUS_NO_MEMORY;
111 }
112
113 *AtomTable = Table;
114 return STATUS_SUCCESS;
115 }
116
117
118 /*
119 * @implemented
120 */
121 NTSTATUS STDCALL
122 RtlDestroyAtomTable(IN PRTL_ATOM_TABLE AtomTable)
123 {
124 PLIST_ENTRY Current;
125 PRTL_ATOM_ENTRY AtomEntry;
126 ULONG i;
127
128 if (RtlpLockAtomTable(AtomTable) == FALSE)
129 {
130 return (STATUS_INVALID_PARAMETER);
131 }
132
133 /* delete all atoms */
134 for (i = 0; i < AtomTable->TableSize; i++)
135 {
136
137 Current = AtomTable->Slot[i].Flink;
138 while (Current != &AtomTable->Slot[i])
139 {
140 AtomEntry = (PRTL_ATOM_ENTRY)Current;
141 RtlFreeUnicodeString(&AtomEntry->Name);
142 RemoveEntryList(&AtomEntry->List);
143 RtlFreeHeap(RtlGetProcessHeap(),
144 0,
145 AtomEntry);
146 Current = AtomTable->Slot[i].Flink;
147 }
148
149 }
150
151 RtlpDestroyAtomHandleTable(AtomTable);
152
153 RtlpUnlockAtomTable(AtomTable);
154
155 RtlpDestroyAtomTableLock(AtomTable);
156
157 RtlFreeHeap(RtlGetProcessHeap(),
158 0,
159 AtomTable);
160
161 return STATUS_SUCCESS;
162 }
163
164
165 /*
166 * @implemented
167 */
168 NTSTATUS STDCALL
169 RtlEmptyAtomTable(PRTL_ATOM_TABLE AtomTable,
170 BOOLEAN DeletePinned)
171 {
172 PLIST_ENTRY Current, Next;
173 PRTL_ATOM_ENTRY AtomEntry;
174 ULONG i;
175
176 DPRINT("RtlEmptyAtomTable (AtomTable %p DeletePinned %x)\n",
177 AtomTable, DeletePinned);
178
179 if (RtlpLockAtomTable(AtomTable) == FALSE)
180 {
181 return (STATUS_INVALID_PARAMETER);
182 }
183
184 /* delete all atoms */
185 for (i = 0; i < AtomTable->TableSize; i++)
186 {
187 Current = AtomTable->Slot[i].Flink;
188 while (Current != &AtomTable->Slot[i])
189 {
190 Next = Current->Flink;
191 AtomEntry = (PRTL_ATOM_ENTRY)Current;
192
193 if ((AtomEntry->Locked == FALSE) ||
194 ((AtomEntry->Locked == TRUE) && (DeletePinned == TRUE)))
195 {
196 RtlFreeUnicodeString(&AtomEntry->Name);
197
198 RtlFreeHandle(AtomTable->HandleTable,
199 AtomEntry->Handle);
200
201 RemoveEntryList(&AtomEntry->List);
202 RtlFreeHeap(RtlGetProcessHeap(),
203 0,
204 AtomEntry);
205 }
206 Current = Next;
207 }
208
209 }
210
211 RtlpUnlockAtomTable(AtomTable);
212
213 return STATUS_SUCCESS;
214 }
215
216
217 /*
218 * @implemented
219 */
220 NTSTATUS STDCALL
221 RtlAddAtomToAtomTable(IN PRTL_ATOM_TABLE AtomTable,
222 IN PWSTR AtomName,
223 OUT PRTL_ATOM Atom)
224 {
225 ULONG Hash;
226 PLIST_ENTRY Current;
227 PRTL_ATOM_ENTRY Entry;
228 USHORT AtomValue;
229 NTSTATUS Status;
230 PRTL_ATOM_HANDLE AtomHandle;
231 ULONG AtomIndex;
232
233 DPRINT("RtlAddAtomToAtomTable (AtomTable %p AtomName %S Atom %p)\n",
234 AtomTable, AtomName, Atom);
235
236 if (RtlpCheckIntegerAtom (AtomName, &AtomValue))
237 {
238 /* integer atom */
239 if (AtomValue >= 0xC000)
240 {
241 AtomValue = 0;
242 Status = STATUS_INVALID_PARAMETER;
243 }
244 else
245 {
246 Status = STATUS_SUCCESS;
247 }
248
249 if (Atom)
250 *Atom = (RTL_ATOM)AtomValue;
251
252 return Status;
253 }
254
255 RtlpLockAtomTable(AtomTable);
256
257 /* string atom */
258 Hash = RtlpHashAtomName(AtomTable->TableSize, AtomName);
259
260 /* search for existing atom */
261 Current = AtomTable->Slot[Hash].Flink;
262 while (Current != &AtomTable->Slot[Hash])
263 {
264 Entry = (PRTL_ATOM_ENTRY)Current;
265
266 DPRINT("Comparing %S and %S\n", Entry->Name.Buffer, AtomName);
267 if (_wcsicmp(Entry->Name.Buffer, AtomName) == 0)
268 {
269 Entry->RefCount++;
270 if (Atom)
271 *Atom = (RTL_ATOM)(Entry->Index + 0xC000);
272 RtlpUnlockAtomTable(AtomTable);
273 return STATUS_SUCCESS;
274 }
275 Current = Current->Flink;
276 }
277
278 /* insert new atom */
279 Entry = RtlAllocateHeap(RtlGetProcessHeap(),
280 HEAP_ZERO_MEMORY,
281 sizeof(RTL_ATOM_ENTRY));
282 if (Entry == NULL)
283 {
284 RtlpUnlockAtomTable(AtomTable);
285 return STATUS_NO_MEMORY;
286 }
287
288 InsertTailList(&AtomTable->Slot[Hash], &Entry->List);
289 RtlCreateUnicodeString (&Entry->Name,
290 AtomName);
291 Entry->RefCount = 1;
292 Entry->Locked = FALSE;
293
294 /* FIXME: use general function instead !! */
295 AtomHandle = (PRTL_ATOM_HANDLE)RtlAllocateHandle(AtomTable->HandleTable,
296 &AtomIndex);
297
298 DPRINT("AtomHandle %p AtomIndex %x\n", AtomHandle, AtomIndex);
299
300 AtomHandle->Entry = Entry;
301 Entry->Index = AtomIndex;
302 Entry->Handle = (PRTL_HANDLE)AtomHandle;
303
304 if (Atom)
305 *Atom = (RTL_ATOM)(AtomIndex + 0xC000);
306
307 RtlpUnlockAtomTable(AtomTable);
308
309 return STATUS_SUCCESS;
310 }
311
312
313 /*
314 * @implemented
315 */
316 NTSTATUS STDCALL
317 RtlDeleteAtomFromAtomTable(IN PRTL_ATOM_TABLE AtomTable,
318 IN RTL_ATOM Atom)
319 {
320 PRTL_ATOM_HANDLE AtomHandle;
321 PRTL_ATOM_ENTRY AtomEntry;
322
323 DPRINT("RtlDeleteAtomFromAtomTable (AtomTable %p Atom %x)\n",
324 AtomTable, Atom);
325
326 if (Atom < 0xC000)
327 {
328 return STATUS_SUCCESS;
329 }
330
331 RtlpLockAtomTable(AtomTable);
332
333 /* FIXME: use general function instead !! */
334 if (!RtlIsValidIndexHandle(AtomTable->HandleTable,
335 (PRTL_HANDLE *)&AtomHandle,
336 (ULONG)Atom - 0xC000))
337 {
338 RtlpUnlockAtomTable(AtomTable);
339 return STATUS_INVALID_HANDLE;
340 }
341
342 DPRINT("AtomHandle %x\n", AtomHandle);
343 DPRINT("AtomHandle->Entry %x\n", AtomHandle->Entry);
344
345 AtomEntry = AtomHandle->Entry;
346
347 DPRINT("Atom name: %wZ\n", &AtomEntry->Name);
348
349 AtomEntry->RefCount--;
350
351 if (AtomEntry->RefCount == 0)
352 {
353 if (AtomEntry->Locked == TRUE)
354 {
355 DPRINT("Atom %wZ is locked!\n", &AtomEntry->Name);
356
357 RtlpUnlockAtomTable(AtomTable);
358 return STATUS_WAS_LOCKED;
359 }
360
361 DPRINT("Removing atom: %wZ\n", &AtomEntry->Name);
362
363 RtlFreeUnicodeString(&AtomEntry->Name);
364 RemoveEntryList(&AtomEntry->List);
365 RtlFreeHeap(RtlGetProcessHeap(),
366 0,
367 AtomEntry);
368 RtlFreeHandle(AtomTable->HandleTable,
369 (PRTL_HANDLE)AtomHandle);
370 }
371
372 RtlpUnlockAtomTable(AtomTable);
373
374 return STATUS_SUCCESS;
375 }
376
377
378 /*
379 * @implemented
380 */
381 NTSTATUS STDCALL
382 RtlLookupAtomInAtomTable(IN PRTL_ATOM_TABLE AtomTable,
383 IN PWSTR AtomName,
384 OUT PRTL_ATOM Atom)
385 {
386 ULONG Hash;
387 PLIST_ENTRY Current;
388 PRTL_ATOM_ENTRY Entry;
389 USHORT AtomValue;
390 NTSTATUS Status;
391
392 DPRINT("RtlLookupAtomInAtomTable (AtomTable %p AtomName %S Atom %p)\n",
393 AtomTable, AtomName, Atom);
394
395 if (RtlpCheckIntegerAtom (AtomName, &AtomValue))
396 {
397 /* integer atom */
398 if (AtomValue >= 0xC000)
399 {
400 AtomValue = 0;
401 Status = STATUS_INVALID_PARAMETER;
402 }
403 else
404 {
405 Status = STATUS_SUCCESS;
406 }
407
408 if (Atom)
409 *Atom = (RTL_ATOM)AtomValue;
410
411 return Status;
412 }
413
414 RtlpLockAtomTable(AtomTable);
415
416 /* string atom */
417 Hash = RtlpHashAtomName(AtomTable->TableSize, AtomName);
418
419 /* search for existing atom */
420 Current = AtomTable->Slot[Hash].Flink;
421 while (Current != &AtomTable->Slot[Hash])
422 {
423 Entry = (PRTL_ATOM_ENTRY)Current;
424
425 DPRINT("Comparing %S and %S\n", Entry->Name.Buffer, AtomName);
426 if (_wcsicmp(Entry->Name.Buffer, AtomName) == 0)
427 {
428 if (Atom)
429 *Atom = (RTL_ATOM)(Entry->Index + 0xC000);
430 RtlpUnlockAtomTable(AtomTable);
431 return STATUS_SUCCESS;
432 }
433
434 Current = Current->Flink;
435 }
436
437 RtlpUnlockAtomTable(AtomTable);
438
439 return STATUS_OBJECT_NAME_NOT_FOUND;
440 }
441
442
443 /*
444 * @implemented
445 */
446 NTSTATUS STDCALL
447 RtlPinAtomInAtomTable(IN PRTL_ATOM_TABLE AtomTable,
448 IN RTL_ATOM Atom)
449 {
450 PRTL_ATOM_HANDLE AtomHandle;
451 PRTL_ATOM_ENTRY AtomEntry;
452
453 DPRINT("RtlPinAtomInAtomTable (AtomTable %p Atom %x)\n",
454 AtomTable, Atom);
455
456 if (Atom < 0xC000)
457 {
458 return STATUS_SUCCESS;
459 }
460
461 RtlpLockAtomTable(AtomTable);
462
463 /* FIXME: use general function instead !! */
464 if (!RtlIsValidIndexHandle(AtomTable->HandleTable,
465 (PRTL_HANDLE *)&AtomHandle,
466 (ULONG)Atom - 0xC000))
467 {
468 RtlpUnlockAtomTable(AtomTable);
469 return STATUS_INVALID_HANDLE;
470 }
471
472 DPRINT("AtomHandle %x\n", AtomHandle);
473 DPRINT("AtomHandle->Entry %x\n", AtomHandle->Entry);
474
475 AtomEntry = AtomHandle->Entry;
476
477 DPRINT("Atom name: %wZ\n", &AtomEntry->Name);
478
479 AtomEntry->Locked = TRUE;
480
481 RtlpUnlockAtomTable(AtomTable);
482
483 return STATUS_SUCCESS;
484 }
485
486
487 /*
488 * @implemented
489 */
490 NTSTATUS STDCALL
491 RtlQueryAtomInAtomTable(PRTL_ATOM_TABLE AtomTable,
492 RTL_ATOM Atom,
493 PULONG RefCount,
494 PULONG PinCount,
495 PWSTR AtomName,
496 PULONG NameLength)
497 {
498 ULONG Length;
499 PRTL_ATOM_HANDLE AtomHandle;
500 PRTL_ATOM_ENTRY AtomEntry;
501
502 if (Atom < 0xC000)
503 {
504 if (RefCount != NULL)
505 {
506 *RefCount = 1;
507 }
508
509 if (PinCount != NULL)
510 {
511 *PinCount = 1;
512 }
513
514 if ((AtomName != NULL) && (NameLength != NULL) && (NameLength > 0))
515 {
516 Length = swprintf(AtomName, L"#%lu", (ULONG)Atom);
517 *NameLength = Length * sizeof(WCHAR);
518 }
519
520 return STATUS_SUCCESS;
521 }
522
523 RtlpLockAtomTable(AtomTable);
524
525 /* FIXME: use general function instead !! */
526 if (!RtlIsValidIndexHandle(AtomTable->HandleTable,
527 (PRTL_HANDLE *)&AtomHandle,
528 (ULONG)Atom - 0xC000))
529 {
530 RtlpUnlockAtomTable(AtomTable);
531 return STATUS_INVALID_HANDLE;
532 }
533
534 DPRINT("AtomHandle %x\n", AtomHandle);
535 DPRINT("AtomHandle->Entry %x\n", AtomHandle->Entry);
536
537 AtomEntry = AtomHandle->Entry;
538
539 DPRINT("Atom name: %wZ\n", &AtomEntry->Name);
540
541 if (RefCount != NULL)
542 {
543 *RefCount = AtomEntry->RefCount;
544 }
545
546 if (PinCount != NULL)
547 {
548 *PinCount = (ULONG)AtomEntry->Locked;
549 }
550
551 if ((AtomName != NULL) && (NameLength != NULL))
552 {
553 if (*NameLength < AtomEntry->Name.Length)
554 {
555 *NameLength = AtomEntry->Name.Length;
556 RtlpUnlockAtomTable(AtomTable);
557 return STATUS_BUFFER_TOO_SMALL;
558 }
559
560 Length = swprintf(AtomName, L"%s", AtomEntry->Name.Buffer);
561 *NameLength = Length * sizeof(WCHAR);
562 }
563
564 RtlpUnlockAtomTable(AtomTable);
565
566 return STATUS_SUCCESS;
567 }
568
569
570 /* INTERNAL FUNCTIONS ********************************************************/
571
572 static ULONG
573 RtlpHashAtomName(ULONG TableSize,
574 PWSTR AtomName)
575 {
576 ULONG q = 0;
577 PWCHAR p;
578
579 DPRINT("RtlpHashAtomName(TableSize %ld AtomName '%S')\n",
580 TableSize, AtomName);
581
582 /* convert the string to an internal representation */
583 p = AtomName;
584 while (*p != 0)
585 {
586 q += (ULONG)towupper(*p);
587 p++;
588 }
589
590 DPRINT("q %lu Hash %lu\n", q, q % TableSize);
591
592 return (q % TableSize);
593 }
594
595
596 static BOOLEAN
597 RtlpCheckIntegerAtom(PWSTR AtomName,
598 PUSHORT AtomValue)
599 {
600 UNICODE_STRING AtomString;
601 USHORT LoValue;
602 ULONG LongValue;
603 PWCHAR p;
604
605 DPRINT("RtlpCheckIntegerAtom(AtomName '%S' AtomValue %p)\n",
606 AtomName, AtomValue);
607
608 if (!((ULONG)AtomName & 0xFFFF0000))
609 {
610 LoValue = (USHORT)((ULONG)AtomName & 0xFFFF);
611
612 if (LoValue >= 0xC000)
613 return FALSE;
614
615 if (LoValue == 0)
616 LoValue = 0xC000;
617
618 if (AtomValue != NULL)
619 *AtomValue = LoValue;
620
621 return TRUE;
622 }
623
624 if (*AtomName != L'#')
625 return FALSE;
626
627 p = AtomName;
628 p++;
629 while (*p)
630 {
631 if ((*p < L'0') || (*p > L'9'))
632 return FALSE;
633 p++;
634 }
635
636 p = AtomName;
637 p++;
638 RtlInitUnicodeString(&AtomString,
639 p);
640
641 RtlUnicodeStringToInteger(&AtomString,10, &LongValue);
642
643 *AtomValue = (USHORT)(LongValue & 0x0000FFFF);
644
645 return TRUE;
646 }
647
648
649 /* lock functions */
650
651 static NTSTATUS
652 RtlpInitAtomTableLock(PRTL_ATOM_TABLE AtomTable)
653 {
654 AtomTable->Lock = RtlAllocateHeap(RtlGetProcessHeap(),
655 HEAP_ZERO_MEMORY,
656 sizeof(CRITICAL_SECTION));
657 if (AtomTable->Lock == NULL)
658 return STATUS_NO_MEMORY;
659
660 RtlInitializeCriticalSection((PCRITICAL_SECTION)AtomTable->Lock);
661
662 return STATUS_SUCCESS;
663 }
664
665
666 static VOID
667 RtlpDestroyAtomTableLock(PRTL_ATOM_TABLE AtomTable)
668 {
669 if (AtomTable->Lock)
670 {
671 RtlDeleteCriticalSection((PCRITICAL_SECTION)AtomTable->Lock);
672 RtlFreeHeap(RtlGetProcessHeap(),
673 0,
674 AtomTable->Lock);
675 AtomTable->Lock = NULL;
676 }
677 }
678
679
680 static BOOLEAN
681 RtlpLockAtomTable(PRTL_ATOM_TABLE AtomTable)
682 {
683 RtlEnterCriticalSection((PCRITICAL_SECTION)AtomTable->Lock);
684 return TRUE;
685 }
686
687
688 static VOID
689 RtlpUnlockAtomTable(PRTL_ATOM_TABLE AtomTable)
690 {
691 RtlLeaveCriticalSection((PCRITICAL_SECTION)AtomTable->Lock);
692 }
693
694
695 /* handle functions */
696
697 static BOOLEAN
698 RtlpCreateAtomHandleTable(PRTL_ATOM_TABLE AtomTable)
699 {
700 AtomTable->HandleTable = RtlAllocateHeap(RtlGetProcessHeap(),
701 HEAP_ZERO_MEMORY,
702 sizeof(RTL_HANDLE_TABLE));
703 if (AtomTable->HandleTable == NULL)
704 return FALSE;
705
706 RtlInitializeHandleTable(0xCFFF,
707 sizeof(RTL_ATOM_HANDLE),
708 (PRTL_HANDLE_TABLE)AtomTable->HandleTable);
709
710 return TRUE;
711 }
712
713 static VOID
714 RtlpDestroyAtomHandleTable(PRTL_ATOM_TABLE AtomTable)
715 {
716 if (AtomTable->HandleTable)
717 {
718 RtlDestroyHandleTable((PRTL_HANDLE_TABLE)AtomTable->HandleTable);
719 RtlFreeHeap(RtlGetProcessHeap(),
720 0,
721 AtomTable->HandleTable);
722 AtomTable->HandleTable = NULL;
723 }
724 }
725
726 /* EOF */