Fix kernel-mode executive atom implementation (mostly add SEH and tidy up the code...
authorAlex Ionescu <aionescu@gmail.com>
Thu, 29 Dec 2005 08:43:45 +0000 (08:43 +0000)
committerAlex Ionescu <aionescu@gmail.com>
Thu, 29 Dec 2005 08:43:45 +0000 (08:43 +0000)
svn path=/trunk/; revision=20414

reactos/lib/kernel32/misc/atom.c
reactos/lib/rtl/atom.c
reactos/ntoskrnl/ex/atom.c

index 7a4a916..1f8cc1c 100644 (file)
-/* $Id$
- *
+/*
  * COPYRIGHT:       See COPYING in the top level directory
  * PROJECT:         ReactOS system libraries
  * FILE:            lib/kernel32/misc/atom.c
  * PURPOSE:         Atom functions
- * PROGRAMMER:      Eric Kohl ( ariadne@xs4all.nl)
- * UPDATE HISTORY:
- *                  Created 01/11/98
- *                  Full rewrite 27/05/2001
+ * PROGRAMMERS:     Alex Ionescu (alex@relsoft.net)
  */
 
+/* INCLUDES ******************************************************************/
 #include <k32.h>
 
 #define NDEBUG
 #include "../include/debug.h"
 
-
 /* GLOBALS *******************************************************************/
 
-static PRTL_ATOM_TABLE LocalAtomTable = NULL;
+PRTL_ATOM_TABLE BaseLocalAtomTable = NULL;
 
-static PRTL_ATOM_TABLE GetLocalAtomTable(VOID);
+/* 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 */
+            SetLastErrorByStatus(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! Use the TEB */
+                AtomNameString = &NtCurrentTeb()->StaticUnicodeString;
+                Status = RtlAnsiStringToUnicodeString(AtomNameString,
+                                                      &AnsiString,
+                                                      FALSE);
+            }
+        }
+
+        /* Check for failure */
+        if (!NT_SUCCESS(Status))
+        {
+            SetLastErrorByStatus(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)) SetLastErrorByStatus(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 */
+            SetLastErrorByStatus(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! Use the TEB */
+                AtomNameString = &NtCurrentTeb()->StaticUnicodeString;
+                Status = RtlAnsiStringToUnicodeString(AtomNameString,
+                                                      &AnsiString,
+                                                      FALSE);
+            }
+        }
+
+        /* Check for failure */
+        if (!NT_SUCCESS(Status))
+        {
+            DPRINT1("Failed\n");
+            SetLastErrorByStatus(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)) SetLastErrorByStatus(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 */
+            SetLastErrorByStatus(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)
+    {
+        SetLastErrorByStatus(STATUS_BUFFER_OVERFLOW);
+        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);
+
+        /* 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 */
+        DPRINT1("Failed: %lx\n", Status);
+        SetLastErrorByStatus(Status);
+    }
+
+    /* Return length */
+    return RetVal;
+}
 
 /* FUNCTIONS *****************************************************************/
 
 /*
  * @implemented
  */
-ATOM STDCALL
+ATOM
+WINAPI
 GlobalAddAtomA(LPCSTR lpString)
 {
-   UNICODE_STRING AtomName;
-   NTSTATUS Status;
-   ATOM Atom;
-
-   if (HIWORD((ULONG)lpString) == 0)
-     {
-       if ((ULONG)lpString >= 0xC000)
-         {
-            SetLastErrorByStatus(STATUS_INVALID_PARAMETER);
-            return (ATOM)0;
-         }
-       return (ATOM)LOWORD((ULONG)lpString);
-     }
-
-   if (lstrlenA(lpString) > 255)
-   {
-      /* This limit does not exist with NtAddAtom so the limit is probably
-       * added for compability. -Gunnar
-       */
-      SetLastError(ERROR_INVALID_PARAMETER);
-      return (ATOM)0;
-   }
-
-   RtlCreateUnicodeStringFromAsciiz(&AtomName,
-                                   (LPSTR)lpString);
-
-   Status = NtAddAtom(AtomName.Buffer,
-                      AtomName.Length,
-                     &Atom);
-   RtlFreeUnicodeString(&AtomName);
-   if (!NT_SUCCESS(Status))
-     {
-       SetLastErrorByStatus(Status);
-       return (ATOM)0;
-     }
-
-   return Atom;
+    return InternalAddAtom(FALSE, FALSE, lpString);
 }
 
-
 /*
  * @implemented
  */
