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
20 #include "wine/winbase16.h"
21 #include "wine/winuser16.h"
24 #include "stackframe.h"
32 #define DEFAULT_ATOMTABLE_SIZE 37
33 #define MIN_STR_ATOM 0xc000
34 #define MAX_ATOM_LEN 255
36 #define ATOMTOHANDLE(atom) ((HANDLE16)(atom) << 2)
37 #define HANDLETOATOM(handle) ((ATOM)(0xc000 | ((handle) >> 2)))
39 #define HAS_ATOM_TABLE(sel) \
40 ((INSTANCEDATA*)PTR_SEG_OFF_TO_LIN(sel,0))->atomtable != 0)
42 #define GET_ATOM_TABLE(sel) ((ATOMTABLE*)PTR_SEG_OFF_TO_LIN(sel, \
43 ((INSTANCEDATA*)PTR_SEG_OFF_TO_LIN(sel,0))->atomtable))
59 static WORD ATOM_GlobalTable = 0;
61 /***********************************************************************
65 * Should this validate the value of entries to be 0 < x < 0x3fff?
71 static HANDLE16 ATOM_InitTable(
72 WORD selector, /* [in] Segment */
73 WORD entries /* [in] Size of atom table */
79 /* We consider the first table to be initialized as the global table.
80 * This works, as USER (both built-in and native) is the first one to
84 if (!ATOM_GlobalTable) ATOM_GlobalTable = selector;
87 /* Allocate the table */
89 handle = LOCAL_Alloc( selector, LMEM_FIXED,
90 sizeof(ATOMTABLE) + (entries-1) * sizeof(HANDLE16) );
91 if (!handle) return 0;
92 table = (ATOMTABLE *)PTR_SEG_OFF_TO_LIN( selector, handle );
93 table->size = entries;
94 for (i = 0; i < entries; i++) table->entries[i] = 0;
96 /* Store a pointer to the table in the instance data */
98 ((INSTANCEDATA *)PTR_SEG_OFF_TO_LIN( selector, 0 ))->atomtable = handle;
103 /***********************************************************************
106 * Global table initialisation.
108 BOOL ATOM_Init( WORD globalTableSel )
110 return ATOM_InitTable( globalTableSel, DEFAULT_ATOMTABLE_SIZE ) != 0;
114 /***********************************************************************
117 * Return a pointer to the atom table of a given segment, creating
121 * Pointer to table: Success
124 static ATOMTABLE *ATOM_GetTable(
125 WORD selector, /* [in] Segment */
126 BOOL create /* [in] Create */ )
128 INSTANCEDATA *ptr = (INSTANCEDATA *)PTR_SEG_OFF_TO_LIN( selector, 0 );
131 ATOMTABLE *table = (ATOMTABLE *)((char *)ptr + ptr->atomtable);
132 if (table->size) return table;
134 if (!create) return NULL;
135 if (!ATOM_InitTable( selector, DEFAULT_ATOMTABLE_SIZE )) return NULL;
136 /* Reload ptr in case it moved in linear memory */
137 ptr = (INSTANCEDATA *)PTR_SEG_OFF_TO_LIN( selector, 0 );
138 return (ATOMTABLE *)((char *)ptr + ptr->atomtable);
142 /***********************************************************************
145 * Make an ATOMENTRY pointer from a handle (obtained from GetAtomHandle()).
147 static ATOMENTRY *ATOM_MakePtr(
148 WORD selector, /* [in] Segment */
149 HANDLE16 handle /* [in] Handle */
151 return (ATOMENTRY *)PTR_SEG_OFF_TO_LIN( selector, handle );
155 /***********************************************************************
158 * The hash value for the input string
160 static WORD ATOM_Hash(
161 WORD entries, /* [in] Total number of entries */
162 LPCSTR str, /* [in] Pointer to string to hash */
163 WORD len /* [in] Length of string */
167 TRACE(atom,"%x, %s, %x\n", entries, str, len);
169 for (i = 0; i < len; i++) hash ^= toupper(str[i]) + i;
170 return hash % entries;
173 static BOOL ATOM_IsIntAtom(LPCSTR atomstr,WORD *atomid) {
176 if (!HIWORD(atomstr)) {
177 *atomid = LOWORD(atomstr);
182 *atomid=strtol(atomstr+1,&xend,10);
184 FIXME(atom,"found atom named '%s'\n",atomstr);
191 /***********************************************************************
194 * Windows DWORD aligns the atom entry size.
195 * The remaining unused string space created by the alignment
196 * gets padded with '\0's in a certain way to ensure
197 * that at least one trailing '\0' remains.
203 static ATOM ATOM_AddAtom(
204 WORD selector, /* [in] Segment */
205 LPCSTR str /* [in] Pointer to the string to add */
209 ATOMENTRY * entryPtr;
214 TRACE(atom,"0x%x, %s\n", selector, str);
216 if (ATOM_IsIntAtom(str,&iatom))
218 if ((len = strlen( str )) > MAX_ATOM_LEN) len = MAX_ATOM_LEN;
219 if (!(table = ATOM_GetTable( selector, TRUE ))) return 0;
220 hash = ATOM_Hash( table->size, str, len );
221 entry = table->entries[hash];
224 entryPtr = ATOM_MakePtr( selector, entry );
225 if ((entryPtr->length == len) &&
226 (!lstrncmpiA( entryPtr->str, str, len )))
228 entryPtr->refCount++;
229 TRACE(atom,"-- existing 0x%x\n", entry);
230 return HANDLETOATOM( entry );
232 entry = entryPtr->next;
235 ae_len = (sizeof(ATOMENTRY)+len+3) & ~3;
236 entry = LOCAL_Alloc( selector, LMEM_FIXED, ae_len);
237 if (!entry) return 0;
238 /* Reload the table ptr in case it moved in linear memory */
239 table = ATOM_GetTable( selector, FALSE );
240 entryPtr = ATOM_MakePtr( selector, entry );
241 entryPtr->next = table->entries[hash];
242 entryPtr->refCount = 1;
243 entryPtr->length = len;
244 strncpy( entryPtr->str, str, ae_len - sizeof(ATOMENTRY) + 1); /* always use strncpy ('\0's padding) */
245 table->entries[hash] = entry;
246 TRACE(atom,"-- new 0x%x\n", entry);
247 return HANDLETOATOM( entry );
251 /***********************************************************************
257 static ATOM ATOM_DeleteAtom(
258 WORD selector, /* [in] Segment */
259 ATOM atom /* [in] Atom to delete */
261 ATOMENTRY * entryPtr;
263 HANDLE16 entry, *prevEntry;
266 TRACE(atom,"0x%x, 0x%x\n", selector, atom);
268 if (atom < MIN_STR_ATOM) return 0; /* Integer atom */
270 if (!(table = ATOM_GetTable( selector, FALSE ))) return 0;
271 entry = ATOMTOHANDLE( atom );
272 entryPtr = ATOM_MakePtr( selector, entry );
274 /* Find previous atom */
275 hash = ATOM_Hash( table->size, entryPtr->str, entryPtr->length );
276 prevEntry = &table->entries[hash];
277 while (*prevEntry && *prevEntry != entry)
279 ATOMENTRY * prevEntryPtr = ATOM_MakePtr( selector, *prevEntry );
280 prevEntry = &prevEntryPtr->next;
282 if (!*prevEntry) return atom;
285 if (--entryPtr->refCount == 0)
287 *prevEntry = entryPtr->next;
288 LOCAL_Free( selector, entry );
294 /***********************************************************************
300 static ATOM ATOM_FindAtom(
301 WORD selector, /* [in] Segment */
302 LPCSTR str /* [in] Pointer to string to find */
309 TRACE(atom,"%x, %s\n", selector, str);
310 if (ATOM_IsIntAtom(str,&iatom))
312 if ((len = strlen( str )) > 255) len = 255;
313 if (!(table = ATOM_GetTable( selector, FALSE ))) return 0;
314 hash = ATOM_Hash( table->size, str, len );
315 entry = table->entries[hash];
318 ATOMENTRY * entryPtr = ATOM_MakePtr( selector, entry );
319 if ((entryPtr->length == len) &&
320 (!lstrncmpiA( entryPtr->str, str, len )))
321 { TRACE(atom,"-- found %x\n", entry);
322 return HANDLETOATOM( entry );
324 entry = entryPtr->next;
326 TRACE(atom,"-- not found\n");
331 /***********************************************************************
334 * Length of string copied to buffer: Success
337 static UINT ATOM_GetAtomName(
338 WORD selector, /* [in] Segment */
339 ATOM atom, /* [in] Atom identifier */
340 LPSTR buffer, /* [out] Pointer to buffer for atom string */
341 INT count /* [in] Size of buffer */
344 ATOMENTRY * entryPtr;
350 TRACE(atom,"%x, %x\n", selector, atom);
352 if (!count) return 0;
353 if (atom < MIN_STR_ATOM)
355 sprintf( text, "#%d", atom );
361 if (!(table = ATOM_GetTable( selector, FALSE ))) return 0;
362 entry = ATOMTOHANDLE( atom );
363 entryPtr = ATOM_MakePtr( selector, entry );
364 len = entryPtr->length;
365 strPtr = entryPtr->str;
367 if (len >= count) len = count-1;
368 memcpy( buffer, strPtr, len );
374 /***********************************************************************
375 * InitAtomTable16 (KERNEL.68)
377 WORD WINAPI InitAtomTable16( WORD entries )
379 if (!entries) entries = DEFAULT_ATOMTABLE_SIZE; /* sanity check */
380 return ATOM_InitTable( CURRENT_DS, entries );
384 /***********************************************************************
385 * GetAtomHandle (KERNEL.73)
387 HANDLE16 WINAPI GetAtomHandle16( ATOM atom )
389 if (atom < MIN_STR_ATOM) return 0;
390 return ATOMTOHANDLE( atom );
394 /***********************************************************************
395 * AddAtom16 (KERNEL.70)
397 ATOM WINAPI AddAtom16( SEGPTR str )
400 HANDLE16 ds = CURRENT_DS;
402 if (!HIWORD(str)) return (ATOM)LOWORD(str); /* Integer atom */
403 if (SELECTOR_TO_ENTRY(LOWORD(str)) == SELECTOR_TO_ENTRY(ds))
405 /* If the string is in the same data segment as the atom table, make */
406 /* a copy of the string to be sure it doesn't move in linear memory. */
407 char buffer[MAX_ATOM_LEN+1];
408 lstrcpynA( buffer, (char *)PTR_SEG_TO_LIN(str), sizeof(buffer) );
409 atom = ATOM_AddAtom( ds, buffer );
411 else atom = ATOM_AddAtom( ds, (LPCSTR)PTR_SEG_TO_LIN(str) );
416 /***********************************************************************
417 * AddAtom32A (KERNEL32.0)
418 * Adds a string to the atom table and returns the atom identifying the
425 ATOM WINAPI AddAtomA(
426 LPCSTR str /* [in] Pointer to string to add */
428 return GlobalAddAtomA( str ); /* FIXME */
432 /***********************************************************************
433 * AddAtom32W (KERNEL32.1)
436 ATOM WINAPI AddAtomW( LPCWSTR str )
438 return GlobalAddAtomW( str ); /* FIXME */
442 /***********************************************************************
443 * DeleteAtom16 (KERNEL.71)
445 ATOM WINAPI DeleteAtom16( ATOM atom )
447 return ATOM_DeleteAtom( CURRENT_DS, atom );
451 /***********************************************************************
452 * DeleteAtom32 (KERNEL32.69)
453 * Decrements the reference count of a string atom. If count becomes
454 * zero, the string associated with the atom is removed from the table.
460 ATOM WINAPI DeleteAtom(
461 ATOM atom /* [in] Atom to delete */
463 return GlobalDeleteAtom( atom ); /* FIXME */
467 /***********************************************************************
468 * FindAtom16 (KERNEL.69)
470 ATOM WINAPI FindAtom16( SEGPTR str )
472 if (!HIWORD(str)) return (ATOM)LOWORD(str); /* Integer atom */
473 return ATOM_FindAtom( CURRENT_DS, (LPCSTR)PTR_SEG_TO_LIN(str) );
477 /***********************************************************************
478 * FindAtom32A (KERNEL32.117)
479 * Searches the local atom table for the string and returns the atom
480 * associated with that string.
486 ATOM WINAPI FindAtomA(
487 LPCSTR str /* [in] Pointer to string to find */
489 return GlobalFindAtomA( str ); /* FIXME */
493 /***********************************************************************
494 * FindAtom32W (KERNEL32.118)
497 ATOM WINAPI FindAtomW( LPCWSTR str )
499 return GlobalFindAtomW( str ); /* FIXME */
503 /***********************************************************************
504 * GetAtomName16 (KERNEL.72)
506 UINT16 WINAPI GetAtomName16( ATOM atom, LPSTR buffer, INT16 count )
508 return (UINT16)ATOM_GetAtomName( CURRENT_DS, atom, buffer, count );
512 /***********************************************************************
513 * GetAtomName32A (KERNEL32.149)
514 * Retrieves a copy of the string associated with the atom.
517 * Length of string: Success
520 UINT WINAPI GetAtomNameA(
521 ATOM atom, /* [in] Atom */
522 LPSTR buffer, /* [out] Pointer to string for atom string */
523 INT count /* [in] Size of buffer */
525 return GlobalGetAtomNameA( atom, buffer, count ); /* FIXME */
529 /***********************************************************************
530 * GetAtomName32W (KERNEL32.150)
533 UINT WINAPI GetAtomNameW( ATOM atom, LPWSTR buffer, INT count )
535 return GlobalGetAtomNameW( atom, buffer, count ); /* FIXME */
539 /***********************************************************************
540 * GlobalAddAtom16 (USER.268)
542 ATOM WINAPI GlobalAddAtom16( SEGPTR str )
544 if (!HIWORD(str)) return (ATOM)LOWORD(str); /* Integer atom */
546 return DDE_GlobalAddAtom( str );
548 return ATOM_AddAtom( ATOM_GlobalTable, (LPCSTR)PTR_SEG_TO_LIN(str) );
553 /***********************************************************************
554 * GlobalAddAtom32A (KERNEL32.313)
555 * Adds a character string to the global atom table and returns a unique
556 * value identifying the string.
562 ATOM WINAPI GlobalAddAtomA(
563 LPCSTR str /* [in] Pointer to string to add */
565 if (!HIWORD(str)) return (ATOM)LOWORD(str); /* Integer atom */
566 return ATOM_AddAtom( ATOM_GlobalTable, str );
570 /***********************************************************************
571 * GlobalAddAtom32W (KERNEL32.314)
572 * See GlobalAddAtom32A
574 ATOM WINAPI GlobalAddAtomW( LPCWSTR str )
576 char buffer[MAX_ATOM_LEN+1];
577 if (!HIWORD(str)) return (ATOM)LOWORD(str); /* Integer atom */
578 lstrcpynWtoA( buffer, str, sizeof(buffer) );
579 return ATOM_AddAtom( ATOM_GlobalTable, buffer );
583 /***********************************************************************
584 * GlobalDeleteAtom (USER.269) (KERNEL32.317)
585 * Decrements the reference count of a string atom. If the count is
586 * zero, the string associated with the atom is removed from the table.
592 ATOM WINAPI GlobalDeleteAtom(
593 ATOM atom /* [in] Atom to delete */
596 return DDE_GlobalDeleteAtom( atom );
598 return ATOM_DeleteAtom( ATOM_GlobalTable, atom );
603 /***********************************************************************
604 * GlobalFindAtom16 (USER.270)
606 ATOM WINAPI GlobalFindAtom16( SEGPTR str )
608 if (!HIWORD(str)) return (ATOM)LOWORD(str); /* Integer atom */
610 return DDE_GlobalFindAtom( str );
612 return ATOM_FindAtom( ATOM_GlobalTable, (LPCSTR)PTR_SEG_TO_LIN(str) );
617 /***********************************************************************
618 * GlobalFindAtom32A (KERNEL32.318)
619 * Searches the atom table for the string and returns the atom
620 * associated with it.
626 ATOM WINAPI GlobalFindAtomA(
627 LPCSTR str /* [in] Pointer to string to search for */
629 if (!HIWORD(str)) return (ATOM)LOWORD(str); /* Integer atom */
630 return ATOM_FindAtom( ATOM_GlobalTable, str );
634 /***********************************************************************
635 * GlobalFindAtom32W (KERNEL32.319)
636 * See GlobalFindAtom32A
638 ATOM WINAPI GlobalFindAtomW( LPCWSTR str )
640 char buffer[MAX_ATOM_LEN+1];
641 if (!HIWORD(str)) return (ATOM)LOWORD(str); /* Integer atom */
642 lstrcpynWtoA( buffer, str, sizeof(buffer) );
643 return ATOM_FindAtom( ATOM_GlobalTable, buffer );
647 /***********************************************************************
648 * GlobalGetAtomName16 (USER.271)
650 UINT16 WINAPI GlobalGetAtomName16( ATOM atom, LPSTR buffer, INT16 count )
653 return DDE_GlobalGetAtomName( atom, buffer, count );
655 return (UINT16)ATOM_GetAtomName( ATOM_GlobalTable, atom, buffer, count );
660 /***********************************************************************
661 * GlobalGetAtomName32A (KERNEL32.323)
662 * Retrieves a copy of the string associated with an atom.
665 * Length of string in characters: Success
668 UINT WINAPI GlobalGetAtomNameA(
669 ATOM atom, /* [in] Atom identifier */
670 LPSTR buffer, /* [out] Pointer to buffer for atom string */
671 INT count /* [in] Size of buffer */
673 return ATOM_GetAtomName( ATOM_GlobalTable, atom, buffer, count );
677 /***********************************************************************
678 * GlobalGetAtomName32W (KERNEL32.324)
679 * See GlobalGetAtomName32A
681 UINT WINAPI GlobalGetAtomNameW( ATOM atom, LPWSTR buffer, INT count )
683 char tmp[MAX_ATOM_LEN+1];
684 ATOM_GetAtomName( ATOM_GlobalTable, atom, tmp, sizeof(tmp) );
685 lstrcpynAtoW( buffer, tmp, count );
686 return lstrlenW( buffer );