2 * Atom table functions - 16 bit variant
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 "kernel16_private.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 * Make an ATOMENTRY pointer from a handle (obtained from GetAtomHandle()).
149 static inline ATOMENTRY *ATOM_MakePtr( HANDLE16 handle /* [in] Handle */ )
151 return MapSL( MAKESEGPTR( CURRENT_DS, handle ) );
155 /***********************************************************************
156 * InitAtomTable (KERNEL.68)
158 WORD WINAPI InitAtomTable16( WORD entries )
164 /* Allocate the table */
166 if (!entries) entries = DEFAULT_ATOMTABLE_SIZE; /* sanity check */
167 handle = LocalAlloc16( LMEM_FIXED, sizeof(ATOMTABLE) + (entries-1) * sizeof(HANDLE16) );
168 if (!handle) return 0;
169 table = MapSL( MAKESEGPTR( CURRENT_DS, handle ) );
170 table->size = entries;
171 for (i = 0; i < entries; i++) table->entries[i] = 0;
173 /* Store a pointer to the table in the instance data */
175 ((INSTANCEDATA *)MapSL( MAKESEGPTR( CURRENT_DS, 0 )))->atomtable = handle;
179 /***********************************************************************
180 * GetAtomHandle (KERNEL.73)
182 HANDLE16 WINAPI GetAtomHandle16( ATOM atom )
184 if (atom < MAXINTATOM) return 0;
185 return ATOMTOHANDLE( atom );
189 /***********************************************************************
190 * AddAtom (KERNEL.70)
192 * Windows DWORD aligns the atom entry size.
193 * The remaining unused string space created by the alignment
194 * gets padded with '\0's in a certain way to ensure
195 * that at least one trailing '\0' remains.
201 ATOM WINAPI AddAtom16( LPCSTR str )
203 char buffer[MAX_ATOM_LEN+1];
206 ATOMENTRY * entryPtr;
211 if (ATOM_IsIntAtomA( str, &iatom )) return iatom;
213 TRACE("%s\n",debugstr_a(str));
215 if (!(table = ATOM_GetTable( TRUE ))) return 0;
217 /* Make a copy of the string to be sure it doesn't move in linear memory. */
218 lstrcpynA( buffer, str, sizeof(buffer) );
220 len = strlen( buffer );
221 hash = ATOM_Hash( table->size, buffer, len );
222 entry = table->entries[hash];
225 entryPtr = ATOM_MakePtr( entry );
226 if ((entryPtr->length == len) &&
227 (!strncasecmp( entryPtr->str, buffer, len )))
229 entryPtr->refCount++;
230 TRACE("-- existing 0x%x\n", entry);
231 return HANDLETOATOM( entry );
233 entry = entryPtr->next;
236 ae_len = (sizeof(ATOMENTRY)+len+3) & ~3;
237 entry = LocalAlloc16( LMEM_FIXED, ae_len );
238 if (!entry) return 0;
239 /* Reload the table ptr in case it moved in linear memory */
240 table = ATOM_GetTable( FALSE );
241 entryPtr = ATOM_MakePtr( entry );
242 entryPtr->next = table->entries[hash];
243 entryPtr->refCount = 1;
244 entryPtr->length = len;
245 memcpy( entryPtr->str, buffer, len);
246 /* Some applications _need_ the '\0' padding provided by memset */
247 /* Note that 1 byte of the str is accounted for in the ATOMENTRY struct */
248 memset( entryPtr->str+len, 0, ae_len - sizeof(ATOMENTRY) - (len - 1));
249 table->entries[hash] = entry;
250 TRACE("-- new 0x%x\n", entry);
251 return HANDLETOATOM( entry );
255 /***********************************************************************
256 * DeleteAtom (KERNEL.71)
258 ATOM WINAPI DeleteAtom16( ATOM atom )
260 ATOMENTRY * entryPtr;
262 HANDLE16 entry, *prevEntry;
265 if (atom < MAXINTATOM) return 0; /* Integer atom */
267 TRACE("0x%x\n",atom);
269 if (!(table = ATOM_GetTable( FALSE ))) return 0;
270 entry = ATOMTOHANDLE( atom );
271 entryPtr = ATOM_MakePtr( entry );
273 /* Find previous atom */
274 hash = ATOM_Hash( table->size, entryPtr->str, entryPtr->length );
275 prevEntry = &table->entries[hash];
276 while (*prevEntry && *prevEntry != entry)
278 ATOMENTRY * prevEntryPtr = ATOM_MakePtr( *prevEntry );
279 prevEntry = &prevEntryPtr->next;
281 if (!*prevEntry) return atom;
284 if (--entryPtr->refCount == 0)
286 *prevEntry = entryPtr->next;
287 LocalFree16( entry );
293 /***********************************************************************
294 * FindAtom (KERNEL.69)
296 ATOM WINAPI FindAtom16( LPCSTR str )
303 TRACE("%s\n",debugstr_a(str));
305 if (ATOM_IsIntAtomA( str, &iatom )) return iatom;
306 if ((len = strlen( str )) > 255) len = 255;
307 if (!(table = ATOM_GetTable( FALSE ))) return 0;
308 hash = ATOM_Hash( table->size, str, len );
309 entry = table->entries[hash];
312 ATOMENTRY * entryPtr = ATOM_MakePtr( entry );
313 if ((entryPtr->length == len) &&
314 (!strncasecmp( entryPtr->str, str, len )))
316 TRACE("-- found %x\n", entry);
317 return HANDLETOATOM( entry );
319 entry = entryPtr->next;
321 TRACE("-- not found\n");
326 /***********************************************************************
327 * GetAtomName (KERNEL.72)
329 UINT16 WINAPI GetAtomName16( ATOM atom, LPSTR buffer, INT16 count )
331 ATOMENTRY * entryPtr;
339 if (!count) return 0;
340 if (atom < MAXINTATOM)
342 sprintf( text, "#%d", atom );
348 if (!ATOM_GetTable( FALSE )) return 0;
349 entry = ATOMTOHANDLE( atom );
350 entryPtr = ATOM_MakePtr( entry );
351 len = entryPtr->length;
352 strPtr = entryPtr->str;
354 if (len >= count) len = count-1;
355 memcpy( buffer, strPtr, len );