-ATOM STDCALL
+ATOM
+WINAPI
 GlobalAddAtomW(LPCWSTR lpString)
 {
-   ATOM Atom;
-   NTSTATUS Status;
-
-   if (HIWORD((ULONG)lpString) == 0)
-     {
-       if ((ULONG)lpString >= 0xC000)
-         {
-            SetLastErrorByStatus(STATUS_INVALID_PARAMETER);
-            return (ATOM)0;
-         }
-       return (ATOM)LOWORD((ULONG)lpString);
-     }
-
-   if (lstrlenW(lpString) > 255)
-   {
-      /* This limit does not exist with NtAddAtom so the limit is probably
-       * added for compability. -Gunnar
-       */
-      SetLastError(ERROR_INVALID_PARAMETER);
-      return (ATOM)0;
-   }
-
-   Status = NtAddAtom((LPWSTR)lpString,
-                      wcslen(lpString),
-                     &Atom);
-   if (!NT_SUCCESS(Status))
-     {
-       SetLastErrorByStatus(Status);
-       return (ATOM)0;
-     }
-
-   return Atom;
+    return InternalAddAtom(FALSE, TRUE, (LPSTR)lpString);
 }
 
-
 /*
  * @implemented
  */
-ATOM STDCALL
+ATOM
+WINAPI
 GlobalDeleteAtom(ATOM nAtom)
 {
-   NTSTATUS Status;
-
-   if (nAtom < 0xC000)
-     {
-       return 0;
-     }
-
-   Status = NtDeleteAtom(nAtom);
-   if (!NT_SUCCESS(Status))
-     {
-       SetLastErrorByStatus(Status);
-       return nAtom;
-     }
-
-   return 0;
+    return InternalDeleteAtom(FALSE, nAtom);
 }
 
-
 /*
  * @implemented
  */
-ATOM STDCALL
+ATOM
+WINAPI
 GlobalFindAtomA(LPCSTR lpString)
 {
-   UNICODE_STRING AtomName;
-   NTSTATUS Status;
-   ATOM Atom;
-
-   if (HIWORD((ULONG)lpString) == 0)
-     {
-       if ((ULONG)lpString >= 0xC000)
-         {
-            SetLastErrorByStatus(STATUS_INVALID_PARAMETER);
-            return (ATOM)0;
-         }
-       return (ATOM)LOWORD((ULONG)lpString);
-     }
-
-   if (lstrlenA(lpString) > 255)
-   {
-      /* This limit does not exist with NtAddAtom so the limit is probably
-       * added for compability. -Gunnar
-       */
-      SetLastError(ERROR_INVALID_PARAMETER);
-      return (ATOM)0;
-   }
-
-   RtlCreateUnicodeStringFromAsciiz(&AtomName,
-                                   (LPSTR)lpString);
-   Status = NtFindAtom(AtomName.Buffer,
-                       AtomName.Length,
-                      &Atom);
-   RtlFreeUnicodeString(&AtomName);
-   if (!NT_SUCCESS(Status))
-     {
-       SetLastErrorByStatus(Status);
-       return (ATOM)0;
-     }
-
-   return Atom;
+    return InternalFindAtom(FALSE, FALSE, lpString);
 }
 
-
 /*
  * @implemented
  */
-ATOM STDCALL
+ATOM
+WINAPI
 GlobalFindAtomW(LPCWSTR lpString)
 {
-   ATOM Atom;
-   NTSTATUS Status;
-
-   if (HIWORD((ULONG)lpString) == 0)
-     {
-       if ((ULONG)lpString >= 0xC000)
-         {
-            SetLastErrorByStatus(STATUS_INVALID_PARAMETER);
-            return (ATOM)0;
-         }
-       return (ATOM)LOWORD((ULONG)lpString);
-     }
-
-   if (lstrlenW(lpString) > 255)
-   {
-      /* This limit does not exist with NtAddAtom so the limit is probably
-       * added for compability. -Gunnar
-       */
-      SetLastError(ERROR_INVALID_PARAMETER);
-      return (ATOM)0;
-   }
-
-   Status = NtFindAtom((LPWSTR)lpString,
-                       wcslen(lpString),
-                      &Atom);
-   if (!NT_SUCCESS(Status))
-     {
-       SetLastErrorByStatus(Status);
-       return (ATOM)0;
-     }
-
-   return Atom;
+    return InternalFindAtom(FALSE, TRUE, (LPSTR)lpString);
 }
 
-
-UINT STDCALL
+/*
+ * @implemented
+ */
+UINT
+WINAPI
 GlobalGetAtomNameA(ATOM nAtom,
-                  LPSTR lpBuffer,
-                  int nSize)
+                   LPSTR lpBuffer,
+                   int nSize)
 {
-   PATOM_BASIC_INFORMATION Buffer;
-   UNICODE_STRING AtomNameU;
-   ANSI_STRING AtomName;
-   ULONG BufferSize;
-   ULONG ReturnLength;
-   NTSTATUS Status;
-
-   BufferSize = sizeof(ATOM_BASIC_INFORMATION) + nSize * sizeof(WCHAR);
-   Buffer = RtlAllocateHeap(RtlGetProcessHeap(),
-                           HEAP_ZERO_MEMORY,
-                           BufferSize);
-   if (Buffer == NULL)
-   {
-       SetLastError(ERROR_NOT_ENOUGH_MEMORY);
-       return 0;
-   }
-
-   Status = NtQueryInformationAtom(nAtom,
-                                  AtomBasicInformation,
-                                  Buffer,
-                                  BufferSize,
-                                  &ReturnLength);
-   if (!NT_SUCCESS(Status))
-     {
-       RtlFreeHeap(RtlGetProcessHeap(),
-                   0,
-                   Buffer);
-        SetLastErrorByStatus(Status);
-       return 0;
-     }
-
-   RtlInitUnicodeString(&AtomNameU,
-                       Buffer->Name);
-   AtomName.Buffer = lpBuffer;
-   AtomName.Length = 0;
-   AtomName.MaximumLength = nSize;
-   RtlUnicodeStringToAnsiString(&AtomName,
-                               &AtomNameU,
-                               FALSE);
-
-   ReturnLength = AtomName.Length;
-   RtlFreeHeap(RtlGetProcessHeap(),
-              0,
-              Buffer);
-
-   return ReturnLength;
+    return InternalGetAtomName(FALSE, FALSE, nAtom, lpBuffer, (DWORD)nSize);
 }
 
