4 * Copyright 1993, 1994, 1995 Alexandre Julliard
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
19 #include "wine/winbase16.h"
20 #include "wine/winuser16.h"
25 #include "stackframe.h"
27 #include "debugtools.h"
29 DEFAULT_DEBUG_CHANNEL(atom)
31 #define DEFAULT_ATOMTABLE_SIZE 37
32 #define MIN_STR_ATOM 0xc000
33 #define MAX_ATOM_LEN 255
35 #define ATOMTOHANDLE(atom) ((HANDLE16)(atom) << 2)
36 #define HANDLETOATOM(handle) ((ATOM)(0xc000 | ((handle) >> 2)))
38 #define HAS_ATOM_TABLE(sel) \
39 ((INSTANCEDATA*)PTR_SEG_OFF_TO_LIN(sel,0))->atomtable != 0)
41 #define GET_ATOM_TABLE(sel) ((ATOMTABLE*)PTR_SEG_OFF_TO_LIN(sel, \
42 ((INSTANCEDATA*)PTR_SEG_OFF_TO_LIN(sel,0))->atomtable))
58 static WORD ATOM_GlobalTable = 0;
60 /***********************************************************************
64 * Should this validate the value of entries to be 0 < x < 0x3fff?
70 static HANDLE16 ATOM_InitTable(
71 WORD selector, /* [in] Segment */
72 WORD entries /* [in] Size of atom table */
78 /* We consider the first table to be initialized as the global table.
79 * This works, as USER (both built-in and native) is the first one to
83 if (!ATOM_GlobalTable) ATOM_GlobalTable = selector;
86 /* Allocate the table */
88 handle = LOCAL_Alloc( selector, LMEM_FIXED,
89 sizeof(ATOMTABLE) + (entries-1) * sizeof(HANDLE16) );
90 if (!handle) return 0;
91 table = (ATOMTABLE *)PTR_SEG_OFF_TO_LIN( selector, handle );
92 table->size = entries;
93 for (i = 0; i < entries; i++) table->entries[i] = 0;
95 /* Store a pointer to the table in the instance data */
97 ((INSTANCEDATA *)PTR_SEG_OFF_TO_LIN( selector, 0 ))->atomtable = handle;
102 /***********************************************************************
105 * Global table initialisation.
107 BOOL ATOM_Init( WORD globalTableSel )
109 return ATOM_InitTable( globalTableSel, DEFAULT_ATOMTABLE_SIZE ) != 0;
113 /***********************************************************************
116 * Return a pointer to the atom table of a given segment, creating
120 * Pointer to table: Success
123 static ATOMTABLE *ATOM_GetTable(
124 WORD selector, /* [in] Segment */
125 BOOL create /* [in] Create */ )
127 INSTANCEDATA *ptr = (INSTANCEDATA *)PTR_SEG_OFF_TO_LIN( selector, 0 );
130 ATOMTABLE *table = (ATOMTABLE *)((char *)ptr + ptr->atomtable);
131 if (table->size) return table;
133 if (!create) return NULL;
134 if (!ATOM_InitTable( selector, DEFAULT_ATOMTABLE_SIZE )) return NULL;
135 /* Reload ptr in case it moved in linear memory */
136 ptr = (INSTANCEDATA *)PTR_SEG_OFF_TO_LIN( selector, 0 );
137 return (ATOMTABLE *)((char *)ptr + ptr->atomtable);
141 /***********************************************************************
144 * Make an ATOMENTRY pointer from a handle (obtained from GetAtomHandle()).
146 static ATOMENTRY *ATOM_MakePtr(
147 WORD selector, /* [in] Segment */
148 HANDLE16 handle /* [in] Handle */
150 return (ATOMENTRY *)PTR_SEG_OFF_TO_LIN( selector, handle );
154 /***********************************************************************
157 * The hash value for the input string
159 static WORD ATOM_Hash(
160 WORD entries, /* [in] Total number of entries */
161 LPCSTR str, /* [in] Pointer to string to hash */
162 WORD len /* [in] Length of string */
166 TRACE("%x, %s, %x\n", entries, str, len);
168 for (i = 0; i < len; i++) hash ^= toupper(str[i]) + i;
169 return hash % entries;
172 static BOOL ATOM_IsIntAtom(LPCSTR atomstr,WORD *atomid) {
175 if (!HIWORD(atomstr)) {
176 *atomid = LOWORD(atomstr);
181 *atomid=strtol(atomstr+1,&xend,10);
183 FIXME("found atom named '%s'\n",atomstr);
190 /***********************************************************************
193 * Windows DWORD aligns the atom entry size.
194 * The remaining unused string space created by the alignment
195 * gets padded with '\0's in a certain way to ensure
196 * that at least one trailing '\0' remains.
202 static ATOM ATOM_AddAtom(
203 WORD selector, /* [in] Segment */
204 LPCSTR str /* [in] Pointer to the string to add */
208 ATOMENTRY * entryPtr;
213 TRACE("0x%x, %s\n", selector, str);
215 if (ATOM_IsIntAtom(str,&iatom))
217 if ((len = strlen( str )) > MAX_ATOM_LEN) len = MAX_ATOM_LEN;
218 if (!(table = ATOM_GetTable( selector, TRUE ))) return 0;
219 hash = ATOM_Hash( table->size, str, len );
220 entry = table->entries[hash];
223 entryPtr = ATOM_MakePtr( selector, entry );
224 if ((entryPtr->length == len) &&
225 (!lstrncmpiA( entryPtr->str, str, len )))
227 entryPtr->refCount++;
228 TRACE("-- existing 0x%x\n", entry);
229 return HANDLETOATOM( entry );
231 entry = entryPtr->next;
234 ae_len = (sizeof(ATOMENTRY)+len+3) & ~3;
235 entry = LOCAL_Alloc( selector, LMEM_FIXED, ae_len);
236 if (!entry) return 0;
237 /* Reload the table ptr in case it moved in linear memory */
238 table = ATOM_GetTable( selector, FALSE );
239 entryPtr = ATOM_MakePtr( selector, entry );
240 entryPtr->next = table->entries[hash];
241 entryPtr->refCount = 1;
242 entryPtr->length = len;
243 strncpy( entryPtr->str, str, ae_len - sizeof(ATOMENTRY) + 1); /* always use strncpy ('\0's padding) */
244 table->entries[hash] = entry;
245 TRACE("-- new 0x%x\n", entry);
246 return HANDLETOATOM( entry );
250 /***********************************************************************
256 static ATOM ATOM_DeleteAtom(
257 WORD selector, /* [in] Segment */
258 ATOM atom /* [in] Atom to delete */
260 ATOMENTRY * entryPtr;
262 HANDLE16 entry, *prevEntry;
265 TRACE("0x%x, 0x%x\n", selector, atom);
267 if (atom < MIN_STR_ATOM) return 0; /* Integer atom */
269 if (!(table = ATOM_GetTable( selector, FALSE ))) return 0;
270 entry = ATOMTOHANDLE( atom );
271 entryPtr = ATOM_MakePtr( selector, 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( selector, *prevEntry );
279 prevEntry = &prevEntryPtr->next;
281 if (!*prevEntry) return atom;
284 if (--entryPtr->refCount == 0)
286 *prevEntry = entryPtr->next;
287 LOCAL_Free( selector, entry );
293 /***********************************************************************
299 static ATOM ATOM_FindAtom(
300 WORD selector, /* [in] Segment */
301 LPCSTR str /* [in] Pointer to string to find */
308 TRACE("%x, %s\n", selector, str);
309 if (ATOM_IsIntAtom(str,&iatom))
311 if ((len = strlen( str )) > 255) len = 255;
312 if (!(table = ATOM_GetTable( selector, FALSE ))) return 0;
313 hash = ATOM_Hash( table->size, str, len );
314 entry = table->entries[hash];
317 ATOMENTRY * entryPtr = ATOM_MakePtr( selector, entry );
318 if ((entryPtr->length == len) &&
319 (!lstrncmpiA( entryPtr->str, str, len )))
320 { TRACE("-- found %x\n", entry);
321 return HANDLETOATOM( entry );
323 entry = entryPtr->next;
325 TRACE("-- not found\n");
330 /***********************************************************************
333 * Length of string copied to buffer: Success
336 static UINT ATOM_GetAtomName(
337 WORD selector, /* [in] Segment */
338 ATOM atom, /* [in] Atom identifier */
339 LPSTR buffer, /* [out] Pointer to buffer for atom string */
340 INT count /* [in] Size of buffer */
343 ATOMENTRY * entryPtr;
349 TRACE("%x, %x\n", selector, atom);
351 if (!count) return 0;
352 if (atom < MIN_STR_ATOM)
354 sprintf( text, "#%d", atom );
360 if (!(table = ATOM_GetTable( selector, FALSE ))) return 0;
361 entry = ATOMTOHANDLE( atom );
362 entryPtr = ATOM_MakePtr( selector, entry );
363 len = entryPtr->length;
364 strPtr = entryPtr->str;
366 if (len >= count) len = count-1;
367 memcpy( buffer, strPtr, len );
373 /***********************************************************************
374 * InitAtomTable16 (KERNEL.68)
376 WORD WINAPI InitAtomTable16( WORD entries )
378 if (!entries) entries = DEFAULT_ATOMTABLE_SIZE; /* sanity check */
379 return ATOM_InitTable( CURRENT_DS, entries );
383 /***********************************************************************
384 * GetAtomHandle (KERNEL.73)
386 HANDLE16 WINAPI GetAtomHandle16( ATOM atom )
388 if (atom < MIN_STR_ATOM) return 0;
389 return ATOMTOHANDLE( atom );
393 /***********************************************************************
394 * AddAtom16 (KERNEL.70)
396 ATOM WINAPI AddAtom16( SEGPTR str )
399 HANDLE16 ds = CURRENT_DS;
401 if (!HIWORD(str)) return (ATOM)LOWORD(str); /* Integer atom */
402 if (SELECTOR_TO_ENTRY(LOWORD(str)) == SELECTOR_TO_ENTRY(ds))
404 /* If the string is in the same data segment as the atom table, make */
405 /* a copy of the string to be sure it doesn't move in linear memory. */
406 char buffer[MAX_ATOM_LEN+1];
407 lstrcpynA( buffer, (char *)PTR_SEG_TO_LIN(str), sizeof(buffer) );
408 atom = ATOM_AddAtom( ds, buffer );
410 else atom = ATOM_AddAtom( ds, (LPCSTR)PTR_SEG_TO_LIN(str) );
415 /***********************************************************************
416 * AddAtom32A (KERNEL32.0)
417 * Adds a string to the atom table and returns the atom identifying the
424 ATOM WINAPI AddAtomA(
425 LPCSTR str /* [in] Pointer to string to add */
427 return GlobalAddAtomA( str ); /* FIXME */
431 /***********************************************************************
432 * AddAtom32W (KERNEL32.1)
435 ATOM WINAPI AddAtomW( LPCWSTR str )
437 return GlobalAddAtomW( str ); /* FIXME */
441 /***********************************************************************
442 * DeleteAtom16 (KERNEL.71)
444 ATOM WINAPI DeleteAtom16( ATOM atom )
446 return ATOM_DeleteAtom( CURRENT_DS, atom );
450 /***********************************************************************
451 * DeleteAtom32 (KERNEL32.69)
452 * Decrements the reference count of a string atom. If count becomes
453 * zero, the string associated with the atom is removed from the table.
459 ATOM WINAPI DeleteAtom(
460 ATOM atom /* [in] Atom to delete */
462 return GlobalDeleteAtom( atom ); /* FIXME */
466 /***********************************************************************
467 * FindAtom16 (KERNEL.69)
469 ATOM WINAPI FindAtom16( SEGPTR str )
471 if (!HIWORD(str)) return (ATOM)LOWORD(str); /* Integer atom */
472 return ATOM_FindAtom( CURRENT_DS, (LPCSTR)PTR_SEG_TO_LIN(str) );
476 /***********************************************************************
477 * FindAtom32A (KERNEL32.117)
478 * Searches the local atom table for the string and returns the atom
479 * associated with that string.
485 ATOM WINAPI FindAtomA(
486 LPCSTR str /* [in] Pointer to string to find */
488 return GlobalFindAtomA( str ); /* FIXME */
492 /***********************************************************************
493 * FindAtom32W (KERNEL32.118)
496 ATOM WINAPI FindAtomW( LPCWSTR str )
498 return GlobalFindAtomW( str ); /* FIXME */
502 /***********************************************************************
503 * GetAtomName16 (KERNEL.72)
505 UINT16 WINAPI GetAtomName16( ATOM atom, LPSTR buffer, INT16 count )
507 return (UINT16)ATOM_GetAtomName( CURRENT_DS, atom, buffer, count );
511 /***********************************************************************
512 * GetAtomName32A (KERNEL32.149)
513 * Retrieves a copy of the string associated with the atom.
516 * Length of string: Success
519 UINT WINAPI GetAtomNameA(
520 ATOM atom, /* [in] Atom */
521 LPSTR buffer, /* [out] Pointer to string for atom string */
522 INT count /* [in] Size of buffer */
524 return GlobalGetAtomNameA( atom, buffer, count ); /* FIXME */
528 /***********************************************************************
529 * GetAtomName32W (KERNEL32.150)
532 UINT WINAPI GetAtomNameW( ATOM atom, LPWSTR buffer, INT count )
534 return GlobalGetAtomNameW( atom, buffer, count ); /* FIXME */
538 /***********************************************************************
539 * GlobalAddAtom16 (USER.268)
541 ATOM WINAPI GlobalAddAtom16( SEGPTR str )
543 if (!HIWORD(str)) return (ATOM)LOWORD(str); /* Integer atom */
544 return ATOM_AddAtom( ATOM_GlobalTable, (LPCSTR)PTR_SEG_TO_LIN(str) );
548 /***********************************************************************
549 * GlobalAddAtom32A (KERNEL32.313)
550 * Adds a character string to the global atom table and returns a unique
551 * value identifying the string.
557 ATOM WINAPI GlobalAddAtomA(
558 LPCSTR str /* [in] Pointer to string to add */
560 if (!HIWORD(str)) return (ATOM)LOWORD(str); /* Integer atom */
561 return ATOM_AddAtom( ATOM_GlobalTable, str );
565 /***********************************************************************
566 * GlobalAddAtom32W (KERNEL32.314)
567 * See GlobalAddAtom32A
569 ATOM WINAPI GlobalAddAtomW( LPCWSTR str )
571 char buffer[MAX_ATOM_LEN+1];
572 if (!HIWORD(str)) return (ATOM)LOWORD(str); /* Integer atom */
573 lstrcpynWtoA( buffer, str, sizeof(buffer) );
574 return ATOM_AddAtom( ATOM_GlobalTable, buffer );
578 /***********************************************************************
579 * GlobalDeleteAtom (USER.269) (KERNEL32.317)
580 * Decrements the reference count of a string atom. If the count is
581 * zero, the string associated with the atom is removed from the table.
587 ATOM WINAPI GlobalDeleteAtom(
588 ATOM atom /* [in] Atom to delete */
590 return ATOM_DeleteAtom( ATOM_GlobalTable, atom );
594 /***********************************************************************
595 * GlobalFindAtom16 (USER.270)
597 ATOM WINAPI GlobalFindAtom16( SEGPTR str )
599 if (!HIWORD(str)) return (ATOM)LOWORD(str); /* Integer atom */
600 return ATOM_FindAtom( ATOM_GlobalTable, (LPCSTR)PTR_SEG_TO_LIN(str) );
604 /***********************************************************************
605 * GlobalFindAtom32A (KERNEL32.318)
606 * Searches the atom table for the string and returns the atom
607 * associated with it.
613 ATOM WINAPI GlobalFindAtomA(
614 LPCSTR str /* [in] Pointer to string to search for */
616 if (!HIWORD(str)) return (ATOM)LOWORD(str); /* Integer atom */
617 return ATOM_FindAtom( ATOM_GlobalTable, str );
621 /***********************************************************************
622 * GlobalFindAtom32W (KERNEL32.319)
623 * See GlobalFindAtom32A
625 ATOM WINAPI GlobalFindAtomW( LPCWSTR str )
627 char buffer[MAX_ATOM_LEN+1];
628 if (!HIWORD(str)) return (ATOM)LOWORD(str); /* Integer atom */
629 lstrcpynWtoA( buffer, str, sizeof(buffer) );
630 return ATOM_FindAtom( ATOM_GlobalTable, buffer );
634 /***********************************************************************
635 * GlobalGetAtomName16 (USER.271)
637 UINT16 WINAPI GlobalGetAtomName16( ATOM atom, LPSTR buffer, INT16 count )
639 return (UINT16)ATOM_GetAtomName( ATOM_GlobalTable, atom, buffer, count );
643 /***********************************************************************
644 * GlobalGetAtomName32A (KERNEL32.323)
645 * Retrieves a copy of the string associated with an atom.
648 * Length of string in characters: Success
651 UINT WINAPI GlobalGetAtomNameA(
652 ATOM atom, /* [in] Atom identifier */
653 LPSTR buffer, /* [out] Pointer to buffer for atom string */
654 INT count /* [in] Size of buffer */
656 return ATOM_GetAtomName( ATOM_GlobalTable, atom, buffer, count );
660 /***********************************************************************
661 * GlobalGetAtomName32W (KERNEL32.324)
662 * See GlobalGetAtomName32A
664 UINT WINAPI GlobalGetAtomNameW( ATOM atom, LPWSTR buffer, INT count )
666 char tmp[MAX_ATOM_LEN+1];
667 ATOM_GetAtomName( ATOM_GlobalTable, atom, tmp, sizeof(tmp) );
668 lstrcpynAtoW( buffer, tmp, count );
669 return lstrlenW( buffer );