ntdll / kernel32: #52-e3

Eric Pouech eric.pouech at wanadoo.fr
Sun Dec 11 02:56:52 CST 2005


Finish moving atom handling from kernel32 to ntdll.
Fixed a couple of failing test at the same time.
A+
-- 
Eric Pouech
-------------- next part --------------
Subject: [PATCH]
- fixed ntdll's function about atom query (local / global)
- implemented kernel32 atom query functions on top of ntdll's ones

---

 dlls/kernel/atom.c             |  177 ++++++++++++++++++----------------------
 dlls/kernel/tests/atom.c       |   23 ++---
 dlls/ntdll/atom.c              |   81 +++++++++++++-----
 server/atom.c                  |    5 +
 server/protocol.def            |    3 -
 5 files changed, 153 insertions(+), 142 deletions(-)

applies-to: 410aa2e7eec4336305e9407ae20067321e790da6
bc0753b7a64146dc9bb5821b9d24fde0f72216c1
diff --git a/dlls/kernel/atom.c b/dlls/kernel/atom.c
index 5db47e8..4ea0f5f 100644
--- a/dlls/kernel/atom.c
+++ b/dlls/kernel/atom.c
@@ -398,59 +398,6 @@ ATOM WINAPI FindAtomW( LPCWSTR str )
 }
 
 
-static UINT ATOM_GetAtomNameA( ATOM atom, LPSTR buffer, INT count, struct atom_table* table )
-{
-    INT len;
-
-    if (count <= 0)
-    {
-        SetLastError( ERROR_MORE_DATA );
-        return 0;
-    }
-    if (atom < MAXINTATOM)
-    {
-        char name[8];
-        if (!atom)
-        {
-            SetLastError( ERROR_INVALID_PARAMETER );
-            return 0;
-        }
-        len = sprintf( name, "#%d", atom );
-        lstrcpynA( buffer, name, count );
-    }
-    else
-    {
-        WCHAR full_name[MAX_ATOM_LEN];
-
-        len = 0;
-        SERVER_START_REQ( get_atom_information )
-        {
-            req->atom = atom;
-            req->table = table;
-            wine_server_set_reply( req, full_name, sizeof(full_name) );
-            if (!wine_server_call_err( req ))
-            {
-                len = WideCharToMultiByte( CP_ACP, 0, full_name,
-                                           wine_server_reply_size(reply) / sizeof(WCHAR),
-                                           buffer, count - 1, NULL, NULL );
-                if (!len) len = count; /* overflow */
-                else buffer[len] = 0;
-            }
-        }
-        SERVER_END_REQ;
-    }
-
-    if (len && count <= len)
-    {
-        SetLastError( ERROR_MORE_DATA );
-        buffer[count-1] = 0;
-        return 0;
-    }
-    TRACE( "(%s) %x -> %s\n", table ? "local" : "global", atom, debugstr_a(buffer) );
-    return len;
-}
-
-
 /***********************************************************************
  *           GlobalGetAtomNameA   (KERNEL32.@)
  *
@@ -465,7 +412,25 @@ UINT WINAPI GlobalGetAtomNameA(
               LPSTR buffer, /* [out] Pointer to buffer for atom string */
               INT count )   /* [in]  Size of buffer */
 {
-    return ATOM_GetAtomNameA( atom, buffer, count, NULL );
+    WCHAR       tmpW[MAX_ATOM_LEN + 1];
+    UINT        wlen, len = 0, c;
+
+    if (count <= 0) SetLastError( ERROR_MORE_DATA );
+    else if ((wlen = GlobalGetAtomNameW( atom, tmpW, MAX_ATOM_LEN + 1 )))
+    {
+        char    tmp[MAX_ATOM_LEN + 1];
+
+        len = WideCharToMultiByte( CP_ACP, 0, tmpW, wlen, tmp, MAX_ATOM_LEN + 1, NULL, NULL );
+        c = min(len, count - 1);
+        memcpy(buffer, tmp, c);
+        buffer[c] = '\0';
+        if (len >= count)
+        {
+            len = 0;
+            SetLastError( ERROR_MORE_DATA );
+        }
+    }
+    return len;
 }
 
 
@@ -483,53 +448,24 @@ UINT WINAPI GetAtomNameA(
               LPSTR buffer, /* [out] Pointer to string for atom string */
               INT count)    /* [in]  Size of buffer */
 {
-    return ATOM_GetAtomNameA( atom, buffer, count, get_local_table(0) );
-}
+    WCHAR       tmpW[MAX_ATOM_LEN + 1];
+    UINT        wlen, len = 0, c;
 