-
 /*
  * @implemented
  */
-UINT STDCALL
+UINT
+WINAPI
 GlobalGetAtomNameW(ATOM nAtom,
-                  LPWSTR lpBuffer,
-                  int nSize)
-{
-   PATOM_BASIC_INFORMATION Buffer;
-   ULONG BufferSize;
-   ULONG ReturnLength;
-   NTSTATUS Status;
-
-   BufferSize = sizeof(ATOM_BASIC_INFORMATION) + nSize * sizeof(WCHAR);
-   Buffer = RtlAllocateHeap(RtlGetProcessHeap(),
-                           HEAP_ZERO_MEMORY,
-                           BufferSize);
-   if (Buffer == NULL)
-   {
-       SetLastError(ERROR_NOT_ENOUGH_MEMORY);
-       return 0;
-   }
-
-   Status = NtQueryInformationAtom(nAtom,
-                                  AtomBasicInformation,
-                                  Buffer,
-                                  BufferSize,
-                                  &ReturnLength);
-   if (!NT_SUCCESS(Status))
-     {
-       RtlFreeHeap(RtlGetProcessHeap(),
-                   0,
-                   Buffer);
-        SetLastErrorByStatus(Status);
-       return 0;
-     }
-
-   memcpy(lpBuffer, Buffer->Name, Buffer->NameLength);
-   ReturnLength = Buffer->NameLength / sizeof(WCHAR);
-   *(lpBuffer + ReturnLength) = 0;
-   RtlFreeHeap(RtlGetProcessHeap(),
-              0,
-              Buffer);
-
-   return ReturnLength;
-}
-
-
-static PRTL_ATOM_TABLE
-GetLocalAtomTable(VOID)
+                   LPWSTR lpBuffer,
+                   int nSize)
 {
-   if (LocalAtomTable != NULL)
-     {
-       return LocalAtomTable;
-     }
-   RtlCreateAtomTable(37,
-                     &LocalAtomTable);
-   return LocalAtomTable;
+    return InternalGetAtomName(FALSE,
+                               TRUE,
+                               nAtom,
+                               (LPSTR)lpBuffer,
+                               (DWORD)nSize);
 }
 
-
 /*
  * @implemented
  */
-BOOL STDCALL
+BOOL
+WINAPI
 InitAtomTable(DWORD nSize)
 {
-   NTSTATUS Status;
+    /* Normalize size */
+    if (nSize < 4 || nSize > 511) nSize = 37;
 
-   /* nSize should be a prime number */
-
-   if ( nSize < 4 || nSize >= 512 )
-     {
-       nSize = 37;
-     }
-
-   if (LocalAtomTable == NULL)
-    {
-       Status = RtlCreateAtomTable(nSize,
-                                   &LocalAtomTable);
-       if (!NT_SUCCESS(Status))
-         {
-            SetLastErrorByStatus(Status);
-            return FALSE;
-         }
-    }
-
-  return TRUE;
+    DPRINT("Here\n");
+    return NT_SUCCESS(RtlCreateAtomTable(nSize, &BaseLocalAtomTable));
 }
 
-
 /*
  * @implemented
  */
-ATOM STDCALL
+ATOM
+WINAPI
 AddAtomA(LPCSTR lpString)
 {
-   PRTL_ATOM_TABLE AtomTable;
-   UNICODE_STRING AtomName;
-   NTSTATUS Status;
-   ATOM Atom;
-
-   if (HIWORD((ULONG)lpString) == 0)
-     {
-       if ((ULONG)lpString >= 0xC000)
-         {
-            SetLastErrorByStatus(STATUS_INVALID_PARAMETER);
-            return (ATOM)0;
-         }
-       return (ATOM)LOWORD((ULONG)lpString);
-     }
-
-   AtomTable = GetLocalAtomTable();
-
-   RtlCreateUnicodeStringFromAsciiz(&AtomName,
-                                   (LPSTR)lpString);
-
-   Status = RtlAddAtomToAtomTable(AtomTable,
-                                 AtomName.Buffer,
-                                 &Atom);
-   RtlFreeUnicodeString(&AtomName);
-   if (!NT_SUCCESS(Status))
-     {
-       SetLastErrorByStatus(Status);
-       return (ATOM)0;
-     }
-
-   return Atom;
+    return InternalAddAtom(TRUE, FALSE, lpString);
 }
 
