3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS kernel
6 * PURPOSE: Atom managment
12 /* INCLUDES *****************************************************************/
19 /* PROTOTYPES ****************************************************************/
21 extern NTSTATUS
RtlpInitAtomTableLock(PRTL_ATOM_TABLE AtomTable
);
22 extern VOID
RtlpDestroyAtomTableLock(PRTL_ATOM_TABLE AtomTable
);
23 extern BOOLEAN
RtlpLockAtomTable(PRTL_ATOM_TABLE AtomTable
);
24 extern VOID
RtlpUnlockAtomTable(PRTL_ATOM_TABLE AtomTable
);
26 extern BOOLEAN
RtlpCreateAtomHandleTable(PRTL_ATOM_TABLE AtomTable
);
27 extern VOID
RtlpDestroyAtomHandleTable(PRTL_ATOM_TABLE AtomTable
);
29 extern PRTL_ATOM_TABLE
RtlpAllocAtomTable(ULONG Size
);
30 extern VOID
RtlpFreeAtomTable(PRTL_ATOM_TABLE AtomTable
);
31 extern PRTL_ATOM_TABLE_ENTRY
RtlpAllocAtomTableEntry(ULONG Size
);
32 extern VOID
RtlpFreeAtomTableEntry(PRTL_ATOM_TABLE_ENTRY Entry
);
34 extern BOOLEAN
RtlpCreateAtomHandle(PRTL_ATOM_TABLE AtomTable
, PRTL_ATOM_TABLE_ENTRY Entry
);
35 extern VOID
RtlpFreeAtomHandle(PRTL_ATOM_TABLE AtomTable
, PRTL_ATOM_TABLE_ENTRY Entry
);
36 extern PRTL_ATOM_TABLE_ENTRY
RtlpGetAtomEntry(PRTL_ATOM_TABLE AtomTable
, ULONG Index
);
38 /* FUNCTIONS *****************************************************************/
40 static PRTL_ATOM_TABLE_ENTRY
41 RtlpHashAtomName(IN PRTL_ATOM_TABLE AtomTable
,
43 OUT PRTL_ATOM_TABLE_ENTRY
**HashLink
)
48 RtlInitUnicodeString(&Name
,
51 if (Name
.Length
!= 0 &&
52 NT_SUCCESS(RtlHashUnicodeString(&Name
,
54 HASH_STRING_ALGORITHM_X65599
,
57 PRTL_ATOM_TABLE_ENTRY Current
;
58 PRTL_ATOM_TABLE_ENTRY
*Link
;
60 Link
= &AtomTable
->Buckets
[Hash
% AtomTable
->NumberOfBuckets
];
62 /* search for an existing entry */
64 while (Current
!= NULL
)
66 if (Current
->NameLength
== Name
.Length
/ sizeof(WCHAR
) &&
67 !_wcsicmp(Current
->Name
, Name
.Buffer
))
72 Link
= &Current
->HashLink
;
73 Current
= Current
->HashLink
;
76 /* no matching atom found, return the hash link */
86 RtlpCheckIntegerAtom(PWSTR AtomName
,
89 UNICODE_STRING AtomString
;
94 DPRINT("RtlpCheckIntegerAtom(AtomName '%S' AtomValue %p)\n",
97 if (!((ULONG
)AtomName
& 0xFFFF0000))
99 LoValue
= (USHORT
)((ULONG
)AtomName
& 0xFFFF);
104 if (AtomValue
!= NULL
)
105 *AtomValue
= LoValue
;
110 if (*AtomName
!= L
'#')
117 if ((*p
< L
'0') || (*p
> L
'9'))
124 RtlInitUnicodeString(&AtomString
,
127 DPRINT("AtomString: %wZ\n", &AtomString
);
129 RtlUnicodeStringToInteger(&AtomString
,10, &LongValue
);
131 DPRINT("LongValue: %lu\n", LongValue
);
133 *AtomValue
= (USHORT
)(LongValue
& 0x0000FFFF);
143 RtlCreateAtomTable(IN ULONG TableSize
,
144 IN OUT PRTL_ATOM_TABLE
*AtomTable
)
146 PRTL_ATOM_TABLE Table
;
149 DPRINT("RtlCreateAtomTable(TableSize %lu AtomTable %p)\n",
150 TableSize
, AtomTable
);
152 if (*AtomTable
!= NULL
)
154 return STATUS_SUCCESS
;
157 /* allocate atom table */
158 Table
= RtlpAllocAtomTable(((TableSize
- 1) * sizeof(PRTL_ATOM_TABLE_ENTRY
)) +
159 sizeof(RTL_ATOM_TABLE
));
162 return STATUS_NO_MEMORY
;
165 /* initialize atom table */
166 Table
->NumberOfBuckets
= TableSize
;
168 Status
= RtlpInitAtomTableLock(Table
);
169 if (!NT_SUCCESS(Status
))
171 RtlpFreeAtomTable(Table
);
175 if (!RtlpCreateAtomHandleTable(Table
))
177 RtlpDestroyAtomTableLock(Table
);
178 RtlpFreeAtomTable(Table
);
179 return STATUS_NO_MEMORY
;
183 return STATUS_SUCCESS
;
191 RtlDestroyAtomTable(IN PRTL_ATOM_TABLE AtomTable
)
193 PRTL_ATOM_TABLE_ENTRY
*CurrentBucket
, *LastBucket
;
194 PRTL_ATOM_TABLE_ENTRY CurrentEntry
, NextEntry
;
196 DPRINT("RtlDestroyAtomTable (AtomTable %p)\n", AtomTable
);
198 if (!RtlpLockAtomTable(AtomTable
))
200 return (STATUS_INVALID_PARAMETER
);
203 /* delete all atoms */
204 LastBucket
= AtomTable
->Buckets
+ AtomTable
->NumberOfBuckets
;
205 for (CurrentBucket
= AtomTable
->Buckets
;
206 CurrentBucket
!= LastBucket
;
209 NextEntry
= *CurrentBucket
;
210 *CurrentBucket
= NULL
;
212 while (NextEntry
!= NULL
)
214 CurrentEntry
= NextEntry
;
215 NextEntry
= NextEntry
->HashLink
;
217 /* no need to delete the atom handle, the handles will all be freed
218 up when destroying the atom handle table! */
220 RtlpFreeAtomTableEntry(CurrentEntry
);
224 RtlpDestroyAtomHandleTable(AtomTable
);
226 RtlpUnlockAtomTable(AtomTable
);
228 RtlpDestroyAtomTableLock(AtomTable
);
230 RtlpFreeAtomTable(AtomTable
);
232 return STATUS_SUCCESS
;
240 RtlEmptyAtomTable(PRTL_ATOM_TABLE AtomTable
,
241 BOOLEAN DeletePinned
)
243 PRTL_ATOM_TABLE_ENTRY
*CurrentBucket
, *LastBucket
;
244 PRTL_ATOM_TABLE_ENTRY CurrentEntry
, NextEntry
, *PtrEntry
;
246 DPRINT("RtlEmptyAtomTable (AtomTable %p DeletePinned %x)\n",
247 AtomTable
, DeletePinned
);
249 if (RtlpLockAtomTable(AtomTable
) == FALSE
)
251 return (STATUS_INVALID_PARAMETER
);
254 /* delete all atoms */
255 LastBucket
= AtomTable
->Buckets
+ AtomTable
->NumberOfBuckets
;
256 for (CurrentBucket
= AtomTable
->Buckets
;
257 CurrentBucket
!= LastBucket
;
260 NextEntry
= *CurrentBucket
;
261 PtrEntry
= CurrentBucket
;
263 while (NextEntry
!= NULL
)
265 CurrentEntry
= NextEntry
;
266 NextEntry
= NextEntry
->HashLink
;
268 if (DeletePinned
|| !(CurrentEntry
->Flags
& RTL_ATOM_IS_PINNED
))
270 *PtrEntry
= NextEntry
;
272 RtlpFreeAtomHandle(AtomTable
,
275 RtlpFreeAtomTableEntry(CurrentEntry
);
279 PtrEntry
= &CurrentEntry
->HashLink
;
284 RtlpUnlockAtomTable(AtomTable
);
286 return STATUS_SUCCESS
;
294 RtlAddAtomToAtomTable(IN PRTL_ATOM_TABLE AtomTable
,
299 PRTL_ATOM_TABLE_ENTRY
*HashLink
;
300 PRTL_ATOM_TABLE_ENTRY Entry
= NULL
;
301 NTSTATUS Status
= STATUS_SUCCESS
;
303 DPRINT("RtlAddAtomToAtomTable (AtomTable %p AtomName %S Atom %p)\n",
304 AtomTable
, AtomName
, Atom
);
306 if (RtlpCheckIntegerAtom (AtomName
, &AtomValue
))
309 if (AtomValue
>= 0xC000)
311 Status
= STATUS_INVALID_PARAMETER
;
313 else if (Atom
!= NULL
)
315 *Atom
= (RTL_ATOM
)AtomValue
;
321 RtlpLockAtomTable(AtomTable
);
323 /* string atom, hash it and try to find an existing atom with the same name */
324 Entry
= RtlpHashAtomName(AtomTable
,
330 /* found another atom, increment the reference counter unless it's pinned */
332 if (!(Entry
->Flags
& RTL_ATOM_IS_PINNED
))
334 if (++Entry
->ReferenceCount
== 0)
336 /* FIXME - references overflowed, pin the atom? */
337 Entry
->Flags
|= RTL_ATOM_IS_PINNED
;
343 *Atom
= (RTL_ATOM
)Entry
->Atom
;
348 /* couldn't find an existing atom, HashLink now points to either the
349 HashLink pointer of the previous atom or to the bucket so we can
350 simply add it to the list */
351 if (HashLink
!= NULL
)
353 ULONG AtomNameLen
= wcslen(AtomName
);
355 Entry
= RtlpAllocAtomTableEntry(sizeof(RTL_ATOM_TABLE_ENTRY
) -
356 sizeof(Entry
->Name
) +
357 (AtomNameLen
+ 1) * sizeof(WCHAR
));
360 Entry
->HashLink
= NULL
;
361 Entry
->ReferenceCount
= 1;
364 Entry
->NameLength
= AtomNameLen
;
365 RtlCopyMemory(Entry
->Name
,
367 (AtomNameLen
+ 1) * sizeof(WCHAR
));
369 if (RtlpCreateAtomHandle(AtomTable
,
372 /* append the atom to the list */
377 *Atom
= (RTL_ATOM
)Entry
->Atom
;
382 RtlpFreeAtomTableEntry(Entry
);
383 Status
= STATUS_NO_MEMORY
;
388 Status
= STATUS_NO_MEMORY
;
393 /* The caller supplied an empty atom name! */
394 Status
= STATUS_OBJECT_NAME_INVALID
;
398 RtlpUnlockAtomTable(AtomTable
);
408 RtlDeleteAtomFromAtomTable(IN PRTL_ATOM_TABLE AtomTable
,
411 PRTL_ATOM_TABLE_ENTRY Entry
;
412 NTSTATUS Status
= STATUS_SUCCESS
;
414 DPRINT("RtlDeleteAtomFromAtomTable (AtomTable %p Atom %x)\n",
419 RtlpLockAtomTable(AtomTable
);
421 Entry
= RtlpGetAtomEntry(AtomTable
,
422 (ULONG
)((USHORT
)Atom
- 0xC000));
424 if (Entry
!= NULL
&& Entry
->Atom
== (USHORT
)Atom
)
426 if (!(Entry
->Flags
& RTL_ATOM_IS_PINNED
))
428 if (--Entry
->ReferenceCount
== 0)
430 PRTL_ATOM_TABLE_ENTRY
*HashLink
;
432 /* it's time to delete the atom. we need to unlink it from
433 the list. The easiest way is to take the atom name and
434 hash it again, this way we get the pointer to either
435 the hash bucket or the previous atom that links to the
436 one we want to delete. This way we can easily bypass
438 if (RtlpHashAtomName(AtomTable
,
442 /* bypass this atom */
443 *HashLink
= Entry
->HashLink
;
445 RtlpFreeAtomHandle(AtomTable
,
448 RtlpFreeAtomTableEntry(Entry
);
452 /* WTF?! This should never happen!!! */
459 /* tried to delete a pinned atom, do nothing and return
460 STATUS_WAS_LOCKED, which is NOT a failure code! */
461 Status
= STATUS_WAS_LOCKED
;
466 Status
= STATUS_INVALID_HANDLE
;
469 RtlpUnlockAtomTable(AtomTable
);
480 RtlLookupAtomInAtomTable(IN PRTL_ATOM_TABLE AtomTable
,
484 PRTL_ATOM_TABLE_ENTRY Entry
, *HashLink
;
486 RTL_ATOM FoundAtom
= 0;
487 NTSTATUS Status
= STATUS_SUCCESS
;
489 DPRINT("RtlLookupAtomInAtomTable (AtomTable %p AtomName %S Atom %p)\n",
490 AtomTable
, AtomName
, Atom
);
492 if (RtlpCheckIntegerAtom (AtomName
, &AtomValue
))
495 if (AtomValue
>= 0xC000)
497 Status
= STATUS_INVALID_PARAMETER
;
499 else if (Atom
!= NULL
)
501 *Atom
= (RTL_ATOM
)AtomValue
;
507 RtlpLockAtomTable(AtomTable
);
509 Status
= STATUS_OBJECT_NAME_NOT_FOUND
;
512 Entry
= RtlpHashAtomName(AtomTable
,
518 Status
= STATUS_SUCCESS
;
519 FoundAtom
= (RTL_ATOM
)Entry
->Atom
;
522 RtlpUnlockAtomTable(AtomTable
);
524 if (NT_SUCCESS(Status
) && Atom
!= NULL
)
537 RtlPinAtomInAtomTable(IN PRTL_ATOM_TABLE AtomTable
,
540 NTSTATUS Status
= STATUS_SUCCESS
;
542 DPRINT("RtlPinAtomInAtomTable (AtomTable %p Atom %x)\n",
547 PRTL_ATOM_TABLE_ENTRY Entry
;
549 RtlpLockAtomTable(AtomTable
);
551 Entry
= RtlpGetAtomEntry(AtomTable
,
552 (ULONG
)((USHORT
)Atom
- 0xC000));
554 if (Entry
!= NULL
&& Entry
->Atom
== (USHORT
)Atom
)
556 Entry
->Flags
|= RTL_ATOM_IS_PINNED
;
560 Status
= STATUS_INVALID_HANDLE
;
563 RtlpUnlockAtomTable(AtomTable
);
574 RtlQueryAtomInAtomTable(PRTL_ATOM_TABLE AtomTable
,
582 PRTL_ATOM_TABLE_ENTRY Entry
;
583 NTSTATUS Status
= STATUS_SUCCESS
;
587 if (RefCount
!= NULL
)
592 if (PinCount
!= NULL
)
597 if ((AtomName
!= NULL
) && (NameLength
!= NULL
) && (NameLength
> 0))
599 WCHAR NameString
[12];
601 Length
= swprintf(NameString
, L
"#%lu", (ULONG
)Atom
) * sizeof(WCHAR
);
603 if (*NameLength
< Length
+ sizeof(WCHAR
))
605 /* prevent underflow! */
606 if (*NameLength
>= sizeof(WCHAR
))
608 Length
= *NameLength
- sizeof(WCHAR
);
613 Status
= STATUS_BUFFER_TOO_SMALL
;
619 RtlCopyMemory(AtomName
,
622 AtomName
[Length
/ sizeof(WCHAR
)] = L
'\0';
623 *NameLength
= Length
;
630 RtlpLockAtomTable(AtomTable
);
632 Entry
= RtlpGetAtomEntry(AtomTable
,
633 (ULONG
)((USHORT
)Atom
- 0xC000));
635 if (Entry
!= NULL
&& Entry
->Atom
== (USHORT
)Atom
)
637 DPRINT("Atom name: %wZ\n", &Entry
->Name
);
639 if (RefCount
!= NULL
)
641 *RefCount
= Entry
->ReferenceCount
;
644 if (PinCount
!= NULL
)
646 *PinCount
= ((Entry
->Flags
& RTL_ATOM_IS_PINNED
) != 0);
649 if ((AtomName
!= NULL
) && (NameLength
!= NULL
))
651 Length
= Entry
->NameLength
* sizeof(WCHAR
);
653 if (*NameLength
< Length
+ sizeof(WCHAR
))
655 /* prevent underflow! */
656 if (*NameLength
>= sizeof(WCHAR
))
658 Length
= *NameLength
- sizeof(WCHAR
);
663 Status
= STATUS_BUFFER_TOO_SMALL
;
669 RtlCopyMemory(AtomName
,
672 AtomName
[Length
/ sizeof(WCHAR
)] = L
'\0';
673 *NameLength
= Length
;
679 Status
= STATUS_INVALID_HANDLE
;
682 RtlpUnlockAtomTable(AtomTable
);
689 * @private - only used by NtQueryInformationAtom
692 RtlQueryAtomListInAtomTable(IN PRTL_ATOM_TABLE AtomTable
,
693 IN ULONG MaxAtomCount
,
694 OUT ULONG
*AtomCount
,
695 OUT RTL_ATOM
*AtomList
)
697 PRTL_ATOM_TABLE_ENTRY
*CurrentBucket
, *LastBucket
;
698 PRTL_ATOM_TABLE_ENTRY CurrentEntry
;
700 NTSTATUS Status
= STATUS_SUCCESS
;
702 RtlpLockAtomTable(AtomTable
);
704 LastBucket
= AtomTable
->Buckets
+ AtomTable
->NumberOfBuckets
;
705 for (CurrentBucket
= AtomTable
->Buckets
;
706 CurrentBucket
!= LastBucket
;
709 CurrentEntry
= *CurrentBucket
;
711 while (CurrentEntry
!= NULL
)
713 if (MaxAtomCount
> 0)
715 *(AtomList
++) = (RTL_ATOM
)CurrentEntry
->Atom
;
720 /* buffer too small, but don't bail. we need to determine the
721 total number of atoms in the table! */
722 Status
= STATUS_INFO_LENGTH_MISMATCH
;
726 CurrentEntry
= CurrentEntry
->HashLink
;
732 RtlpUnlockAtomTable(AtomTable
);