1 /*
2 * Atom table functions - 16 bit variant
3 *
4 * Copyright 1993, 1994, 1995 Alexandre Julliard
5 *
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.
10 *
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.
15 *
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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19 */
20
21 /*
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
25 * have to be changed.
26 */
27
28 #include "config.h"
29 #include "wine/port.h"
30
31 #include <stdlib.h>
32 #include <stdarg.h>
33 #include <stdio.h>
34 #include <string.h>
35 #include <ctype.h>
36
37 #include "windef.h"
38 #include "winbase.h"
39 #include "winerror.h"
40 #include "winternl.h"
41
42 #include "wine/unicode.h"
43 #include "wine/winbase16.h"
44 #include "kernel16_private.h"
45
46 #include "wine/debug.h"
47
48 WINE_DEFAULT_DEBUG_CHANNEL(atom);
49
50 #define DEFAULT_ATOMTABLE_SIZE 37
51 #define MAX_ATOM_LEN 255
52
53 #define ATOMTOHANDLE(atom) ((HANDLE16)(atom) << 2)
54 #define HANDLETOATOM(handle) ((ATOM)(0xc000 | ((handle) >> 2)))
55
56 typedef struct
57 {
58 HANDLE16 next;
59 WORD refCount;
60 BYTE length;
61 CHAR str[1];
62 } ATOMENTRY;
63
64 typedef struct
65 {
66 WORD size;
67 HANDLE16 entries[1];
68 } ATOMTABLE;
69
70
71 /***********************************************************************
72 * ATOM_GetTable
73 *
74 * Return a pointer to the atom table of a given segment, creating
75 * it if necessary.
76 *
77 * RETURNS
78 * Pointer to table: Success
79 * NULL: Failure
80 */
81 static ATOMTABLE *ATOM_GetTable( BOOL create /* [in] Create */ )
82 {
83 INSTANCEDATA *ptr = MapSL( MAKESEGPTR( CURRENT_DS, 0 ) );
84 if (ptr->atomtable)
85 {
86 ATOMTABLE *table = (ATOMTABLE *)((char *)ptr + ptr->atomtable);
87 if (table->size) return table;
88 }
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);
94 }
95
96
97 /***********************************************************************
98 * ATOM_Hash
99 * RETURNS
100 * The hash value for the input string
101 */
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 */
106 ) {
107 WORD i, hash = 0;
108
109 TRACE("%x, %s, %x\n", entries, str, len);
110
111 for (i = 0; i < len; i++) hash ^= toupper(str[i]) + i;
112 return hash % entries;
113 }
114
115
116 /***********************************************************************
117 * ATOM_IsIntAtomA
118 */
119 static BOOL ATOM_IsIntAtomA(LPCSTR atomstr,WORD *atomid)
120 {
121 UINT atom = 0;
122 if (!HIWORD(atomstr)) atom = LOWORD(atomstr);
123 else
124 {
125 if (*atomstr++ != '#') return FALSE;
126 while (*atomstr >= '' && *atomstr <= '9')
127 {
128 atom = atom * 10 + *atomstr - '';
129 atomstr++;
130 }
131 if (*atomstr) return FALSE;
132 }
133 if (atom >= MAXINTATOM)
134 {
135 SetLastError( ERROR_INVALID_PARAMETER );
136 atom = 0;
137 }
138 *atomid = atom;
139 return TRUE;
140 }
141
142
143 /***********************************************************************
144 * ATOM_MakePtr
145 *
146 * Make an ATOMENTRY pointer from a handle (obtained from GetAtomHandle()).
147 */
148 static inline ATOMENTRY *ATOM_MakePtr( HANDLE16 handle /* [in] Handle */ )
149 {
150 return MapSL( MAKESEGPTR( CURRENT_DS, handle ) );
151 }
152
153
154 /***********************************************************************
155 * InitAtomTable (KERNEL.68)
156 */
157 WORD WINAPI InitAtomTable16( WORD entries )
158 {
159 int i;
160 HANDLE16 handle;
161 ATOMTABLE *table;
162
163 /* Allocate the table */
164
165 if (!entries) entries = DEFAULT_ATOMTABLE_SIZE; /* sanity check */
166 handle = LocalAlloc16( LMEM_FIXED, sizeof(ATOMTABLE) + (entries-1) * sizeof(HANDLE16) );
167 if (!handle) return 0;
168 table = MapSL( MAKESEGPTR( CURRENT_DS, handle ) );
169 table->size = entries;
170 for (i = 0; i < entries; i++) table->entries[i] = 0;
171
172 /* Store a pointer to the table in the instance data */
173
174 ((INSTANCEDATA *)MapSL( MAKESEGPTR( CURRENT_DS, 0 )))->atomtable = handle;
175 return handle;
176 }
177
178 /***********************************************************************
179 * GetAtomHandle (KERNEL.73)
180 */
181 HANDLE16 WINAPI GetAtomHandle16( ATOM atom )
182 {
183 if (atom < MAXINTATOM) return 0;
184 return ATOMTOHANDLE( atom );
185 }
186
187
188 /***********************************************************************
189 * AddAtom (KERNEL.70)
190 *
191 * Windows DWORD aligns the atom entry size.
192 * The remaining unused string space created by the alignment
193 * gets padded with '\0's in a certain way to ensure
194 * that at least one trailing '\0' remains.
195 *
196 * RETURNS
197 * Atom: Success
198 * 0: Failure
199 */
200 ATOM WINAPI AddAtom16( LPCSTR str )
201 {
202 char buffer[MAX_ATOM_LEN+1];
203 WORD hash;
204 HANDLE16 entry;
205 ATOMENTRY * entryPtr;
206 ATOMTABLE * table;
207 int len, ae_len;
208 WORD iatom;
209
210 if (ATOM_IsIntAtomA( str, &iatom )) return iatom;
211
212 TRACE("%s\n",debugstr_a(str));
213
214 if (!(table = ATOM_GetTable( TRUE ))) return 0;
215
216 /* Make a copy of the string to be sure it doesn't move in linear memory. */
217 lstrcpynA( buffer, str, sizeof(buffer) );
218
219 len = strlen( buffer );
220 hash = ATOM_Hash( table->size, buffer, len );
221 entry = table->entries[hash];
222 while (entry)
223 {
224 entryPtr = ATOM_MakePtr( entry );
225 if ((entryPtr->length == len) &&
226 (!strncasecmp( entryPtr->str, buffer, len )))
227 {
228 entryPtr->refCount++;
229 TRACE("-- existing 0x%x\n", entry);
230 return HANDLETOATOM( entry );
231 }
232 entry = entryPtr->next;
233 }
234
235 ae_len = (sizeof(ATOMENTRY)+len+3) & ~3;
236 entry = LocalAlloc16( LMEM_FIXED, ae_len );
237 if (!entry) return 0;
238 /* Reload the table ptr in case it moved in linear memory */
239 table = ATOM_GetTable( FALSE );
240 entryPtr = ATOM_MakePtr( entry );
241 entryPtr->next = table->entries[hash];
242 entryPtr->refCount = 1;
243 entryPtr->length = len;
244 memcpy( entryPtr->str, buffer, len);
245 /* Some applications _need_ the '\0' padding provided by memset */
246 /* Note that 1 byte of the str is accounted for in the ATOMENTRY struct */
247 memset( entryPtr->str+len, 0, ae_len - sizeof(ATOMENTRY) - (len - 1));
248 table->entries[hash] = entry;
249 TRACE("-- new 0x%x\n", entry);
250 return HANDLETOATOM( entry );
251 }
252
253
254 /***********************************************************************
255 * DeleteAtom (KERNEL.71)
256 */
257 ATOM WINAPI DeleteAtom16( ATOM atom )
258 {
259 ATOMENTRY * entryPtr;
260 ATOMTABLE * table;
261 HANDLE16 entry, *prevEntry;
262 WORD hash;
263
264 if (atom < MAXINTATOM) return 0; /* Integer atom */
265
266 TRACE("0x%x\n",atom);
267
268 if (!(table = ATOM_GetTable( FALSE ))) return 0;
269 entry = ATOMTOHANDLE( atom );
270 entryPtr = ATOM_MakePtr( entry );
271
272 /* Find previous atom */
273 hash = ATOM_Hash( table->size, entryPtr->str, entryPtr->length );
274 prevEntry = &table->entries[hash];
275 while (*prevEntry && *prevEntry != entry)
276 {
277 ATOMENTRY * prevEntryPtr = ATOM_MakePtr( *prevEntry );
278 prevEntry = &prevEntryPtr->next;
279 }
280 if (!*prevEntry) return atom;
281
282 /* Delete atom */
283 if (--entryPtr->refCount == 0)
284 {
285 *prevEntry = entryPtr->next;
286 LocalFree16( entry );
287 }
288 return 0;
289 }
290
291
292 /***********************************************************************
293 * FindAtom (KERNEL.69)
294 */
295 ATOM WINAPI FindAtom16( LPCSTR str )
296 {
297 ATOMTABLE * table;
298 WORD hash,iatom;
299 HANDLE16 entry;
300 int len;
301
302 TRACE("%s\n",debugstr_a(str));
303
304 if (ATOM_IsIntAtomA( str, &iatom )) return iatom;
305 if ((len = strlen( str )) > 255) len = 255;
306 if (!(table = ATOM_GetTable( FALSE ))) return 0;
307 hash = ATOM_Hash( table->size, str, len );
308 entry = table->entries[hash];
309 while (entry)
310 {
311 ATOMENTRY * entryPtr = ATOM_MakePtr( entry );
312 if ((entryPtr->length == len) &&
313 (!strncasecmp( entryPtr->str, str, len )))
314 {
315 TRACE("-- found %x\n", entry);
316 return HANDLETOATOM( entry );
317 }
318 entry = entryPtr->next;
319 }
320 TRACE("-- not found\n");
321 return 0;
322 }
323
324
325 /***********************************************************************
326 * GetAtomName (KERNEL.72)
327 */
328 UINT16 WINAPI GetAtomName16( ATOM atom, LPSTR buffer, INT16 count )
329 {
330 ATOMENTRY * entryPtr;
331 HANDLE16 entry;
332 char * strPtr;
333 INT len;
334 char text[8];
335
336 TRACE("%x\n",atom);
337
338 if (!count) return 0;
339 if (atom < MAXINTATOM)
340 {
341 sprintf( text, "#%d", atom );
342 len = strlen(text);
343 strPtr = text;
344 }
345 else
346 {
347 if (!ATOM_GetTable( FALSE )) return 0;
348 entry = ATOMTOHANDLE( atom );
349 entryPtr = ATOM_MakePtr( entry );
350 len = entryPtr->length;
351 strPtr = entryPtr->str;
352 }
353 if (len >= count) len = count-1;
354 memcpy( buffer, strPtr, len );
355 buffer[len] = '\0';
356 return len;
357 }
358
This page was automatically generated by the
LXR engine.
Visit the LXR main site for more
information.