-
 /*
  * @implemented
  */
-ATOM STDCALL
+ATOM
+WINAPI
 AddAtomW(LPCWSTR lpString)
 {
-   PRTL_ATOM_TABLE AtomTable;
-   ATOM Atom;
-   NTSTATUS Status;
-
-   if (HIWORD((ULONG)lpString) == 0)
-     {
-       if ((ULONG)lpString >= 0xC000)
-         {
-            SetLastErrorByStatus(STATUS_INVALID_PARAMETER);
-            return (ATOM)0;
-         }
-       return (ATOM)LOWORD((ULONG)lpString);
-     }
-
-   AtomTable = GetLocalAtomTable();
-
-   Status = RtlAddAtomToAtomTable(AtomTable,
-                                 (LPWSTR)lpString,
-                                 &Atom);
-   if (!NT_SUCCESS(Status))
-     {
-       SetLastErrorByStatus(Status);
-       return (ATOM)0;
-     }
-
-   return Atom;
+    return InternalAddAtom(TRUE, TRUE, (LPSTR)lpString);
 }
 
-
 /*
  * @implemented
  */
-ATOM STDCALL
+ATOM
+WINAPI
 DeleteAtom(ATOM nAtom)
 {
-   PRTL_ATOM_TABLE AtomTable;
-   NTSTATUS Status;
-
-   if (nAtom < 0xC000)
-     {
-       return 0;
-     }
-
-   AtomTable = GetLocalAtomTable();
-
-   Status = RtlDeleteAtomFromAtomTable(AtomTable,
-                                      nAtom);
-   if (!NT_SUCCESS(Status))
-     {
-       SetLastErrorByStatus(Status);
-       return nAtom;
-     }
-
-   return 0;
+    return InternalDeleteAtom(TRUE, nAtom);
 }
 
-
 /*
  * @implemented
  */
-ATOM STDCALL
+ATOM
+WINAPI
 FindAtomA(LPCSTR lpString)
 {
-   PRTL_ATOM_TABLE AtomTable;
-   UNICODE_STRING AtomName;
-   NTSTATUS Status;
-   ATOM Atom;
-
-   if (HIWORD((ULONG)lpString) == 0)
-     {
-       if ((ULONG)lpString >= 0xC000)
-         {
-            SetLastErrorByStatus(STATUS_INVALID_PARAMETER);
-            return (ATOM)0;
-         }
-       return (ATOM)LOWORD((ULONG)lpString);
-     }
-
-   AtomTable = GetLocalAtomTable();
-   RtlCreateUnicodeStringFromAsciiz(&AtomName,
-                                   (LPSTR)lpString);
-   Status = RtlLookupAtomInAtomTable(AtomTable,
-                                    AtomName.Buffer,
-                                    &Atom);
-   RtlFreeUnicodeString(&AtomName);
-   if (!NT_SUCCESS(Status))
-     {
-       SetLastErrorByStatus(Status);
-       return (ATOM)0;
-     }
-
-   return Atom;
+    return InternalFindAtom(TRUE, FALSE, lpString);
 }
 
-
 /*
  * @implemented
  */
-ATOM STDCALL
+ATOM
+WINAPI
 FindAtomW(LPCWSTR lpString)
 {
-   PRTL_ATOM_TABLE AtomTable;
-   ATOM Atom;
-   NTSTATUS Status;
-
-   if (HIWORD((ULONG)lpString) == 0)
-     {
-       if ((ULONG)lpString >= 0xC000)
-         {
-            SetLastErrorByStatus(STATUS_INVALID_PARAMETER);
-            return (ATOM)0;
-         }
-       return (ATOM)LOWORD((ULONG)lpString);
-     }
-
-   AtomTable = GetLocalAtomTable();
-
-   Status = RtlLookupAtomInAtomTable(AtomTable,
-                                    (LPWSTR)lpString,
-                                    &Atom);
-   if (!NT_SUCCESS(Status))
-     {
-       SetLastErrorByStatus(Status);
-       return (ATOM)0;
-     }
-
-   return Atom;
-}
+    return InternalFindAtom(TRUE, TRUE, (LPSTR)lpString);
 
+}
 
 /*
  * @implemented
  */
