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"
24 #include "stackframe.h"
26 #include "debugtools.h"
32 DEFAULT_DEBUG_CHANNEL(atom)
34 #define DEFAULT_ATOMTABLE_SIZE 37
35 #define MIN_STR_ATOM 0xc000
36 #define MAX_ATOM_LEN 255
38 #define ATOMTOHANDLE(atom) ((HANDLE16)(atom) << 2)
39 #define HANDLETOATOM(handle) ((ATOM)(0xc000 | ((handle) >> 2)))
41 #define HAS_ATOM_TABLE(sel) \
42 ((INSTANCEDATA*)PTR_SEG_OFF_TO_LIN(sel,0))->atomtable != 0)
44 #define GET_ATOM_TABLE(sel) ((ATOMTABLE*)PTR_SEG_OFF_TO_LIN(sel, \
45 ((INSTANCEDATA*)PTR_SEG_OFF_TO_LIN(sel,0))->atomtable))
61 static WORD ATOM_GlobalTable = 0;
63 /***********************************************************************
67 * Should this validate the value of entries to be 0 < x < 0x3fff?
73 static HANDLE16 ATOM_InitTable(
74 WORD selector, /* [in] Segment */
75 WORD entries /* [in] Size of atom table */
81 /* We consider the first table to be initialized as the global table.
82 * This works, as USER (both built-in and native) is the first one to
86 if (!ATOM_GlobalTable) ATOM_GlobalTable = selector;
89 /* Allocate the table */
91 handle = LOCAL_Alloc( selector, LMEM_FIXED,
92 sizeof(ATOMTABLE) + (entries-1) * sizeof(HANDLE16) );
93 if (!handle) return 0;
94 table = (ATOMTABLE *)PTR_SEG_OFF_TO_LIN( selector, handle );
95 table->size = entries;
96 for (i = 0; i < entries; i++) table->entries[i] = 0;
98 /* Store a pointer to the table in the instance data */
100 ((INSTANCEDATA *)PTR_SEG_OFF_TO_LIN( selector, 0 ))->atomtable = handle;
105 /***********************************************************************
108 * Global table initialisation.
110 BOOL ATOM_Init( WORD globalTableSel )
112 return ATOM_InitTable( globalTableSel, DEFAULT_ATOMTABLE_SIZE ) != 0;
116 /***********************************************************************
119 * Return a pointer to the atom table of a given segment, creating
123 * Pointer to table: Success
126 static ATOMTABLE *ATOM_GetTable(
127 WORD selector, /* [in] Segment */
128 BOOL create /* [in] Create */ )
130 INSTANCEDATA *ptr = (INSTANCEDATA *)PTR_SEG_OFF_TO_LIN( selector, 0 );
133 ATOMTABLE *table = (ATOMTABLE *)((char *)ptr + ptr->atomtable);
134 if (table->size) return table;
136 if (!create) return NULL;
137 if (!ATOM_InitTable( selector, DEFAULT_ATOMTABLE_SIZE )) return NULL;
138 /* Reload ptr in case it moved in linear memory */
139 ptr = (INSTANCEDATA *)PTR_SEG_OFF_TO_LIN( selector, 0 );
140 return (ATOMTABLE *)((char *)ptr + ptr->atomtable);
144 /***********************************************************************
147 * Make an ATOMENTRY pointer from a handle (obtained from GetAtomHandle()).
149 static ATOMENTRY *ATOM_MakePtr(
150 WORD selector, /* [in] Segment */
151 HANDLE16 handle /* [in] Handle */
153 return (ATOMENTRY *)PTR_SEG_OFF_TO_LIN( selector, handle );
157 /***********************************************************************
160 * The hash value for the input string
162 static WORD ATOM_Hash(
163 WORD entries, /* [in] Total number of entries */
164 LPCSTR str, /* [in] Pointer to string to hash */
165 WORD len /* [in] Length of string */
169 TRACE("%x, %s, %x\n", entries, str, len);
171 for (i = 0; i < len; i++) hash ^= toupper(str[i]) + i;
172 return hash % entries;
175 static BOOL ATOM_IsIntAtom(LPCSTR atomstr,WORD *atomid) {
178 if (!HIWORD(atomstr)) {
179 *atomid = LOWORD(atomstr);
184 *atomid=strtol(atomstr+1,&xend,10);
186 FIXME("found atom named '%s'\n",atomstr);
193 /***********************************************************************
196 * Windows DWORD aligns the atom entry size.
197 * The remaining unused string space created by the alignment
198 * gets padded with '\0's in a certain way to ensure
199 * that at least one trailing '\0' remains.
205 static ATOM ATOM_AddAtom(
206 WORD selector, /* [in] Segment */
207 LPCSTR str /* [in] Pointer to the string to add */
211 ATOMENTRY * entryPtr;
216 TRACE("0x%x, %s\n", selector, str);
218 if (ATOM_IsIntAtom(str,&iatom))
220 if ((len = strlen( str )) > MAX_ATOM_LEN) len = MAX_ATOM_LEN;
221 if (!(table = ATOM_GetTable( selector, TRUE ))) return 0;
222 hash = ATOM_Hash( table->size, str, len );
223 entry = table->entries[hash];
226 entryPtr = ATOM_MakePtr( selector, entry );
227 if ((entryPtr->length == len) &&
228 (!lstrncmpiA( entryPtr->str, str, len )))
230 entryPtr->refCount++;
231 TRACE("-- existing 0x%x\n", entry);
232 return HANDLETOATOM( entry );
234 entry = entryPtr->next;
237 ae_len = (sizeof(ATOMENTRY)+len+3) & ~3;
238 entry = LOCAL_Alloc( selector, LMEM_FIXED, ae_len);
239 if (!entry) return 0;
240 /* Reload the table ptr in case it moved in linear memory */
241 table = ATOM_GetTable( selector, FALSE );
242 entryPtr = ATOM_MakePtr( selector, entry );
243 entryPtr->next = table->entries[hash];
244 entryPtr->refCount = 1;
245 entryPtr->length = len;
246 strncpy( entryPtr->str, str, ae_len - sizeof(ATOMENTRY) + 1); /* always use strncpy ('\0's padding) */
247 table->entries[hash] = entry;
248 TRACE("-- new 0x%x\n", entry);
249 return HANDLETOATOM( entry );
253 /***********************************************************************
259 static ATOM ATOM_DeleteAtom(
260 WORD selector, /* [in] Segment */
261 ATOM atom /* [in] Atom to delete */
263 ATOMENTRY * entryPtr;
265 HANDLE16 entry, *prevEntry;
268 TRACE("0x%x, 0x%x\n", selector, atom);
270 if (atom < MIN_STR_ATOM) return 0; /* Integer atom */
272 if (!(table = ATOM_GetTable( selector, FALSE ))) return 0;
273 entry = ATOMTOHANDLE( atom );
274 entryPtr = ATOM_MakePtr( selector, entry );
276 /* Find previous atom */
277 hash = ATOM_Hash( table->size, entryPtr->str, entryPtr->length );
278 prevEntry = &table->entries[hash];
279 while (*prevEntry && *prevEntry != entry)
281 ATOMENTRY * prevEntryPtr = ATOM_MakePtr( selector, *prevEntry );
282 prevEntry = &prevEntryPtr->next;
284 if (!*prevEntry) return atom;
287 if (--entryPtr->refCount == 0)
289 *prevEntry = entryPtr->next;
290 LOCAL_Free( selector, entry );
296 /***********************************************************************
302 static ATOM ATOM_FindAtom(
303 WORD selector, /* [in] Segment */
304 LPCSTR str /* [in] Pointer to string to find */
311 TRACE("%x, %s\n", selector, str);
312 if (ATOM_IsIntAtom(str,&iatom))
314 if ((len = strlen( str )) > 255) len = 255;
315 if (!(table = ATOM_GetTable( selector, FALSE ))) return 0;
316 hash = ATOM_Hash( table->size, str, len );
317 entry = table->entries[hash];
320 ATOMENTRY * entryPtr = ATOM_MakePtr( selector, entry );
321 if ((entryPtr->length == len) &&
322 (!lstrncmpiA( entryPtr->str, str, len )))
323 { TRACE("-- found %x\n", entry);
324 return HANDLETOATOM( entry );
326 entry = entryPtr->next;
328 TRACE("-- not found\n");
333 /***********************************************************************
336 * Length of string copied to buffer: Success
339 static UINT ATOM_GetAtomName(
340 WORD selector, /* [in] Segment */
341 ATOM atom, /* [in] Atom identifier */
342 LPSTR buffer, /* [out] Pointer to buffer for atom string */
343 INT count /* [in] Size of buffer */
346 ATOMENTRY * entryPtr;
352 TRACE("%x, %x\n", selector, atom);
354 if (!count) return 0;
355 if (atom < MIN_STR_ATOM)
357 sprintf( text, "#%d", atom );
363 if (!(table = ATOM_GetTable( selector, FALSE ))) return 0;
364 entry = ATOMTOHANDLE( atom );
365 entryPtr = ATOM_MakePtr( selector, entry );
366 len = entryPtr->length;
367 strPtr = entryPtr->str;
369 if (len >= count) len = count-1;
370 memcpy( buffer, strPtr, len );
376 /***********************************************************************
377 * InitAtomTable16 (KERNEL.68)
379 WORD WINAPI InitAtomTable16( WORD entries )
381 if (!entries) entries = DEFAULT_ATOMTABLE_SIZE; /* sanity check */
382 return ATOM_InitTable( CURRENT_DS, entries );
386 /***********************************************************************
387 * GetAtomHandle (KERNEL.73)
389 HANDLE16 WINAPI GetAtomHandle16( ATOM atom )
391 if (atom < MIN_STR_ATOM) return 0;
392 return ATOMTOHANDLE( atom );
396 /***********************************************************************
397 * AddAtom16 (KERNEL.70)
399 ATOM WINAPI AddAtom16( SEGPTR str )
402 HANDLE16 ds = CURRENT_DS;
404 if (!HIWORD(str)) return (ATOM)LOWORD(str); /* Integer atom */
405 if (SELECTOR_TO_ENTRY(LOWORD(str)) == SELECTOR_TO_ENTRY(ds))
407 /* If the string is in the same data segment as the atom table, make */
408 /* a copy of the string to be sure it doesn't move in linear memory. */
409 char buffer[MAX_ATOM_LEN+1];
410 lstrcpynA( buffer, (char *)PTR_SEG_TO_LIN(str), sizeof(buffer) );
411 atom = ATOM_AddAtom( ds, buffer );
413 else atom = ATOM_AddAtom( ds, (LPCSTR)PTR_SEG_TO_LIN(str) );
418 /***********************************************************************
419 * AddAtom32A (KERNEL32.0)
420 * Adds a string to the atom table and returns the atom identifying the
427 ATOM WINAPI AddAtomA(
428 LPCSTR str /* [in] Pointer to string to add */
430 return GlobalAddAtomA( str ); /* FIXME */
434 /***********************************************************************
435 * AddAtom32W (KERNEL32.1)
438 ATOM WINAPI AddAtomW( LPCWSTR str )
440 return GlobalAddAtomW( str ); /* FIXME */
444 /***********************************************************************
445 * DeleteAtom16 (KERNEL.71)
447 ATOM WINAPI DeleteAtom16( ATOM atom )
449 return ATOM_DeleteAtom( CURRENT_DS, atom );
453 /***********************************************************************
454 * DeleteAtom32 (KERNEL32.69)
455 * Decrements the reference count of a string atom. If count becomes
456 * zero, the string associated with the atom is removed from the table.
462 ATOM WINAPI DeleteAtom(
463 ATOM atom /* [in] Atom to delete */
465 return GlobalDeleteAtom( atom ); /* FIXME */
469 /***********************************************************************
470 * FindAtom16 (KERNEL.69)
472 ATOM WINAPI FindAtom16( SEGPTR str )
474 if (!HIWORD(str)) return (ATOM)LOWORD(str); /* Integer atom */
475 return ATOM_FindAtom( CURRENT_DS, (LPCSTR)PTR_SEG_TO_LIN(str) );
479 /***********************************************************************
480 * FindAtom32A (KERNEL32.117)
481 * Searches the local atom table for the string and returns the atom
482 * associated with that string.
488 ATOM WINAPI FindAtomA(
489 LPCSTR str /* [in] Pointer to string to find */
491 return GlobalFindAtomA( str ); /* FIXME */
495 /***********************************************************************
496 * FindAtom32W (KERNEL32.118)
499 ATOM WINAPI FindAtomW( LPCWSTR str )
501 return GlobalFindAtomW( str ); /* FIXME */
505 /***********************************************************************
506 * GetAtomName16 (KERNEL.72)
508 UINT16 WINAPI GetAtomName16( ATOM atom, LPSTR buffer, INT16 count )
510 return (UINT16)ATOM_GetAtomName( CURRENT_DS, atom, buffer, count );
514 /***********************************************************************
515 * GetAtomName32A (KERNEL32.149)
516 * Retrieves a copy of the string associated with the atom.
519 * Length of string: Success
522 UINT WINAPI GetAtomNameA(
523 ATOM atom, /* [in] Atom */
524 LPSTR buffer, /* [out] Pointer to string for atom string */
525 INT count /* [in] Size of buffer */
527 return GlobalGetAtomNameA( atom, buffer, count ); /* FIXME */
531 /***********************************************************************
532 * GetAtomName32W (KERNEL32.150)
535 UINT WINAPI GetAtomNameW( ATOM atom, LPWSTR buffer, INT count )
537 return GlobalGetAtomNameW( atom, buffer, count ); /* FIXME */
541 /***********************************************************************
542 * GlobalAddAtom16 (USER.268)
544 ATOM WINAPI GlobalAddAtom16( SEGPTR str )
546 if (!HIWORD(str)) return (ATOM)LOWORD(str); /* Integer atom */
548 return DDE_GlobalAddAtom( str );
550 return ATOM_AddAtom( ATOM_GlobalTable, (LPCSTR)PTR_SEG_TO_LIN(str) );
555 /***********************************************************************
556 * GlobalAddAtom32A (KERNEL32.313)
557 * Adds a character string to the global atom table and returns a unique
558 * value identifying the string.
564 ATOM WINAPI GlobalAddAtomA(
565 LPCSTR str /* [in] Pointer to string to add */
567 if (!HIWORD(str)) return (ATOM)LOWORD(str); /* Integer atom */
568 return ATOM_AddAtom( ATOM_GlobalTable, str );
572 /***********************************************************************
573 * GlobalAddAtom32W (KERNEL32.314)
574 * See GlobalAddAtom32A
576 ATOM WINAPI GlobalAddAtomW( LPCWSTR str )
578 char buffer[MAX_ATOM_LEN+1];
579 if (!HIWORD(str)) return (ATOM)LOWORD(str); /* Integer atom */
580 lstrcpynWtoA( buffer, str, sizeof(buffer) );
581 return ATOM_AddAtom( ATOM_GlobalTable, buffer );
585 /***********************************************************************
586 * GlobalDeleteAtom (USER.269) (KERNEL32.317)
587 * Decrements the reference count of a string atom. If the count is
588 * zero, the string associated with the atom is removed from the table.
594 ATOM WINAPI GlobalDeleteAtom(
595 ATOM atom /* [in] Atom to delete */
598 return DDE_GlobalDeleteAtom( atom );
600 return ATOM_DeleteAtom( ATOM_GlobalTable, atom );
605 /***********************************************************************
606 * GlobalFindAtom16 (USER.270)
608 ATOM WINAPI GlobalFindAtom16( SEGPTR str )
610 if (!HIWORD(str)) return (ATOM)LOWORD(str); /* Integer atom */
612 return DDE_GlobalFindAtom( str );
614 return ATOM_FindAtom( ATOM_GlobalTable, (LPCSTR)PTR_SEG_TO_LIN(str) );
619 /***********************************************************************
620 * GlobalFindAtom32A (KERNEL32.318)
621 * Searches the atom table for the string and returns the atom
622 * associated with it.
628 ATOM WINAPI GlobalFindAtomA(
629 LPCSTR str /* [in] Pointer to string to search for */
631 if (!HIWORD(str)) return (ATOM)LOWORD(str); /* Integer atom */
632 return ATOM_FindAtom( ATOM_GlobalTable, str );
636 /***********************************************************************
637 * GlobalFindAtom32W (KERNEL32.319)
638 * See GlobalFindAtom32A
640 ATOM WINAPI GlobalFindAtomW( LPCWSTR str )
642 char buffer[MAX_ATOM_LEN+1];
643 if (!HIWORD(str)) return (ATOM)LOWORD(str); /* Integer atom */
644 lstrcpynWtoA( buffer, str, sizeof(buffer) );
645 return ATOM_FindAtom( ATOM_GlobalTable, buffer );
649 /***********************************************************************
650 * GlobalGetAtomName16 (USER.271)
652 UINT16 WINAPI GlobalGetAtomName16( ATOM atom, LPSTR buffer, INT16 count )
655 return DDE_GlobalGetAtomName( atom, buffer, count );
657 return (UINT16)ATOM_GetAtomName( ATOM_GlobalTable, atom, buffer, count );
662 /***********************************************************************
663 * GlobalGetAtomName32A (KERNEL32.323)
664 * Retrieves a copy of the string associated with an atom.
667 * Length of string in characters: Success
670 UINT WINAPI GlobalGetAtomNameA(
671 ATOM atom, /* [in] Atom identifier */
672 LPSTR buffer, /* [out] Pointer to buffer for atom string */
673 INT count /* [in] Size of buffer */
675 return ATOM_GetAtomName( ATOM_GlobalTable, atom, buffer, count );
679 /***********************************************************************
680 * GlobalGetAtomName32W (KERNEL32.324)
681 * See GlobalGetAtomName32A
683 UINT WINAPI GlobalGetAtomNameW( ATOM atom, LPWSTR buffer, INT count )
685 char tmp[MAX_ATOM_LEN+1];
686 ATOM_GetAtomName( ATOM_GlobalTable, atom, tmp, sizeof(tmp) );
687 lstrcpynAtoW( buffer, tmp, count );
688 return lstrlenW( buffer );