810 lines
21 KiB
C
810 lines
21 KiB
C
/*
|
|
* Atom table functions
|
|
*
|
|
* Copyright 1993, 1994, 1995 Alexandre Julliard
|
|
*/
|
|
|
|
/*
|
|
* Warning: The code assumes that LocalAlloc() returns a block aligned
|
|
* on a 4-bytes boundary (because of the shifting done in
|
|
* HANDLETOATOM). If this is not the case, the allocation code will
|
|
* have to be changed.
|
|
*/
|
|
|
|
#include "config.h"
|
|
|
|
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <ctype.h>
|
|
|
|
#include "windef.h"
|
|
#include "winerror.h"
|
|
|
|
#include "wine/server.h"
|
|
#include "wine/unicode.h"
|
|
#include "wine/winbase16.h"
|
|
#include "global.h"
|
|
#include "instance.h"
|
|
#include "stackframe.h"
|
|
|
|
#include "debugtools.h"
|
|
|
|
DEFAULT_DEBUG_CHANNEL(atom);
|
|
|
|
#define DEFAULT_ATOMTABLE_SIZE 37
|
|
#define MIN_STR_ATOM 0xc000
|
|
#define MAX_ATOM_LEN 255
|
|
|
|
#define ATOMTOHANDLE(atom) ((HANDLE16)(atom) << 2)
|
|
#define HANDLETOATOM(handle) ((ATOM)(0xc000 | ((handle) >> 2)))
|
|
|
|
typedef struct
|
|
{
|
|
HANDLE16 next;
|
|
WORD refCount;
|
|
BYTE length;
|
|
BYTE str[1];
|
|
} ATOMENTRY;
|
|
|
|
typedef struct
|
|
{
|
|
WORD size;
|
|
HANDLE16 entries[1];
|
|
} ATOMTABLE;
|
|
|
|
static WORD ATOM_UserDS = 0; /* USER data segment */
|
|
|
|
/***********************************************************************
|
|
* ATOM_Init
|
|
*
|
|
* Global table initialisation.
|
|
*/
|
|
BOOL ATOM_Init( WORD globalTableSel )
|
|
{
|
|
ATOM_UserDS = globalTableSel;
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
* ATOM_GetTable
|
|
*
|
|
* Return a pointer to the atom table of a given segment, creating
|
|
* it if necessary.
|
|
*
|
|
* RETURNS
|
|
* Pointer to table: Success
|
|
* NULL: Failure
|
|
*/
|
|
static ATOMTABLE *ATOM_GetTable( BOOL create /* [in] Create */ )
|
|
{
|
|
INSTANCEDATA *ptr = MapSL( MAKESEGPTR( CURRENT_DS, 0 ) );
|
|
if (ptr->atomtable)
|
|
{
|
|
ATOMTABLE *table = (ATOMTABLE *)((char *)ptr + ptr->atomtable);
|
|
if (table->size) return table;
|
|
}
|
|
if (!create) return NULL;
|
|
if (!InitAtomTable16( 0 )) return NULL;
|
|
/* Reload ptr in case it moved in linear memory */
|
|
ptr = MapSL( MAKESEGPTR( CURRENT_DS, 0 ) );
|
|
return (ATOMTABLE *)((char *)ptr + ptr->atomtable);
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
* ATOM_Hash
|
|
* RETURNS
|
|
* The hash value for the input string
|
|
*/
|
|
static WORD ATOM_Hash(
|
|
WORD entries, /* [in] Total number of entries */
|
|
LPCSTR str, /* [in] Pointer to string to hash */
|
|
WORD len /* [in] Length of string */
|
|
) {
|
|
WORD i, hash = 0;
|
|
|
|
TRACE("%x, %s, %x\n", entries, str, len);
|
|
|
|
for (i = 0; i < len; i++) hash ^= toupper(str[i]) + i;
|
|
return hash % entries;
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
* ATOM_IsIntAtomA
|
|
*/
|
|
static BOOL ATOM_IsIntAtomA(LPCSTR atomstr,WORD *atomid)
|
|
{
|
|
UINT atom = 0;
|
|
if (!HIWORD(atomstr)) atom = LOWORD(atomstr);
|
|
else
|
|
{
|
|
if (*atomstr++ != '#') return FALSE;
|
|
while (*atomstr >= '0' && *atomstr <= '9')
|
|
{
|
|
atom = atom * 10 + *atomstr - '0';
|
|
atomstr++;
|
|
}
|
|
if (*atomstr) return FALSE;
|
|
}
|
|
if (!atom || (atom >= MIN_STR_ATOM))
|
|
{
|
|
SetLastError( ERROR_INVALID_PARAMETER );
|
|
atom = 0;
|
|
}
|
|
*atomid = atom;
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
* ATOM_IsIntAtomW
|
|
*/
|
|
static BOOL ATOM_IsIntAtomW(LPCWSTR atomstr,WORD *atomid)
|
|
{
|
|
UINT atom = 0;
|
|
if (!HIWORD(atomstr)) atom = LOWORD(atomstr);
|
|
else
|
|
{
|
|
if (*atomstr++ != '#') return FALSE;
|
|
while (*atomstr >= '0' && *atomstr <= '9')
|
|
{
|
|
atom = atom * 10 + *atomstr - '0';
|
|
atomstr++;
|
|
}
|
|
if (*atomstr) return FALSE;
|
|
}
|
|
if (!atom || (atom >= MIN_STR_ATOM))
|
|
{
|
|
SetLastError( ERROR_INVALID_PARAMETER );
|
|
atom = 0;
|
|
}
|
|
*atomid = atom;
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
* ATOM_MakePtr
|
|
*
|
|
* Make an ATOMENTRY pointer from a handle (obtained from GetAtomHandle()).
|
|
*/
|
|
static inline ATOMENTRY *ATOM_MakePtr( HANDLE16 handle /* [in] Handle */ )
|
|
{
|
|
return MapSL( MAKESEGPTR( CURRENT_DS, handle ) );
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
* InitAtomTable (KERNEL.68)
|
|
*/
|
|
WORD WINAPI InitAtomTable16( WORD entries )
|
|
{
|
|
int i;
|
|
HANDLE16 handle;
|
|
ATOMTABLE *table;
|
|
|
|
/* We consider the first table to be initialized as the global table.
|
|
* This works, as USER (both built-in and native) is the first one to
|
|
* register ...
|
|
*/
|
|
|
|
if (!ATOM_UserDS)
|
|
{
|
|
ATOM_UserDS = CURRENT_DS;
|
|
/* return dummy local handle */
|
|
return LocalAlloc16( LMEM_FIXED, 1 );
|
|
}
|
|
|
|
/* Allocate the table */
|
|
|
|
if (!entries) entries = DEFAULT_ATOMTABLE_SIZE; /* sanity check */
|
|
handle = LocalAlloc16( LMEM_FIXED, sizeof(ATOMTABLE) + (entries-1) * sizeof(HANDLE16) );
|
|
if (!handle) return 0;
|
|
table = MapSL( MAKESEGPTR( CURRENT_DS, handle ) );
|
|
table->size = entries;
|
|
for (i = 0; i < entries; i++) table->entries[i] = 0;
|
|
|
|
/* Store a pointer to the table in the instance data */
|
|
|
|
((INSTANCEDATA *)MapSL( MAKESEGPTR( CURRENT_DS, 0 )))->atomtable = handle;
|
|
return handle;
|
|
}
|
|
|
|
/***********************************************************************
|
|
* GetAtomHandle (KERNEL.73)
|
|
*/
|
|
HANDLE16 WINAPI GetAtomHandle16( ATOM atom )
|
|
{
|
|
if (atom < MIN_STR_ATOM) return 0;
|
|
return ATOMTOHANDLE( atom );
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
* AddAtom (KERNEL.70)
|
|
*
|
|
* Windows DWORD aligns the atom entry size.
|
|
* The remaining unused string space created by the alignment
|
|
* gets padded with '\0's in a certain way to ensure
|
|
* that at least one trailing '\0' remains.
|
|
*
|
|
* RETURNS
|
|
* Atom: Success
|
|
* 0: Failure
|
|
*/
|
|
ATOM WINAPI AddAtom16( LPCSTR str )
|
|
{
|
|
char buffer[MAX_ATOM_LEN+1];
|
|
WORD hash;
|
|
HANDLE16 entry;
|
|
ATOMENTRY * entryPtr;
|
|
ATOMTABLE * table;
|
|
int len, ae_len;
|
|
WORD iatom;
|
|
|
|
if (ATOM_IsIntAtomA( str, &iatom )) return iatom;
|
|
|
|
TRACE("%s\n",debugstr_a(buffer));
|
|
|
|
/* Make a copy of the string to be sure it doesn't move in linear memory. */
|
|
lstrcpynA( buffer, str, sizeof(buffer) );
|
|
|
|
len = strlen( buffer );
|
|
if (!(table = ATOM_GetTable( TRUE ))) return 0;
|
|
if (CURRENT_DS == ATOM_UserDS) return GlobalAddAtomA( str );
|
|
|
|
hash = ATOM_Hash( table->size, buffer, len );
|
|
entry = table->entries[hash];
|
|
while (entry)
|
|
{
|
|
entryPtr = ATOM_MakePtr( entry );
|
|
if ((entryPtr->length == len) &&
|
|
(!strncasecmp( entryPtr->str, buffer, len )))
|
|
{
|
|
entryPtr->refCount++;
|
|
TRACE("-- existing 0x%x\n", entry);
|
|
return HANDLETOATOM( entry );
|
|
}
|
|
entry = entryPtr->next;
|
|
}
|
|
|
|
ae_len = (sizeof(ATOMENTRY)+len+3) & ~3;
|
|
entry = LocalAlloc16( LMEM_FIXED, ae_len );
|
|
if (!entry) return 0;
|
|
/* Reload the table ptr in case it moved in linear memory */
|
|
table = ATOM_GetTable( FALSE );
|
|
entryPtr = ATOM_MakePtr( entry );
|
|
entryPtr->next = table->entries[hash];
|
|
entryPtr->refCount = 1;
|
|
entryPtr->length = len;
|
|
/* Some applications _need_ the '\0' padding provided by this strncpy */
|
|
strncpy( entryPtr->str, buffer, ae_len - sizeof(ATOMENTRY) + 1 );
|
|
entryPtr->str[ae_len - sizeof(ATOMENTRY)] = '\0';
|
|
table->entries[hash] = entry;
|
|
TRACE("-- new 0x%x\n", entry);
|
|
return HANDLETOATOM( entry );
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
* DeleteAtom (KERNEL.71)
|
|
*/
|
|
ATOM WINAPI DeleteAtom16( ATOM atom )
|
|
{
|
|
ATOMENTRY * entryPtr;
|
|
ATOMTABLE * table;
|
|
HANDLE16 entry, *prevEntry;
|
|
WORD hash;
|
|
|
|
if (atom < MIN_STR_ATOM) return 0; /* Integer atom */
|
|
if (CURRENT_DS == ATOM_UserDS) return GlobalDeleteAtom( atom );
|
|
|
|
TRACE("0x%x\n",atom);
|
|
|
|
if (!(table = ATOM_GetTable( FALSE ))) return 0;
|
|
entry = ATOMTOHANDLE( atom );
|
|
entryPtr = ATOM_MakePtr( entry );
|
|
|
|
/* Find previous atom */
|
|
hash = ATOM_Hash( table->size, entryPtr->str, entryPtr->length );
|
|
prevEntry = &table->entries[hash];
|
|
while (*prevEntry && *prevEntry != entry)
|
|
{
|
|
ATOMENTRY * prevEntryPtr = ATOM_MakePtr( *prevEntry );
|
|
prevEntry = &prevEntryPtr->next;
|
|
}
|
|
if (!*prevEntry) return atom;
|
|
|
|
/* Delete atom */
|
|
if (--entryPtr->refCount == 0)
|
|
{
|
|
*prevEntry = entryPtr->next;
|
|
LocalFree16( entry );
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
* FindAtom (KERNEL.69)
|
|
*/
|
|
ATOM WINAPI FindAtom16( LPCSTR str )
|
|
{
|
|
ATOMTABLE * table;
|
|
WORD hash,iatom;
|
|
HANDLE16 entry;
|
|
int len;
|
|
|
|
if (CURRENT_DS == ATOM_UserDS) return GlobalFindAtomA( str );
|
|
|
|
TRACE("%s\n",debugres_a(str));
|
|
|
|
if (ATOM_IsIntAtomA( str, &iatom )) return iatom;
|
|
if ((len = strlen( str )) > 255) len = 255;
|
|
if (!(table = ATOM_GetTable( FALSE ))) return 0;
|
|
hash = ATOM_Hash( table->size, str, len );
|
|
entry = table->entries[hash];
|
|
while (entry)
|
|
{
|
|
ATOMENTRY * entryPtr = ATOM_MakePtr( entry );
|
|
if ((entryPtr->length == len) &&
|
|
(!strncasecmp( entryPtr->str, str, len )))
|
|
{
|
|
TRACE("-- found %x\n", entry);
|
|
return HANDLETOATOM( entry );
|
|
}
|
|
entry = entryPtr->next;
|
|
}
|
|
TRACE("-- not found\n");
|
|
return 0;
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
* GetAtomName (KERNEL.72)
|
|
*/
|
|
UINT16 WINAPI GetAtomName16( ATOM atom, LPSTR buffer, INT16 count )
|
|
{
|
|
ATOMTABLE * table;
|
|
ATOMENTRY * entryPtr;
|
|
HANDLE16 entry;
|
|
char * strPtr;
|
|
UINT len;
|
|
char text[8];
|
|
|
|
if (CURRENT_DS == ATOM_UserDS) return GlobalGetAtomNameA( atom, buffer, count );
|
|
|
|
TRACE("%x\n",atom);
|
|
|
|
if (!count) return 0;
|
|
if (atom < MIN_STR_ATOM)
|
|
{
|
|
sprintf( text, "#%d", atom );
|
|
len = strlen(text);
|
|
strPtr = text;
|
|
}
|
|
else
|
|
{
|
|
if (!(table = ATOM_GetTable( FALSE ))) return 0;
|
|
entry = ATOMTOHANDLE( atom );
|
|
entryPtr = ATOM_MakePtr( entry );
|
|
len = entryPtr->length;
|
|
strPtr = entryPtr->str;
|
|
}
|
|
if (len >= count) len = count-1;
|
|
memcpy( buffer, strPtr, len );
|
|
buffer[len] = '\0';
|
|
return len;
|
|
}
|
|
|
|
/***********************************************************************
|
|
* InitAtomTable (KERNEL32.@)
|
|
*/
|
|
BOOL WINAPI InitAtomTable( DWORD entries )
|
|
{
|
|
BOOL ret;
|
|
SERVER_START_REQ( init_atom_table )
|
|
{
|
|
req->entries = entries;
|
|
ret = !SERVER_CALL_ERR();
|
|
}
|
|
SERVER_END_REQ;
|
|
return ret;
|
|
}
|
|
|
|
|
|
static ATOM ATOM_AddAtomA( LPCSTR str, BOOL local )
|
|
{
|
|
ATOM atom = 0;
|
|
if (!ATOM_IsIntAtomA( str, &atom ))
|
|
{
|
|
DWORD len = MultiByteToWideChar( CP_ACP, 0, str, strlen(str), NULL, 0 );
|
|
if (len > MAX_ATOM_LEN)
|
|
{
|
|
SetLastError( ERROR_INVALID_PARAMETER );
|
|
return 0;
|
|
}
|
|
SERVER_START_VAR_REQ( add_atom, len * sizeof(WCHAR) )
|
|
{
|
|
MultiByteToWideChar( CP_ACP, 0, str, strlen(str), server_data_ptr(req), len );
|
|
req->local = local;
|
|
if (!SERVER_CALL_ERR()) atom = req->atom;
|
|
}
|
|
SERVER_END_VAR_REQ;
|
|
}
|
|
TRACE( "(%s) %s -> %x\n", local ? "local" : "global", debugres_a(str), atom );
|
|
return atom;
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
* GlobalAddAtomA (KERNEL32.@)
|
|
*
|
|
* Adds a character string to the global atom table and returns a unique
|
|
* value identifying the string.
|
|
*
|
|
* RETURNS
|
|
* Atom: Success
|
|
* 0: Failure
|
|
*/
|
|
ATOM WINAPI GlobalAddAtomA( LPCSTR str /* [in] Pointer to string to add */ )
|
|
{
|
|
return ATOM_AddAtomA( str, FALSE );
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
* AddAtomA (KERNEL32.@)
|
|
* Adds a string to the atom table and returns the atom identifying the
|
|
* string.
|
|
*
|
|
* RETURNS
|
|
* Atom: Success
|
|
* 0: Failure
|
|
*/
|
|
ATOM WINAPI AddAtomA( LPCSTR str /* [in] Pointer to string to add */ )
|
|
{
|
|
return ATOM_AddAtomA( str, TRUE );
|
|
}
|
|
|
|
|
|
static ATOM ATOM_AddAtomW( LPCWSTR str, BOOL local )
|
|
{
|
|
ATOM atom = 0;
|
|
if (!ATOM_IsIntAtomW( str, &atom ))
|
|
{
|
|
DWORD len = strlenW(str);
|
|
if (len > MAX_ATOM_LEN)
|
|
{
|
|
SetLastError( ERROR_INVALID_PARAMETER );
|
|
return 0;
|
|
}
|
|
SERVER_START_VAR_REQ( add_atom, len * sizeof(WCHAR) )
|
|
{
|
|
memcpy( server_data_ptr(req), str, len * sizeof(WCHAR) );
|
|
req->local = local;
|
|
if (!SERVER_CALL_ERR()) atom = req->atom;
|
|
}
|
|
SERVER_END_VAR_REQ;
|
|
}
|
|
TRACE( "(%s) %s -> %x\n", local ? "local" : "global", debugres_w(str), atom );
|
|
return atom;
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
* GlobalAddAtomW (KERNEL32.@)
|
|
*/
|
|
ATOM WINAPI GlobalAddAtomW( LPCWSTR str )
|
|
{
|
|
return ATOM_AddAtomW( str, FALSE );
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
* AddAtomW (KERNEL32.@)
|
|
*/
|
|
ATOM WINAPI AddAtomW( LPCWSTR str )
|
|
{
|
|
return ATOM_AddAtomW( str, TRUE );
|
|
}
|
|
|
|
|
|
static ATOM ATOM_DeleteAtom( ATOM atom, BOOL local)
|
|
{
|
|
TRACE( "(%s) %x\n", local ? "local" : "global", atom );
|
|
if (atom < MIN_STR_ATOM) atom = 0;
|
|
else
|
|
{
|
|
SERVER_START_REQ( delete_atom )
|
|
{
|
|
req->atom = atom;
|
|
req->local = local;
|
|
if (!SERVER_CALL_ERR()) atom = 0;
|
|
}
|
|
SERVER_END_REQ;
|
|
}
|
|
return atom;
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
* GlobalDeleteAtom (KERNEL32.@)
|
|
* Decrements the reference count of a string atom. If the count is
|
|
* zero, the string associated with the atom is removed from the table.
|
|
*
|
|
* RETURNS
|
|
* 0: Success
|
|
* Atom: Failure
|
|
*/
|
|
ATOM WINAPI GlobalDeleteAtom( ATOM atom /* [in] Atom to delete */ )
|
|
{
|
|
return ATOM_DeleteAtom( atom, FALSE);
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
* DeleteAtom (KERNEL32.@)
|
|
* Decrements the reference count of a string atom. If count becomes
|
|
* zero, the string associated with the atom is removed from the table.
|
|
*
|
|
* RETURNS
|
|
* 0: Success
|
|
* Atom: Failure
|
|
*/
|
|
ATOM WINAPI DeleteAtom( ATOM atom /* [in] Atom to delete */ )
|
|
{
|
|
return ATOM_DeleteAtom( atom, TRUE );
|
|
}
|
|
|
|
|
|
static ATOM ATOM_FindAtomA( LPCSTR str, BOOL local )
|
|
{
|
|
ATOM atom = 0;
|
|
if (!ATOM_IsIntAtomA( str, &atom ))
|
|
{
|
|
DWORD len = MultiByteToWideChar( CP_ACP, 0, str, strlen(str), NULL, 0 );
|
|
if (len > MAX_ATOM_LEN)
|
|
{
|
|
SetLastError( ERROR_INVALID_PARAMETER );
|
|
return 0;
|
|
}
|
|
SERVER_START_VAR_REQ( find_atom, len * sizeof(WCHAR) )
|
|
{
|
|
MultiByteToWideChar( CP_ACP, 0, str, strlen(str), server_data_ptr(req), len );
|
|
req->local = local;
|
|
if (!SERVER_CALL_ERR()) atom = req->atom;
|
|
}
|
|
SERVER_END_VAR_REQ;
|
|
}
|
|
TRACE( "(%s) %s -> %x\n", local ? "local" : "global", debugres_a(str), atom );
|
|
return atom;
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
* GlobalFindAtomA (KERNEL32.@)
|
|
*
|
|
* Searches the atom table for the string and returns the atom
|
|
* associated with it.
|
|
*
|
|
* RETURNS
|
|
* Atom: Success
|
|
* 0: Failure
|
|
*/
|
|
ATOM WINAPI GlobalFindAtomA( LPCSTR str /* [in] Pointer to string to search for */ )
|
|
{
|
|
return ATOM_FindAtomA( str, FALSE );
|
|
}
|
|
|
|
/***********************************************************************
|
|
* FindAtomA (KERNEL32.@)
|
|
* Searches the local atom table for the string and returns the atom
|
|
* associated with that string.
|
|
*
|
|
* RETURNS
|
|
* Atom: Success
|
|
* 0: Failure
|
|
*/
|
|
ATOM WINAPI FindAtomA( LPCSTR str /* [in] Pointer to string to find */ )
|
|
{
|
|
return ATOM_FindAtomA( str, TRUE );
|
|
}
|
|
|
|
|
|
static ATOM ATOM_FindAtomW( LPCWSTR str, BOOL local )
|
|
{
|
|
ATOM atom = 0;
|
|
if (!ATOM_IsIntAtomW( str, &atom ))
|
|
{
|
|
DWORD len = strlenW(str);
|
|
if (len > MAX_ATOM_LEN)
|
|
{
|
|
SetLastError( ERROR_INVALID_PARAMETER );
|
|
return 0;
|
|
}
|
|
SERVER_START_VAR_REQ( find_atom, len * sizeof(WCHAR) )
|
|
{
|
|
memcpy( server_data_ptr(req), str, len * sizeof(WCHAR) );
|
|
req->local = local;
|
|
if (!SERVER_CALL_ERR()) atom = req->atom;
|
|
}
|
|
SERVER_END_VAR_REQ;
|
|
}
|
|
TRACE( "(%s) %s -> %x\n", local ? "local" : "global", debugres_w(str), atom );
|
|
return atom;
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
* GlobalFindAtomW (KERNEL32.@)
|
|
*/
|
|
ATOM WINAPI GlobalFindAtomW( LPCWSTR str )
|
|
{
|
|
return ATOM_FindAtomW( str, FALSE );
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
* FindAtomW (KERNEL32.@)
|
|
*/
|
|
ATOM WINAPI FindAtomW( LPCWSTR str )
|
|
{
|
|
return ATOM_FindAtomW( str, TRUE );
|
|
}
|
|
|
|
|
|
static UINT ATOM_GetAtomNameA( ATOM atom, LPSTR buffer, INT count, BOOL local )
|
|
{
|
|
INT len;
|
|
|
|
if (count <= 0)
|
|
{
|
|
SetLastError( ERROR_MORE_DATA );
|
|
return 0;
|
|
}
|
|
if (atom < MIN_STR_ATOM)
|
|
{
|
|
char name[8];
|
|
if (!atom)
|
|
{
|
|
SetLastError( ERROR_INVALID_PARAMETER );
|
|
return 0;
|
|
}
|
|
len = sprintf( name, "#%d", atom );
|
|
lstrcpynA( buffer, name, count );
|
|
}
|
|
else
|
|
{
|
|
len = 0;
|
|
SERVER_START_VAR_REQ( get_atom_name, MAX_ATOM_LEN * sizeof(WCHAR) )
|
|
{
|
|
req->atom = atom;
|
|
req->local = local;
|
|
if (!SERVER_CALL_ERR())
|
|
{
|
|
len = WideCharToMultiByte( CP_ACP, 0, server_data_ptr(req),
|
|
server_data_size(req) / sizeof(WCHAR),
|
|
buffer, count - 1, NULL, NULL );
|
|
if (!len) len = count; /* overflow */
|
|
else buffer[len] = 0;
|
|
}
|
|
}
|
|
SERVER_END_VAR_REQ;
|
|
}
|
|
|
|
if (len && count <= len)
|
|
{
|
|
SetLastError( ERROR_MORE_DATA );
|
|
buffer[count-1] = 0;
|
|
return 0;
|
|
}
|
|
TRACE( "(%s) %x -> %s\n", local ? "local" : "global", atom, debugstr_a(buffer) );
|
|
return len;
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
* GlobalGetAtomNameA (KERNEL32.@)
|
|
*
|
|
* Retrieves a copy of the string associated with an atom.
|
|
*
|
|
* RETURNS
|
|
* Length of string in characters: Success
|
|
* 0: Failure
|
|
*/
|
|
UINT WINAPI GlobalGetAtomNameA(
|
|
ATOM atom, /* [in] Atom identifier */
|
|
LPSTR buffer, /* [out] Pointer to buffer for atom string */
|
|
INT count ) /* [in] Size of buffer */
|
|
{
|
|
return ATOM_GetAtomNameA( atom, buffer, count, FALSE );
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
* GetAtomNameA (KERNEL32.@)
|
|
* Retrieves a copy of the string associated with the atom.
|
|
*
|
|
* RETURNS
|
|
* Length of string: Success
|
|
* 0: Failure
|
|
*/
|
|
UINT WINAPI GetAtomNameA(
|
|
ATOM atom, /* [in] Atom */
|
|
LPSTR buffer, /* [out] Pointer to string for atom string */
|
|
INT count) /* [in] Size of buffer */
|
|
{
|
|
return ATOM_GetAtomNameA( atom, buffer, count, TRUE );
|
|
}
|
|
|
|
|
|
static UINT ATOM_GetAtomNameW( ATOM atom, LPWSTR buffer, INT count, BOOL local )
|
|
{
|
|
INT len;
|
|
|
|
if (count <= 0)
|
|
{
|
|
SetLastError( ERROR_MORE_DATA );
|
|
return 0;
|
|
}
|
|
if (atom < MIN_STR_ATOM)
|
|
{
|
|
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
|
|
{
|
|
len = 0;
|
|
SERVER_START_VAR_REQ( get_atom_name, MAX_ATOM_LEN * sizeof(WCHAR) )
|
|
{
|
|
req->atom = atom;
|
|
req->local = local;
|
|
if (!SERVER_CALL_ERR())
|
|
{
|
|
len = server_data_size(req) / sizeof(WCHAR);
|
|
if (count > len) count = len + 1;
|
|
memcpy( buffer, server_data_ptr(req), (count-1) * sizeof(WCHAR) );
|
|
buffer[count-1] = 0;
|
|
}
|
|
}
|
|
SERVER_END_VAR_REQ;
|
|
if (!len) return 0;
|
|
}
|
|
if (count <= len)
|
|
{
|
|
SetLastError( ERROR_MORE_DATA );
|
|
return 0;
|
|
}
|
|
TRACE( "(%s) %x -> %s\n", local ? "local" : "global", atom, debugstr_w(buffer) );
|
|
return len;
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
* GlobalGetAtomNameW (KERNEL32.@)
|
|
*/
|
|
UINT WINAPI GlobalGetAtomNameW( ATOM atom, LPWSTR buffer, INT count )
|
|
{
|
|
return ATOM_GetAtomNameW( atom, buffer, count, FALSE);
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
* GetAtomNameW (KERNEL32.@)
|
|
*/
|
|
UINT WINAPI GetAtomNameW( ATOM atom, LPWSTR buffer, INT count )
|
|
{
|
|
return ATOM_GetAtomNameW( atom, buffer, count, TRUE );
|
|
}
|