-UINT STDCALL
+UINT
+WINAPI
 GetAtomNameA(ATOM nAtom,
-            LPSTR lpBuffer,
-            int nSize)
+             LPSTR lpBuffer,
+             int nSize)
 {
-   PRTL_ATOM_TABLE AtomTable;
-   PWCHAR Buffer;
-   UNICODE_STRING AtomNameU;
-   ANSI_STRING AtomName;
-   ULONG NameLength;
-   NTSTATUS Status;
-
-   AtomTable = GetLocalAtomTable();
-
-   NameLength = nSize * sizeof(WCHAR);
-   Buffer = RtlAllocateHeap(RtlGetProcessHeap(),
-                           HEAP_ZERO_MEMORY,
-                           NameLength);
-   if (Buffer == NULL)
-   {
-       SetLastError(ERROR_NOT_ENOUGH_MEMORY);
-       return 0;
-   }
-
-   Status = RtlQueryAtomInAtomTable(AtomTable,
-                                   nAtom,
-                                   NULL,
-                                   NULL,
-                                   Buffer,
-                                   &NameLength);
-   if (!NT_SUCCESS(Status))
-     {
-       RtlFreeHeap(RtlGetProcessHeap(),
-                   0,
-                   Buffer);
-        SetLastErrorByStatus(Status);
-       return 0;
-     }
-
-   RtlInitUnicodeString(&AtomNameU,
-                       Buffer);
-   AtomName.Buffer = lpBuffer;
-   AtomName.Length = 0;
-   AtomName.MaximumLength = nSize;
-   RtlUnicodeStringToAnsiString(&AtomName,
-                               &AtomNameU,
-                               FALSE);
-
-   NameLength = AtomName.Length;
-   RtlFreeHeap(RtlGetProcessHeap(),
-              0,
-              Buffer);
-
-   return NameLength;
+    return InternalGetAtomName(TRUE, FALSE, nAtom, lpBuffer, (DWORD)nSize);
 }
 
-
 /*
  * @implemented
  */
-UINT STDCALL
+UINT
+WINAPI
 GetAtomNameW(ATOM nAtom,
-            LPWSTR lpBuffer,
-            int nSize)
+             LPWSTR lpBuffer,
+             int nSize)
 {
-   PRTL_ATOM_TABLE AtomTable;
-   ULONG NameLength;
-   NTSTATUS Status;
-
-   AtomTable = GetLocalAtomTable();
-
-   NameLength = nSize * sizeof(WCHAR);
-   Status = RtlQueryAtomInAtomTable(AtomTable,
-                                   nAtom,
-                                   NULL,
-                                   NULL,
-                                   lpBuffer,
-                                   &NameLength);
-   if (!NT_SUCCESS(Status))
-     {
-       return 0;
-     }
-
-   return(NameLength / sizeof(WCHAR));
+    return InternalGetAtomName(TRUE,
+                               TRUE,
+                               nAtom,
+                               (LPSTR)lpBuffer,
+                               (DWORD)nSize);
 }
-
 /* EOF */
index 166b979..1c643df 100644 (file)
@@ -150,6 +150,9 @@ RtlCreateAtomTable(IN ULONG TableSize,
         return STATUS_SUCCESS;
      }
 
+   /* Use default if size was incorrect */
+   if (TableSize <= 1) TableSize = 37;
+
    /* allocate atom table */
    Table = RtlpAllocAtomTable(((TableSize - 1) * sizeof(PRTL_ATOM_TABLE_ENTRY)) +
                               sizeof(RTL_ATOM_TABLE));
@@ -507,27 +510,22 @@ RtlLookupAtomInAtomTable(IN PRTL_ATOM_TABLE AtomTable,
      }
 
    RtlpLockAtomTable(AtomTable);
-
    Status = STATUS_OBJECT_NAME_NOT_FOUND;
 
    /* string atom */
    Entry = RtlpHashAtomName(AtomTable,
                             AtomName,
                             &HashLink);
-
    if (Entry != NULL)
      {
         Status = STATUS_SUCCESS;
         FoundAtom = (RTL_ATOM)Entry->Atom;
      }
-
    RtlpUnlockAtomTable(AtomTable);
-
    if (NT_SUCCESS(Status) && Atom != NULL)
      {
         *Atom = FoundAtom;
      }
-
    return Status;
 }
 
index be573da..0326d51 100644 (file)
@@ -13,6 +13,8 @@
 #define NDEBUG\r
 #include <internal/debug.h>\r
 \r
