1 /* COPYRIGHT: See COPYING in the top level directory
2 * PROJECT: ReactOS system libraries
4 * PURPOSE: Atom managment
5 * PROGRAMMER: Thomas Weidenmueller
8 /* INCLUDES *****************************************************************/
15 /* PROTOTYPES ****************************************************************/
17 extern NTSTATUS
RtlpInitAtomTableLock(PRTL_ATOM_TABLE AtomTable
);
18 extern VOID
RtlpDestroyAtomTableLock(PRTL_ATOM_TABLE AtomTable
);
19 extern BOOLEAN
RtlpLockAtomTable(PRTL_ATOM_TABLE AtomTable
);
20 extern VOID
RtlpUnlockAtomTable(PRTL_ATOM_TABLE AtomTable
);
22 extern BOOLEAN
RtlpCreateAtomHandleTable(PRTL_ATOM_TABLE AtomTable
);
23 extern VOID
RtlpDestroyAtomHandleTable(PRTL_ATOM_TABLE AtomTable
);
25 extern PRTL_ATOM_TABLE
RtlpAllocAtomTable(ULONG Size
);
26 extern VOID
RtlpFreeAtomTable(PRTL_ATOM_TABLE AtomTable
);
27 extern PRTL_ATOM_TABLE_ENTRY
RtlpAllocAtomTableEntry(ULONG Size
);
28 extern VOID
RtlpFreeAtomTableEntry(PRTL_ATOM_TABLE_ENTRY Entry
);
30 extern BOOLEAN
RtlpCreateAtomHandle(PRTL_ATOM_TABLE AtomTable
, PRTL_ATOM_TABLE_ENTRY Entry
);
31 extern VOID
RtlpFreeAtomHandle(PRTL_ATOM_TABLE AtomTable
, PRTL_ATOM_TABLE_ENTRY Entry
);
32 extern PRTL_ATOM_TABLE_ENTRY
RtlpGetAtomEntry(PRTL_ATOM_TABLE AtomTable
, ULONG Index
);
34 /* FUNCTIONS *****************************************************************/
36 static PRTL_ATOM_TABLE_ENTRY
37 RtlpHashAtomName(IN PRTL_ATOM_TABLE AtomTable
,
39 OUT PRTL_ATOM_TABLE_ENTRY
**HashLink
)
44 RtlInitUnicodeString(&Name
,
47 if (Name
.Length
!= 0 &&
48 NT_SUCCESS(RtlHashUnicodeString(&Name
,
50 HASH_STRING_ALGORITHM_X65599
,
53 PRTL_ATOM_TABLE_ENTRY Current
;
54 PRTL_ATOM_TABLE_ENTRY
*Link
;
56 Link
= &AtomTable
->Buckets
[Hash
% AtomTable
->NumberOfBuckets
];
58 /* search for an existing entry */
60 while (Current
!= NULL
)
62 if (Current
->NameLength
== Name
.Length
/ sizeof(WCHAR
) &&
63 !_wcsicmp(Current
->Name
, Name
.Buffer
))
68 Link
= &Current
->HashLink
;
69 Current
= Current
->HashLink
;
72 /* no matching atom found, return the hash link */
82 RtlpCheckIntegerAtom(PWSTR AtomName
,
85 UNICODE_STRING AtomString
;
90 DPRINT("RtlpCheckIntegerAtom(AtomName '%S' AtomValue %p)\n",
93 if (!((ULONG
)AtomName
& 0xFFFF0000))
95 LoValue
= (USHORT
)((ULONG
)AtomName
& 0xFFFF);
100 if (AtomValue
!= NULL
)
101 *AtomValue
= LoValue
;
106 if (*AtomName
!= L
'#')
113 if ((*p
< L
'0') || (*p
> L
'9'))
120 RtlInitUnicodeString(&AtomString
,
123 DPRINT("AtomString: %wZ\n", &AtomString
);
125 RtlUnicodeStringToInteger(&AtomString
,10, &LongValue
);
127 DPRINT("LongValue: %lu\n", LongValue
);
129 *AtomValue
= (USHORT
)(LongValue
& 0x0000FFFF);
139 RtlCreateAtomTable(IN ULONG TableSize
,
140 IN OUT PRTL_ATOM_TABLE
*AtomTable
)
142 PRTL_ATOM_TABLE Table
;
145 DPRINT("RtlCreateAtomTable(TableSize %lu AtomTable %p)\n",
146 TableSize
, AtomTable
);
148 if (*AtomTable
!= NULL
)
150 return STATUS_SUCCESS
;
153 /* allocate atom table */
154 Table
= RtlpAllocAtomTable(((TableSize
- 1) * sizeof(PRTL_ATOM_TABLE_ENTRY
)) +
155 sizeof(RTL_ATOM_TABLE
));
158 return STATUS_NO_MEMORY
;
161 /* initialize atom table */
162 Table
->NumberOfBuckets
= TableSize
;
164 Status
= RtlpInitAtomTableLock(Table
);
165 if (!NT_SUCCESS(Status
))
167 RtlpFreeAtomTable(Table
);
171 if (!RtlpCreateAtomHandleTable(Table
))
173 RtlpDestroyAtomTableLock(Table
);
174 RtlpFreeAtomTable(Table
);
175 return STATUS_NO_MEMORY
;
179 return STATUS_SUCCESS
;
187 RtlDestroyAtomTable(IN PRTL_ATOM_TABLE AtomTable
)
189 PRTL_ATOM_TABLE_ENTRY
*CurrentBucket
, *LastBucket
;
190 PRTL_ATOM_TABLE_ENTRY CurrentEntry
, NextEntry
;
192 DPRINT("RtlDestroyAtomTable (AtomTable %p)\n", AtomTable
);
194 if (!RtlpLockAtomTable(AtomTable
))
196 return (STATUS_INVALID_PARAMETER
);
199 /* delete all atoms */
200 LastBucket
= AtomTable
->Buckets
+ AtomTable
->NumberOfBuckets
;
201 for (CurrentBucket
= AtomTable
->Buckets
;
202 CurrentBucket
!= LastBucket
;
205 NextEntry
= *CurrentBucket
;
206 *CurrentBucket
= NULL
;
208 while (NextEntry
!= NULL
)
210 CurrentEntry
= NextEntry
;
211 NextEntry
= NextEntry
->HashLink
;
213 /* no need to delete the atom handle, the handles will all be freed
214 up when destroying the atom handle table! */
216 RtlpFreeAtomTableEntry(CurrentEntry
);
220 RtlpDestroyAtomHandleTable(AtomTable
);
222 RtlpUnlockAtomTable(AtomTable
);
224 RtlpDestroyAtomTableLock(AtomTable
);
226 RtlpFreeAtomTable(AtomTable
);
228 return STATUS_SUCCESS
;
236 RtlEmptyAtomTable(PRTL_ATOM_TABLE AtomTable
,
237 BOOLEAN DeletePinned
)
239 PRTL_ATOM_TABLE_ENTRY
*CurrentBucket
, *LastBucket
;
240 PRTL_ATOM_TABLE_ENTRY CurrentEntry
, NextEntry
, *PtrEntry
;
242 DPRINT("RtlEmptyAtomTable (AtomTable %p DeletePinned %x)\n",
243 AtomTable
, DeletePinned
);
245 if (RtlpLockAtomTable(AtomTable
) == FALSE
)
247 return (STATUS_INVALID_PARAMETER
);
250 /* delete all atoms */
251 LastBucket
= AtomTable
->Buckets
+ AtomTable
->NumberOfBuckets
;
252 for (CurrentBucket
= AtomTable
->Buckets
;
253 CurrentBucket
!= LastBucket
;
256 NextEntry
= *CurrentBucket
;
257 PtrEntry
= CurrentBucket
;
259 while (NextEntry
!= NULL
)
261 CurrentEntry
= NextEntry
;
262 NextEntry
= NextEntry
->HashLink
;
264 if (DeletePinned
|| !(CurrentEntry
->Flags
& RTL_ATOM_IS_PINNED
))
266 *PtrEntry
= NextEntry
;
268 RtlpFreeAtomHandle(AtomTable
,
271 RtlpFreeAtomTableEntry(CurrentEntry
);
275 PtrEntry
= &CurrentEntry
->HashLink
;
280 RtlpUnlockAtomTable(AtomTable
);
282 return STATUS_SUCCESS
;
290 RtlAddAtomToAtomTable(IN PRTL_ATOM_TABLE AtomTable
,
295 PRTL_ATOM_TABLE_ENTRY
*HashLink
;
296 PRTL_ATOM_TABLE_ENTRY Entry
= NULL
;
297 NTSTATUS Status
= STATUS_SUCCESS
;
299 DPRINT("RtlAddAtomToAtomTable (AtomTable %p AtomName %S Atom %p)\n",
300 AtomTable
, AtomName
, Atom
);
302 if (RtlpCheckIntegerAtom (AtomName
, &AtomValue
))
305 if (AtomValue
>= 0xC000)
307 Status
= STATUS_INVALID_PARAMETER
;
309 else if (Atom
!= NULL
)
311 *Atom
= (RTL_ATOM
)AtomValue
;
317 RtlpLockAtomTable(AtomTable
);
319 /* string atom, hash it and try to find an existing atom with the same name */
320 Entry
= RtlpHashAtomName(AtomTable
,
326 /* found another atom, increment the reference counter unless it's pinned */
328 if (!(Entry
->Flags
& RTL_ATOM_IS_PINNED
))
330 if (++Entry
->ReferenceCount
== 0)
332 /* FIXME - references overflowed, pin the atom? */
333 Entry
->Flags
|= RTL_ATOM_IS_PINNED
;
339 *Atom
= (RTL_ATOM
)Entry
->Atom
;
344 /* couldn't find an existing atom, HashLink now points to either the
345 HashLink pointer of the previous atom or to the bucket so we can
346 simply add it to the list */
347 if (HashLink
!= NULL
)
349 ULONG AtomNameLen
= wcslen(AtomName
);
351 Entry
= RtlpAllocAtomTableEntry(sizeof(RTL_ATOM_TABLE_ENTRY
) -
352 sizeof(Entry
->Name
) +
353 (AtomNameLen
+ 1) * sizeof(WCHAR
));
356 Entry
->HashLink
= NULL
;
357 Entry
->ReferenceCount
= 1;
360 Entry
->NameLength
= AtomNameLen
;
361 RtlCopyMemory(Entry
->Name
,
363 (AtomNameLen
+ 1) * sizeof(WCHAR
));
365 if (RtlpCreateAtomHandle(AtomTable
,
368 /* append the atom to the list */
373 *Atom
= (RTL_ATOM
)Entry
->Atom
;
378 RtlpFreeAtomTableEntry(Entry
);
379 Status
= STATUS_NO_MEMORY
;
384 Status
= STATUS_NO_MEMORY
;
389 /* The caller supplied an empty atom name! */
390 Status
= STATUS_OBJECT_NAME_INVALID
;
394 RtlpUnlockAtomTable(AtomTable
);
404 RtlDeleteAtomFromAtomTable(IN PRTL_ATOM_TABLE AtomTable
,
407 PRTL_ATOM_TABLE_ENTRY Entry
;
408 NTSTATUS Status
= STATUS_SUCCESS
;
410 DPRINT("RtlDeleteAtomFromAtomTable (AtomTable %p Atom %x)\n",
415 RtlpLockAtomTable(AtomTable
);
417 Entry
= RtlpGetAtomEntry(AtomTable
,
418 (ULONG
)((USHORT
)Atom
- 0xC000));
420 if (Entry
!= NULL
&& Entry
->Atom
== (USHORT
)Atom
)
422 if (!(Entry
->Flags
& RTL_ATOM_IS_PINNED
))
424 if (--Entry
->ReferenceCount
== 0)
426 PRTL_ATOM_TABLE_ENTRY
*HashLink
;
428 /* it's time to delete the atom. we need to unlink it from
429 the list. The easiest way is to take the atom name and
430 hash it again, this way we get the pointer to either
431 the hash bucket or the previous atom that links to the
432 one we want to delete. This way we can easily bypass
434 if (RtlpHashAtomName(AtomTable
,
438 /* bypass this atom */
439 *HashLink
= Entry
->HashLink
;
441 RtlpFreeAtomHandle(AtomTable
,
444 RtlpFreeAtomTableEntry(Entry
);
448 /* WTF?! This should never happen!!! */
455 /* tried to delete a pinned atom, do nothing and return
456 STATUS_WAS_LOCKED, which is NOT a failure code! */
457 Status
= STATUS_WAS_LOCKED
;
462 Status
= STATUS_INVALID_HANDLE
;
465 RtlpUnlockAtomTable(AtomTable
);
476 RtlLookupAtomInAtomTable(IN PRTL_ATOM_TABLE AtomTable
,
480 PRTL_ATOM_TABLE_ENTRY Entry
, *HashLink
;
482 RTL_ATOM FoundAtom
= 0;
483 NTSTATUS Status
= STATUS_SUCCESS
;
485 DPRINT("RtlLookupAtomInAtomTable (AtomTable %p AtomName %S Atom %p)\n",
486 AtomTable
, AtomName
, Atom
);
488 if (RtlpCheckIntegerAtom (AtomName
, &AtomValue
))
491 if (AtomValue
>= 0xC000)
493 Status
= STATUS_INVALID_PARAMETER
;
495 else if (Atom
!= NULL
)
497 *Atom
= (RTL_ATOM
)AtomValue
;
503 RtlpLockAtomTable(AtomTable
);
505 Status
= STATUS_OBJECT_NAME_NOT_FOUND
;
508 Entry
= RtlpHashAtomName(AtomTable
,
514 Status
= STATUS_SUCCESS
;
515 FoundAtom
= (RTL_ATOM
)Entry
->Atom
;
518 RtlpUnlockAtomTable(AtomTable
);
520 if (NT_SUCCESS(Status
) && Atom
!= NULL
)
533 RtlPinAtomInAtomTable(IN PRTL_ATOM_TABLE AtomTable
,
536 NTSTATUS Status
= STATUS_SUCCESS
;
538 DPRINT("RtlPinAtomInAtomTable (AtomTable %p Atom %x)\n",
543 PRTL_ATOM_TABLE_ENTRY Entry
;
545 RtlpLockAtomTable(AtomTable
);
547 Entry
= RtlpGetAtomEntry(AtomTable
,
548 (ULONG
)((USHORT
)Atom
- 0xC000));
550 if (Entry
!= NULL
&& Entry
->Atom
== (USHORT
)Atom
)
552 Entry
->Flags
|= RTL_ATOM_IS_PINNED
;
556 Status
= STATUS_INVALID_HANDLE
;
559 RtlpUnlockAtomTable(AtomTable
);
570 RtlQueryAtomInAtomTable(PRTL_ATOM_TABLE AtomTable
,
578 PRTL_ATOM_TABLE_ENTRY Entry
;
579 NTSTATUS Status
= STATUS_SUCCESS
;
583 if (RefCount
!= NULL
)
588 if (PinCount
!= NULL
)
593 if ((AtomName
!= NULL
) && (NameLength
!= NULL
) && (NameLength
> 0))
595 WCHAR NameString
[12];
597 Length
= swprintf(NameString
, L
"#%lu", (ULONG
)Atom
) * sizeof(WCHAR
);
599 if (*NameLength
< Length
+ sizeof(WCHAR
))
601 *NameLength
= Length
;
602 Status
= STATUS_BUFFER_TOO_SMALL
;
606 RtlCopyMemory(AtomName
,
609 AtomName
[Length
/ sizeof(WCHAR
)] = L
'\0';
610 *NameLength
= Length
;
613 else if (NameLength
!= NULL
)
615 *NameLength
= (Entry
->NameLength
+ 1) * sizeof(WCHAR
);
621 RtlpLockAtomTable(AtomTable
);
623 Entry
= RtlpGetAtomEntry(AtomTable
,
624 (ULONG
)((USHORT
)Atom
- 0xC000));
626 if (Entry
!= NULL
&& Entry
->Atom
== (USHORT
)Atom
)
628 DPRINT("Atom name: %wZ\n", &Entry
->Name
);
630 if (RefCount
!= NULL
)
632 *RefCount
= Entry
->ReferenceCount
;
635 if (PinCount
!= NULL
)
637 *PinCount
= ((Entry
->Flags
& RTL_ATOM_IS_PINNED
) != 0);
640 if ((AtomName
!= NULL
) && (NameLength
!= NULL
))
642 Length
= Entry
->NameLength
* sizeof(WCHAR
);
644 if (*NameLength
< Length
+ sizeof(WCHAR
))
646 *NameLength
= Length
;
647 Status
= STATUS_BUFFER_TOO_SMALL
;
651 RtlCopyMemory(AtomName
,
654 AtomName
[Length
/ sizeof(WCHAR
)] = L
'\0';
655 *NameLength
= Length
;
658 else if (NameLength
!= NULL
)
660 *NameLength
= (Entry
->NameLength
+ 1) * sizeof(WCHAR
);
665 Status
= STATUS_INVALID_HANDLE
;
668 RtlpUnlockAtomTable(AtomTable
);
675 * @private - only used by NtQueryInformationAtom
678 RtlQueryAtomListInAtomTable(IN PRTL_ATOM_TABLE AtomTable
,
679 IN ULONG MaxAtomCount
,
680 OUT ULONG
*AtomCount
,
681 OUT RTL_ATOM
*AtomList
)
683 PRTL_ATOM_TABLE_ENTRY
*CurrentBucket
, *LastBucket
;
684 PRTL_ATOM_TABLE_ENTRY CurrentEntry
;
686 NTSTATUS Status
= STATUS_SUCCESS
;
688 RtlpLockAtomTable(AtomTable
);
690 LastBucket
= AtomTable
->Buckets
+ AtomTable
->NumberOfBuckets
;
691 for (CurrentBucket
= AtomTable
->Buckets
;
692 CurrentBucket
!= LastBucket
;
695 CurrentEntry
= *CurrentBucket
;
697 while (CurrentEntry
!= NULL
)
699 if (MaxAtomCount
> 0)
701 *(AtomList
++) = (RTL_ATOM
)CurrentEntry
->Atom
;
706 /* buffer too small, but don't bail. we need to determine the
707 total number of atoms in the table! */
708 Status
= STATUS_INFO_LENGTH_MISMATCH
;
712 CurrentEntry
= CurrentEntry
->HashLink
;
718 RtlpUnlockAtomTable(AtomTable
);