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
22 #include "stackframe.h"
30 #define DEFAULT_ATOMTABLE_SIZE 37
31 #define MIN_STR_ATOM 0xc000
32 #define MAX_ATOM_LEN 255
34 #define ATOMTOHANDLE(atom) ((HANDLE16)(atom) << 2)
35 #define HANDLETOATOM(handle) ((ATOM)(0xc000 | ((handle) >> 2)))
37 #define HAS_ATOM_TABLE(sel) \
38 ((INSTANCEDATA*)PTR_SEG_OFF_TO_LIN(sel,0))->atomtable != 0)
40 #define GET_ATOM_TABLE(sel) ((ATOMTABLE*)PTR_SEG_OFF_TO_LIN(sel, \
41 ((INSTANCEDATA*)PTR_SEG_OFF_TO_LIN(sel,0))->atomtable))
57 static WORD ATOM_GlobalTable = 0;
59 /***********************************************************************
63 * Should this validate the value of entries to be 0 < x < 0x3fff?
69 static HANDLE16 ATOM_InitTable(
70 WORD selector, /* [in] Segment */
71 WORD entries /* [in] Size of atom table */
77 /* We consider the first table to be initialized as the global table.
78 * This works, as USER (both built-in and native) is the first one to
82 if (!ATOM_GlobalTable) ATOM_GlobalTable = selector;
85 /* Allocate the table */
87 handle = LOCAL_Alloc( selector, LMEM_FIXED,
88 sizeof(ATOMTABLE) + (entries-1) * sizeof(HANDLE16) );
89 if (!handle) return 0;
90 table = (ATOMTABLE *)PTR_SEG_OFF_TO_LIN( selector, handle );
91 table->size = entries;
92 for (i = 0; i < entries; i++) table->entries[i] = 0;
94 /* Store a pointer to the table in the instance data */
96 ((INSTANCEDATA *)PTR_SEG_OFF_TO_LIN( selector, 0 ))->atomtable = handle;
101 /***********************************************************************
104 * Global table initialisation.
106 BOOL32 ATOM_Init( WORD globalTableSel )
108 return ATOM_InitTable( globalTableSel, DEFAULT_ATOMTABLE_SIZE ) != 0;
112 /***********************************************************************
115 * Return a pointer to the atom table of a given segment, creating
119 * Pointer to table: Success
122 static ATOMTABLE *ATOM_GetTable(
123 WORD selector, /* [in] Segment */
124 BOOL32 create /* [in] Create */ )
126 INSTANCEDATA *ptr = (INSTANCEDATA *)PTR_SEG_OFF_TO_LIN( selector, 0 );
129 ATOMTABLE *table = (ATOMTABLE *)((char *)ptr + ptr->atomtable);
130 if (table->size) return table;
132 if (!create) return NULL;
133 if (!ATOM_InitTable( selector, DEFAULT_ATOMTABLE_SIZE )) return NULL;
134 /* Reload ptr in case it moved in linear memory */
135 ptr = (INSTANCEDATA *)PTR_SEG_OFF_TO_LIN( selector, 0 );
136 return (ATOMTABLE *)((char *)ptr + ptr->atomtable);
140 /***********************************************************************
143 * Make an ATOMENTRY pointer from a handle (obtained from GetAtomHandle()).
145 static ATOMENTRY *ATOM_MakePtr(
146 WORD selector, /* [in] Segment */
147 HANDLE16 handle /* [in] Handle */
149 return (ATOMENTRY *)PTR_SEG_OFF_TO_LIN( selector, handle );
153 /***********************************************************************
156 * The hash value for the input string
158 static WORD ATOM_Hash(
159 WORD entries, /* [in] Total number of entries */
160 LPCSTR str, /* [in] Pointer to string to hash */
161 WORD len /* [in] Length of string */
165 TRACE(atom,"%x, %s, %x\n", entries, str, len);
167 for (i = 0; i < len; i++) hash ^= toupper(str[i]) + i;
168 return hash % entries;
171 static BOOL32 ATOM_IsIntAtom(LPCSTR atomstr,WORD *atomid) {
174 if (!HIWORD(atomstr)) {
175 *atomid = LOWORD(atomstr);
180 *atomid=strtol(atomstr+1,&xend,10);
182 FIXME(atom,"found atom named '%s'\n",atomstr);
189 /***********************************************************************
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 static ATOM ATOM_AddAtom(
202 WORD selector, /* [in] Segment */
203 LPCSTR str /* [in] Pointer to the string to add */
207 ATOMENTRY * entryPtr;
212 TRACE(atom,"0x%x, %s\n", selector, str);
214 if (ATOM_IsIntAtom(str,&iatom))
216 if ((len = strlen( str )) > MAX_ATOM_LEN) len = MAX_ATOM_LEN;
217 if (!(table = ATOM_GetTable( selector, TRUE ))) return 0;
218 hash = ATOM_Hash( table->size, str, len );
219 entry = table->entries[hash];
222 entryPtr = ATOM_MakePtr( selector, entry );
223 if ((entryPtr->length == len) &&
224 (!lstrncmpi32A( entryPtr->str, str, len )))
226 entryPtr->refCount++;
227 TRACE(atom,"-- existing 0x%x\n", entry);
228 return HANDLETOATOM( entry );
230 entry = entryPtr->next;
233 ae_len = (sizeof(ATOMENTRY)+len+3) & ~3;
234 entry = LOCAL_Alloc( selector, LMEM_FIXED, ae_len);
235 if (!entry) return 0;
236 /* Reload the table ptr in case it moved in linear memory */
237 table = ATOM_GetTable( selector, FALSE );
238 entryPtr = ATOM_MakePtr( selector, entry );
239 entryPtr->next = table->entries[hash];
240 entryPtr->refCount = 1;
241 entryPtr->length = len;
242 strncpy( entryPtr->str, str, ae_len - sizeof(ATOMENTRY) + 1); /* always use strncpy ('\0's padding) */
243 table->entries[hash] = entry;
244 TRACE(atom,"-- new 0x%x\n", entry);
245 return HANDLETOATOM( entry );
249 /***********************************************************************
255 static ATOM ATOM_DeleteAtom(
256 WORD selector, /* [in] Segment */
257 ATOM atom /* [in] Atom to delete */
259 ATOMENTRY * entryPtr;
261 HANDLE16 entry, *prevEntry;
264 TRACE(atom,"0x%x, 0x%x\n", selector, atom);
266 if (atom < MIN_STR_ATOM) return 0; /* Integer atom */
268 if (!(table = ATOM_GetTable( selector, FALSE ))) return 0;
269 entry = ATOMTOHANDLE( atom );
270 entryPtr = ATOM_MakePtr( selector, entry );
272 /* Find previous atom */
273 hash = ATOM_Hash( table->size, entryPtr->str, entryPtr->length );
274 prevEntry = &table->entries[hash];
275 while (*prevEntry && *prevEntry != entry)
277 ATOMENTRY * prevEntryPtr = ATOM_MakePtr( selector, *prevEntry );
278 prevEntry = &prevEntryPtr->next;
280 if (!*prevEntry) return atom;
283 if (--entryPtr->refCount == 0)
285 *prevEntry = entryPtr->next;
286 LOCAL_Free( selector, entry );
292 /***********************************************************************
298 static ATOM ATOM_FindAtom(
299 WORD selector, /* [in] Segment */
300 LPCSTR str /* [in] Pointer to string to find */
307 TRACE(atom,"%x, %s\n", selector, str);
308 if (ATOM_IsIntAtom(str,&iatom))
310 if ((len = strlen( str )) > 255) len = 255;
311 if (!(table = ATOM_GetTable( selector, FALSE ))) return 0;
312 hash = ATOM_Hash( table->size, str, len );
313 entry = table->entries[hash];
316 ATOMENTRY * entryPtr = ATOM_MakePtr( selector, entry );
317 if ((entryPtr->length == len) &&
318 (!lstrncmpi32A( entryPtr->str, str, len )))
319 { TRACE(atom,"-- found %x\n", entry);
320 return HANDLETOATOM( entry );
322 entry = entryPtr->next;
324 TRACE(atom,"-- not found\n");
329 /***********************************************************************
332 * Length of string copied to buffer: Success
335 static UINT32 ATOM_GetAtomName(
336 WORD selector, /* [in] Segment */
337 ATOM atom, /* [in] Atom identifier */
338 LPSTR buffer, /* [out] Pointer to buffer for atom string */
339 INT32 count /* [in] Size of buffer */
342 ATOMENTRY * entryPtr;
348 TRACE(atom,"%x, %x\n", selector, atom);
350 if (!count) return 0;
351 if (atom < MIN_STR_ATOM)
353 sprintf( text, "#%d", atom );
359 if (!(table = ATOM_GetTable( selector, FALSE ))) return 0;
360 entry = ATOMTOHANDLE( atom );
361 entryPtr = ATOM_MakePtr( selector, entry );
362 len = entryPtr->length;
363 strPtr = entryPtr->str;
365 if (len >= count) len = count-1;
366 memcpy( buffer, strPtr, len );
372 /***********************************************************************
373 * InitAtomTable16 (KERNEL.68)
375 WORD WINAPI InitAtomTable16( WORD entries )
377 if (!entries) entries = DEFAULT_ATOMTABLE_SIZE; /* sanity check */
378 return ATOM_InitTable( CURRENT_DS, entries );
382 /***********************************************************************
383 * GetAtomHandle (KERNEL.73)
385 HANDLE16 WINAPI GetAtomHandle( ATOM atom )
387 if (atom < MIN_STR_ATOM) return 0;
388 return ATOMTOHANDLE( atom );
392 /***********************************************************************
393 * AddAtom16 (KERNEL.70)
395 ATOM WINAPI AddAtom16( SEGPTR str )
398 HANDLE16 ds = CURRENT_DS;
400 if (!HIWORD(str)) return (ATOM)LOWORD(str); /* Integer atom */
401 if (SELECTOR_TO_ENTRY(LOWORD(str)) == SELECTOR_TO_ENTRY(ds))
403 /* If the string is in the same data segment as the atom table, make */
404 /* a copy of the string to be sure it doesn't move in linear memory. */
405 char buffer[MAX_ATOM_LEN+1];
406 lstrcpyn32A( buffer, (char *)PTR_SEG_TO_LIN(str), sizeof(buffer) );
407 atom = ATOM_AddAtom( ds, buffer );
409 else atom = ATOM_AddAtom( ds, (LPCSTR)PTR_SEG_TO_LIN(str) );
414 /***********************************************************************
415 * AddAtom32A (KERNEL32.0)
416 * Adds a string to the atom table and returns the atom identifying the
423 ATOM WINAPI AddAtom32A(
424 LPCSTR str /* [in] Pointer to string to add */
426 return GlobalAddAtom32A( str ); /* FIXME */
430 /***********************************************************************
431 * AddAtom32W (KERNEL32.1)
434 ATOM WINAPI AddAtom32W( LPCWSTR str )
436 return GlobalAddAtom32W( str ); /* FIXME */
440 /***********************************************************************
441 * DeleteAtom16 (KERNEL.71)
443 ATOM WINAPI DeleteAtom16( ATOM atom )
445 return ATOM_DeleteAtom( CURRENT_DS, atom );
449 /***********************************************************************
450 * DeleteAtom32 (KERNEL32.69)
451 * Decrements the reference count of a string atom. If count becomes
452 * zero, the string associated with the atom is removed from the table.
458 ATOM WINAPI DeleteAtom32(
459 ATOM atom /* [in] Atom to delete */
461 return GlobalDeleteAtom( atom ); /* FIXME */
465 /***********************************************************************
466 * FindAtom16 (KERNEL.69)
468 ATOM WINAPI FindAtom16( SEGPTR str )
470 if (!HIWORD(str)) return (ATOM)LOWORD(str); /* Integer atom */
471 return ATOM_FindAtom( CURRENT_DS, (LPCSTR)PTR_SEG_TO_LIN(str) );
475 /***********************************************************************
476 * FindAtom32A (KERNEL32.117)
477 * Searches the local atom table for the string and returns the atom
478 * associated with that string.
484 ATOM WINAPI FindAtom32A(
485 LPCSTR str /* [in] Pointer to string to find */
487 return GlobalFindAtom32A( str ); /* FIXME */
491 /***********************************************************************
492 * FindAtom32W (KERNEL32.118)
495 ATOM WINAPI FindAtom32W( LPCWSTR str )
497 return GlobalFindAtom32W( str ); /* FIXME */
501 /***********************************************************************
502 * GetAtomName16 (KERNEL.72)
504 UINT16 WINAPI GetAtomName16( ATOM atom, LPSTR buffer, INT16 count )
506 return (UINT16)ATOM_GetAtomName( CURRENT_DS, atom, buffer, count );
510 /***********************************************************************
511 * GetAtomName32A (KERNEL32.149)
512 * Retrieves a copy of the string associated with the atom.
515 * Length of string: Success
518 UINT32 WINAPI GetAtomName32A(
519 ATOM atom, /* [in] Atom */
520 LPSTR buffer, /* [out] Pointer to string for atom string */
521 INT32 count /* [in] Size of buffer */
523 return GlobalGetAtomName32A( atom, buffer, count ); /* FIXME */
527 /***********************************************************************
528 * GetAtomName32W (KERNEL32.150)
531 UINT32 WINAPI GetAtomName32W( ATOM atom, LPWSTR buffer, INT32 count )
533 return GlobalGetAtomName32W( atom, buffer, count ); /* FIXME */
537 /***********************************************************************
538 * GlobalAddAtom16 (USER.268)
540 ATOM WINAPI GlobalAddAtom16( SEGPTR str )
542 if (!HIWORD(str)) return (ATOM)LOWORD(str); /* Integer atom */
544 return DDE_GlobalAddAtom( str );
546 return ATOM_AddAtom( ATOM_GlobalTable, (LPCSTR)PTR_SEG_TO_LIN(str) );
551 /***********************************************************************
552 * GlobalAddAtom32A (KERNEL32.313)
553 * Adds a character string to the global atom table and returns a unique
554 * value identifying the string.
560 ATOM WINAPI GlobalAddAtom32A(
561 LPCSTR str /* [in] Pointer to string to add */
563 if (!HIWORD(str)) return (ATOM)LOWORD(str); /* Integer atom */
564 return ATOM_AddAtom( ATOM_GlobalTable, str );
568 /***********************************************************************
569 * GlobalAddAtom32W (KERNEL32.314)
570 * See GlobalAddAtom32A
572 ATOM WINAPI GlobalAddAtom32W( LPCWSTR str )
574 char buffer[MAX_ATOM_LEN+1];
575 if (!HIWORD(str)) return (ATOM)LOWORD(str); /* Integer atom */
576 lstrcpynWtoA( buffer, str, sizeof(buffer) );
577 return ATOM_AddAtom( ATOM_GlobalTable, buffer );
581 /***********************************************************************
582 * GlobalDeleteAtom (USER.269) (KERNEL32.317)
583 * Decrements the reference count of a string atom. If the count is
584 * zero, the string associated with the atom is removed from the table.
590 ATOM WINAPI GlobalDeleteAtom(
591 ATOM atom /* [in] Atom to delete */
594 return DDE_GlobalDeleteAtom( atom );
596 return ATOM_DeleteAtom( ATOM_GlobalTable, atom );
601 /***********************************************************************
602 * GlobalFindAtom16 (USER.270)
604 ATOM WINAPI GlobalFindAtom16( SEGPTR str )
606 if (!HIWORD(str)) return (ATOM)LOWORD(str); /* Integer atom */
608 return DDE_GlobalFindAtom( str );
610 return ATOM_FindAtom( ATOM_GlobalTable, (LPCSTR)PTR_SEG_TO_LIN(str) );
615 /***********************************************************************
616 * GlobalFindAtom32A (KERNEL32.318)
617 * Searches the atom table for the string and returns the atom
618 * associated with it.
624 ATOM WINAPI GlobalFindAtom32A(
625 LPCSTR str /* [in] Pointer to string to search for */
627 if (!HIWORD(str)) return (ATOM)LOWORD(str); /* Integer atom */
628 return ATOM_FindAtom( ATOM_GlobalTable, str );
632 /***********************************************************************
633 * GlobalFindAtom32W (KERNEL32.319)
634 * See GlobalFindAtom32A
636 ATOM WINAPI GlobalFindAtom32W( LPCWSTR str )
638 char buffer[MAX_ATOM_LEN+1];
639 if (!HIWORD(str)) return (ATOM)LOWORD(str); /* Integer atom */
640 lstrcpynWtoA( buffer, str, sizeof(buffer) );
641 return ATOM_FindAtom( ATOM_GlobalTable, buffer );
645 /***********************************************************************
646 * GlobalGetAtomName16 (USER.271)
648 UINT16 WINAPI GlobalGetAtomName16( ATOM atom, LPSTR buffer, INT16 count )
651 return DDE_GlobalGetAtomName( atom, buffer, count );
653 return (UINT16)ATOM_GetAtomName( ATOM_GlobalTable, atom, buffer, count );
658 /***********************************************************************
659 * GlobalGetAtomName32A (KERNEL32.323)
660 * Retrieves a copy of the string associated with an atom.
663 * Length of string in characters: Success
666 UINT32 WINAPI GlobalGetAtomName32A(
667 ATOM atom, /* [in] Atom identifier */
668 LPSTR buffer, /* [out] Pointer to buffer for atom string */
669 INT32 count /* [in] Size of buffer */
671 return ATOM_GetAtomName( ATOM_GlobalTable, atom, buffer, count );
675 /***********************************************************************
676 * GlobalGetAtomName32W (KERNEL32.324)
677 * See GlobalGetAtomName32A
679 UINT32 WINAPI GlobalGetAtomName32W( ATOM atom, LPWSTR buffer, INT32 count )
681 char tmp[MAX_ATOM_LEN+1];
682 ATOM_GetAtomName( ATOM_GlobalTable, atom, tmp, sizeof(tmp) );
683 lstrcpynAtoW( buffer, tmp, count );
684 return lstrlen32W( buffer );