+#define TAG_ATOM TAG('A', 't', 'o', 'm')\r
+\r
 /* GLOBALS ****************************************************************/\r
 \r
 /* \r
@@ -45,79 +47,6 @@ ExpGetGlobalAtomTable(VOID)
     return GlobalAtomTable;\r
 }\r
 \r
-NTSTATUS\r
-NTAPI\r
-RtlpQueryAtomInformation(PRTL_ATOM_TABLE AtomTable,\r
-                         RTL_ATOM Atom,\r
-                         PATOM_BASIC_INFORMATION AtomInformation,\r
-                         ULONG AtomInformationLength,\r
-                         PULONG ReturnLength)\r
-{\r
-    NTSTATUS Status;\r
-    ULONG UsageCount;\r
-    ULONG Flags;\r
-    ULONG NameLength;\r
-\r
-    NameLength = AtomInformationLength - sizeof(ATOM_BASIC_INFORMATION) + sizeof(WCHAR);\r
-    Status = RtlQueryAtomInAtomTable(AtomTable,\r
-                                     Atom,\r
-                                     &UsageCount,\r
-                                     &Flags,\r
-                                     AtomInformation->Name,\r
-                                     &NameLength);\r
-\r
-    if (!NT_SUCCESS(Status)) return Status;\r
-    DPRINT("NameLength: %lu\n", NameLength);\r
-\r
-    if (ReturnLength != NULL)\r
-    {\r
-        *ReturnLength = NameLength + sizeof(ATOM_BASIC_INFORMATION);\r
-    }\r
-\r
-    if (NameLength + sizeof(ATOM_BASIC_INFORMATION) > AtomInformationLength)\r
-    {\r
-        return STATUS_INFO_LENGTH_MISMATCH;\r
-    }\r
-\r
-    AtomInformation->UsageCount = (USHORT)UsageCount;\r
-    AtomInformation->Flags = (USHORT)Flags;\r
-    AtomInformation->NameLength = (USHORT)NameLength;\r
-\r
-    return STATUS_SUCCESS;\r
-}\r
-\r
-NTSTATUS\r
-NTAPI\r
-RtlpQueryAtomTableInformation(PRTL_ATOM_TABLE AtomTable,\r
-                              RTL_ATOM Atom,\r
-                              PATOM_TABLE_INFORMATION AtomInformation,\r
-                              ULONG AtomInformationLength,\r
-                              PULONG ReturnLength)\r
-{\r
-    ULONG Length;\r
-    NTSTATUS Status;\r
-\r
-    Length = sizeof(ATOM_TABLE_INFORMATION);\r
-    DPRINT("RequiredLength: %lu\n", Length);\r
-\r
-    if (ReturnLength) *ReturnLength = Length;\r
-\r
-    if (Length > AtomInformationLength) return STATUS_INFO_LENGTH_MISMATCH;\r
-\r
-    Status = RtlQueryAtomListInAtomTable(AtomTable,\r
-                                         (AtomInformationLength - Length) /\r
-                                         sizeof(RTL_ATOM),\r
-                                         &AtomInformation->NumberOfAtoms,\r
-                                         AtomInformation->Atoms);\r
-    if (NT_SUCCESS(Status))\r
-    {\r
-        ReturnLength += AtomInformation->NumberOfAtoms * sizeof(RTL_ATOM);\r
-        if (ReturnLength != NULL) *ReturnLength = Length;\r
-    }\r
-\r
-    return Status;\r
-}\r
-\r
 /* FUNCTIONS ****************************************************************/\r
 \r
 /*\r
@@ -130,14 +59,96 @@ NtAddAtom(IN PWSTR AtomName,
           OUT PRTL_ATOM Atom)\r
 {\r
     PRTL_ATOM_TABLE AtomTable = ExpGetGlobalAtomTable();\r
+    NTSTATUS Status = STATUS_SUCCESS;\r
+    KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();\r
+    LPWSTR CapturedName = NULL;\r
+    ULONG CapturedSize;\r
+    RTL_ATOM SafeAtom;\r
+    PAGED_CODE();\r
 \r
     /* Check for the table */\r
     if (AtomTable == NULL) return STATUS_ACCESS_DENIED;\r
 \r
-    /* FIXME: SEH! */\r
+    /* Check for valid name */\r
+    if (AtomNameLength > (RTL_MAXIMUM_ATOM_LENGTH * sizeof(WCHAR)))\r
+    {\r
+        /* Fail */\r
+        DPRINT1("Atom name too long\n");\r
+        return STATUS_INVALID_PARAMETER;\r
+    }\r
 \r
