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"
46 #include "stackframe.h"
48 #include "wine/debug.h"
50 WINE_DEFAULT_DEBUG_CHANNEL(atom);
52 #define DEFAULT_ATOMTABLE_SIZE 37
53 #define MAX_ATOM_LEN 255
55 #define ATOMTOHANDLE(atom) ((HANDLE16)(atom) << 2)
56 #define HANDLETOATOM(handle) ((ATOM)(0xc000 | ((handle) >> 2)))
73 /***********************************************************************
76 * Return a pointer to the atom table of a given segment, creating
80 * Pointer to table: Success
83 static ATOMTABLE *ATOM_GetTable( BOOL create /* [in] Create */ )
85 INSTANCEDATA *ptr = MapSL( MAKESEGPTR( CURRENT_DS, 0 ) );
88 ATOMTABLE *table = (ATOMTABLE *)((char *)ptr + ptr->atomtable);
89 if (table->size) return table;
91 if (!create) return NULL;
92 if (!InitAtomTable16( 0 )) return NULL;
93 /* Reload ptr in case it moved in linear memory */
94 ptr = MapSL( MAKESEGPTR( CURRENT_DS, 0 ) );
95 return (ATOMTABLE *)((char *)ptr + ptr->atomtable);
99 /***********************************************************************
102 * The hash value for the input string
104 static WORD ATOM_Hash(
105 WORD entries, /* [in] Total number of entries */
106 LPCSTR str, /* [in] Pointer to string to hash */
107 WORD len /* [in] Length of string */
111 TRACE("%x, %s, %x\n", entries, str, len);
113 for (i = 0; i < len; i++) hash ^= toupper(str[i]) + i;
114 return hash % entries;
118 /***********************************************************************
121 static BOOL ATOM_IsIntAtomA(LPCSTR atomstr,WORD *atomid)
124 if (!HIWORD(atomstr)) atom = LOWORD(atomstr);
127 if (*atomstr++ != '#') return FALSE;
128 while (*atomstr >= '0' && *atomstr <= '9')
130 atom = atom * 10 + *atomstr - '0';
133 if (*atomstr) return FALSE;
135 if (atom >= MAXINTATOM)
137 SetLastError( ERROR_INVALID_PARAMETER );
145 /***********************************************************************
148 static BOOL ATOM_IsIntAtomW(LPCWSTR atomstr,WORD *atomid)
151 if (!HIWORD(atomstr)) atom = LOWORD(atomstr);
154 if (*atomstr++ != '#') return FALSE;
155 while (*atomstr >= '0' && *atomstr <= '9')
157 atom = atom * 10 + *atomstr - '0';
160 if (*atomstr) return FALSE;
162 if (atom >= MAXINTATOM)
164 SetLastError( ERROR_INVALID_PARAMETER );
172 /***********************************************************************
175 * Make an ATOMENTRY pointer from a handle (obtained from GetAtomHandle()).
177 static inline ATOMENTRY *ATOM_MakePtr( HANDLE16 handle /* [in] Handle */ )
179 return MapSL( MAKESEGPTR( CURRENT_DS, handle ) );
183 /***********************************************************************
184 * InitAtomTable (KERNEL.68)
186 WORD WINAPI InitAtomTable16( WORD entries )
192 /* Allocate the table */
194 if (!entries) entries = DEFAULT_ATOMTABLE_SIZE; /* sanity check */
195 handle = LocalAlloc16( LMEM_FIXED, sizeof(ATOMTABLE) + (entries-1) * sizeof(HANDLE16) );
196 if (!handle) return 0;
197 table = MapSL( MAKESEGPTR( CURRENT_DS, handle ) );
198 table->size = entries;
199 for (i = 0; i < entries; i++) table->entries[i] = 0;
201 /* Store a pointer to the table in the instance data */
203 ((INSTANCEDATA *)MapSL( MAKESEGPTR( CURRENT_DS, 0 )))->atomtable = handle;
207 /***********************************************************************
208 * GetAtomHandle (KERNEL.73)
210 HANDLE16 WINAPI GetAtomHandle16( ATOM atom )
212 if (atom < MAXINTATOM) return 0;
213 return ATOMTOHANDLE( atom );
217 /***********************************************************************
218 * AddAtom (KERNEL.70)
220 * Windows DWORD aligns the atom entry size.
221 * The remaining unused string space created by the alignment
222 * gets padded with '\0's in a certain way to ensure
223 * that at least one trailing '\0' remains.
229 ATOM WINAPI AddAtom16( LPCSTR str )
231 char buffer[MAX_ATOM_LEN+1];
234 ATOMENTRY * entryPtr;
239 if (ATOM_IsIntAtomA( str, &iatom )) return iatom;
241 TRACE("%s\n",debugstr_a(buffer));
243 /* Make a copy of the string to be sure it doesn't move in linear memory. */
244 lstrcpynA( buffer, str, sizeof(buffer) );
246 len = strlen( buffer );
247 if (!(table = ATOM_GetTable( TRUE ))) return 0;
249 hash = ATOM_Hash( table->size, buffer, len );
250 entry = table->entries[hash];
253 entryPtr = ATOM_MakePtr( entry );
254 if ((entryPtr->length == len) &&
255 (!strncasecmp( entryPtr->str, buffer, len )))
257 entryPtr->refCount++;
258 TRACE("-- existing 0x%x\n", entry);
259 return HANDLETOATOM( entry );
261 entry = entryPtr->next;
264 ae_len = (sizeof(ATOMENTRY)+len+3) & ~3;
265 entry = LocalAlloc16( LMEM_FIXED, ae_len );
266 if (!entry) return 0;
267 /* Reload the table ptr in case it moved in linear memory */
268 table = ATOM_GetTable( FALSE );
269 entryPtr = ATOM_MakePtr( entry );
270 entryPtr->next = table->entries[hash];
271 entryPtr->refCount = 1;
272 entryPtr->length = len;
273 /* Some applications _need_ the '\0' padding provided by this strncpy */
274 strncpy( entryPtr->str, buffer, ae_len - sizeof(ATOMENTRY) + 1 );
275 entryPtr->str[ae_len - sizeof(ATOMENTRY)] = '\0';
276 table->entries[hash] = entry;
277 TRACE("-- new 0x%x\n", entry);
278 return HANDLETOATOM( entry );
282 /***********************************************************************
283 * DeleteAtom (KERNEL.71)
285 ATOM WINAPI DeleteAtom16( ATOM atom )
287 ATOMENTRY * entryPtr;
289 HANDLE16 entry, *prevEntry;
292 if (atom < MAXINTATOM) return 0; /* Integer atom */
294 TRACE("0x%x\n",atom);
296 if (!(table = ATOM_GetTable( FALSE ))) return 0;
297 entry = ATOMTOHANDLE( atom );
298 entryPtr = ATOM_MakePtr( entry );
300 /* Find previous atom */
301 hash = ATOM_Hash( table->size, entryPtr->str, entryPtr->length );
302 prevEntry = &table->entries[hash];
303 while (*prevEntry && *prevEntry != entry)
305 ATOMENTRY * prevEntryPtr = ATOM_MakePtr( *prevEntry );
306 prevEntry = &prevEntryPtr->next;
308 if (!*prevEntry) return atom;
311 if (--entryPtr->refCount == 0)
313 *prevEntry = entryPtr->next;
314 LocalFree16( entry );
320 /***********************************************************************
321 * FindAtom (KERNEL.69)
323 ATOM WINAPI FindAtom16( LPCSTR str )
330 TRACE("%s\n",debugstr_a(str));
332 if (ATOM_IsIntAtomA( str, &iatom )) return iatom;
333 if ((len = strlen( str )) > 255) len = 255;
334 if (!(table = ATOM_GetTable( FALSE ))) return 0;
335 hash = ATOM_Hash( table->size, str, len );
336 entry = table->entries[hash];
339 ATOMENTRY * entryPtr = ATOM_MakePtr( entry );
340 if ((entryPtr->length == len) &&
341 (!strncasecmp( entryPtr->str, str, len )))
343 TRACE("-- found %x\n", entry);
344 return HANDLETOATOM( entry );
346 entry = entryPtr->next;
348 TRACE("-- not found\n");
353 /***********************************************************************
354 * GetAtomName (KERNEL.72)
356 UINT16 WINAPI GetAtomName16( ATOM atom, LPSTR buffer, INT16 count )
359 ATOMENTRY * entryPtr;
367 if (!count) return 0;
368 if (atom < MAXINTATOM)
370 sprintf( text, "#%d", atom );
376 if (!(table = ATOM_GetTable( FALSE ))) return 0;
377 entry = ATOMTOHANDLE( atom );
378 entryPtr = ATOM_MakePtr( entry );
379 len = entryPtr->length;
380 strPtr = entryPtr->str;
382 if (len >= count) len = count-1;
383 memcpy( buffer, strPtr, len );
388 /***********************************************************************
389 * InitAtomTable (KERNEL32.@)
391 * Initialise the global atom table.
394 * entries [I] The number of entries to reserve in the table.
400 BOOL WINAPI InitAtomTable( DWORD entries )
403 SERVER_START_REQ( init_atom_table )
405 req->entries = entries;
406 ret = !wine_server_call_err( req );
413 static ATOM ATOM_AddAtomA( LPCSTR str, BOOL local )
416 if (!ATOM_IsIntAtomA( str, &atom ))
418 WCHAR buffer[MAX_ATOM_LEN];
420 DWORD len = MultiByteToWideChar( CP_ACP, 0, str, strlen(str), buffer, MAX_ATOM_LEN );
423 SetLastError( ERROR_INVALID_PARAMETER );
426 SERVER_START_REQ( add_atom )
428 wine_server_add_data( req, buffer, len * sizeof(WCHAR) );
430 if (!wine_server_call_err(req)) atom = reply->atom;
434 TRACE( "(%s) %s -> %x\n", local ? "local" : "global", debugstr_a(str), atom );
439 /***********************************************************************
440 * GlobalAddAtomA (KERNEL32.@)
442 * Add a character string to the global atom table and return a unique
443 * value identifying it.
446 * Success: The atom allocated to str.
449 ATOM WINAPI GlobalAddAtomA( LPCSTR str /* [in] String to add */ )
451 return ATOM_AddAtomA( str, FALSE );
455 /***********************************************************************
456 * AddAtomA (KERNEL32.@)
458 * Add a character string to the global atom table and return a unique
459 * value identifying it.
462 * Success: The atom allocated to str.
465 ATOM WINAPI AddAtomA( LPCSTR str /* [in] String to add */ )
467 return ATOM_AddAtomA( str, TRUE );
471 static ATOM ATOM_AddAtomW( LPCWSTR str, BOOL local )
474 if (!ATOM_IsIntAtomW( str, &atom ))
476 DWORD len = strlenW(str);
477 if (len > MAX_ATOM_LEN)
479 SetLastError( ERROR_INVALID_PARAMETER );
482 SERVER_START_REQ( add_atom )
485 wine_server_add_data( req, str, len * sizeof(WCHAR) );
486 if (!wine_server_call_err(req)) atom = reply->atom;
490 TRACE( "(%s) %s -> %x\n", local ? "local" : "global", debugstr_w(str), atom );
495 /***********************************************************************
496 * GlobalAddAtomW (KERNEL32.@)
498 * Unicode version of GlobalAddAtomA.
500 ATOM WINAPI GlobalAddAtomW( LPCWSTR str )
502 return ATOM_AddAtomW( str, FALSE );
506 /***********************************************************************
507 * AddAtomW (KERNEL32.@)
509 * Unicode version of AddAtomA.
511 ATOM WINAPI AddAtomW( LPCWSTR str )
513 return ATOM_AddAtomW( str, TRUE );
517 static ATOM ATOM_DeleteAtom( ATOM atom, BOOL local)
519 TRACE( "(%s) %x\n", local ? "local" : "global", atom );
520 if (atom >= MAXINTATOM)
522 SERVER_START_REQ( delete_atom )
526 wine_server_call_err( req );
534 /***********************************************************************
535 * GlobalDeleteAtom (KERNEL32.@)
537 * Decrement the reference count of a string atom. If the count is
538 * zero, the string associated with the atom is removed from the table.
544 ATOM WINAPI GlobalDeleteAtom( ATOM atom /* [in] Atom to delete */ )
546 return ATOM_DeleteAtom( atom, FALSE);
550 /***********************************************************************
551 * DeleteAtom (KERNEL32.@)
553 * Decrement the reference count of a string atom. If the count becomes
554 * zero, the string associated with the atom is removed from the table.
560 ATOM WINAPI DeleteAtom( ATOM atom /* [in] Atom to delete */ )
562 return ATOM_DeleteAtom( atom, TRUE );
566 static ATOM ATOM_FindAtomA( LPCSTR str, BOOL local )
569 if (!ATOM_IsIntAtomA( str, &atom ))
571 WCHAR buffer[MAX_ATOM_LEN];
573 DWORD len = MultiByteToWideChar( CP_ACP, 0, str, strlen(str), buffer, MAX_ATOM_LEN );
576 SetLastError( ERROR_INVALID_PARAMETER );
579 SERVER_START_REQ( find_atom )
582 wine_server_add_data( req, buffer, len * sizeof(WCHAR) );
583 if (!wine_server_call_err(req)) atom = reply->atom;
587 TRACE( "(%s) %s -> %x\n", local ? "local" : "global", debugstr_a(str), atom );
592 /***********************************************************************
593 * GlobalFindAtomA (KERNEL32.@)
595 * Get the atom associated with a string.
598 * Success: The associated atom.
601 ATOM WINAPI GlobalFindAtomA( LPCSTR str /* [in] Pointer to string to search for */ )
603 return ATOM_FindAtomA( str, FALSE );
606 /***********************************************************************
607 * FindAtomA (KERNEL32.@)
609 * Get the atom associated with a string.
612 * Success: The associated atom.
615 ATOM WINAPI FindAtomA( LPCSTR str /* [in] Pointer to string to find */ )
617 return ATOM_FindAtomA( str, TRUE );
621 static ATOM ATOM_FindAtomW( LPCWSTR str, BOOL local )
624 if (!ATOM_IsIntAtomW( str, &atom ))
626 DWORD len = strlenW(str);
627 if (len > MAX_ATOM_LEN)
629 SetLastError( ERROR_INVALID_PARAMETER );
632 SERVER_START_REQ( find_atom )
634 wine_server_add_data( req, str, len * sizeof(WCHAR) );
636 if (!wine_server_call_err( req )) atom = reply->atom;
640 TRACE( "(%s) %s -> %x\n", local ? "local" : "global", debugstr_w(str), atom );
645 /***********************************************************************
646 * GlobalFindAtomW (KERNEL32.@)
648 * Unicode version of GlobalFindAtomA.
650 ATOM WINAPI GlobalFindAtomW( LPCWSTR str )
652 return ATOM_FindAtomW( str, FALSE );
656 /***********************************************************************
657 * FindAtomW (KERNEL32.@)
659 * Unicode version of FindAtomA.
661 ATOM WINAPI FindAtomW( LPCWSTR str )
663 return ATOM_FindAtomW( str, TRUE );
667 static UINT ATOM_GetAtomNameA( ATOM atom, LPSTR buffer, INT count, BOOL local )
673 SetLastError( ERROR_MORE_DATA );
676 if (atom < MAXINTATOM)
681 SetLastError( ERROR_INVALID_PARAMETER );
684 len = sprintf( name, "#%d", atom );
685 lstrcpynA( buffer, name, count );
689 WCHAR full_name[MAX_ATOM_LEN];
692 SERVER_START_REQ( get_atom_name )
696 wine_server_set_reply( req, full_name, sizeof(full_name) );
697 if (!wine_server_call_err( req ))
699 len = WideCharToMultiByte( CP_ACP, 0, full_name,
700 wine_server_reply_size(reply) / sizeof(WCHAR),
701 buffer, count - 1, NULL, NULL );
702 if (!len) len = count; /* overflow */
703 else buffer[len] = 0;
709 if (len && count <= len)
711 SetLastError( ERROR_MORE_DATA );
715 TRACE( "(%s) %x -> %s\n", local ? "local" : "global", atom, debugstr_a(buffer) );
720 /***********************************************************************
721 * GlobalGetAtomNameA (KERNEL32.@)
723 * Get a copy of the string associated with an atom.
726 * Success: The length of the returned string in characters.
729 UINT WINAPI GlobalGetAtomNameA(
730 ATOM atom, /* [in] Atom identifier */
731 LPSTR buffer, /* [out] Pointer to buffer for atom string */
732 INT count ) /* [in] Size of buffer */
734 return ATOM_GetAtomNameA( atom, buffer, count, FALSE );
738 /***********************************************************************
739 * GetAtomNameA (KERNEL32.@)
741 * Get a copy of the string associated with an atom.
744 * Success: The length of the returned string in characters.
747 UINT WINAPI GetAtomNameA(
748 ATOM atom, /* [in] Atom */
749 LPSTR buffer, /* [out] Pointer to string for atom string */
750 INT count) /* [in] Size of buffer */
752 return ATOM_GetAtomNameA( atom, buffer, count, TRUE );
756 static UINT ATOM_GetAtomNameW( ATOM atom, LPWSTR buffer, INT count, BOOL local )
762 SetLastError( ERROR_MORE_DATA );
765 if (atom < MAXINTATOM)
770 SetLastError( ERROR_INVALID_PARAMETER );
773 sprintf( name, "#%d", atom );
774 len = MultiByteToWideChar( CP_ACP, 0, name, -1, buffer, count );
775 if (!len) buffer[count-1] = 0; /* overflow */
779 WCHAR full_name[MAX_ATOM_LEN];
782 SERVER_START_REQ( get_atom_name )
786 wine_server_set_reply( req, full_name, sizeof(full_name) );
787 if (!wine_server_call_err( req ))
789 len = wine_server_reply_size(reply) / sizeof(WCHAR);
790 if (count > len) count = len + 1;
791 memcpy( buffer, full_name, (count-1) * sizeof(WCHAR) );
798 TRACE( "(%s) %x -> %s\n", local ? "local" : "global", atom, debugstr_w(buffer) );
803 /***********************************************************************
804 * GlobalGetAtomNameW (KERNEL32.@)
806 * Unicode version of GlobalGetAtomNameA.
808 UINT WINAPI GlobalGetAtomNameW( ATOM atom, LPWSTR buffer, INT count )
810 return ATOM_GetAtomNameW( atom, buffer, count, FALSE);
814 /***********************************************************************
815 * GetAtomNameW (KERNEL32.@)
817 * Unicode version of GetAtomNameA.
819 UINT WINAPI GetAtomNameW( ATOM atom, LPWSTR buffer, INT count )
821 return ATOM_GetAtomNameW( atom, buffer, count, TRUE );