Release 960712
[wine] / memory / atom.c
1 /*
2  * Atom table functions
3  *
4  * Copyright 1993, 1994, 1995 Alexandre Julliard
5  */
6
7 /*
8  * Warning: The code assumes that LocalAlloc() returns a block aligned
9  * on a 4-bytes boundary (because of the shifting done in
10  * HANDLETOATOM).  If this is not the case, the allocation code will
11  * have to be changed.
12  */
13
14 #include <stdlib.h>
15 #include <stdio.h>
16 #include <string.h>
17 #include <ctype.h>
18
19 #include "atom.h"
20 #include "instance.h"
21 #include "ldt.h"
22 #include "stackframe.h"
23 #include "user.h"
24
25 #ifdef CONFIG_IPC
26 #include "dde_atom.h"
27 #include "options.h"
28 #endif
29
30 #define DEFAULT_ATOMTABLE_SIZE    37
31 #define MIN_STR_ATOM              0xc000
32 #define MAX_ATOM_LEN              255
33
34 #define ATOMTOHANDLE(atom)        ((HANDLE)(atom) << 2)
35 #define HANDLETOATOM(handle)      ((ATOM)(0xc000 | ((handle) >> 2)))
36
37 #define HAS_ATOM_TABLE(sel)  \
38           ((INSTANCEDATA*)PTR_SEG_OFF_TO_LIN(sel,0))->atomtable != 0)
39
40 #define GET_ATOM_TABLE(sel)  ((ATOMTABLE*)PTR_SEG_OFF_TO_LIN(sel, \
41           ((INSTANCEDATA*)PTR_SEG_OFF_TO_LIN(sel,0))->atomtable))
42                 
43
44 /***********************************************************************
45  *           ATOM_InitTable
46  */
47 static HANDLE16 ATOM_InitTable( WORD selector, WORD entries )
48 {
49     int i;
50     HANDLE16 handle;
51     ATOMTABLE *table;
52
53       /* Allocate the table */
54
55     handle = LOCAL_Alloc( selector, LMEM_FIXED,
56                           sizeof(ATOMTABLE) + (entries-1) * sizeof(HANDLE) );
57     if (!handle) return 0;
58     table = (ATOMTABLE *)PTR_SEG_OFF_TO_LIN( selector, handle );
59     table->size = entries;
60     for (i = 0; i < entries; i++) table->entries[i] = 0;
61
62       /* Store a pointer to the table in the instance data */
63
64     ((INSTANCEDATA *)PTR_SEG_OFF_TO_LIN( selector, 0 ))->atomtable = handle;
65     return handle;
66 }
67
68
69 /***********************************************************************
70  *           ATOM_Init
71  *
72  * Global table initialisation.
73  */
74 BOOL ATOM_Init(void)
75 {
76     return ATOM_InitTable( USER_HeapSel, DEFAULT_ATOMTABLE_SIZE ) != 0;
77 }
78
79
80 /***********************************************************************
81  *           ATOM_GetTable
82  *
83  * Return a pointer to the atom table of a given segment, creating
84  * it if necessary.
85  */
86 static ATOMTABLE * ATOM_GetTable( WORD selector, BOOL create )
87 {
88     INSTANCEDATA *ptr = (INSTANCEDATA *)PTR_SEG_OFF_TO_LIN( selector, 0 );
89     if (!ptr->atomtable)
90     {
91         if (!create) return NULL;
92         if (!ATOM_InitTable( selector, DEFAULT_ATOMTABLE_SIZE )) return NULL;
93         /* Reload ptr in case it moved in linear memory */
94         ptr = (INSTANCEDATA *)PTR_SEG_OFF_TO_LIN( selector, 0 );
95     }
96     return (ATOMTABLE *)((char *)ptr + ptr->atomtable);
97 }
98
99
100 /***********************************************************************
101  *           ATOM_MakePtr
102  *
103  * Make an ATOMENTRY pointer from a handle (obtained from GetAtomHandle()).
104  */
105 static ATOMENTRY * ATOM_MakePtr( WORD selector, HANDLE handle )
106 {
107     return (ATOMENTRY *)PTR_SEG_OFF_TO_LIN( selector, handle );
108 }
109
110
111 /***********************************************************************
112  *           ATOM_Hash
113  */
114 static WORD ATOM_Hash( WORD entries, LPCSTR str, WORD len )
115 {
116     WORD i, hash = 0;
117
118     for (i = 0; i < len; i++) hash ^= toupper(str[i]) + i;
119     return hash % entries;
120 }
121
122
123 /***********************************************************************
124  *           ATOM_AddAtom
125  */
126 static ATOM ATOM_AddAtom( WORD selector, LPCSTR str )
127 {
128     WORD hash;
129     HANDLE entry;
130     ATOMENTRY * entryPtr;
131     ATOMTABLE * table;
132     int len;
133
134     if (str[0] == '#') return atoi( &str[1] );  /* Check for integer atom */
135     if ((len = strlen( str )) > 255) len = 255;
136     if (!(table = ATOM_GetTable( selector, TRUE ))) return 0;
137     hash = ATOM_Hash( table->size, str, len );
138     entry = table->entries[hash];
139     while (entry)
140     {
141         entryPtr = ATOM_MakePtr( selector, entry );
142         if ((entryPtr->length == len) && 
143             (!lstrncmpi32A( entryPtr->str, str, len )))
144         {
145             entryPtr->refCount++;
146             return HANDLETOATOM( entry );
147         }
148         entry = entryPtr->next;
149     }
150
151     entry = LOCAL_Alloc( selector, LMEM_FIXED, sizeof(ATOMENTRY)+len-1 );
152     if (!entry) return 0;
153     /* Reload the table ptr in case it moved in linear memory */
154     table = ATOM_GetTable( selector, FALSE );
155     entryPtr = ATOM_MakePtr( selector, entry );
156     entryPtr->next = table->entries[hash];
157     entryPtr->refCount = 1;
158     entryPtr->length = len;
159     memcpy( entryPtr->str, str, len );
160     table->entries[hash] = entry;
161     return HANDLETOATOM( entry );
162 }
163
164
165 /***********************************************************************
166  *           ATOM_DeleteAtom
167  */
168 static ATOM ATOM_DeleteAtom( WORD selector, ATOM atom )
169 {
170     ATOMENTRY * entryPtr;
171     ATOMTABLE * table;
172     HANDLE entry, *prevEntry;
173     WORD hash;
174     
175     if (atom < MIN_STR_ATOM) return 0;  /* Integer atom */
176
177     if (!(table = ATOM_GetTable( selector, FALSE ))) return 0;
178     entry = ATOMTOHANDLE( atom );
179     entryPtr = ATOM_MakePtr( selector, entry );
180
181       /* Find previous atom */
182     hash = ATOM_Hash( table->size, entryPtr->str, entryPtr->length );
183     prevEntry = &table->entries[hash];
184     while (*prevEntry && *prevEntry != entry)
185     {
186         ATOMENTRY * prevEntryPtr = ATOM_MakePtr( selector, *prevEntry );
187         prevEntry = &prevEntryPtr->next;
188     }    
189     if (!*prevEntry) return atom;
190
191       /* Delete atom */
192     if (--entryPtr->refCount == 0)
193     {
194         *prevEntry = entryPtr->next;
195         LOCAL_Free( selector, entry );
196     }    
197     return 0;
198 }
199
200
201 /***********************************************************************
202  *           ATOM_FindAtom
203  */
204 static ATOM ATOM_FindAtom( WORD selector, LPCSTR str )
205 {
206     ATOMTABLE * table;
207     WORD hash;
208     HANDLE entry;
209     int len;
210
211     if (str[0] == '#') return atoi( &str[1] );  /* Check for integer atom */
212     if ((len = strlen( str )) > 255) len = 255;
213     if (!(table = ATOM_GetTable( selector, FALSE ))) return 0;
214     hash = ATOM_Hash( table->size, str, len );
215     entry = table->entries[hash];
216     while (entry)
217     {
218         ATOMENTRY * entryPtr = ATOM_MakePtr( selector, entry );
219         if ((entryPtr->length == len) && 
220             (!lstrncmpi32A( entryPtr->str, str, len )))
221             return HANDLETOATOM( entry );
222         entry = entryPtr->next;
223     }
224     return 0;
225 }
226
227
228 /***********************************************************************
229  *           ATOM_GetAtomName
230  */
231 static UINT32 ATOM_GetAtomName( WORD selector, ATOM atom,
232                                 LPSTR buffer, INT32 count )
233 {
234     ATOMTABLE * table;
235     ATOMENTRY * entryPtr;
236     HANDLE entry;
237     char * strPtr;
238     UINT32 len;
239     char text[8];
240     
241     if (!count) return 0;
242     if (atom < MIN_STR_ATOM)
243     {
244         sprintf( text, "#%d", atom );
245         len = strlen(text);
246         strPtr = text;
247     }
248     else
249     {
250         if (!(table = ATOM_GetTable( selector, FALSE ))) return 0;
251         entry = ATOMTOHANDLE( atom );
252         entryPtr = ATOM_MakePtr( selector, entry );
253         len = entryPtr->length;
254         strPtr = entryPtr->str;
255     }
256     if (len >= count) len = count-1;
257     memcpy( buffer, strPtr, len );
258     buffer[len] = '\0';
259     return len;
260 }
261
262
263 /***********************************************************************
264  *           InitAtomTable   (KERNEL.68)
265  */
266 WORD InitAtomTable( WORD entries )
267 {
268     return ATOM_InitTable( CURRENT_DS, entries );
269 }
270
271
272 /***********************************************************************
273  *           GetAtomHandle   (KERNEL.73)
274  */
275 HANDLE GetAtomHandle( ATOM atom )
276 {
277     if (atom < MIN_STR_ATOM) return 0;
278     return ATOMTOHANDLE( atom );
279 }
280
281
282 /***********************************************************************
283  *           AddAtom   (KERNEL.70)
284  */
285 ATOM AddAtom( SEGPTR str )
286 {
287     ATOM atom;
288     HANDLE16 ds = CURRENT_DS;
289
290     if (!HIWORD(str)) return (ATOM)LOWORD(str);  /* Integer atom */
291     if (SELECTOR_TO_ENTRY(LOWORD(str)) == SELECTOR_TO_ENTRY(ds))
292     {
293         /* If the string is in the same data segment as the atom table, make */
294         /* a copy of the string to be sure it doesn't move in linear memory. */
295         char buffer[256];
296         lstrcpyn32A( buffer, (char *)PTR_SEG_TO_LIN(str), sizeof(buffer) );
297         atom = ATOM_AddAtom( ds, buffer );
298     }
299     else atom = ATOM_AddAtom( ds, (LPCSTR)PTR_SEG_TO_LIN(str) );
300     return atom;
301 }
302
303
304 /***********************************************************************
305  *           DeleteAtom   (KERNEL.71)
306  */
307 ATOM DeleteAtom( ATOM atom )
308 {
309     return ATOM_DeleteAtom( CURRENT_DS, atom );
310 }
311
312
313 /***********************************************************************
314  *           FindAtom   (KERNEL.69)
315  */
316 ATOM FindAtom( SEGPTR str )
317 {
318     if (!HIWORD(str)) return (ATOM)LOWORD(str);  /* Integer atom */
319     return ATOM_FindAtom( CURRENT_DS, (LPCSTR)PTR_SEG_TO_LIN(str) );
320 }
321
322
323 /***********************************************************************
324  *           GetAtomName   (KERNEL.72)
325  */
326 WORD GetAtomName( ATOM atom, LPSTR buffer, short count )
327 {
328     return (WORD)ATOM_GetAtomName( CURRENT_DS, atom, buffer, count );
329 }
330
331
332 /***********************************************************************
333  *           GlobalAddAtom16   (USER.268)
334  */
335 ATOM GlobalAddAtom16( SEGPTR str )
336 {
337     if (!HIWORD(str)) return (ATOM)LOWORD(str);  /* Integer atom */
338 #ifdef CONFIG_IPC
339     if (Options.ipc) return DDE_GlobalAddAtom( str );
340 #endif
341     return ATOM_AddAtom( USER_HeapSel, (LPCSTR)PTR_SEG_TO_LIN(str) );
342 }
343
344
345 /***********************************************************************
346  *           GlobalAddAtom32A   (KERNEL32.313)
347  */
348 ATOM GlobalAddAtom32A( LPCSTR str )
349 {
350     if (!HIWORD(str)) return (ATOM)LOWORD(str);  /* Integer atom */
351     return ATOM_AddAtom( USER_HeapSel, str );
352 }
353
354
355 /***********************************************************************
356  *           GlobalAddAtom32W   (KERNEL32.314)
357  */
358 ATOM GlobalAddAtom32W( LPCWSTR str )
359 {
360     char buffer[MAX_ATOM_LEN+1];
361     if (!HIWORD(str)) return (ATOM)LOWORD(str);  /* Integer atom */
362     lstrcpynWtoA( buffer, str, sizeof(buffer) );
363     return ATOM_AddAtom( USER_HeapSel, buffer );
364 }
365
366
367 /***********************************************************************
368  *           GlobalDeleteAtom   (USER.269) (KERNEL32.317)
369  */
370 ATOM GlobalDeleteAtom( ATOM atom )
371 {
372 #ifdef CONFIG_IPC
373     if (Options.ipc) return DDE_GlobalDeleteAtom( atom );
374 #endif
375     return ATOM_DeleteAtom( USER_HeapSel, atom );
376 }
377
378
379 /***********************************************************************
380  *           GlobalFindAtom16   (USER.270)
381  */
382 ATOM GlobalFindAtom16( SEGPTR str )
383 {
384     if (!HIWORD(str)) return (ATOM)LOWORD(str);  /* Integer atom */
385 #ifdef CONFIG_IPC
386     if (Options.ipc) return DDE_GlobalFindAtom( str );
387 #endif
388     return ATOM_FindAtom( USER_HeapSel, (LPCSTR)PTR_SEG_TO_LIN(str) );
389 }
390
391
392 /***********************************************************************
393  *           GlobalFindAtom32A   (KERNEL32.318)
394  */
395 ATOM GlobalFindAtom32A( LPCSTR str )
396 {
397     if (!HIWORD(str)) return (ATOM)LOWORD(str);  /* Integer atom */
398     return ATOM_FindAtom( USER_HeapSel, str );
399 }
400
401
402 /***********************************************************************
403  *           GlobalFindAtom32W   (KERNEL32.319)
404  */
405 ATOM GlobalFindAtom32W( LPCWSTR str )
406 {
407     char buffer[MAX_ATOM_LEN+1];
408     if (!HIWORD(str)) return (ATOM)LOWORD(str);  /* Integer atom */
409     lstrcpynWtoA( buffer, str, sizeof(buffer) );
410     return ATOM_FindAtom( USER_HeapSel, buffer );
411 }
412
413
414 /***********************************************************************
415  *           GlobalGetAtomName16   (USER.271)
416  */
417 UINT16 GlobalGetAtomName16( ATOM atom, LPSTR buffer, INT16 count )
418 {
419 #ifdef CONFIG_IPC
420     if (Options.ipc) return DDE_GlobalGetAtomName( atom, buffer, count );
421 #endif
422     return (UINT16)ATOM_GetAtomName( USER_HeapSel, atom, buffer, count );
423 }
424
425
426 /***********************************************************************
427  *           GlobalGetAtomName32A   (KERNEL32.323)
428  */
429 UINT32 GlobalGetAtomName32A( ATOM atom, LPSTR buffer, INT32 count )
430 {
431     return ATOM_GetAtomName( USER_HeapSel, atom, buffer, count );
432 }
433
434 /***********************************************************************
435  *           GlobalGetAtomName32W   (KERNEL32.324)
436  */
437 UINT32 GlobalGetAtomName32W( ATOM atom, LPWSTR buffer, INT32 count )
438 {
439     char tmp[MAX_ATOM_LEN+1];
440     ATOM_GetAtomName( USER_HeapSel, atom, tmp, sizeof(tmp) );
441     lstrcpynAtoW( buffer, tmp, count );
442     return lstrlen32W( buffer );
443 }