-    /* Call the worker function */\r
-    return RtlAddAtomToAtomTable(AtomTable, AtomName, Atom);\r
+    /* Check if we're called from user-mode*/\r
+    if (PreviousMode != KernelMode)\r
+    {\r
+        /* Enter SEH */\r
+        _SEH_TRY\r
+        {\r
+            /* Check if we have a name */\r
+            if (AtomName)\r
+            {\r
+                /* Probe the atom */\r
+                ProbeForRead(AtomName, AtomNameLength, sizeof(WCHAR));\r
+\r
+                /* Allocate an aligned buffer + the null char */\r
+                CapturedSize = ((AtomNameLength + sizeof(WCHAR)) &~\r
+                                (sizeof(WCHAR) -1));\r
+                CapturedName = ExAllocatePoolWithTag(PagedPool,\r
+                                                     CapturedSize,\r
+                                                     TAG_ATOM);\r
+                if (!CapturedName)\r
+                {\r
+                    /* Fail the call */\r
+                    Status = STATUS_INSUFFICIENT_RESOURCES;\r
+                }\r
+                else\r
+                {\r
+                    /* Copy the name and null-terminate it */\r
+                    RtlMoveMemory(CapturedName, AtomName, AtomNameLength);\r
+                    CapturedName[AtomNameLength / sizeof(WCHAR)] = UNICODE_NULL;\r
+                }\r
+\r
+                /* Probe the atom too */\r
+                if (Atom) ProbeForWriteUshort(Atom);\r
+            }\r
+        }\r
+        _SEH_EXCEPT(_SEH_ExSystemExceptionFilter)\r
+        {\r
+            Status = _SEH_GetExceptionCode();\r
+        }\r
+        _SEH_END;\r
+    }\r
+    else\r
+    {\r
+        /* Simplify code and re-use one variable */\r
+        if (AtomName) CapturedName = AtomName;\r
+    }\r
+\r
+    /* Make sure probe worked */\r
+    if (NT_SUCCESS(Status))\r
+    {\r
+        /* Call the runtime function */\r
+        Status = RtlAddAtomToAtomTable(AtomTable, CapturedName, &SafeAtom);\r
+        if (NT_SUCCESS(Status) && (Atom))\r
+        {\r
+            /* Success and caller wants the atom back.. .enter SEH */\r
+            _SEH_TRY\r
+            {\r
+                /* Return the atom */\r
+                *Atom = SafeAtom;\r
+            }\r
+            _SEH_EXCEPT(_SEH_ExSystemExceptionFilter)\r
+            {\r
+                Status = _SEH_GetExceptionCode();\r
+            }\r
+            _SEH_END;\r
+        }\r
+    }\r
+\r
+    /* If we captured anything, free it */\r
+    if ((CapturedName) && (CapturedName != AtomName)) ExFreePool(CapturedName);\r
+\r
+    /* Return to caller */\r
+    return Status;\r
 }\r
 \r
 /*\r
@@ -148,6 +159,7 @@ NTAPI
 NtDeleteAtom(IN RTL_ATOM Atom)\r
 {\r
     PRTL_ATOM_TABLE AtomTable = ExpGetGlobalAtomTable();\r
+    PAGED_CODE();\r
 \r
     /* Check for valid table */\r
     if (AtomTable == NULL) return STATUS_ACCESS_DENIED;\r
@@ -166,14 +178,96 @@ NtFindAtom(IN PWSTR AtomName,
            OUT PRTL_ATOM Atom)\r
 {\r
     PRTL_ATOM_TABLE AtomTable = ExpGetGlobalAtomTable();\r
+    NTSTATUS Status = STATUS_SUCCESS;\r
+    KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();\r
+    LPWSTR CapturedName = NULL;\r
+    ULONG CapturedSize;\r
+    RTL_ATOM SafeAtom;\r
+    PAGED_CODE();\r
 \r
-    /* Check for valid table */\r
+    /* Check for the table */\r
     if (AtomTable == NULL) return STATUS_ACCESS_DENIED;\r
 \r
-    /* FIXME: SEH!!! */\r
+    /* Check for valid name */\r
+    if (AtomNameLength > (RTL_MAXIMUM_ATOM_LENGTH * sizeof(WCHAR)))\r
+    {\r
+        /* Fail */\r
+        DPRINT1("Atom name too long\n");\r
+        return STATUS_INVALID_PARAMETER;\r
+    }\r
+\r
+    /* Check if we're called from user-mode*/\r
+    if (PreviousMode != KernelMode)\r
+    {\r
+        /* Enter SEH */\r
+        _SEH_TRY\r
+        {\r
+            /* Check if we have a name */\r
+            if (AtomName)\r
+            {\r
+                /* Probe the atom */\r
+                ProbeForRead(AtomName, AtomNameLength, sizeof(WCHAR));\r
+\r
+                /* Allocate an aligned buffer + the null char */\r
+                CapturedSize = ((AtomNameLength + sizeof(WCHAR)) &~\r
+                                (sizeof(WCHAR) -1));\r
+                CapturedName = ExAllocatePoolWithTag(PagedPool,\r
+                                                     CapturedSize,\r
+                                                     TAG_ATOM);\r
+                if (!CapturedName)\r
+                {\r
+                    /* Fail the call */\r
+                    Status = STATUS_INSUFFICIENT_RESOURCES;\r
+                }\r
+                else\r
+                {\r
+                    /* Copy the name and null-terminate it */\r
+                    RtlMoveMemory(CapturedName, AtomName, AtomNameLength);\r
+                    CapturedName[AtomNameLength / sizeof(WCHAR)] = UNICODE_NULL;\r
+                }\r
+\r
+                /* Probe the atom too */\r
+                if (Atom) ProbeForWriteUshort(Atom);\r
+            }\r
+        }\r
+        _SEH_EXCEPT(_SEH_ExSystemExceptionFilter)\r
+        {\r
+            Status = _SEH_GetExceptionCode();\r
+        }\r
+        _SEH_END;\r
+    }\r
+    else\r
+    {\r
+        /* Simplify code and re-use one variable */\r
+        if (AtomName) CapturedName = AtomName;\r
+    }\r
 \r
-    /* Call worker function */\r
-    return RtlLookupAtomInAtomTable(AtomTable, AtomName, Atom);\r
+    /* Make sure probe worked */\r
+    if (NT_SUCCESS(Status))\r
+    {\r
+        /* Call the runtime function */\r
+        Status = RtlLookupAtomInAtomTable(AtomTable, CapturedName, &SafeAtom);\r
+        if (NT_SUCCESS(Status) && (Atom))\r
+        {\r
+            /* Success and caller wants the atom back.. .enter SEH */\r
+            _SEH_TRY\r
+            {\r
+                /* Return the atom */\r
+                *Atom = SafeAtom;\r
+            }\r
+            _SEH_EXCEPT(_SEH_ExSystemExceptionFilter)\r
+            {\r
+                Status = _SEH_GetExceptionCode();\r
+            }\r
+            _SEH_END;\r
+        }\r
+    }\r
+\r
+    /* If we captured anything, free it */\r
+    if ((CapturedName) && (CapturedName != AtomName)) ExFreePool(CapturedName);\r
+\r
+    /* Return to caller */\r
+    return Status;\r
 }\r
 \r
 /*\r
@@ -188,7 +282,10 @@ NtQueryInformationAtom(RTL_ATOM Atom,
                        PULONG ReturnLength)\r
 {\r
     PRTL_ATOM_TABLE AtomTable = ExpGetGlobalAtomTable();\r
+    PATOM_BASIC_INFORMATION BasicInformation = AtomInformation;\r
+    PATOM_TABLE_INFORMATION TableInformation = AtomInformation;\r
     NTSTATUS Status;\r
+    ULONG Flags, UsageCount, NameLength;\r
 \r
     /* Check for valid table */\r
     if (AtomTable == NULL) return STATUS_ACCESS_DENIED;\r
