mirror of
https://github.com/reactos/reactos.git
synced 2024-10-31 11:56:26 +00:00
4f0b8d3db0
svn path=/branches/ntvdm/; revision=59241
600 lines
14 KiB
C
600 lines
14 KiB
C
/*
|
|
* COPYRIGHT: See COPYING in the top level directory
|
|
* PROJECT: ReactOS system libraries
|
|
* FILE: lib/kernel32/misc/atom.c
|
|
* PURPOSE: Atom functions
|
|
* PROGRAMMERS: Alex Ionescu (alex@relsoft.net)
|
|
*/
|
|
|
|
/* INCLUDES ******************************************************************/
|
|
#include <k32.h>
|
|
|
|
#define NDEBUG
|
|
#include <debug.h>
|
|
|
|
/* GLOBALS *******************************************************************/
|
|
|
|
PRTL_ATOM_TABLE BaseLocalAtomTable = NULL;
|
|
|
|
/* FUNCTIONS *****************************************************************/
|
|
|
|
PVOID
|
|
WINAPI
|
|
InternalInitAtomTable(VOID)
|
|
{
|
|
/* Create or return the local table */
|
|
if (!BaseLocalAtomTable) RtlCreateAtomTable(0, &BaseLocalAtomTable);
|
|
return BaseLocalAtomTable;
|
|
}
|
|
|
|
ATOM
|
|
WINAPI
|
|
InternalAddAtom(BOOLEAN Local,
|
|
BOOLEAN Unicode,
|
|
LPCSTR AtomName)
|
|
{
|
|
NTSTATUS Status;
|
|
ANSI_STRING AnsiString;
|
|
UNICODE_STRING UnicodeString;
|
|
PUNICODE_STRING AtomNameString;
|
|
ATOM Atom = INVALID_ATOM;
|
|
|
|
/* Check if it's an integer atom */
|
|
if ((ULONG_PTR)AtomName <= 0xFFFF)
|
|
{
|
|
/* Convert the name to an atom */
|
|
Atom = (ATOM)PtrToShort((PVOID)AtomName);
|
|
if (Atom >= MAXINTATOM)
|
|
{
|
|
/* Fail, atom number too large */
|
|
BaseSetLastNTError(STATUS_INVALID_PARAMETER);
|
|
return INVALID_ATOM;
|
|
}
|
|
|
|
/* Return it */
|
|
return Atom;
|
|
}
|
|
else
|
|
{
|
|
/* Check if this is a unicode atom */
|
|
if (Unicode)
|
|
{
|
|
/* Use a unicode string */
|
|
AtomNameString = &UnicodeString;
|
|
RtlInitUnicodeString(AtomNameString, (LPWSTR)AtomName);
|
|
Status = STATUS_SUCCESS;
|
|
}
|
|
else
|
|
{
|
|
/* Use an ansi string */
|
|
RtlInitAnsiString(&AnsiString, AtomName );
|
|
|
|
/* Check if we can abuse the TEB */
|
|
if (AnsiString.MaximumLength > 260)
|
|
{
|
|
/* We can't, allocate a new string */
|
|
AtomNameString = &UnicodeString;
|
|
Status = RtlAnsiStringToUnicodeString(AtomNameString,
|
|
&AnsiString,
|
|
TRUE);
|
|
}
|
|
else
|
|
{
|
|
/* We can! Get the TEB String */
|
|
AtomNameString = &NtCurrentTeb()->StaticUnicodeString;
|
|
|
|
/* Convert it into the TEB */
|
|
Status = RtlAnsiStringToUnicodeString(AtomNameString,
|
|
&AnsiString,
|
|
FALSE);
|
|
}
|
|
}
|
|
|
|
/* Check for failure */
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
BaseSetLastNTError(Status);
|
|
return Atom;
|
|
}
|
|
}
|
|
|
|
/* Check if we're doing local add */
|
|
if (Local)
|
|
{
|
|
/* Do a local add */
|
|
Status = RtlAddAtomToAtomTable(InternalInitAtomTable(),
|
|
AtomNameString->Buffer,
|
|
&Atom);
|
|
}
|
|
else
|
|
{
|
|
/* Do a global add */
|
|
Status = NtAddAtom(AtomNameString->Buffer,
|
|
AtomNameString->Length,
|
|
&Atom);
|
|
}
|
|
|
|
/* Check for failure */
|
|
if (!NT_SUCCESS(Status)) BaseSetLastNTError(Status);
|
|
|
|
/* Check if we were non-static ANSI */
|
|
if (!(Unicode) && (AtomNameString == &UnicodeString))
|
|
{
|
|
/* Free the allocated buffer */
|
|
RtlFreeUnicodeString(AtomNameString);
|
|
}
|
|
|
|
/* Return the atom */
|
|
return Atom;
|
|
}
|
|
|
|
ATOM
|
|
WINAPI
|
|
InternalFindAtom(BOOLEAN Local,
|
|
BOOLEAN Unicode,
|
|
LPCSTR AtomName)
|
|
{
|
|
NTSTATUS Status;
|
|
ANSI_STRING AnsiString;
|
|
UNICODE_STRING UnicodeString;
|
|
PUNICODE_STRING AtomNameString;
|
|
ATOM Atom = INVALID_ATOM;
|
|
|
|
/* Check if it's an integer atom */
|
|
if ((ULONG_PTR)AtomName <= 0xFFFF)
|
|
{
|
|
/* Convert the name to an atom */
|
|
Atom = (ATOM)PtrToShort((PVOID)AtomName);
|
|
if (Atom >= MAXINTATOM)
|
|
{
|
|
/* Fail, atom number too large */
|
|
BaseSetLastNTError(STATUS_INVALID_PARAMETER);
|
|
DPRINT1("Invalid atom\n");
|
|
}
|
|
|
|
/* Return it */
|
|
return Atom;
|
|
}
|
|
else
|
|
{
|
|
/* Check if this is a unicode atom */
|
|
if (Unicode)
|
|
{
|
|
/* Use a unicode string */
|
|
AtomNameString = &UnicodeString;
|
|
RtlInitUnicodeString(AtomNameString, (LPWSTR)AtomName);
|
|
Status = STATUS_SUCCESS;
|
|
}
|
|
else
|
|
{
|
|
/* Use an ansi string */
|
|
RtlInitAnsiString(&AnsiString, AtomName);
|
|
|
|
/* Check if we can abuse the TEB */
|
|
if (AnsiString.MaximumLength > 260)
|
|
{
|
|
/* We can't, allocate a new string */
|
|
AtomNameString = &UnicodeString;
|
|
Status = RtlAnsiStringToUnicodeString(AtomNameString,
|
|
&AnsiString,
|
|
TRUE);
|
|
}
|
|
else
|
|
{
|
|
/* We can! Get the TEB String */
|
|
AtomNameString = &NtCurrentTeb()->StaticUnicodeString;
|
|
|
|
/* Convert it into the TEB */
|
|
Status = RtlAnsiStringToUnicodeString(AtomNameString,
|
|
&AnsiString,
|
|
FALSE);
|
|
}
|
|
}
|
|
|
|
/* Check for failure */
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
DPRINT1("Failed\n");
|
|
BaseSetLastNTError(Status);
|
|
return Atom;
|
|
}
|
|
}
|
|
|
|
/* Check if we're doing local lookup */
|
|
if (Local)
|
|
{
|
|
/* Do a local lookup */
|
|
Status = RtlLookupAtomInAtomTable(InternalInitAtomTable(),
|
|
AtomNameString->Buffer,
|
|
&Atom);
|
|
}
|
|
else
|
|
{
|
|
/* Do a global search */
|
|
if (!AtomNameString->Length)
|
|
{
|
|
/* This is illegal in win32 */
|
|
DPRINT1("No name given\n");
|
|
Status = STATUS_OBJECT_NAME_NOT_FOUND;
|
|
}
|
|
else
|
|
{
|
|
/* Call the global function */
|
|
Status = NtFindAtom(AtomNameString->Buffer,
|
|
AtomNameString->Length,
|
|
&Atom);
|
|
}
|
|
}
|
|
|
|
/* Check for failure */
|
|
if (!NT_SUCCESS(Status)) BaseSetLastNTError(Status);
|
|
|
|
/* Check if we were non-static ANSI */
|
|
if (!(Unicode) && (AtomNameString == &UnicodeString))
|
|
{
|
|
/* Free the allocated buffer */
|
|
RtlFreeUnicodeString(AtomNameString);
|
|
}
|
|
|
|
/* Return the atom */
|
|
return Atom;
|
|
}
|
|
|
|
ATOM
|
|
WINAPI
|
|
InternalDeleteAtom(BOOLEAN Local,
|
|
ATOM Atom)
|
|
{
|
|
NTSTATUS Status;
|
|
|
|
/* Validate it */
|
|
if (Atom >= MAXINTATOM)
|
|
{
|
|
/* Check if it's a local delete */
|
|
if (Local)
|
|
{
|
|
/* Delete it locally */
|
|
Status = RtlDeleteAtomFromAtomTable(InternalInitAtomTable(), Atom);
|
|
}
|
|
else
|
|
{
|
|
/* Delete it globall */
|
|
Status = NtDeleteAtom(Atom);
|
|
}
|
|
|
|
/* Check for success */
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
/* Fail */
|
|
BaseSetLastNTError(Status);
|
|
return INVALID_ATOM;
|
|
}
|
|
}
|
|
|
|
/* Return failure */
|
|
return 0;
|
|
}
|
|
|
|
UINT
|
|
WINAPI
|
|
InternalGetAtomName(BOOLEAN Local,
|
|
BOOLEAN Unicode,
|
|
ATOM Atom,
|
|
LPSTR AtomName,
|
|
DWORD Size)
|
|
{
|
|
NTSTATUS Status;
|
|
DWORD RetVal = 0;
|
|
ANSI_STRING AnsiString;
|
|
UNICODE_STRING UnicodeString;
|
|
PVOID TempBuffer = NULL;
|
|
PWSTR AtomNameString;
|
|
ULONG AtomInfoLength;
|
|
ULONG AtomNameLength;
|
|
PATOM_BASIC_INFORMATION AtomInfo;
|
|
|
|
/* Normalize the size as not to overflow */
|
|
if (!Unicode && Size > 0x7000) Size = 0x7000;
|
|
|
|
/* Make sure it's valid too */
|
|
if (!Size)
|
|
{
|
|
BaseSetLastNTError(STATUS_BUFFER_OVERFLOW);
|
|
return 0;
|
|
}
|
|
if (!Atom)
|
|
{
|
|
BaseSetLastNTError(STATUS_INVALID_PARAMETER);
|
|
return 0;
|
|
}
|
|
|
|
/* Check if this is a global query */
|
|
if (Local)
|
|
{
|
|
/* Set the query length */
|
|
AtomNameLength = Size * sizeof(WCHAR);
|
|
|
|
/* If it's unicode, just keep the name */
|
|
if (Unicode)
|
|
{
|
|
AtomNameString = (PWSTR)AtomName;
|
|
}
|
|
else
|
|
{
|
|
/* Allocate memory for the ansi buffer */
|
|
TempBuffer = RtlAllocateHeap(RtlGetProcessHeap(),
|
|
0,
|
|
AtomNameLength);
|
|
AtomNameString = TempBuffer;
|
|
}
|
|
|
|
/* Query the name */
|
|
Status = RtlQueryAtomInAtomTable(InternalInitAtomTable(),
|
|
Atom,
|
|
NULL,
|
|
NULL,
|
|
AtomNameString,
|
|
&AtomNameLength);
|
|
}
|
|
else
|
|
{
|
|
/* We're going to do a global query, so allocate a buffer */
|
|
AtomInfoLength = sizeof(ATOM_BASIC_INFORMATION) +
|
|
(Size * sizeof(WCHAR));
|
|
AtomInfo = TempBuffer = RtlAllocateHeap(RtlGetProcessHeap(),
|
|
0,
|
|
AtomInfoLength);
|
|
|
|
if (!AtomInfo)
|
|
{
|
|
BaseSetLastNTError(STATUS_NO_MEMORY);
|
|
return 0;
|
|
}
|
|
|
|
/* Query the name */
|
|
Status = NtQueryInformationAtom(Atom,
|
|
AtomBasicInformation,
|
|
AtomInfo,
|
|
AtomInfoLength,
|
|
&AtomInfoLength);
|
|
if (NT_SUCCESS(Status))
|
|
{
|
|
/* Success. Update the length and get the name */
|
|
AtomNameLength = (ULONG)AtomInfo->NameLength;
|
|
AtomNameString = AtomInfo->Name;
|
|
}
|
|
}
|
|
|
|
/* Check for global success */
|
|
if (NT_SUCCESS(Status))
|
|
{
|
|
/* Check if it was unicode */
|
|
if (Unicode)
|
|
{
|
|
/* We return the length in chars */
|
|
RetVal = AtomNameLength / sizeof(WCHAR);
|
|
|
|
/* Copy the memory if this was a global query */
|
|
if (AtomNameString != (PWSTR)AtomName)
|
|
{
|
|
RtlMoveMemory(AtomName, AtomNameString, AtomNameLength);
|
|
}
|
|
|
|
/* And null-terminate it if the buffer was too large */
|
|
if (RetVal < Size)
|
|
{
|
|
((PWCHAR)AtomName)[RetVal] = UNICODE_NULL;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* First create a unicode string with our data */
|
|
UnicodeString.Buffer = AtomNameString;
|
|
UnicodeString.Length = (USHORT)AtomNameLength;
|
|
UnicodeString.MaximumLength = (USHORT)(UnicodeString.Length +
|
|
sizeof(WCHAR));
|
|
|
|
/* Now prepare an ansi string for conversion */
|
|
AnsiString.Buffer = AtomName;
|
|
AnsiString.Length = 0;
|
|
AnsiString.MaximumLength = (USHORT)Size;
|
|
|
|
/* Convert it */
|
|
Status = RtlUnicodeStringToAnsiString(&AnsiString,
|
|
&UnicodeString,
|
|
FALSE);
|
|
|
|
/* Return the length */
|
|
if (NT_SUCCESS(Status)) RetVal = AnsiString.Length;
|
|
}
|
|
}
|
|
|
|
/* Free the temporary buffer if we have one */
|
|
if (TempBuffer) RtlFreeHeap(RtlGetProcessHeap(), 0, TempBuffer);
|
|
|
|
/* Check for failure */
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
/* Fail */
|
|
DPRINT("Failed: %lx\n", Status);
|
|
BaseSetLastNTError(Status);
|
|
}
|
|
|
|
/* Return length */
|
|
return RetVal;
|
|
}
|
|
|
|
/* FUNCTIONS *****************************************************************/
|
|
|
|
/*
|
|
* @implemented
|
|
*/
|
|
ATOM
|
|
WINAPI
|
|
GlobalAddAtomA(LPCSTR lpString)
|
|
{
|
|
return InternalAddAtom(FALSE, FALSE, lpString);
|
|
}
|
|
|
|
/*
|
|
* @implemented
|
|
*/
|
|
ATOM
|
|
WINAPI
|
|
GlobalAddAtomW(LPCWSTR lpString)
|
|
{
|
|
return InternalAddAtom(FALSE, TRUE, (LPSTR)lpString);
|
|
}
|
|
|
|
/*
|
|
* @implemented
|
|
*/
|
|
ATOM
|
|
WINAPI
|
|
GlobalDeleteAtom(ATOM nAtom)
|
|
{
|
|
return InternalDeleteAtom(FALSE, nAtom);
|
|
}
|
|
|
|
/*
|
|
* @implemented
|
|
*/
|
|
ATOM
|
|
WINAPI
|
|
GlobalFindAtomA(LPCSTR lpString)
|
|
{
|
|
return InternalFindAtom(FALSE, FALSE, lpString);
|
|
}
|
|
|
|
/*
|
|
* @implemented
|
|
*/
|
|
ATOM
|
|
WINAPI
|
|
GlobalFindAtomW(LPCWSTR lpString)
|
|
{
|
|
return InternalFindAtom(FALSE, TRUE, (LPSTR)lpString);
|
|
}
|
|
|
|
/*
|
|
* @implemented
|
|
*/
|
|
UINT
|
|
WINAPI
|
|
GlobalGetAtomNameA(ATOM nAtom,
|
|
LPSTR lpBuffer,
|
|
int nSize)
|
|
{
|
|
return InternalGetAtomName(FALSE, FALSE, nAtom, lpBuffer, (DWORD)nSize);
|
|
}
|
|
|
|
/*
|
|
* @implemented
|
|
*/
|
|
UINT
|
|
WINAPI
|
|
GlobalGetAtomNameW(ATOM nAtom,
|
|
LPWSTR lpBuffer,
|
|
int nSize)
|
|
{
|
|
return InternalGetAtomName(FALSE,
|
|
TRUE,
|
|
nAtom,
|
|
(LPSTR)lpBuffer,
|
|
(DWORD)nSize);
|
|
}
|
|
|
|
/*
|
|
* @implemented
|
|
*/
|
|
BOOL
|
|
WINAPI
|
|
InitAtomTable(DWORD nSize)
|
|
{
|
|
/* Normalize size */
|
|
if (nSize < 4 || nSize > 511) nSize = 37;
|
|
|
|
DPRINT("Here\n");
|
|
return NT_SUCCESS(RtlCreateAtomTable(nSize, &BaseLocalAtomTable));
|
|
}
|
|
|
|
/*
|
|
* @implemented
|
|
*/
|
|
ATOM
|
|
WINAPI
|
|
AddAtomA(LPCSTR lpString)
|
|
{
|
|
return InternalAddAtom(TRUE, FALSE, lpString);
|
|
}
|
|
|
|
/*
|
|
* @implemented
|
|
*/
|
|
ATOM
|
|
WINAPI
|
|
AddAtomW(LPCWSTR lpString)
|
|
{
|
|
return InternalAddAtom(TRUE, TRUE, (LPSTR)lpString);
|
|
}
|
|
|
|
/*
|
|
* @implemented
|
|
*/
|
|
ATOM
|
|
WINAPI
|
|
DeleteAtom(ATOM nAtom)
|
|
{
|
|
return InternalDeleteAtom(TRUE, nAtom);
|
|
}
|
|
|
|
/*
|
|
* @implemented
|
|
*/
|
|
ATOM
|
|
WINAPI
|
|
FindAtomA(LPCSTR lpString)
|
|
{
|
|
return InternalFindAtom(TRUE, FALSE, lpString);
|
|
}
|
|
|
|
/*
|
|
* @implemented
|
|
*/
|
|
ATOM
|
|
WINAPI
|
|
FindAtomW(LPCWSTR lpString)
|
|
{
|
|
return InternalFindAtom(TRUE, TRUE, (LPSTR)lpString);
|
|
|
|
}
|
|
|
|
/*
|
|
* @implemented
|
|
*/
|
|
UINT
|
|
WINAPI
|
|
GetAtomNameA(ATOM nAtom,
|
|
LPSTR lpBuffer,
|
|
int nSize)
|
|
{
|
|
return InternalGetAtomName(TRUE, FALSE, nAtom, lpBuffer, (DWORD)nSize);
|
|
}
|
|
|
|
/*
|
|
* @implemented
|
|
*/
|
|
UINT
|
|
WINAPI
|
|
GetAtomNameW(ATOM nAtom,
|
|
LPWSTR lpBuffer,
|
|
int nSize)
|
|
{
|
|
return InternalGetAtomName(TRUE,
|
|
TRUE,
|
|
nAtom,
|
|
(LPSTR)lpBuffer,
|
|
(DWORD)nSize);
|
|
}
|
|
/* EOF */
|