-
-static UINT ATOM_GetAtomNameW( ATOM atom, LPWSTR buffer, INT count, struct atom_table* table )
-{
-    INT len;
-
-    if (count <= 0)
+    if (count <= 0) SetLastError( ERROR_MORE_DATA );
+    else if ((wlen = GetAtomNameW( atom, tmpW, MAX_ATOM_LEN + 1 )))
     {
-        SetLastError( ERROR_MORE_DATA );
-        return 0;
-    }
-    if (atom < MAXINTATOM)
-    {
-        char name[8];
-        if (!atom)
-        {
-            SetLastError( ERROR_INVALID_PARAMETER );
-            return 0;
-        }
-        sprintf( name, "#%d", atom );
-        len = MultiByteToWideChar( CP_ACP, 0, name, -1, buffer, count );
-        if (!len) buffer[count-1] = 0;  /* overflow */
-    }
-    else
-    {
-        WCHAR full_name[MAX_ATOM_LEN];
+        char    tmp[MAX_ATOM_LEN + 1];
 
-        len = 0;
-        SERVER_START_REQ( get_atom_information )
+        len = WideCharToMultiByte( CP_ACP, 0, tmpW, wlen, tmp, MAX_ATOM_LEN + 1, NULL, NULL );
+        c = min(len, count - 1);
+        memcpy(buffer, tmp, c);
+        buffer[c] = '\0';
+        if (len >= count)
         {
-            req->atom = atom;
-            req->table = table;
-            wine_server_set_reply( req, full_name, sizeof(full_name) );
-            if (!wine_server_call_err( req ))
-            {
-                len = wine_server_reply_size(reply) / sizeof(WCHAR);
-                if (count > len) count = len + 1;
-                memcpy( buffer, full_name, (count-1) * sizeof(WCHAR) );
-                buffer[count-1] = 0;
-            }
+            len = c;
+            SetLastError( ERROR_MORE_DATA );
         }
-        SERVER_END_REQ;
-        if (!len) return 0;
     }
-    TRACE( "(%s) %x -> %s\n", table ? "local" : "global", atom, debugstr_w(buffer) );
     return len;
 }
 