@@ -198,23 +295,70 @@ NtQueryInformationAtom(RTL_ATOM Atom,
     /* Choose class */\r
     switch (AtomInformationClass)\r
     {\r
+        /* Caller requested info about an atom */\r
         case AtomBasicInformation:\r
-            Status = RtlpQueryAtomInformation(AtomTable,\r
-                                              Atom,\r
-                                              AtomInformation,\r
-                                              AtomInformationLength,\r
-                                              ReturnLength);\r
+\r
+            /* Size check */\r
+            *ReturnLength = FIELD_OFFSET(ATOM_BASIC_INFORMATION, Name);\r
+            if (*ReturnLength > AtomInformationLength)\r
+            {\r
+                /* Fail */\r
+                DPRINT1("Buffer too small\n");\r
+                return STATUS_INFO_LENGTH_MISMATCH;\r
+            }\r
+\r
+            /* Prepare query */\r
+            UsageCount = 0;\r
+            NameLength = AtomInformationLength - *ReturnLength;\r
+            BasicInformation->Name[0] = UNICODE_NULL;\r
+\r
+            /* Query the data */\r
+            Status = RtlQueryAtomInAtomTable(AtomTable,\r
+                                             Atom,\r
+                                             &UsageCount,\r
+                                             &Flags,\r
+                                             BasicInformation->Name,\r
+                                             &NameLength);\r
+            if (NT_SUCCESS(Status))\r
+            {\r
+                /* Return data */\r
+                BasicInformation->UsageCount = (USHORT)UsageCount;\r
+                BasicInformation->Flags = (USHORT)Flags;\r
+                BasicInformation->NameLength = (USHORT)NameLength;\r
+                *ReturnLength += NameLength + sizeof(WCHAR);\r
+            }\r
             break;\r
 \r
+        /* Caller requested info about an Atom Table */\r
         case AtomTableInformation:\r
-            Status = RtlpQueryAtomTableInformation(AtomTable,\r
-                                                   Atom,\r
-                                                   AtomInformation,\r
-                                                   AtomInformationLength,\r
-                                                   ReturnLength);\r
+\r
+            /* Size check */\r
+            *ReturnLength = FIELD_OFFSET(ATOM_TABLE_INFORMATION, Atoms);\r
+            if (*ReturnLength > AtomInformationLength)\r
+            {\r
+                /* Fail */\r
+                DPRINT1("Buffer too small\n");\r
+                return STATUS_INFO_LENGTH_MISMATCH;\r
+            }\r
+\r
+            /* Query the data */\r
+            Status = RtlQueryAtomListInAtomTable(AtomTable,\r
+                                                 (AtomInformationLength - *ReturnLength) /\r
+                                                 sizeof(RTL_ATOM),\r
+                                                 &TableInformation->NumberOfAtoms,\r
+                                                 TableInformation->Atoms);\r
+            if (NT_SUCCESS(Status))\r
+            {\r
+                /* Update the return length */\r
+                *ReturnLength += TableInformation->NumberOfAtoms *\r
+                                 sizeof(RTL_ATOM);\r
+            }\r
             break;\r
 \r
+        /* Caller was on crack */\r
         default:\r
+\r
+            /* Unrecognized class */\r
             Status = STATUS_INVALID_INFO_CLASS;\r
     }\r
 \r