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
39 #include "wine/server.h"
40 #include "wine/unicode.h"
41 #include "wine/winbase16.h"
44 #include "stackframe.h"
46 #include "wine/debug.h"
48 WINE_DEFAULT_DEBUG_CHANNEL(atom);
50 #define DEFAULT_ATOMTABLE_SIZE 37
51 #define MAX_ATOM_LEN 255
53 #define ATOMTOHANDLE(atom) ((HANDLE16)(atom) << 2)
54 #define HANDLETOATOM(handle) ((ATOM)(0xc000 | ((handle) >> 2)))
71 /***********************************************************************
74 * Return a pointer to the atom table of a given segment, creating
78 * Pointer to table: Success
81 static ATOMTABLE *ATOM_GetTable( BOOL create /* [in] Create */ )
83 INSTANCEDATA *ptr = MapSL( MAKESEGPTR( CURRENT_DS, 0 ) );
86 ATOMTABLE *table = (ATOMTABLE *)((char *)ptr + ptr->atomtable);
87 if (table->size) return table;
89 if (!create) return NULL;
90 if (!InitAtomTable16( 0 )) return NULL;
91 /* Reload ptr in case it moved in linear memory */
92 ptr = MapSL( MAKESEGPTR( CURRENT_DS, 0 ) );
93 return (ATOMTABLE *)((char *)ptr + ptr->atomtable);
97 /***********************************************************************
100 * The hash value for the input string
102 static WORD ATOM_Hash(
103 WORD entries, /* [in] Total number of entries */
104 LPCSTR str, /* [in] Pointer to string to hash */
105 WORD len /* [in] Length of string */
109 TRACE("%x, %s, %x\n", entries, str, len);
111 for (i = 0; i < len; i++) hash ^= toupper(str[i]) + i;
112 return hash % entries;
116 /***********************************************************************
119 static BOOL ATOM_IsIntAtomA(LPCSTR atomstr,WORD *atomid)
122 if (!HIWORD(atomstr)) atom = LOWORD(atomstr);
125 if (*atomstr++ != '#') return FALSE;
126 while (*atomstr >= '0' && *atomstr <= '9')
128 atom = atom * 10 + *atomstr - '0';
131 if (*atomstr) return FALSE;
133 if (!atom || (atom >= MAXINTATOM))
135 SetLastError( ERROR_INVALID_PARAMETER );
143 /***********************************************************************
146 static BOOL ATOM_IsIntAtomW(LPCWSTR atomstr,WORD *atomid)
149 if (!HIWORD(atomstr)) atom = LOWORD(atomstr);
152 if (*atomstr++ != '#') return FALSE;
153 while (*atomstr >= '0' && *atomstr <= '9')
155 atom = atom * 10 + *atomstr - '0';
158 if (*atomstr) return FALSE;
160 if (!atom || (atom >= MAXINTATOM))
162 SetLastError( ERROR_INVALID_PARAMETER );
170 /***********************************************************************
173 * Make an ATOMENTRY pointer from a handle (obtained from GetAtomHandle()).
175 static inline ATOMENTRY *ATOM_MakePtr( HANDLE16 handle /* [in] Handle */ )
177 return MapSL( MAKESEGPTR( CURRENT_DS, handle ) );
181 /***********************************************************************
182 * InitAtomTable (KERNEL.68)
184 WORD WINAPI InitAtomTable16( WORD entries )
190 /* Allocate the table */
192 if (!entries) entries = DEFAULT_ATOMTABLE_SIZE; /* sanity check */
193 handle = LocalAlloc16( LMEM_FIXED, sizeof(ATOMTABLE) + (entries-1) * sizeof(HANDLE16) );
194 if (!handle) return 0;
195 table = MapSL( MAKESEGPTR( CURRENT_DS, handle ) );
196 table->size = entries;
197 for (i = 0; i < entries; i++) table->entries[i] = 0;
199 /* Store a pointer to the table in the instance data */
201 ((INSTANCEDATA *)MapSL( MAKESEGPTR( CURRENT_DS, 0 )))->atomtable = handle;
205 /***********************************************************************
206 * GetAtomHandle (KERNEL.73)
208 HANDLE16 WINAPI GetAtomHandle16( ATOM atom )
210 if (atom < MAXINTATOM) return 0;
211 return ATOMTOHANDLE( atom );
215 /***********************************************************************
216 * AddAtom (KERNEL.70)
218 * Windows DWORD aligns the atom entry size.
219 * The remaining unused string space created by the alignment
220 * gets padded with '\0's in a certain way to ensure
221 * that at least one trailing '\0' remains.
227 ATOM WINAPI AddAtom16( LPCSTR str )
229 char buffer[MAX_ATOM_LEN+1];
232 ATOMENTRY * entryPtr;
237 if (ATOM_IsIntAtomA( str, &iatom )) return iatom;
239 TRACE("%s\n",debugstr_a(buffer));
241 /* Make a copy of the string to be sure it doesn't move in linear memory. */
242 lstrcpynA( buffer, str, sizeof(buffer) );
244 len = strlen( buffer );
245 if (!(table = ATOM_GetTable( TRUE ))) return 0;
247 hash = ATOM_Hash( table->size, buffer, len );
248 entry = table->entries[hash];
251 entryPtr = ATOM_MakePtr( entry );
252 if ((entryPtr->length == len) &&
253 (!strncasecmp( entryPtr->str, buffer, len )))
255 entryPtr->refCount++;
256 TRACE("-- existing 0x%x\n", entry);
257 return HANDLETOATOM( entry );
259 entry = entryPtr->next;
262 ae_len = (sizeof(ATOMENTRY)+len+3) & ~3;
263 entry = LocalAlloc16( LMEM_FIXED, ae_len );
264 if (!entry) return 0;
265 /* Reload the table ptr in case it moved in linear memory */
266 table = ATOM_GetTable( FALSE );
267 entryPtr = ATOM_MakePtr( entry );
268 entryPtr->next = table->entries[hash];
269 entryPtr->refCount = 1;
270 entryPtr->length = len;
271 /* Some applications _need_ the '\0' padding provided by this strncpy */
272 strncpy( entryPtr->str, buffer, ae_len - sizeof(ATOMENTRY) + 1 );
273 entryPtr->str[ae_len - sizeof(ATOMENTRY)] = '\0';
274 table->entries[hash] = entry;
275 TRACE("-- new 0x%x\n", entry);
276 return HANDLETOATOM( entry );
280 /***********************************************************************
281 * DeleteAtom (KERNEL.71)
283 ATOM WINAPI DeleteAtom16( ATOM atom )
285 ATOMENTRY * entryPtr;
287 HANDLE16 entry, *prevEntry;
290 if (atom < MAXINTATOM) return 0; /* Integer atom */
292 TRACE("0x%x\n",atom);
294 if (!(table = ATOM_GetTable( FALSE ))) return 0;
295 entry = ATOMTOHANDLE( atom );
296 entryPtr = ATOM_MakePtr( entry );
298 /* Find previous atom */
299 hash = ATOM_Hash( table->size, entryPtr->str, entryPtr->length );
300 prevEntry = &table->entries[hash];
301 while (*prevEntry && *prevEntry != entry)
303 ATOMENTRY * prevEntryPtr = ATOM_MakePtr( *prevEntry );
304 prevEntry = &prevEntryPtr->next;
306 if (!*prevEntry) return atom;
309 if (--entryPtr->refCount == 0)
311 *prevEntry = entryPtr->next;
312 LocalFree16( entry );
318 /***********************************************************************
319 * FindAtom (KERNEL.69)
321 ATOM WINAPI FindAtom16( LPCSTR str )
328 TRACE("%s\n",debugstr_a(str));
330 if (ATOM_IsIntAtomA( str, &iatom )) return iatom;
331 if ((len = strlen( str )) > 255) len = 255;
332 if (!(table = ATOM_GetTable( FALSE ))) return 0;
333 hash = ATOM_Hash( table->size, str, len );
334 entry = table->entries[hash];
337 ATOMENTRY * entryPtr = ATOM_MakePtr( entry );
338 if ((entryPtr->length == len) &&
339 (!strncasecmp( entryPtr->str, str, len )))
341 TRACE("-- found %x\n", entry);
342 return HANDLETOATOM( entry );
344 entry = entryPtr->next;
346 TRACE("-- not found\n");
351 /***********************************************************************
352 * GetAtomName (KERNEL.72)
354 UINT16 WINAPI GetAtomName16( ATOM atom, LPSTR buffer, INT16 count )
357 ATOMENTRY * entryPtr;
365 if (!count) return 0;
366 if (atom < MAXINTATOM)
368 sprintf( text, "#%d", atom );
374 if (!(table = ATOM_GetTable( FALSE ))) return 0;
375 entry = ATOMTOHANDLE( atom );
376 entryPtr = ATOM_MakePtr( entry );
377 len = entryPtr->length;
378 strPtr = entryPtr->str;
380 if (len >= count) len = count-1;
381 memcpy( buffer, strPtr, len );
386 /***********************************************************************
387 * InitAtomTable (KERNEL32.@)
389 BOOL WINAPI InitAtomTable( DWORD entries )
392 SERVER_START_REQ( init_atom_table )
394 req->entries = entries;
395 ret = !wine_server_call_err( req );
402 static ATOM ATOM_AddAtomA( LPCSTR str, BOOL local )
405 if (!ATOM_IsIntAtomA( str, &atom ))
407 WCHAR buffer[MAX_ATOM_LEN];
409 DWORD len = MultiByteToWideChar( CP_ACP, 0, str, strlen(str), buffer, MAX_ATOM_LEN );
412 SetLastError( ERROR_INVALID_PARAMETER );
415 SERVER_START_REQ( add_atom )
417 wine_server_add_data( req, buffer, len * sizeof(WCHAR) );
419 if (!wine_server_call_err(req)) atom = reply->atom;
423 TRACE( "(%s) %s -> %x\n", local ? "local" : "global", debugstr_a(str), atom );
428 /***********************************************************************
429 * GlobalAddAtomA (KERNEL32.@)
431 * Adds a character string to the global atom table and returns a unique
432 * value identifying the string.
438 ATOM WINAPI GlobalAddAtomA( LPCSTR str /* [in] Pointer to string to add */ )
440 return ATOM_AddAtomA( str, FALSE );
444 /***********************************************************************
445 * AddAtomA (KERNEL32.@)
446 * Adds a string to the atom table and returns the atom identifying the
453 ATOM WINAPI AddAtomA( LPCSTR str /* [in] Pointer to string to add */ )
455 return ATOM_AddAtomA( str, TRUE );
459 static ATOM ATOM_AddAtomW( LPCWSTR str, BOOL local )
462 if (!ATOM_IsIntAtomW( str, &atom ))
464 DWORD len = strlenW(str);
465 if (len > MAX_ATOM_LEN)
467 SetLastError( ERROR_INVALID_PARAMETER );
470 SERVER_START_REQ( add_atom )
473 wine_server_add_data( req, str, len * sizeof(WCHAR) );
474 if (!wine_server_call_err(req)) atom = reply->atom;
478 TRACE( "(%s) %s -> %x\n", local ? "local" : "global", debugstr_w(str), atom );
483 /***********************************************************************
484 * GlobalAddAtomW (KERNEL32.@)
486 ATOM WINAPI GlobalAddAtomW( LPCWSTR str )
488 return ATOM_AddAtomW( str, FALSE );
492 /***********************************************************************
493 * AddAtomW (KERNEL32.@)
495 ATOM WINAPI AddAtomW( LPCWSTR str )
497 return ATOM_AddAtomW( str, TRUE );
501 static ATOM ATOM_DeleteAtom( ATOM atom, BOOL local)
503 TRACE( "(%s) %x\n", local ? "local" : "global", atom );
504 if (atom < MAXINTATOM) atom = 0;
507 SERVER_START_REQ( delete_atom )
511 if (!wine_server_call_err( req )) atom = 0;
519 /***********************************************************************
520 * GlobalDeleteAtom (KERNEL32.@)
521 * Decrements the reference count of a string atom. If the count is
522 * zero, the string associated with the atom is removed from the table.
528 ATOM WINAPI GlobalDeleteAtom( ATOM atom /* [in] Atom to delete */ )
530 return ATOM_DeleteAtom( atom, FALSE);
534 /***********************************************************************
535 * DeleteAtom (KERNEL32.@)
536 * Decrements the reference count of a string atom. If count becomes
537 * zero, the string associated with the atom is removed from the table.
543 ATOM WINAPI DeleteAtom( ATOM atom /* [in] Atom to delete */ )
545 return ATOM_DeleteAtom( atom, TRUE );
549 static ATOM ATOM_FindAtomA( LPCSTR str, BOOL local )
552 if (!ATOM_IsIntAtomA( str, &atom ))
554 WCHAR buffer[MAX_ATOM_LEN];
556 DWORD len = MultiByteToWideChar( CP_ACP, 0, str, strlen(str), buffer, MAX_ATOM_LEN );
559 SetLastError( ERROR_INVALID_PARAMETER );
562 SERVER_START_REQ( find_atom )
565 wine_server_add_data( req, buffer, len * sizeof(WCHAR) );
566 if (!wine_server_call_err(req)) atom = reply->atom;
570 TRACE( "(%s) %s -> %x\n", local ? "local" : "global", debugstr_a(str), atom );
575 /***********************************************************************
576 * GlobalFindAtomA (KERNEL32.@)
578 * Searches the atom table for the string and returns the atom
579 * associated with it.
585 ATOM WINAPI GlobalFindAtomA( LPCSTR str /* [in] Pointer to string to search for */ )
587 return ATOM_FindAtomA( str, FALSE );
590 /***********************************************************************
591 * FindAtomA (KERNEL32.@)
592 * Searches the local atom table for the string and returns the atom
593 * associated with that string.
599 ATOM WINAPI FindAtomA( LPCSTR str /* [in] Pointer to string to find */ )
601 return ATOM_FindAtomA( str, TRUE );
605 static ATOM ATOM_FindAtomW( LPCWSTR str, BOOL local )
608 if (!ATOM_IsIntAtomW( str, &atom ))
610 DWORD len = strlenW(str);
611 if (len > MAX_ATOM_LEN)
613 SetLastError( ERROR_INVALID_PARAMETER );
616 SERVER_START_REQ( find_atom )
618 wine_server_add_data( req, str, len * sizeof(WCHAR) );
620 if (!wine_server_call_err( req )) atom = reply->atom;
624 TRACE( "(%s) %s -> %x\n", local ? "local" : "global", debugstr_w(str), atom );
629 /***********************************************************************
630 * GlobalFindAtomW (KERNEL32.@)
632 ATOM WINAPI GlobalFindAtomW( LPCWSTR str )
634 return ATOM_FindAtomW( str, FALSE );
638 /***********************************************************************
639 * FindAtomW (KERNEL32.@)
641 ATOM WINAPI FindAtomW( LPCWSTR str )
643 return ATOM_FindAtomW( str, TRUE );
647 static UINT ATOM_GetAtomNameA( ATOM atom, LPSTR buffer, INT count, BOOL local )
653 SetLastError( ERROR_MORE_DATA );
656 if (atom < MAXINTATOM)
661 SetLastError( ERROR_INVALID_PARAMETER );
664 len = sprintf( name, "#%d", atom );
665 lstrcpynA( buffer, name, count );
669 WCHAR full_name[MAX_ATOM_LEN];
672 SERVER_START_REQ( get_atom_name )
676 wine_server_set_reply( req, full_name, sizeof(full_name) );
677 if (!wine_server_call_err( req ))
679 len = WideCharToMultiByte( CP_ACP, 0, full_name,
680 wine_server_reply_size(reply) / sizeof(WCHAR),
681 buffer, count - 1, NULL, NULL );
682 if (!len) len = count; /* overflow */
683 else buffer[len] = 0;
689 if (len && count <= len)
691 SetLastError( ERROR_MORE_DATA );
695 TRACE( "(%s) %x -> %s\n", local ? "local" : "global", atom, debugstr_a(buffer) );
700 /***********************************************************************
701 * GlobalGetAtomNameA (KERNEL32.@)
703 * Retrieves a copy of the string associated with an atom.
706 * Length of string in characters: Success
709 UINT WINAPI GlobalGetAtomNameA(
710 ATOM atom, /* [in] Atom identifier */
711 LPSTR buffer, /* [out] Pointer to buffer for atom string */
712 INT count ) /* [in] Size of buffer */
714 return ATOM_GetAtomNameA( atom, buffer, count, FALSE );
718 /***********************************************************************
719 * GetAtomNameA (KERNEL32.@)
720 * Retrieves a copy of the string associated with the atom.
723 * Length of string: Success
726 UINT WINAPI GetAtomNameA(
727 ATOM atom, /* [in] Atom */
728 LPSTR buffer, /* [out] Pointer to string for atom string */
729 INT count) /* [in] Size of buffer */
731 return ATOM_GetAtomNameA( atom, buffer, count, TRUE );
735 static UINT ATOM_GetAtomNameW( ATOM atom, LPWSTR buffer, INT count, BOOL local )
741 SetLastError( ERROR_MORE_DATA );
744 if (atom < MAXINTATOM)
749 SetLastError( ERROR_INVALID_PARAMETER );
752 sprintf( name, "#%d", atom );
753 len = MultiByteToWideChar( CP_ACP, 0, name, -1, buffer, count );
754 if (!len) buffer[count-1] = 0; /* overflow */
758 WCHAR full_name[MAX_ATOM_LEN];
761 SERVER_START_REQ( get_atom_name )
765 wine_server_set_reply( req, full_name, sizeof(full_name) );
766 if (!wine_server_call_err( req ))
768 len = wine_server_reply_size(reply) / sizeof(WCHAR);
769 if (count > len) count = len + 1;
770 memcpy( buffer, full_name, (count-1) * sizeof(WCHAR) );
779 SetLastError( ERROR_MORE_DATA );
782 TRACE( "(%s) %x -> %s\n", local ? "local" : "global", atom, debugstr_w(buffer) );
787 /***********************************************************************
788 * GlobalGetAtomNameW (KERNEL32.@)
790 UINT WINAPI GlobalGetAtomNameW( ATOM atom, LPWSTR buffer, INT count )
792 return ATOM_GetAtomNameW( atom, buffer, count, FALSE);
796 /***********************************************************************
797 * GetAtomNameW (KERNEL32.@)
799 UINT WINAPI GetAtomNameW( ATOM atom, LPWSTR buffer, INT count )
801 return ATOM_GetAtomNameW( atom, buffer, count, TRUE );