4 * Copyright 1993, 1994, 1995 Alexandre Julliard
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 * Warning: The code assumes that LocalAlloc() returns a block aligned
23 * on a 4-bytes boundary (because of the shifting done in
24 * HANDLETOATOM). If this is not the case, the allocation code will
29 #include "wine/port.h"
41 #include "wine/server.h"
42 #include "wine/unicode.h"
43 #include "wine/winbase16.h"
44 #include "kernel_private.h"
45 #include "stackframe.h"
47 #include "wine/debug.h"
49 WINE_DEFAULT_DEBUG_CHANNEL(atom);
51 #define DEFAULT_ATOMTABLE_SIZE 37
52 #define MAX_ATOM_LEN 255
54 #define ATOMTOHANDLE(atom) ((HANDLE16)(atom) << 2)
55 #define HANDLETOATOM(handle) ((ATOM)(0xc000 | ((handle) >> 2)))
72 /***********************************************************************
75 * Return a pointer to the atom table of a given segment, creating
79 * Pointer to table: Success
82 static ATOMTABLE *ATOM_GetTable( BOOL create /* [in] Create */ )
84 INSTANCEDATA *ptr = MapSL( MAKESEGPTR( CURRENT_DS, 0 ) );
87 ATOMTABLE *table = (ATOMTABLE *)((char *)ptr + ptr->atomtable);
88 if (table->size) return table;
90 if (!create) return NULL;
91 if (!InitAtomTable16( 0 )) return NULL;
92 /* Reload ptr in case it moved in linear memory */
93 ptr = MapSL( MAKESEGPTR( CURRENT_DS, 0 ) );
94 return (ATOMTABLE *)((char *)ptr + ptr->atomtable);
98 /***********************************************************************
101 * The hash value for the input string
103 static WORD ATOM_Hash(
104 WORD entries, /* [in] Total number of entries */
105 LPCSTR str, /* [in] Pointer to string to hash */
106 WORD len /* [in] Length of string */
110 TRACE("%x, %s, %x\n", entries, str, len);
112 for (i = 0; i < len; i++) hash ^= toupper(str[i]) + i;
113 return hash % entries;
117 /***********************************************************************
120 static BOOL ATOM_IsIntAtomA(LPCSTR atomstr,WORD *atomid)
123 if (!HIWORD(atomstr)) atom = LOWORD(atomstr);
126 if (*atomstr++ != '#') return FALSE;
127 while (*atomstr >= '0' && *atomstr <= '9')
129 atom = atom * 10 + *atomstr - '0';
132 if (*atomstr) return FALSE;
134 if (atom >= MAXINTATOM)
136 SetLastError( ERROR_INVALID_PARAMETER );
144 /***********************************************************************
147 static BOOL ATOM_IsIntAtomW(LPCWSTR atomstr,WORD *atomid)
150 if (!HIWORD(atomstr)) atom = LOWORD(atomstr);
153 if (*atomstr++ != '#') return FALSE;
154 while (*atomstr >= '0' && *atomstr <= '9')
156 atom = atom * 10 + *atomstr - '0';
159 if (*atomstr) return FALSE;
161 if (atom >= MAXINTATOM)
163 SetLastError( ERROR_INVALID_PARAMETER );
171 /***********************************************************************
174 * Make an ATOMENTRY pointer from a handle (obtained from GetAtomHandle()).
176 static inline ATOMENTRY *ATOM_MakePtr( HANDLE16 handle /* [in] Handle */ )
178 return MapSL( MAKESEGPTR( CURRENT_DS, handle ) );
182 /***********************************************************************
183 * InitAtomTable (KERNEL.68)
185 WORD WINAPI InitAtomTable16( WORD entries )
191 /* Allocate the table */
193 if (!entries) entries = DEFAULT_ATOMTABLE_SIZE; /* sanity check */
194 handle = LocalAlloc16( LMEM_FIXED, sizeof(ATOMTABLE) + (entries-1) * sizeof(HANDLE16) );
195 if (!handle) return 0;
196 table = MapSL( MAKESEGPTR( CURRENT_DS, handle ) );
197 table->size = entries;
198 for (i = 0; i < entries; i++) table->entries[i] = 0;
200 /* Store a pointer to the table in the instance data */
202 ((INSTANCEDATA *)MapSL( MAKESEGPTR( CURRENT_DS, 0 )))->atomtable = handle;
206 /***********************************************************************
207 * GetAtomHandle (KERNEL.73)
209 HANDLE16 WINAPI GetAtomHandle16( ATOM atom )
211 if (atom < MAXINTATOM) return 0;
212 return ATOMTOHANDLE( atom );
216 /***********************************************************************
217 * AddAtom (KERNEL.70)
219 * Windows DWORD aligns the atom entry size.
220 * The remaining unused string space created by the alignment
221 * gets padded with '\0's in a certain way to ensure
222 * that at least one trailing '\0' remains.
228 ATOM WINAPI AddAtom16( LPCSTR str )
230 char buffer[MAX_ATOM_LEN+1];
233 ATOMENTRY * entryPtr;
238 if (ATOM_IsIntAtomA( str, &iatom )) return iatom;
240 TRACE("%s\n",debugstr_a(buffer));
242 /* Make a copy of the string to be sure it doesn't move in linear memory. */
243 lstrcpynA( buffer, str, sizeof(buffer) );
245 len = strlen( buffer );
246 if (!(table = ATOM_GetTable( TRUE ))) return 0;
248 hash = ATOM_Hash( table->size, buffer, len );
249 entry = table->entries[hash];
252 entryPtr = ATOM_MakePtr( entry );
253 if ((entryPtr->length == len) &&
254 (!strncasecmp( entryPtr->str, buffer, len )))
256 entryPtr->refCount++;
257 TRACE("-- existing 0x%x\n", entry);
258 return HANDLETOATOM( entry );
260 entry = entryPtr->next;
263 ae_len = (sizeof(ATOMENTRY)+len+3) & ~3;
264 entry = LocalAlloc16( LMEM_FIXED, ae_len );
265 if (!entry) return 0;
266 /* Reload the table ptr in case it moved in linear memory */
267 table = ATOM_GetTable( FALSE );
268 entryPtr = ATOM_MakePtr( entry );
269 entryPtr->next = table->entries[hash];
270 entryPtr->refCount = 1;
271 entryPtr->length = len;
272 /* Some applications _need_ the '\0' padding provided by this strncpy */
273 strncpy( entryPtr->str, buffer, ae_len - sizeof(ATOMENTRY) + 1 );
274 entryPtr->str[ae_len - sizeof(ATOMENTRY)] = '\0';
275 table->entries[hash] = entry;
276 TRACE("-- new 0x%x\n", entry);
277 return HANDLETOATOM( entry );
281 /***********************************************************************
282 * DeleteAtom (KERNEL.71)
284 ATOM WINAPI DeleteAtom16( ATOM atom )
286 ATOMENTRY * entryPtr;
288 HANDLE16 entry, *prevEntry;
291 if (atom < MAXINTATOM) return 0; /* Integer atom */
293 TRACE("0x%x\n",atom);
295 if (!(table = ATOM_GetTable( FALSE ))) return 0;
296 entry = ATOMTOHANDLE( atom );
297 entryPtr = ATOM_MakePtr( entry );
299 /* Find previous atom */
300 hash = ATOM_Hash( table->size, entryPtr->str, entryPtr->length );
301 prevEntry = &table->entries[hash];
302 while (*prevEntry && *prevEntry != entry)
304 ATOMENTRY * prevEntryPtr = ATOM_MakePtr( *prevEntry );
305 prevEntry = &prevEntryPtr->next;
307 if (!*prevEntry) return atom;
310 if (--entryPtr->refCount == 0)
312 *prevEntry = entryPtr->next;
313 LocalFree16( entry );
319 /***********************************************************************
320 * FindAtom (KERNEL.69)
322 ATOM WINAPI FindAtom16( LPCSTR str )
329 TRACE("%s\n",debugstr_a(str));
331 if (ATOM_IsIntAtomA( str, &iatom )) return iatom;
332 if ((len = strlen( str )) > 255) len = 255;
333 if (!(table = ATOM_GetTable( FALSE ))) return 0;
334 hash = ATOM_Hash( table->size, str, len );
335 entry = table->entries[hash];
338 ATOMENTRY * entryPtr = ATOM_MakePtr( entry );
339 if ((entryPtr->length == len) &&
340 (!strncasecmp( entryPtr->str, str, len )))
342 TRACE("-- found %x\n", entry);
343 return HANDLETOATOM( entry );
345 entry = entryPtr->next;
347 TRACE("-- not found\n");
352 /***********************************************************************
353 * GetAtomName (KERNEL.72)
355 UINT16 WINAPI GetAtomName16( ATOM atom, LPSTR buffer, INT16 count )
358 ATOMENTRY * entryPtr;
366 if (!count) return 0;
367 if (atom < MAXINTATOM)
369 sprintf( text, "#%d", atom );
375 if (!(table = ATOM_GetTable( FALSE ))) return 0;
376 entry = ATOMTOHANDLE( atom );
377 entryPtr = ATOM_MakePtr( entry );
378 len = entryPtr->length;
379 strPtr = entryPtr->str;
381 if (len >= count) len = count-1;
382 memcpy( buffer, strPtr, len );
387 /***********************************************************************
388 * InitAtomTable (KERNEL32.@)
390 * Initialise the global atom table.
393 * entries [I] The number of entries to reserve in the table.
399 BOOL WINAPI InitAtomTable( DWORD entries )
402 SERVER_START_REQ( init_atom_table )
404 req->entries = entries;
405 ret = !wine_server_call_err( req );
412 static ATOM ATOM_AddAtomA( LPCSTR str, BOOL local )
415 if (!ATOM_IsIntAtomA( str, &atom ))
417 WCHAR buffer[MAX_ATOM_LEN];
419 DWORD len = MultiByteToWideChar( CP_ACP, 0, str, strlen(str), buffer, MAX_ATOM_LEN );
422 SetLastError( ERROR_INVALID_PARAMETER );
425 SERVER_START_REQ( add_atom )
427 wine_server_add_data( req, buffer, len * sizeof(WCHAR) );
429 if (!wine_server_call_err(req)) atom = reply->atom;
433 TRACE( "(%s) %s -> %x\n", local ? "local" : "global", debugstr_a(str), atom );
438 /***********************************************************************
439 * GlobalAddAtomA (KERNEL32.@)
441 * Add a character string to the global atom table and return a unique
442 * value identifying it.
445 * Success: The atom allocated to str.
448 ATOM WINAPI GlobalAddAtomA( LPCSTR str /* [in] String to add */ )
450 return ATOM_AddAtomA( str, FALSE );
454 /***********************************************************************
455 * AddAtomA (KERNEL32.@)
457 * Add a character string to the global atom table and return a unique
458 * value identifying it.
461 * Success: The atom allocated to str.
464 ATOM WINAPI AddAtomA( LPCSTR str /* [in] String to add */ )
466 return ATOM_AddAtomA( str, TRUE );
470 static ATOM ATOM_AddAtomW( LPCWSTR str, BOOL local )
473 if (!ATOM_IsIntAtomW( str, &atom ))
475 DWORD len = strlenW(str);
476 if (len > MAX_ATOM_LEN)
478 SetLastError( ERROR_INVALID_PARAMETER );
481 SERVER_START_REQ( add_atom )
484 wine_server_add_data( req, str, len * sizeof(WCHAR) );
485 if (!wine_server_call_err(req)) atom = reply->atom;
489 TRACE( "(%s) %s -> %x\n", local ? "local" : "global", debugstr_w(str), atom );
494 /***********************************************************************
495 * GlobalAddAtomW (KERNEL32.@)
497 * Unicode version of GlobalAddAtomA.
499 ATOM WINAPI GlobalAddAtomW( LPCWSTR str )
501 return ATOM_AddAtomW( str, FALSE );
505 /***********************************************************************
506 * AddAtomW (KERNEL32.@)
508 * Unicode version of AddAtomA.
510 ATOM WINAPI AddAtomW( LPCWSTR str )
512 return ATOM_AddAtomW( str, TRUE );
516 static ATOM ATOM_DeleteAtom( ATOM atom, BOOL local)
518 TRACE( "(%s) %x\n", local ? "local" : "global", atom );
519 if (atom >= MAXINTATOM)
521 SERVER_START_REQ( delete_atom )
525 wine_server_call_err( req );
533 /***********************************************************************
534 * GlobalDeleteAtom (KERNEL32.@)
536 * Decrement the reference count of a string atom. If the count is
537 * zero, the string associated with the atom is removed from the table.
543 ATOM WINAPI GlobalDeleteAtom( ATOM atom /* [in] Atom to delete */ )
545 return ATOM_DeleteAtom( atom, FALSE);
549 /***********************************************************************
550 * DeleteAtom (KERNEL32.@)
552 * Decrement the reference count of a string atom. If the count becomes
553 * zero, the string associated with the atom is removed from the table.
559 ATOM WINAPI DeleteAtom( ATOM atom /* [in] Atom to delete */ )
561 return ATOM_DeleteAtom( atom, TRUE );
565 static ATOM ATOM_FindAtomA( LPCSTR str, BOOL local )
568 if (!ATOM_IsIntAtomA( str, &atom ))
570 WCHAR buffer[MAX_ATOM_LEN];
572 DWORD len = MultiByteToWideChar( CP_ACP, 0, str, strlen(str), buffer, MAX_ATOM_LEN );
575 SetLastError( ERROR_INVALID_PARAMETER );
578 SERVER_START_REQ( find_atom )
581 wine_server_add_data( req, buffer, len * sizeof(WCHAR) );
582 if (!wine_server_call_err(req)) atom = reply->atom;
586 TRACE( "(%s) %s -> %x\n", local ? "local" : "global", debugstr_a(str), atom );
591 /***********************************************************************
592 * GlobalFindAtomA (KERNEL32.@)
594 * Get the atom associated with a string.
597 * Success: The associated atom.
600 ATOM WINAPI GlobalFindAtomA( LPCSTR str /* [in] Pointer to string to search for */ )
602 return ATOM_FindAtomA( str, FALSE );
605 /***********************************************************************
606 * FindAtomA (KERNEL32.@)
608 * Get the atom associated with a string.
611 * Success: The associated atom.
614 ATOM WINAPI FindAtomA( LPCSTR str /* [in] Pointer to string to find */ )
616 return ATOM_FindAtomA( str, TRUE );
620 static ATOM ATOM_FindAtomW( LPCWSTR str, BOOL local )
623 if (!ATOM_IsIntAtomW( str, &atom ))
625 DWORD len = strlenW(str);
626 if (len > MAX_ATOM_LEN)
628 SetLastError( ERROR_INVALID_PARAMETER );
631 SERVER_START_REQ( find_atom )
633 wine_server_add_data( req, str, len * sizeof(WCHAR) );
635 if (!wine_server_call_err( req )) atom = reply->atom;
639 TRACE( "(%s) %s -> %x\n", local ? "local" : "global", debugstr_w(str), atom );
644 /***********************************************************************
645 * GlobalFindAtomW (KERNEL32.@)
647 * Unicode version of GlobalFindAtomA.
649 ATOM WINAPI GlobalFindAtomW( LPCWSTR str )
651 return ATOM_FindAtomW( str, FALSE );
655 /***********************************************************************
656 * FindAtomW (KERNEL32.@)
658 * Unicode version of FindAtomA.
660 ATOM WINAPI FindAtomW( LPCWSTR str )
662 return ATOM_FindAtomW( str, TRUE );
666 static UINT ATOM_GetAtomNameA( ATOM atom, LPSTR buffer, INT count, BOOL local )
672 SetLastError( ERROR_MORE_DATA );
675 if (atom < MAXINTATOM)
680 SetLastError( ERROR_INVALID_PARAMETER );
683 len = sprintf( name, "#%d", atom );
684 lstrcpynA( buffer, name, count );
688 WCHAR full_name[MAX_ATOM_LEN];
691 SERVER_START_REQ( get_atom_name )
695 wine_server_set_reply( req, full_name, sizeof(full_name) );
696 if (!wine_server_call_err( req ))
698 len = WideCharToMultiByte( CP_ACP, 0, full_name,
699 wine_server_reply_size(reply) / sizeof(WCHAR),
700 buffer, count - 1, NULL, NULL );
701 if (!len) len = count; /* overflow */
702 else buffer[len] = 0;
708 if (len && count <= len)
710 SetLastError( ERROR_MORE_DATA );
714 TRACE( "(%s) %x -> %s\n", local ? "local" : "global", atom, debugstr_a(buffer) );
719 /***********************************************************************
720 * GlobalGetAtomNameA (KERNEL32.@)
722 * Get a copy of the string associated with an atom.
725 * Success: The length of the returned string in characters.
728 UINT WINAPI GlobalGetAtomNameA(
729 ATOM atom, /* [in] Atom identifier */
730 LPSTR buffer, /* [out] Pointer to buffer for atom string */
731 INT count ) /* [in] Size of buffer */
733 return ATOM_GetAtomNameA( atom, buffer, count, FALSE );
737 /***********************************************************************
738 * GetAtomNameA (KERNEL32.@)
740 * Get a copy of the string associated with an atom.
743 * Success: The length of the returned string in characters.
746 UINT WINAPI GetAtomNameA(
747 ATOM atom, /* [in] Atom */
748 LPSTR buffer, /* [out] Pointer to string for atom string */
749 INT count) /* [in] Size of buffer */
751 return ATOM_GetAtomNameA( atom, buffer, count, TRUE );
755 static UINT ATOM_GetAtomNameW( ATOM atom, LPWSTR buffer, INT count, BOOL local )
761 SetLastError( ERROR_MORE_DATA );
764 if (atom < MAXINTATOM)
769 SetLastError( ERROR_INVALID_PARAMETER );
772 sprintf( name, "#%d", atom );
773 len = MultiByteToWideChar( CP_ACP, 0, name, -1, buffer, count );
774 if (!len) buffer[count-1] = 0; /* overflow */
778 WCHAR full_name[MAX_ATOM_LEN];
781 SERVER_START_REQ( get_atom_name )
785 wine_server_set_reply( req, full_name, sizeof(full_name) );
786 if (!wine_server_call_err( req ))
788 len = wine_server_reply_size(reply) / sizeof(WCHAR);
789 if (count > len) count = len + 1;
790 memcpy( buffer, full_name, (count-1) * sizeof(WCHAR) );
797 TRACE( "(%s) %x -> %s\n", local ? "local" : "global", atom, debugstr_w(buffer) );
802 /***********************************************************************
803 * GlobalGetAtomNameW (KERNEL32.@)
805 * Unicode version of GlobalGetAtomNameA.
807 UINT WINAPI GlobalGetAtomNameW( ATOM atom, LPWSTR buffer, INT count )
809 return ATOM_GetAtomNameW( atom, buffer, count, FALSE);
813 /***********************************************************************
814 * GetAtomNameW (KERNEL32.@)
816 * Unicode version of GetAtomNameA.
818 UINT WINAPI GetAtomNameW( ATOM atom, LPWSTR buffer, INT count )
820 return ATOM_GetAtomNameW( atom, buffer, count, TRUE );