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
21 #include "stackframe.h"
29 #define DEFAULT_ATOMTABLE_SIZE 37
30 #define MIN_STR_ATOM 0xc000
31 #define MAX_ATOM_LEN 255
33 #define ATOMTOHANDLE(atom) ((HANDLE16)(atom) << 2)
34 #define HANDLETOATOM(handle) ((ATOM)(0xc000 | ((handle) >> 2)))
36 #define HAS_ATOM_TABLE(sel) \
37 ((INSTANCEDATA*)PTR_SEG_OFF_TO_LIN(sel,0))->atomtable != 0)
39 #define GET_ATOM_TABLE(sel) ((ATOMTABLE*)PTR_SEG_OFF_TO_LIN(sel, \
40 ((INSTANCEDATA*)PTR_SEG_OFF_TO_LIN(sel,0))->atomtable))
56 static WORD ATOM_GlobalTable = 0;
58 /***********************************************************************
62 * Should this validate the value of entries to be 0 < x < 0x3fff?
68 static HANDLE16 ATOM_InitTable(
69 WORD selector, /* [in] Segment */
70 WORD entries /* [in] Size of atom table */
76 /* We consider the first table to be initialized as the global table.
77 * This works, as USER (both built-in and native) is the first one to
81 if (!ATOM_GlobalTable) ATOM_GlobalTable = selector;
84 /* Allocate the table */
86 handle = LOCAL_Alloc( selector, LMEM_FIXED,
87 sizeof(ATOMTABLE) + (entries-1) * sizeof(HANDLE16) );
88 if (!handle) return 0;
89 table = (ATOMTABLE *)PTR_SEG_OFF_TO_LIN( selector, handle );
90 table->size = entries;
91 for (i = 0; i < entries; i++) table->entries[i] = 0;
93 /* Store a pointer to the table in the instance data */
95 ((INSTANCEDATA *)PTR_SEG_OFF_TO_LIN( selector, 0 ))->atomtable = handle;
100 /***********************************************************************
103 * Global table initialisation.
105 BOOL32 ATOM_Init( WORD globalTableSel )
107 return ATOM_InitTable( globalTableSel, DEFAULT_ATOMTABLE_SIZE ) != 0;
111 /***********************************************************************
114 * Return a pointer to the atom table of a given segment, creating
118 * Pointer to table: Success
121 static ATOMTABLE *ATOM_GetTable(
122 WORD selector, /* [in] Segment */
123 BOOL32 create /* [in] Create */ )
125 INSTANCEDATA *ptr = (INSTANCEDATA *)PTR_SEG_OFF_TO_LIN( selector, 0 );
128 ATOMTABLE *table = (ATOMTABLE *)((char *)ptr + ptr->atomtable);
129 if (table->size) return table;
131 if (!create) return NULL;
132 if (!ATOM_InitTable( selector, DEFAULT_ATOMTABLE_SIZE )) return NULL;
133 /* Reload ptr in case it moved in linear memory */
134 ptr = (INSTANCEDATA *)PTR_SEG_OFF_TO_LIN( selector, 0 );
135 return (ATOMTABLE *)((char *)ptr + ptr->atomtable);
139 /***********************************************************************
142 * Make an ATOMENTRY pointer from a handle (obtained from GetAtomHandle()).
144 static ATOMENTRY *ATOM_MakePtr(
145 WORD selector, /* [in] Segment */
146 HANDLE16 handle /* [in] Handle */
148 return (ATOMENTRY *)PTR_SEG_OFF_TO_LIN( selector, handle );
152 /***********************************************************************
155 * The hash value for the input string
157 static WORD ATOM_Hash(
158 WORD entries, /* [in] Total number of entries */
159 LPCSTR str, /* [in] Pointer to string to hash */
160 WORD len /* [in] Length of string */
164 TRACE(atom,"%x, %s, %x\n", entries, str, len);
166 for (i = 0; i < len; i++) hash ^= toupper(str[i]) + i;
167 return hash % entries;
170 static BOOL32 ATOM_IsIntAtom(LPCSTR atomstr,WORD *atomid) {
173 if (!HIWORD(atomstr)) {
174 *atomid = LOWORD(atomstr);
179 *atomid=strtol(atomstr+1,&xend,10);
181 FIXME(atom,"found atom named '%s'\n",atomstr);
188 /***********************************************************************
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.
200 static ATOM ATOM_AddAtom(
201 WORD selector, /* [in] Segment */
202 LPCSTR str /* [in] Pointer to the string to add */
206 ATOMENTRY * entryPtr;
211 TRACE(atom,"0x%x, %s\n", selector, str);
213 if (ATOM_IsIntAtom(str,&iatom))
215 if ((len = strlen( str )) > MAX_ATOM_LEN) len = MAX_ATOM_LEN;
216 if (!(table = ATOM_GetTable( selector, TRUE ))) return 0;
217 hash = ATOM_Hash( table->size, str, len );
218 entry = table->entries[hash];
221 entryPtr = ATOM_MakePtr( selector, entry );
222 if ((entryPtr->length == len) &&
223 (!lstrncmpi32A( entryPtr->str, str, len )))
225 entryPtr->refCount++;
226 TRACE(atom,"-- existing 0x%x\n", entry);
227 return HANDLETOATOM( entry );
229 entry = entryPtr->next;
232 ae_len = (sizeof(ATOMENTRY)+len+3) & ~3;
233 entry = LOCAL_Alloc( selector, LMEM_FIXED, ae_len);
234 if (!entry) return 0;
235 /* Reload the table ptr in case it moved in linear memory */
236 table = ATOM_GetTable( selector, FALSE );
237 entryPtr = ATOM_MakePtr( selector, entry );
238 entryPtr->next = table->entries[hash];
239 entryPtr->refCount = 1;
240 entryPtr->length = len;
241 strncpy( entryPtr->str, str, ae_len - sizeof(ATOMENTRY) + 1); /* always use strncpy ('\0's padding) */
242 table->entries[hash] = entry;
243 TRACE(atom,"-- new 0x%x\n", entry);
244 return HANDLETOATOM( entry );
248 /***********************************************************************
254 static ATOM ATOM_DeleteAtom(
255 WORD selector, /* [in] Segment */
256 ATOM atom /* [in] Atom to delete */
258 ATOMENTRY * entryPtr;
260 HANDLE16 entry, *prevEntry;
263 TRACE(atom,"0x%x, 0x%x\n", selector, atom);
265 if (atom < MIN_STR_ATOM) return 0; /* Integer atom */
267 if (!(table = ATOM_GetTable( selector, FALSE ))) return 0;
268 entry = ATOMTOHANDLE( atom );
269 entryPtr = ATOM_MakePtr( selector, entry );
271 /* Find previous atom */
272 hash = ATOM_Hash( table->size, entryPtr->str, entryPtr->length );
273 prevEntry = &table->entries[hash];
274 while (*prevEntry && *prevEntry != entry)
276 ATOMENTRY * prevEntryPtr = ATOM_MakePtr( selector, *prevEntry );
277 prevEntry = &prevEntryPtr->next;
279 if (!*prevEntry) return atom;
282 if (--entryPtr->refCount == 0)
284 *prevEntry = entryPtr->next;
285 LOCAL_Free( selector, entry );
291 /***********************************************************************
297 static ATOM ATOM_FindAtom(
298 WORD selector, /* [in] Segment */
299 LPCSTR str /* [in] Pointer to string to find */
306 TRACE(atom,"%x, %s\n", selector, str);
307 if (ATOM_IsIntAtom(str,&iatom))
309 if ((len = strlen( str )) > 255) len = 255;
310 if (!(table = ATOM_GetTable( selector, FALSE ))) return 0;
311 hash = ATOM_Hash( table->size, str, len );
312 entry = table->entries[hash];
315 ATOMENTRY * entryPtr = ATOM_MakePtr( selector, entry );
316 if ((entryPtr->length == len) &&
317 (!lstrncmpi32A( entryPtr->str, str, len )))
318 { TRACE(atom,"-- found %x\n", entry);
319 return HANDLETOATOM( entry );
321 entry = entryPtr->next;
323 TRACE(atom,"-- not found\n");
328 /***********************************************************************
331 * Length of string copied to buffer: Success
334 static UINT32 ATOM_GetAtomName(
335 WORD selector, /* [in] Segment */
336 ATOM atom, /* [in] Atom identifier */
337 LPSTR buffer, /* [out] Pointer to buffer for atom string */
338 INT32 count /* [in] Size of buffer */
341 ATOMENTRY * entryPtr;
347 TRACE(atom,"%x, %x\n", selector, atom);
349 if (!count) return 0;
350 if (atom < MIN_STR_ATOM)
352 sprintf( text, "#%d", atom );
358 if (!(table = ATOM_GetTable( selector, FALSE ))) return 0;
359 entry = ATOMTOHANDLE( atom );
360 entryPtr = ATOM_MakePtr( selector, entry );
361 len = entryPtr->length;
362 strPtr = entryPtr->str;
364 if (len >= count) len = count-1;
365 memcpy( buffer, strPtr, len );
371 /***********************************************************************
372 * InitAtomTable16 (KERNEL.68)
374 WORD WINAPI InitAtomTable16( WORD entries )
376 if (!entries) entries = DEFAULT_ATOMTABLE_SIZE; /* sanity check */
377 return ATOM_InitTable( CURRENT_DS, entries );
381 /***********************************************************************
382 * GetAtomHandle (KERNEL.73)
384 HANDLE16 WINAPI GetAtomHandle( ATOM atom )
386 if (atom < MIN_STR_ATOM) return 0;
387 return ATOMTOHANDLE( atom );
391 /***********************************************************************
392 * AddAtom16 (KERNEL.70)
394 ATOM WINAPI AddAtom16( SEGPTR str )
397 HANDLE16 ds = CURRENT_DS;
399 if (!HIWORD(str)) return (ATOM)LOWORD(str); /* Integer atom */
400 if (SELECTOR_TO_ENTRY(LOWORD(str)) == SELECTOR_TO_ENTRY(ds))
402 /* If the string is in the same data segment as the atom table, make */
403 /* a copy of the string to be sure it doesn't move in linear memory. */
404 char buffer[MAX_ATOM_LEN+1];
405 lstrcpyn32A( buffer, (char *)PTR_SEG_TO_LIN(str), sizeof(buffer) );
406 atom = ATOM_AddAtom( ds, buffer );
408 else atom = ATOM_AddAtom( ds, (LPCSTR)PTR_SEG_TO_LIN(str) );
413 /***********************************************************************
414 * AddAtom32A (KERNEL32.0)
415 * Adds a string to the atom table and returns the atom identifying the
422 ATOM WINAPI AddAtom32A(
423 LPCSTR str /* [in] Pointer to string to add */
425 return GlobalAddAtom32A( str ); /* FIXME */
429 /***********************************************************************
430 * AddAtom32W (KERNEL32.1)
433 ATOM WINAPI AddAtom32W( LPCWSTR str )
435 return GlobalAddAtom32W( str ); /* FIXME */
439 /***********************************************************************
440 * DeleteAtom16 (KERNEL.71)
442 ATOM WINAPI DeleteAtom16( ATOM atom )
444 return ATOM_DeleteAtom( CURRENT_DS, atom );
448 /***********************************************************************
449 * DeleteAtom32 (KERNEL32.69)
450 * Decrements the reference count of a string atom. If count becomes
451 * zero, the string associated with the atom is removed from the table.
457 ATOM WINAPI DeleteAtom32(
458 ATOM atom /* [in] Atom to delete */
460 return GlobalDeleteAtom( atom ); /* FIXME */
464 /***********************************************************************
465 * FindAtom16 (KERNEL.69)
467 ATOM WINAPI FindAtom16( SEGPTR str )
469 if (!HIWORD(str)) return (ATOM)LOWORD(str); /* Integer atom */
470 return ATOM_FindAtom( CURRENT_DS, (LPCSTR)PTR_SEG_TO_LIN(str) );
474 /***********************************************************************
475 * FindAtom32A (KERNEL32.117)
476 * Searches the local atom table for the string and returns the atom
477 * associated with that string.
483 ATOM WINAPI FindAtom32A(
484 LPCSTR str /* [in] Pointer to string to find */
486 return GlobalFindAtom32A( str ); /* FIXME */
490 /***********************************************************************
491 * FindAtom32W (KERNEL32.118)
494 ATOM WINAPI FindAtom32W( LPCWSTR str )
496 return GlobalFindAtom32W( str ); /* FIXME */
500 /***********************************************************************
501 * GetAtomName16 (KERNEL.72)
503 UINT16 WINAPI GetAtomName16( ATOM atom, LPSTR buffer, INT16 count )
505 return (UINT16)ATOM_GetAtomName( CURRENT_DS, atom, buffer, count );
509 /***********************************************************************
510 * GetAtomName32A (KERNEL32.149)
511 * Retrieves a copy of the string associated with the atom.
514 * Length of string: Success
517 UINT32 WINAPI GetAtomName32A(
518 ATOM atom, /* [in] Atom */
519 LPSTR buffer, /* [out] Pointer to string for atom string */
520 INT32 count /* [in] Size of buffer */
522 return GlobalGetAtomName32A( atom, buffer, count ); /* FIXME */
526 /***********************************************************************
527 * GetAtomName32W (KERNEL32.150)
530 UINT32 WINAPI GetAtomName32W( ATOM atom, LPWSTR buffer, INT32 count )
532 return GlobalGetAtomName32W( atom, buffer, count ); /* FIXME */
536 /***********************************************************************
537 * GlobalAddAtom16 (USER.268)
539 ATOM WINAPI GlobalAddAtom16( SEGPTR str )
541 if (!HIWORD(str)) return (ATOM)LOWORD(str); /* Integer atom */
543 return DDE_GlobalAddAtom( str );
545 return ATOM_AddAtom( ATOM_GlobalTable, (LPCSTR)PTR_SEG_TO_LIN(str) );
550 /***********************************************************************
551 * GlobalAddAtom32A (KERNEL32.313)
552 * Adds a character string to the global atom table and returns a unique
553 * value identifying the string.
559 ATOM WINAPI GlobalAddAtom32A(
560 LPCSTR str /* [in] Pointer to string to add */
562 if (!HIWORD(str)) return (ATOM)LOWORD(str); /* Integer atom */
563 return ATOM_AddAtom( ATOM_GlobalTable, str );
567 /***********************************************************************
568 * GlobalAddAtom32W (KERNEL32.314)
569 * See GlobalAddAtom32A
571 ATOM WINAPI GlobalAddAtom32W( LPCWSTR str )
573 char buffer[MAX_ATOM_LEN+1];
574 if (!HIWORD(str)) return (ATOM)LOWORD(str); /* Integer atom */
575 lstrcpynWtoA( buffer, str, sizeof(buffer) );
576 return ATOM_AddAtom( ATOM_GlobalTable, buffer );
580 /***********************************************************************
581 * GlobalDeleteAtom (USER.269) (KERNEL32.317)
582 * Decrements the reference count of a string atom. If the count is
583 * zero, the string associated with the atom is removed from the table.
589 ATOM WINAPI GlobalDeleteAtom(
590 ATOM atom /* [in] Atom to delete */
593 return DDE_GlobalDeleteAtom( atom );
595 return ATOM_DeleteAtom( ATOM_GlobalTable, atom );
600 /***********************************************************************
601 * GlobalFindAtom16 (USER.270)
603 ATOM WINAPI GlobalFindAtom16( SEGPTR str )
605 if (!HIWORD(str)) return (ATOM)LOWORD(str); /* Integer atom */
607 return DDE_GlobalFindAtom( str );
609 return ATOM_FindAtom( ATOM_GlobalTable, (LPCSTR)PTR_SEG_TO_LIN(str) );
614 /***********************************************************************
615 * GlobalFindAtom32A (KERNEL32.318)
616 * Searches the atom table for the string and returns the atom
617 * associated with it.
623 ATOM WINAPI GlobalFindAtom32A(
624 LPCSTR str /* [in] Pointer to string to search for */
626 if (!HIWORD(str)) return (ATOM)LOWORD(str); /* Integer atom */
627 return ATOM_FindAtom( ATOM_GlobalTable, str );
631 /***********************************************************************
632 * GlobalFindAtom32W (KERNEL32.319)
633 * See GlobalFindAtom32A
635 ATOM WINAPI GlobalFindAtom32W( LPCWSTR str )
637 char buffer[MAX_ATOM_LEN+1];
638 if (!HIWORD(str)) return (ATOM)LOWORD(str); /* Integer atom */
639 lstrcpynWtoA( buffer, str, sizeof(buffer) );
640 return ATOM_FindAtom( ATOM_GlobalTable, buffer );
644 /***********************************************************************
645 * GlobalGetAtomName16 (USER.271)
647 UINT16 WINAPI GlobalGetAtomName16( ATOM atom, LPSTR buffer, INT16 count )
650 return DDE_GlobalGetAtomName( atom, buffer, count );
652 return (UINT16)ATOM_GetAtomName( ATOM_GlobalTable, atom, buffer, count );
657 /***********************************************************************
658 * GlobalGetAtomName32A (KERNEL32.323)
659 * Retrieves a copy of the string associated with an atom.
662 * Length of string in characters: Success
665 UINT32 WINAPI GlobalGetAtomName32A(
666 ATOM atom, /* [in] Atom identifier */
667 LPSTR buffer, /* [out] Pointer to buffer for atom string */
668 INT32 count /* [in] Size of buffer */
670 return ATOM_GetAtomName( ATOM_GlobalTable, atom, buffer, count );
674 /***********************************************************************
675 * GlobalGetAtomName32W (KERNEL32.324)
676 * See GlobalGetAtomName32A
678 UINT32 WINAPI GlobalGetAtomName32W( ATOM atom, LPWSTR buffer, INT32 count )
680 char tmp[MAX_ATOM_LEN+1];
681 ATOM_GetAtomName( ATOM_GlobalTable, atom, tmp, sizeof(tmp) );
682 lstrcpynAtoW( buffer, tmp, count );
683 return lstrlen32W( buffer );