@@ -541,7 +477,31 @@ static UINT ATOM_GetAtomNameW( ATOM atom
  */
 UINT WINAPI GlobalGetAtomNameW( ATOM atom, LPWSTR buffer, INT count )
 {
-    return ATOM_GetAtomNameW( atom, buffer, count, NULL);
+    char        ptr[sizeof(ATOM_BASIC_INFORMATION) + MAX_ATOM_LEN * sizeof(WCHAR)];
+    ATOM_BASIC_INFORMATION*     abi = (ATOM_BASIC_INFORMATION*)ptr;
+    ULONG       ptr_size = sizeof(ATOM_BASIC_INFORMATION) + MAX_ATOM_LEN * sizeof(WCHAR);
+    NTSTATUS    status;
+    UINT        length = 0;
+
+    if (count <= 0)
+    {
+        SetLastError( ERROR_MORE_DATA );
+        return 0;
+    }
+    status = NtQueryInformationAtom( atom, AtomBasicInformation, (void*)ptr, ptr_size, NULL );
+    if (status) SetLastError( RtlNtStatusToDosError( status ) );
+    else
+    {
+        length = min( abi->NameLength / sizeof(WCHAR), count);
+        memcpy( buffer, abi->Name, length * sizeof(WCHAR) );
+        if (length < abi->NameLength / sizeof(WCHAR))
+        {
+            SetLastError( ERROR_MORE_DATA );
+            length = count;
+        }
+        else buffer[length] = '\0';
+    }
+    return length;
 }
 
 
@@ -552,5 +512,28 @@ UINT WINAPI GlobalGetAtomNameW( ATOM ato
  */
 UINT WINAPI GetAtomNameW( ATOM atom, LPWSTR buffer, INT count )
 {
-    return ATOM_GetAtomNameW( atom, buffer, count, get_local_table(0) );
+    NTSTATUS            status;
+    RTL_ATOM_TABLE      table;
+    DWORD               length;
+    WCHAR               tmp[MAX_ATOM_LEN + 1];
+
+    if (count <= 0)
+    {
+        SetLastError( ERROR_MORE_DATA );
+        return 0;
+    }
+    if (!(table = get_local_table( 0 ))) return 0;
+    length = sizeof(tmp);
+    status = RtlQueryAtomInAtomTable( table, atom, NULL, NULL, tmp, &length );
+    if (status)
+    {
+        SetLastError( RtlNtStatusToDosError( status ) );
+        return 0;
+    }
+    length = min(length, (count - 1) * sizeof(WCHAR));
+    if (length) memcpy(buffer, tmp, length);
+    else SetLastError( ERROR_INSUFFICIENT_BUFFER );
+    length /= sizeof(WCHAR);
+    buffer[length] = '\0';
+    return length;
 }
diff --git a/dlls/kernel/tests/atom.c b/dlls/kernel/tests/atom.c
index 5ab53b7..2fbce32 100644
--- a/dlls/kernel/tests/atom.c
+++ b/dlls/kernel/tests/atom.c
@@ -262,10 +262,7 @@ static void test_get_atom_name(void)
             {
                 WCHAR res[20];
                 
-                if (len < 7) /* FIXME: temporary before we fix it */
-                    ok( (len > 1) && (len < 7), "bad length %d\n", len );
-                else
-                    todo_wine ok( (len > 1) && (len < 7), "bad length %d\n", len );
+                ok( (len > 1) && (len < 7), "bad length %d\n", len );
                 print_integral( res, i );
                 memset( res + lstrlenW(res) + 1, 'a', 10 * sizeof(WCHAR));
                 ok( !memcmp( res, outW, 10 * sizeof(WCHAR) ), "bad buffer contents for %d\n", i );
@@ -277,7 +274,7 @@ static void test_get_atom_name(void)
             len = GlobalGetAtomNameW( (ATOM)i, outW, 1);
             if (i)
             {
-                todo_wine ok(len == 1, "succeed (got %u instead of 1)\n", len);
+                ok(len == 1, "succeed (got %u instead of 1)\n", len);
                 ok(outW[1] == DOUBLE('.'), "buffer overwrite\n");
             }
             else ok(len == 0 && GetLastError() == ERROR_INVALID_PARAMETER, "0 badly handled\n");
@@ -295,13 +292,10 @@ static void test_get_atom_name(void)
         ok(outW[255] == '\0', "wrong end of string\n");
         memset(outW, '.', sizeof(outW));
         len = GlobalGetAtomNameW(atom, outW, 10);
-        todo_wine ok(len == 10, "succeeded\n");
+        ok(len == 10, "succeeded\n");
         for (i = 0; i < 10; i++)
         {
-            if (i < 9) /* FIXME: temporary */
-                ok(outW[i] == "abcdefghij"[i % 10], "wrong string at %i (%c instead of %c)\n", i, outW[i], "abcdefghij"[i % 10]);
-            else
-                todo_wine ok(outW[i] == "abcdefghij"[i % 10], "wrong string at %i (%c instead of %c)\n", i, outW[i], "abcdefghij"[i % 10]);
+            ok(outW[i] == "abcdefghij"[i % 10], "wrong string at %i (%c instead of %c)\n", i, outW[i], "abcdefghij"[i % 10]);
         }
         ok(outW[10] == DOUBLE('.'), "wrote after end of buf\n");
         do_initW(inW, "abcdefghij", 256);
@@ -488,7 +482,7 @@ static void test_local_get_atom_name(voi
     ok(out[255] == '\0', "wrong end of string\n");
     memset(out, '.', sizeof(out));
     len = GetAtomNameA(atom, out, 10);
-    todo_wine ok(len == 9, "succeeded %d\n", len);
+    ok(len == 9, "succeeded %d\n", len);
     for (i = 0; i < 9; i++)
     {
         ok(out[i] == "abcdefghij"[i % 10], "wrong string at %i (%c instead of %c)\n", i, out[i], "abcdefghij"[i % 10]);
@@ -516,10 +510,7 @@ static void test_local_get_atom_name(voi
             {
                 WCHAR res[20];
                 
-                if (len < 7) /* FIXME: temporary before we fix it */
-                    ok( (len > 1) && (len < 7), "bad length %d\n", len );
-                else
-                    todo_wine ok( (len > 1) && (len < 7), "bad length %d\n", len );
+                ok( (len > 1) && (len < 7), "bad length %d\n", len );
                 print_integral( res, i );
                 memset( res + lstrlenW(res) + 1, 'a', 10 * sizeof(WCHAR));
                 ok( !memcmp( res, outW, 10 * sizeof(WCHAR) ), "bad buffer contents for %d\n", i );
@@ -547,7 +538,7 @@ static void test_local_get_atom_name(voi
         ok(outW[255] == '\0', "wrong end of string\n");
         memset(outW, '.', sizeof(outW));
         len = GetAtomNameW(atom, outW, 10);
-        todo_wine ok(len == 9, "succeeded %d\n", len);
+        ok(len == 9, "succeeded %d\n", len);
         for (i = 0; i < 9; i++)
         {
             ok(outW[i] == "abcdefghij"[i % 10], "wrong string at %i (%c instead of %c)\n", i, outW[i], "abcdefghij"[i % 10]);
diff --git a/dlls/ntdll/atom.c b/dlls/ntdll/atom.c
index bdef98b..4d63217 100644
--- a/dlls/ntdll/atom.c
+++ b/dlls/ntdll/atom.c
@@ -98,24 +98,43 @@ NTSTATUS WINAPI RtlDeleteAtomFromAtomTab
 }
 
 /******************************************************************
+ *		integral_atom_name (internal)
+ *
+ * Helper for fetching integral (local/global) atoms names.
+ */
+static ULONG integral_atom_name(WCHAR* buffer, ULONG len, RTL_ATOM atom)
+{
+    static WCHAR fmt[] = {'#','%','d',0};
+    int ret;
+
+    if (!len)
+    {
+        WCHAR   tmp[16];
+        return integral_atom_name( tmp, sizeof(tmp)/sizeof(tmp[0]), atom );
+    }
+    len /= sizeof(WCHAR);
+    ret = snprintfW( buffer, len, fmt, atom );
+    if (ret == -1)
+        buffer[--len] = '\0';
+    else
+        len = ret;
+    return len * sizeof(WCHAR);
+}
+
+/******************************************************************
  *		RtlQueryAtomInAtomTable (NTDLL.@)
  */
 NTSTATUS WINAPI RtlQueryAtomInAtomTable( RTL_ATOM_TABLE table, RTL_ATOM atom, ULONG* ref,
                                          ULONG* pin, WCHAR* name, ULONG* len )
 {
     NTSTATUS    status = STATUS_SUCCESS;
-    WCHAR       full_name[MAX_ATOM_LEN];
     DWORD       wlen = 0;
 
     if (!table) status = STATUS_INVALID_PARAMETER;
     else if (atom < MAXINTATOM)
     {
         if (!atom) return STATUS_INVALID_PARAMETER;
-        if (len)
-        {
-            static WCHAR fmt[] = {'#','%','d',0};
-            wlen = sprintfW( full_name, fmt, atom ) * sizeof(WCHAR);
-        }
+        if (len) wlen = integral_atom_name( name, *len, atom);
         if (ref) *ref = 1;
         if (pin) *pin = 1;
     }
@@ -125,11 +144,12 @@ NTSTATUS WINAPI RtlQueryAtomInAtomTable(
         {
             req->atom = atom;
             req->table = table;
-            if (len) wine_server_set_reply( req, full_name, sizeof(full_name) );
+            if (len && *len && name)
+                wine_server_set_reply( req, name, *len );
             status = wine_server_call( req );
             if (status == STATUS_SUCCESS)
             {
-                wlen = wine_server_reply_size( reply );
+                wlen = reply->total;
                 if (ref) *ref = reply->count;
                 if (pin) *pin = reply->pinned;
             }
@@ -138,17 +158,17 @@ NTSTATUS WINAPI RtlQueryAtomInAtomTable(
     }
     if (status == STATUS_SUCCESS && len)
     {
-        if (*len > wlen)
+        if (*len)
         {
-            memcpy( name, full_name, wlen );
-            name[wlen / sizeof(WCHAR)] = 0;
+            wlen = min( *len - sizeof(WCHAR), wlen );
+            if (name) name[wlen / sizeof(WCHAR)] = 0;
         }
         else status = STATUS_BUFFER_TOO_SMALL;
         *len = wlen;
     }
 
-    TRACE( "%p %x -> %s (%lu)\n",
-           table, atom, len ? debugstr_w(name) : NULL, status );
+    TRACE( "%p %x -> %s (%lx)\n",
+           table, atom, len ? debugstr_wn(name, wlen / sizeof(WCHAR)) : NULL, status );
     return status;
 }
 
@@ -372,20 +392,20 @@ NTSTATUS WINAPI NtQueryInformationAtom( 
             ULONG name_len;
             ATOM_BASIC_INFORMATION* abi = (ATOM_BASIC_INFORMATION*)ptr;
 
-            name_len = size - (sizeof(ATOM_BASIC_INFORMATION) - sizeof(WCHAR));
+            if (size < sizeof(ATOM_BASIC_INFORMATION))
+                return STATUS_INVALID_PARAMETER;
+            name_len = size - sizeof(ATOM_BASIC_INFORMATION);
 
             if (atom < MAXINTATOM)
             {
-                if (!atom) status = STATUS_INVALID_PARAMETER;
-                else if (name_len >= 7 * sizeof(WCHAR))
+                if (atom)
                 {
-                    static WCHAR fmt[] = {'#','%','d',0};
-                    abi->NameLength = snprintfW( abi->Name, name_len / sizeof(WCHAR), fmt, atom ) * sizeof(WCHAR);
+                    abi->NameLength = integral_atom_name( abi->Name, name_len, atom );
+                    status = (name_len) ? STATUS_SUCCESS : STATUS_BUFFER_TOO_SMALL;
                     abi->ReferenceCount = 1;
                     abi->Pinned = 1;
-                    status = STATUS_SUCCESS;
                 }
-                else status = STATUS_BUFFER_TOO_SMALL;
+                else status = STATUS_INVALID_PARAMETER;
             }
             else
             {
@@ -395,19 +415,32 @@ NTSTATUS WINAPI NtQueryInformationAtom( 
                     req->table = NULL;
                     if (name_len) wine_server_set_reply( req, abi->Name, name_len );
                     status = wine_server_call( req );
-                    name_len = wine_server_reply_size( reply );
                     if (status == STATUS_SUCCESS)
                     {
-                        abi->NameLength = name_len;
+                        name_len = wine_server_reply_size( reply );
+                        if (name_len)
+                        {
+                            abi->NameLength = name_len;
+                            abi->Name[name_len / sizeof(WCHAR)] = '\0';
+                        }
+                        else
+                        {
+                            name_len = reply->total;
+                            abi->NameLength = name_len;
+                            status = STATUS_BUFFER_TOO_SMALL;
+                        }
                         abi->ReferenceCount = reply->count;
                         abi->Pinned = reply->pinned;
                     }
+                    else name_len = 0;
                 }
                 SERVER_END_REQ;
             }
-            TRACE( "%x -> %s (%lu)\n", atom, debugstr_wn(abi->Name, name_len/sizeof(WCHAR)), status );
+            TRACE( "%x -> %s (%lu)\n", 
+                   atom, debugstr_wn(abi->Name, abi->NameLength / sizeof(WCHAR)),
+                   status );
             if (psize)
-                *psize = sizeof(ATOM_BASIC_INFORMATION) - sizeof(WCHAR) + name_len;
+                *psize = sizeof(ATOM_BASIC_INFORMATION) + name_len;
         }
         break;
     default:
diff --git a/server/atom.c b/server/atom.c
index e42a503..3ad6c04 100644
--- a/server/atom.c
+++ b/server/atom.c
@@ -412,10 +412,11 @@ DECL_HANDLER(get_atom_information)
         if ((entry = get_atom_entry( table, req->atom )))
         {
             size_t len = entry->len * sizeof(WCHAR);
-            if (len <= get_reply_max_size()) set_reply_data( entry->str, len );
-            else if (get_reply_max_size()) set_error( STATUS_BUFFER_OVERFLOW );
+            if (get_reply_max_size())
+                set_reply_data( entry->str, min( len, get_reply_max_size()));
             reply->count = entry->count;
             reply->pinned = entry->pinned;
+            reply->total = len;
         }
         else reply->count = -1;
         release_object( table );
diff --git a/server/protocol.def b/server/protocol.def
index 3d055cb..58e369b 100644
--- a/server/protocol.def
+++ b/server/protocol.def
@@ -1476,6 +1476,7 @@ enum char_info_mode
 @REPLY
     int          count;        /* atom lock count */
     int          pinned;       /* whether the atom has been pinned */
+    size_t       total;        /* actual length of atom name */
     VARARG(name,unicode_str);  /* atom name */
 @END
 
---
0.99.9k


More information about the wine-patches mailing list