reactos/reactos/lib/ntdll/rtl/atom.c
2003-07-11 13:50:23 +00:00

724 lines
15 KiB
C

/* $Id: atom.c,v 1.5 2003/07/11 13:50:23 royce Exp $
*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS kernel
* FILE: lib/ntdll/rtl/atom.c
* PURPOSE: Atom managment
* PROGRAMMER: Nobody
* UPDATE HISTORY:
* Created 22/05/98
*/
/* INCLUDES *****************************************************************/
#include <ddk/ntddk.h>
#include <ntdll/rtl.h>
#include <ntos/heap.h>
#define NDEBUG
#include <ntdll/ntdll.h>
/* LOCAL TYPES ***************************************************************/
typedef struct _RTL_ATOM_ENTRY
{
LIST_ENTRY List;
UNICODE_STRING Name;
ULONG RefCount;
BOOLEAN Locked;
ULONG Index;
PRTL_HANDLE Handle;
} RTL_ATOM_ENTRY, *PRTL_ATOM_ENTRY;
typedef struct _RTL_ATOM_HANDLE
{
RTL_HANDLE Handle;
PRTL_ATOM_ENTRY Entry;
} RTL_ATOM_HANDLE, *PRTL_ATOM_HANDLE;
/* PROTOTYPES ****************************************************************/
static ULONG RtlpHashAtomName(ULONG TableSize, PWSTR AtomName);
static BOOLEAN RtlpCheckIntegerAtom(PWSTR AtomName, PUSHORT AtomValue);
static NTSTATUS RtlpInitAtomTableLock(PRTL_ATOM_TABLE AtomTable);
static VOID RtlpDestroyAtomTableLock(PRTL_ATOM_TABLE AtomTable);
static BOOLEAN RtlpLockAtomTable(PRTL_ATOM_TABLE AtomTable);
static VOID RtlpUnlockAtomTable(PRTL_ATOM_TABLE AtomTable);
static BOOLEAN RtlpCreateAtomHandleTable(PRTL_ATOM_TABLE AtomTable);
static VOID RtlpDestroyAtomHandleTable(PRTL_ATOM_TABLE AtomTable);
/* FUNCTIONS *****************************************************************/
/*
* @implemented
*/
NTSTATUS STDCALL
RtlCreateAtomTable(ULONG TableSize,
PRTL_ATOM_TABLE *AtomTable)
{
PRTL_ATOM_TABLE Table;
ULONG i;
NTSTATUS Status;
DPRINT("RtlCreateAtomTable(TableSize %lu AtomTable %p)\n",
TableSize, AtomTable);
if (*AtomTable != NULL)
{
return STATUS_SUCCESS;
}
/* allocate atom table */
Table = RtlAllocateHeap(RtlGetProcessHeap(),
HEAP_ZERO_MEMORY,
TableSize * sizeof(LIST_ENTRY) +
sizeof(RTL_ATOM_TABLE));
if (Table == NULL)
{
return STATUS_NO_MEMORY;
}
/* initialize atom table */
Table->TableSize = TableSize;
for (i = 0; i < TableSize; i++)
{
InitializeListHead(&Table->Slot[i]);
}
Status = RtlpInitAtomTableLock(Table);
if (!NT_SUCCESS(Status))
{
RtlFreeHeap(RtlGetProcessHeap(),
0,
Table);
return Status;
}
if (RtlpCreateAtomHandleTable(Table) == FALSE)
{
RtlpDestroyAtomTableLock(Table);
RtlFreeHeap(RtlGetProcessHeap(),
0,
Table);
return STATUS_NO_MEMORY;
}
*AtomTable = Table;
return STATUS_SUCCESS;
}
/*
* @implemented
*/
NTSTATUS STDCALL
RtlDestroyAtomTable(IN PRTL_ATOM_TABLE AtomTable)
{
PLIST_ENTRY Current;
PRTL_ATOM_ENTRY AtomEntry;
ULONG i;
if (RtlpLockAtomTable(AtomTable) == FALSE)
{
return (STATUS_INVALID_PARAMETER);
}
/* delete all atoms */
for (i = 0; i < AtomTable->TableSize; i++)
{
Current = AtomTable->Slot[i].Flink;
while (Current != &AtomTable->Slot[i])
{
AtomEntry = (PRTL_ATOM_ENTRY)Current;
RtlFreeUnicodeString(&AtomEntry->Name);
RemoveEntryList(&AtomEntry->List);
RtlFreeHeap(RtlGetProcessHeap(),
0,
AtomEntry);
Current = AtomTable->Slot[i].Flink;
}
}
RtlpDestroyAtomHandleTable(AtomTable);
RtlpUnlockAtomTable(AtomTable);
RtlpDestroyAtomTableLock(AtomTable);
RtlFreeHeap(RtlGetProcessHeap(),
0,
AtomTable);
return STATUS_SUCCESS;
}
/*
* @implemented
*/
NTSTATUS STDCALL
RtlEmptyAtomTable(PRTL_ATOM_TABLE AtomTable,
BOOLEAN DeletePinned)
{
PLIST_ENTRY Current, Next;
PRTL_ATOM_ENTRY AtomEntry;
ULONG i;
DPRINT("RtlEmptyAtomTable (AtomTable %p DeletePinned %x)\n",
AtomTable, DeletePinned);
if (RtlpLockAtomTable(AtomTable) == FALSE)
{
return (STATUS_INVALID_PARAMETER);
}
/* delete all atoms */
for (i = 0; i < AtomTable->TableSize; i++)
{
Current = AtomTable->Slot[i].Flink;
while (Current != &AtomTable->Slot[i])
{
Next = Current->Flink;
AtomEntry = (PRTL_ATOM_ENTRY)Current;
if ((AtomEntry->Locked == FALSE) ||
((AtomEntry->Locked == TRUE) && (DeletePinned == TRUE)))
{
RtlFreeUnicodeString(&AtomEntry->Name);
RtlFreeHandle(AtomTable->HandleTable,
AtomEntry->Handle);
RemoveEntryList(&AtomEntry->List);
RtlFreeHeap(RtlGetProcessHeap(),
0,
AtomEntry);
}
Current = Next;
}
}
RtlpUnlockAtomTable(AtomTable);
return STATUS_SUCCESS;
}
/*
* @implemented
*/
NTSTATUS STDCALL
RtlAddAtomToAtomTable(IN PRTL_ATOM_TABLE AtomTable,
IN PWSTR AtomName,
OUT PRTL_ATOM Atom)
{
ULONG Hash;
PLIST_ENTRY Current;
PRTL_ATOM_ENTRY Entry;
USHORT AtomValue;
NTSTATUS Status;
PRTL_ATOM_HANDLE AtomHandle;
ULONG AtomIndex;
DPRINT("RtlAddAtomToAtomTable (AtomTable %p AtomName %S Atom %p)\n",
AtomTable, AtomName, Atom);
if (RtlpCheckIntegerAtom (AtomName, &AtomValue))
{
/* integer atom */
if (AtomValue >= 0xC000)
{
AtomValue = 0;
Status = STATUS_INVALID_PARAMETER;
}
else
{
Status = STATUS_SUCCESS;
}
if (Atom)
*Atom = (RTL_ATOM)AtomValue;
return Status;
}
RtlpLockAtomTable(AtomTable);
/* string atom */
Hash = RtlpHashAtomName(AtomTable->TableSize, AtomName);
/* search for existing atom */
Current = AtomTable->Slot[Hash].Flink;
while (Current != &AtomTable->Slot[Hash])
{
Entry = (PRTL_ATOM_ENTRY)Current;
DPRINT("Comparing %S and %S\n", Entry->Name.Buffer, AtomName);
if (_wcsicmp(Entry->Name.Buffer, AtomName) == 0)
{
Entry->RefCount++;
if (Atom)
*Atom = (RTL_ATOM)(Entry->Index + 0xC000);
RtlpUnlockAtomTable(AtomTable);
return STATUS_SUCCESS;
}
Current = Current->Flink;
}
/* insert new atom */
Entry = RtlAllocateHeap(RtlGetProcessHeap(),
HEAP_ZERO_MEMORY,
sizeof(RTL_ATOM_ENTRY));
if (Entry == NULL)
{
RtlpUnlockAtomTable(AtomTable);
return STATUS_NO_MEMORY;
}
InsertTailList(&AtomTable->Slot[Hash], &Entry->List)
RtlCreateUnicodeString (&Entry->Name,
AtomName);
Entry->RefCount = 1;
Entry->Locked = FALSE;
/* FIXME: use general function instead !! */
AtomHandle = (PRTL_ATOM_HANDLE)RtlAllocateHandle(AtomTable->HandleTable,
&AtomIndex);
DPRINT("AtomHandle %p AtomIndex %x\n", AtomHandle, AtomIndex);
AtomHandle->Entry = Entry;
Entry->Index = AtomIndex;
Entry->Handle = (PRTL_HANDLE)AtomHandle;
if (Atom)
*Atom = (RTL_ATOM)(AtomIndex + 0xC000);
RtlpUnlockAtomTable(AtomTable);
return STATUS_SUCCESS;
}
/*
* @implemented
*/
NTSTATUS STDCALL
RtlDeleteAtomFromAtomTable(IN PRTL_ATOM_TABLE AtomTable,
IN RTL_ATOM Atom)
{
PRTL_ATOM_HANDLE AtomHandle;
PRTL_ATOM_ENTRY AtomEntry;
DPRINT("RtlDeleteAtomFromAtomTable (AtomTable %p Atom %x)\n",
AtomTable, Atom);
if (Atom < 0xC000)
{
return STATUS_SUCCESS;
}
RtlpLockAtomTable(AtomTable);
/* FIXME: use general function instead !! */
if (!RtlIsValidIndexHandle(AtomTable->HandleTable,
(PRTL_HANDLE *)&AtomHandle,
(ULONG)Atom - 0xC000))
{
RtlpUnlockAtomTable(AtomTable);
return STATUS_INVALID_HANDLE;
}
DPRINT("AtomHandle %x\n", AtomHandle);
DPRINT("AtomHandle->Entry %x\n", AtomHandle->Entry);
AtomEntry = AtomHandle->Entry;
DPRINT("Atom name: %wZ\n", &AtomEntry->Name);
AtomEntry->RefCount--;
if (AtomEntry->RefCount == 0)
{
if (AtomEntry->Locked == TRUE)
{
DPRINT("Atom %wZ is locked!\n", &AtomEntry->Name);
RtlpUnlockAtomTable(AtomTable);
return STATUS_WAS_LOCKED;
}
DPRINT("Removing atom: %wZ\n", &AtomEntry->Name);
RtlFreeUnicodeString(&AtomEntry->Name);
RemoveEntryList(&AtomEntry->List);
RtlFreeHeap(RtlGetProcessHeap(),
0,
AtomEntry);
RtlFreeHandle(AtomTable->HandleTable,
(PRTL_HANDLE)AtomHandle);
}
RtlpUnlockAtomTable(AtomTable);
return STATUS_SUCCESS;
}
/*
* @implemented
*/
NTSTATUS STDCALL
RtlLookupAtomInAtomTable(IN PRTL_ATOM_TABLE AtomTable,
IN PWSTR AtomName,
OUT PRTL_ATOM Atom)
{
ULONG Hash;
PLIST_ENTRY Current;
PRTL_ATOM_ENTRY Entry;
USHORT AtomValue;
NTSTATUS Status;
DPRINT("RtlLookupAtomInAtomTable (AtomTable %p AtomName %S Atom %p)\n",
AtomTable, AtomName, Atom);
if (RtlpCheckIntegerAtom (AtomName, &AtomValue))
{
/* integer atom */
if (AtomValue >= 0xC000)
{
AtomValue = 0;
Status = STATUS_INVALID_PARAMETER;
}
else
{
Status = STATUS_SUCCESS;
}
if (Atom)
*Atom = (RTL_ATOM)AtomValue;
return Status;
}
RtlpLockAtomTable(AtomTable);
/* string atom */
Hash = RtlpHashAtomName(AtomTable->TableSize, AtomName);
/* search for existing atom */
Current = AtomTable->Slot[Hash].Flink;
while (Current != &AtomTable->Slot[Hash])
{
Entry = (PRTL_ATOM_ENTRY)Current;
DPRINT("Comparing %S and %S\n", Entry->Name.Buffer, AtomName);
if (_wcsicmp(Entry->Name.Buffer, AtomName) == 0)
{
if (Atom)
*Atom = (RTL_ATOM)(Entry->Index + 0xC000);
RtlpUnlockAtomTable(AtomTable);
return STATUS_SUCCESS;
}
Current = Current->Flink;
}
return STATUS_OBJECT_NAME_NOT_FOUND;
}
/*
* @implemented
*/
NTSTATUS STDCALL
RtlPinAtomInAtomTable(IN PRTL_ATOM_TABLE AtomTable,
IN RTL_ATOM Atom)
{
PRTL_ATOM_HANDLE AtomHandle;
PRTL_ATOM_ENTRY AtomEntry;
DPRINT("RtlPinAtomInAtomTable (AtomTable %p Atom %x)\n",
AtomTable, Atom);
if (Atom < 0xC000)
{
return STATUS_SUCCESS;
}
RtlpLockAtomTable(AtomTable);
/* FIXME: use general function instead !! */
if (!RtlIsValidIndexHandle(AtomTable->HandleTable,
(PRTL_HANDLE *)&AtomHandle,
(ULONG)Atom - 0xC000))
{
RtlpUnlockAtomTable(AtomTable);
return STATUS_INVALID_HANDLE;
}
DPRINT("AtomHandle %x\n", AtomHandle);
DPRINT("AtomHandle->Entry %x\n", AtomHandle->Entry);
AtomEntry = AtomHandle->Entry;
DPRINT("Atom name: %wZ\n", &AtomEntry->Name);
AtomEntry->Locked = TRUE;
RtlpUnlockAtomTable(AtomTable);
return STATUS_SUCCESS;
}
/*
* @implemented
*/
NTSTATUS STDCALL
RtlQueryAtomInAtomTable(PRTL_ATOM_TABLE AtomTable,
RTL_ATOM Atom,
PULONG RefCount,
PULONG PinCount,
PWSTR AtomName,
PULONG NameLength)
{
ULONG Length;
PRTL_ATOM_HANDLE AtomHandle;
PRTL_ATOM_ENTRY AtomEntry;
if (Atom < 0xC000)
{
if (RefCount != NULL)
{
*RefCount = 1;
}
if (PinCount != NULL)
{
*PinCount = 1;
}
if ((AtomName != NULL) && (NameLength != NULL) && (NameLength > 0))
{
Length = swprintf(AtomName, L"#%lu", (ULONG)Atom);
*NameLength = Length * sizeof(WCHAR);
}
return STATUS_SUCCESS;
}
RtlpLockAtomTable(AtomTable);
/* FIXME: use general function instead !! */
if (!RtlIsValidIndexHandle(AtomTable->HandleTable,
(PRTL_HANDLE *)&AtomHandle,
(ULONG)Atom - 0xC000))
{
RtlpUnlockAtomTable(AtomTable);
return STATUS_INVALID_HANDLE;
}
DPRINT("AtomHandle %x\n", AtomHandle);
DPRINT("AtomHandle->Entry %x\n", AtomHandle->Entry);
AtomEntry = AtomHandle->Entry;
DPRINT("Atom name: %wZ\n", &AtomEntry->Name);
if (RefCount != NULL)
{
*RefCount = AtomEntry->RefCount;
}
if (PinCount != NULL)
{
*PinCount = (ULONG)AtomEntry->Locked;
}
if ((AtomName != NULL) && (NameLength != NULL))
{
if (*NameLength < AtomEntry->Name.Length)
{
*NameLength = AtomEntry->Name.Length;
RtlpUnlockAtomTable(AtomTable);
return STATUS_BUFFER_TOO_SMALL;
}
Length = swprintf(AtomName, L"%s", AtomEntry->Name.Buffer);
*NameLength = Length * sizeof(WCHAR);
}
RtlpUnlockAtomTable(AtomTable);
return STATUS_SUCCESS;
}
/* INTERNAL FUNCTIONS ********************************************************/
static ULONG
RtlpHashAtomName(ULONG TableSize,
PWSTR AtomName)
{
ULONG q = 0;
PWCHAR p;
DPRINT("RtlpHashAtomName(TableSize %ld AtomName '%S')\n",
TableSize, AtomName);
/* convert the string to an internal representation */
p = AtomName;
while (*p != 0)
{
q += (ULONG)towupper(*p);
p++;
}
DPRINT("q %lu Hash %lu\n", q, q % TableSize);
return (q % TableSize);
}
static BOOLEAN
RtlpCheckIntegerAtom(PWSTR AtomName,
PUSHORT AtomValue)
{
UNICODE_STRING AtomString;
USHORT LoValue;
ULONG LongValue;
PWCHAR p;
DPRINT("RtlpCheckIntegerAtom(AtomName '%S' AtomValue %p)\n",
AtomName, AtomValue);
if (!((ULONG)AtomName & 0xFFFF0000))
{
LoValue = (USHORT)((ULONG)AtomName & 0xFFFF);
if (LoValue >= 0xC000)
return FALSE;
if (LoValue == 0)
LoValue = 0xC000;
if (AtomValue != NULL)
*AtomValue = LoValue;
return TRUE;
}
if (*AtomName != L'#')
return FALSE;
p = AtomName;
p++;
while (*p)
{
if ((*p < L'0') || (*p > L'9'))
return FALSE;
p++;
}
p = AtomName;
p++;
RtlInitUnicodeString(&AtomString,
p);
RtlUnicodeStringToInteger(&AtomString,10, &LongValue);
*AtomValue = (USHORT)(LongValue & 0x0000FFFF);
return TRUE;
}
/* lock functions */
static NTSTATUS
RtlpInitAtomTableLock(PRTL_ATOM_TABLE AtomTable)
{
AtomTable->Lock = RtlAllocateHeap(RtlGetProcessHeap(),
HEAP_ZERO_MEMORY,
sizeof(CRITICAL_SECTION));
if (AtomTable->Lock == NULL)
return STATUS_NO_MEMORY;
RtlInitializeCriticalSection((PCRITICAL_SECTION)AtomTable->Lock);
return STATUS_SUCCESS;
}
static VOID
RtlpDestroyAtomTableLock(PRTL_ATOM_TABLE AtomTable)
{
if (AtomTable->Lock)
{
RtlDeleteCriticalSection((PCRITICAL_SECTION)AtomTable->Lock);
RtlFreeHeap(RtlGetProcessHeap(),
0,
AtomTable->Lock);
AtomTable->Lock = NULL;
}
}
static BOOLEAN
RtlpLockAtomTable(PRTL_ATOM_TABLE AtomTable)
{
RtlEnterCriticalSection((PCRITICAL_SECTION)AtomTable->Lock);
return TRUE;
}
static VOID
RtlpUnlockAtomTable(PRTL_ATOM_TABLE AtomTable)
{
RtlLeaveCriticalSection((PCRITICAL_SECTION)AtomTable->Lock);
}
/* handle functions */
static BOOLEAN
RtlpCreateAtomHandleTable(PRTL_ATOM_TABLE AtomTable)
{
AtomTable->HandleTable = RtlAllocateHeap(RtlGetProcessHeap(),
HEAP_ZERO_MEMORY,
sizeof(RTL_HANDLE_TABLE));
if (AtomTable->HandleTable == NULL)
return FALSE;
RtlInitializeHandleTable(0xCFFF,
sizeof(RTL_ATOM_HANDLE),
(PRTL_HANDLE_TABLE)AtomTable->HandleTable);
return TRUE;
}
static VOID
RtlpDestroyAtomHandleTable(PRTL_ATOM_TABLE AtomTable)
{
if (AtomTable->HandleTable)
{
RtlDestroyHandleTable((PRTL_HANDLE_TABLE)AtomTable->HandleTable);
RtlFreeHeap(RtlGetProcessHeap(),
0,
AtomTable->HandleTable);
AtomTable->HandleTable = NULL;
}
}
/* EOF */