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"
33 DEFAULT_DEBUG_CHANNEL(atom)
35 #define DEFAULT_ATOMTABLE_SIZE 37
36 #define MIN_STR_ATOM 0xc000
37 #define MAX_ATOM_LEN 255
39 #define ATOMTOHANDLE(atom) ((HANDLE16)(atom) << 2)
40 #define HANDLETOATOM(handle) ((ATOM)(0xc000 | ((handle) >> 2)))
42 #define HAS_ATOM_TABLE(sel) \
43 ((INSTANCEDATA*)PTR_SEG_OFF_TO_LIN(sel,0))->atomtable != 0)
45 #define GET_ATOM_TABLE(sel) ((ATOMTABLE*)PTR_SEG_OFF_TO_LIN(sel, \
46 ((INSTANCEDATA*)PTR_SEG_OFF_TO_LIN(sel,0))->atomtable))
62 static WORD ATOM_GlobalTable = 0;
64 /***********************************************************************
68 * Should this validate the value of entries to be 0 < x < 0x3fff?
74 static HANDLE16 ATOM_InitTable(
75 WORD selector, /* [in] Segment */
76 WORD entries /* [in] Size of atom table */
82 /* We consider the first table to be initialized as the global table.
83 * This works, as USER (both built-in and native) is the first one to
87 if (!ATOM_GlobalTable) ATOM_GlobalTable = selector;
90 /* Allocate the table */
92 handle = LOCAL_Alloc( selector, LMEM_FIXED,
93 sizeof(ATOMTABLE) + (entries-1) * sizeof(HANDLE16) );
94 if (!handle) return 0;
95 table = (ATOMTABLE *)PTR_SEG_OFF_TO_LIN( selector, handle );
96 table->size = entries;
97 for (i = 0; i < entries; i++) table->entries[i] = 0;
99 /* Store a pointer to the table in the instance data */
101 ((INSTANCEDATA *)PTR_SEG_OFF_TO_LIN( selector, 0 ))->atomtable = handle;
106 /***********************************************************************
109 * Global table initialisation.
111 BOOL ATOM_Init( WORD globalTableSel )
113 return ATOM_InitTable( globalTableSel, DEFAULT_ATOMTABLE_SIZE ) != 0;
117 /***********************************************************************
120 * Return a pointer to the atom table of a given segment, creating
124 * Pointer to table: Success
127 static ATOMTABLE *ATOM_GetTable(
128 WORD selector, /* [in] Segment */
129 BOOL create /* [in] Create */ )
131 INSTANCEDATA *ptr = (INSTANCEDATA *)PTR_SEG_OFF_TO_LIN( selector, 0 );
134 ATOMTABLE *table = (ATOMTABLE *)((char *)ptr + ptr->atomtable);
135 if (table->size) return table;
137 if (!create) return NULL;
138 if (!ATOM_InitTable( selector, DEFAULT_ATOMTABLE_SIZE )) return NULL;
139 /* Reload ptr in case it moved in linear memory */
140 ptr = (INSTANCEDATA *)PTR_SEG_OFF_TO_LIN( selector, 0 );
141 return (ATOMTABLE *)((char *)ptr + ptr->atomtable);
145 /***********************************************************************
148 * Make an ATOMENTRY pointer from a handle (obtained from GetAtomHandle()).
150 static ATOMENTRY *ATOM_MakePtr(
151 WORD selector, /* [in] Segment */
152 HANDLE16 handle /* [in] Handle */
154 return (ATOMENTRY *)PTR_SEG_OFF_TO_LIN( selector, handle );
158 /***********************************************************************
161 * The hash value for the input string
163 static WORD ATOM_Hash(
164 WORD entries, /* [in] Total number of entries */
165 LPCSTR str, /* [in] Pointer to string to hash */
166 WORD len /* [in] Length of string */
170 TRACE("%x, %s, %x\n", entries, str, len);
172 for (i = 0; i < len; i++) hash ^= toupper(str[i]) + i;
173 return hash % entries;
176 static BOOL ATOM_IsIntAtom(LPCSTR atomstr,WORD *atomid) {
179 if (!HIWORD(atomstr)) {
180 *atomid = LOWORD(atomstr);
185 *atomid=strtol(atomstr+1,&xend,10);
187 FIXME("found atom named '%s'\n",atomstr);
194 /***********************************************************************
197 * Windows DWORD aligns the atom entry size.
198 * The remaining unused string space created by the alignment
199 * gets padded with '\0's in a certain way to ensure
200 * that at least one trailing '\0' remains.
206 static ATOM ATOM_AddAtom(
207 WORD selector, /* [in] Segment */
208 LPCSTR str /* [in] Pointer to the string to add */
212 ATOMENTRY * entryPtr;
217 TRACE("0x%x, %s\n", selector, str);
219 if (ATOM_IsIntAtom(str,&iatom))
221 if ((len = strlen( str )) > MAX_ATOM_LEN) len = MAX_ATOM_LEN;
222 if (!(table = ATOM_GetTable( selector, TRUE ))) return 0;
223 hash = ATOM_Hash( table->size, str, len );
224 entry = table->entries[hash];
227 entryPtr = ATOM_MakePtr( selector, entry );
228 if ((entryPtr->length == len) &&
229 (!lstrncmpiA( entryPtr->str, str, len )))
231 entryPtr->refCount++;
232 TRACE("-- existing 0x%x\n", entry);
233 return HANDLETOATOM( entry );
235 entry = entryPtr->next;
238 ae_len = (sizeof(ATOMENTRY)+len+3) & ~3;
239 entry = LOCAL_Alloc( selector, LMEM_FIXED, ae_len);
240 if (!entry) return 0;
241 /* Reload the table ptr in case it moved in linear memory */
242 table = ATOM_GetTable( selector, FALSE );
243 entryPtr = ATOM_MakePtr( selector, entry );
244 entryPtr->next = table->entries[hash];
245 entryPtr->refCount = 1;
246 entryPtr->length = len;
247 strncpy( entryPtr->str, str, ae_len - sizeof(ATOMENTRY) + 1); /* always use strncpy ('\0's padding) */
248 table->entries[hash] = entry;
249 TRACE("-- new 0x%x\n", entry);
250 return HANDLETOATOM( entry );
254 /***********************************************************************
260 static ATOM ATOM_DeleteAtom(
261 WORD selector, /* [in] Segment */
262 ATOM atom /* [in] Atom to delete */
264 ATOMENTRY * entryPtr;
266 HANDLE16 entry, *prevEntry;
269 TRACE("0x%x, 0x%x\n", selector, atom);
271 if (atom < MIN_STR_ATOM) return 0; /* Integer atom */
273 if (!(table = ATOM_GetTable( selector, FALSE ))) return 0;
274 entry = ATOMTOHANDLE( atom );
275 entryPtr = ATOM_MakePtr( selector, entry );
277 /* Find previous atom */
278 hash = ATOM_Hash( table->size, entryPtr->str, entryPtr->length );
279 prevEntry = &table->entries[hash];
280 while (*prevEntry && *prevEntry != entry)
282 ATOMENTRY * prevEntryPtr = ATOM_MakePtr( selector, *prevEntry );
283 prevEntry = &prevEntryPtr->next;
285 if (!*prevEntry) return atom;
288 if (--entryPtr->refCount == 0)
290 *prevEntry = entryPtr->next;
291 LOCAL_Free( selector, entry );
297 /***********************************************************************
303 static ATOM ATOM_FindAtom(
304 WORD selector, /* [in] Segment */
305 LPCSTR str /* [in] Pointer to string to find */
312 TRACE("%x, %s\n", selector, str);
313 if (ATOM_IsIntAtom(str,&iatom))
315 if ((len = strlen( str )) > 255) len = 255;
316 if (!(table = ATOM_GetTable( selector, FALSE ))) return 0;
317 hash = ATOM_Hash( table->size, str, len );
318 entry = table->entries[hash];
321 ATOMENTRY * entryPtr = ATOM_MakePtr( selector, entry );
322 if ((entryPtr->length == len) &&
323 (!lstrncmpiA( entryPtr->str, str, len )))
324 { TRACE("-- found %x\n", entry);
325 return HANDLETOATOM( entry );
327 entry = entryPtr->next;
329 TRACE("-- not found\n");
334 /***********************************************************************
337 * Length of string copied to buffer: Success
340 static UINT ATOM_GetAtomName(
341 WORD selector, /* [in] Segment */
342 ATOM atom, /* [in] Atom identifier */
343 LPSTR buffer, /* [out] Pointer to buffer for atom string */
344 INT count /* [in] Size of buffer */
347 ATOMENTRY * entryPtr;
353 TRACE("%x, %x\n", selector, atom);
355 if (!count) return 0;
356 if (atom < MIN_STR_ATOM)
358 sprintf( text, "#%d", atom );
364 if (!(table = ATOM_GetTable( selector, FALSE ))) return 0;
365 entry = ATOMTOHANDLE( atom );
366 entryPtr = ATOM_MakePtr( selector, entry );
367 len = entryPtr->length;
368 strPtr = entryPtr->str;
370 if (len >= count) len = count-1;
371 memcpy( buffer, strPtr, len );
377 /***********************************************************************
378 * InitAtomTable16 (KERNEL.68)
380 WORD WINAPI InitAtomTable16( WORD entries )
382 if (!entries) entries = DEFAULT_ATOMTABLE_SIZE; /* sanity check */
383 return ATOM_InitTable( CURRENT_DS, entries );
387 /***********************************************************************
388 * GetAtomHandle (KERNEL.73)
390 HANDLE16 WINAPI GetAtomHandle16( ATOM atom )
392 if (atom < MIN_STR_ATOM) return 0;
393 return ATOMTOHANDLE( atom );
397 /***********************************************************************
398 * AddAtom16 (KERNEL.70)
400 ATOM WINAPI AddAtom16( SEGPTR str )
403 HANDLE16 ds = CURRENT_DS;
405 if (!HIWORD(str)) return (ATOM)LOWORD(str); /* Integer atom */
406 if (SELECTOR_TO_ENTRY(LOWORD(str)) == SELECTOR_TO_ENTRY(ds))
408 /* If the string is in the same data segment as the atom table, make */
409 /* a copy of the string to be sure it doesn't move in linear memory. */
410 char buffer[MAX_ATOM_LEN+1];
411 lstrcpynA( buffer, (char *)PTR_SEG_TO_LIN(str), sizeof(buffer) );
412 atom = ATOM_AddAtom( ds, buffer );
414 else atom = ATOM_AddAtom( ds, (LPCSTR)PTR_SEG_TO_LIN(str) );
419 /***********************************************************************
420 * AddAtom32A (KERNEL32.0)
421 * Adds a string to the atom table and returns the atom identifying the
428 ATOM WINAPI AddAtomA(
429 LPCSTR str /* [in] Pointer to string to add */
431 return GlobalAddAtomA( str ); /* FIXME */
435 /***********************************************************************
436 * AddAtom32W (KERNEL32.1)
439 ATOM WINAPI AddAtomW( LPCWSTR str )
441 return GlobalAddAtomW( str ); /* FIXME */
445 /***********************************************************************
446 * DeleteAtom16 (KERNEL.71)
448 ATOM WINAPI DeleteAtom16( ATOM atom )
450 return ATOM_DeleteAtom( CURRENT_DS, atom );
454 /***********************************************************************
455 * DeleteAtom32 (KERNEL32.69)
456 * Decrements the reference count of a string atom. If count becomes
457 * zero, the string associated with the atom is removed from the table.
463 ATOM WINAPI DeleteAtom(
464 ATOM atom /* [in] Atom to delete */
466 return GlobalDeleteAtom( atom ); /* FIXME */
470 /***********************************************************************
471 * FindAtom16 (KERNEL.69)
473 ATOM WINAPI FindAtom16( SEGPTR str )
475 if (!HIWORD(str)) return (ATOM)LOWORD(str); /* Integer atom */
476 return ATOM_FindAtom( CURRENT_DS, (LPCSTR)PTR_SEG_TO_LIN(str) );
480 /***********************************************************************
481 * FindAtom32A (KERNEL32.117)
482 * Searches the local atom table for the string and returns the atom
483 * associated with that string.
489 ATOM WINAPI FindAtomA(
490 LPCSTR str /* [in] Pointer to string to find */
492 return GlobalFindAtomA( str ); /* FIXME */
496 /***********************************************************************
497 * FindAtom32W (KERNEL32.118)
500 ATOM WINAPI FindAtomW( LPCWSTR str )
502 return GlobalFindAtomW( str ); /* FIXME */
506 /***********************************************************************
507 * GetAtomName16 (KERNEL.72)
509 UINT16 WINAPI GetAtomName16( ATOM atom, LPSTR buffer, INT16 count )
511 return (UINT16)ATOM_GetAtomName( CURRENT_DS, atom, buffer, count );
515 /***********************************************************************
516 * GetAtomName32A (KERNEL32.149)
517 * Retrieves a copy of the string associated with the atom.
520 * Length of string: Success
523 UINT WINAPI GetAtomNameA(
524 ATOM atom, /* [in] Atom */
525 LPSTR buffer, /* [out] Pointer to string for atom string */
526 INT count /* [in] Size of buffer */
528 return GlobalGetAtomNameA( atom, buffer, count ); /* FIXME */
532 /***********************************************************************
533 * GetAtomName32W (KERNEL32.150)
536 UINT WINAPI GetAtomNameW( ATOM atom, LPWSTR buffer, INT count )
538 return GlobalGetAtomNameW( atom, buffer, count ); /* FIXME */
542 /***********************************************************************
543 * GlobalAddAtom16 (USER.268)
545 ATOM WINAPI GlobalAddAtom16( SEGPTR str )
547 if (!HIWORD(str)) return (ATOM)LOWORD(str); /* Integer atom */
549 return DDE_GlobalAddAtom( str );
551 return ATOM_AddAtom( ATOM_GlobalTable, (LPCSTR)PTR_SEG_TO_LIN(str) );
556 /***********************************************************************
557 * GlobalAddAtom32A (KERNEL32.313)
558 * Adds a character string to the global atom table and returns a unique
559 * value identifying the string.
565 ATOM WINAPI GlobalAddAtomA(
566 LPCSTR str /* [in] Pointer to string to add */
568 if (!HIWORD(str)) return (ATOM)LOWORD(str); /* Integer atom */
569 return ATOM_AddAtom( ATOM_GlobalTable, str );
573 /***********************************************************************
574 * GlobalAddAtom32W (KERNEL32.314)
575 * See GlobalAddAtom32A
577 ATOM WINAPI GlobalAddAtomW( LPCWSTR str )
579 char buffer[MAX_ATOM_LEN+1];
580 if (!HIWORD(str)) return (ATOM)LOWORD(str); /* Integer atom */
581 lstrcpynWtoA( buffer, str, sizeof(buffer) );
582 return ATOM_AddAtom( ATOM_GlobalTable, buffer );
586 /***********************************************************************
587 * GlobalDeleteAtom (USER.269) (KERNEL32.317)
588 * Decrements the reference count of a string atom. If the count is
589 * zero, the string associated with the atom is removed from the table.
595 ATOM WINAPI GlobalDeleteAtom(
596 ATOM atom /* [in] Atom to delete */
599 return DDE_GlobalDeleteAtom( atom );
601 return ATOM_DeleteAtom( ATOM_GlobalTable, atom );
606 /***********************************************************************
607 * GlobalFindAtom16 (USER.270)
609 ATOM WINAPI GlobalFindAtom16( SEGPTR str )
611 if (!HIWORD(str)) return (ATOM)LOWORD(str); /* Integer atom */
613 return DDE_GlobalFindAtom( str );
615 return ATOM_FindAtom( ATOM_GlobalTable, (LPCSTR)PTR_SEG_TO_LIN(str) );
620 /***********************************************************************
621 * GlobalFindAtom32A (KERNEL32.318)
622 * Searches the atom table for the string and returns the atom
623 * associated with it.
629 ATOM WINAPI GlobalFindAtomA(
630 LPCSTR str /* [in] Pointer to string to search for */
632 if (!HIWORD(str)) return (ATOM)LOWORD(str); /* Integer atom */
633 return ATOM_FindAtom( ATOM_GlobalTable, str );
637 /***********************************************************************
638 * GlobalFindAtom32W (KERNEL32.319)
639 * See GlobalFindAtom32A
641 ATOM WINAPI GlobalFindAtomW( LPCWSTR str )
643 char buffer[MAX_ATOM_LEN+1];
644 if (!HIWORD(str)) return (ATOM)LOWORD(str); /* Integer atom */
645 lstrcpynWtoA( buffer, str, sizeof(buffer) );
646 return ATOM_FindAtom( ATOM_GlobalTable, buffer );
650 /***********************************************************************
651 * GlobalGetAtomName16 (USER.271)
653 UINT16 WINAPI GlobalGetAtomName16( ATOM atom, LPSTR buffer, INT16 count )
656 return DDE_GlobalGetAtomName( atom, buffer, count );
658 return (UINT16)ATOM_GetAtomName( ATOM_GlobalTable, atom, buffer, count );
663 /***********************************************************************
664 * GlobalGetAtomName32A (KERNEL32.323)
665 * Retrieves a copy of the string associated with an atom.
668 * Length of string in characters: Success
671 UINT WINAPI GlobalGetAtomNameA(
672 ATOM atom, /* [in] Atom identifier */
673 LPSTR buffer, /* [out] Pointer to buffer for atom string */
674 INT count /* [in] Size of buffer */
676 return ATOM_GetAtomName( ATOM_GlobalTable, atom, buffer, count );
680 /***********************************************************************
681 * GlobalGetAtomName32W (KERNEL32.324)
682 * See GlobalGetAtomName32A
684 UINT WINAPI GlobalGetAtomNameW( ATOM atom, LPWSTR buffer, INT count )
686 char tmp[MAX_ATOM_LEN+1];
687 ATOM_GetAtomName( ATOM_GlobalTable, atom, tmp, sizeof(tmp) );
688 lstrcpynAtoW( buffer, tmp, count );
689 return lstrlenW( buffer );