Changed the initialisation of the KeyState array.
[wine] / memory / atom.c
1 /*
2  * Atom table functions
3  *
4  * Copyright 1993, 1994, 1995 Alexandre Julliard
5  */
6
7 /*
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
11  * have to be changed.
12  */
13
14 #include <stdlib.h>
15 #include <stdio.h>
16 #include <string.h>
17 #include <ctype.h>
18
19 #include "wine/winbase16.h"
20 #include "wine/winuser16.h"
21 #include "winuser.h"
22 #include "global.h"
23 #include "instance.h"
24 #include "ldt.h"
25 #include "stackframe.h"
26 #include "user.h"
27 #include "debugtools.h"
28
29 DEFAULT_DEBUG_CHANNEL(atom)
30
31 #define DEFAULT_ATOMTABLE_SIZE    37
32 #define MIN_STR_ATOM              0xc000
33 #define MAX_ATOM_LEN              255
34
35 #define ATOMTOHANDLE(atom)        ((HANDLE16)(atom) << 2)
36 #define HANDLETOATOM(handle)      ((ATOM)(0xc000 | ((handle) >> 2)))
37
38 #define HAS_ATOM_TABLE(sel)  \
39           ((INSTANCEDATA*)PTR_SEG_OFF_TO_LIN(sel,0))->atomtable != 0)
40
41 #define GET_ATOM_TABLE(sel)  ((ATOMTABLE*)PTR_SEG_OFF_TO_LIN(sel, \
42           ((INSTANCEDATA*)PTR_SEG_OFF_TO_LIN(sel,0))->atomtable))
43
44 typedef struct
45 {
46     HANDLE16    next;
47     WORD        refCount;
48     BYTE        length;
49     BYTE        str[1];
50 } ATOMENTRY;
51
52 typedef struct
53 {
54     WORD        size;
55     HANDLE16    entries[1];
56 } ATOMTABLE;
57                 
58 static WORD ATOM_GlobalTable = 0;
59
60 /***********************************************************************
61  *           ATOM_InitTable
62  *
63  * NOTES
64  *      Should this validate the value of entries to be 0 < x < 0x3fff?
65  *
66  * RETURNS
67  *      Handle: Success
68  *      0: Failure
69  */
70 static HANDLE16 ATOM_InitTable(
71                 WORD selector, /* [in] Segment */
72                 WORD entries   /* [in] Size of atom table */
73 ) {
74     int i;
75     HANDLE16 handle;
76     ATOMTABLE *table;
77
78       /* We consider the first table to be initialized as the global table. 
79        * This works, as USER (both built-in and native) is the first one to 
80        * register ... 
81        */
82
83     if (!ATOM_GlobalTable) ATOM_GlobalTable = selector; 
84
85
86       /* Allocate the table */
87
88     handle = LOCAL_Alloc( selector, LMEM_FIXED,
89                           sizeof(ATOMTABLE) + (entries-1) * sizeof(HANDLE16) );
90     if (!handle) return 0;
91     table = (ATOMTABLE *)PTR_SEG_OFF_TO_LIN( selector, handle );
92     table->size = entries;
93     for (i = 0; i < entries; i++) table->entries[i] = 0;
94
95       /* Store a pointer to the table in the instance data */
96
97     ((INSTANCEDATA *)PTR_SEG_OFF_TO_LIN( selector, 0 ))->atomtable = handle;
98     return handle;
99 }
100
101
102 /***********************************************************************
103  *           ATOM_Init
104  *
105  * Global table initialisation.
106  */
107 BOOL ATOM_Init( WORD globalTableSel )
108 {
109     return ATOM_InitTable( globalTableSel, DEFAULT_ATOMTABLE_SIZE ) != 0;
110 }
111
112
113 /***********************************************************************
114  *           ATOM_GetTable
115  *
116  * Return a pointer to the atom table of a given segment, creating
117  * it if necessary.
118  *
119  * RETURNS
120  *      Pointer to table: Success
121  *      NULL: Failure
122  */
123 static ATOMTABLE *ATOM_GetTable(
124                   WORD selector, /* [in] Segment */
125                   BOOL create  /* [in] Create */ )
126 {
127     INSTANCEDATA *ptr = (INSTANCEDATA *)PTR_SEG_OFF_TO_LIN( selector, 0 );
128     if (ptr->atomtable)
129     {
130         ATOMTABLE *table = (ATOMTABLE *)((char *)ptr + ptr->atomtable);
131         if (table->size) return table;
132     }
133     if (!create) return NULL;
134     if (!ATOM_InitTable( selector, DEFAULT_ATOMTABLE_SIZE )) return NULL;
135     /* Reload ptr in case it moved in linear memory */
136     ptr = (INSTANCEDATA *)PTR_SEG_OFF_TO_LIN( selector, 0 );
137     return (ATOMTABLE *)((char *)ptr + ptr->atomtable);
138 }
139
140
141 /***********************************************************************
142  *           ATOM_MakePtr
143  *
144  * Make an ATOMENTRY pointer from a handle (obtained from GetAtomHandle()).
145  */
146 static ATOMENTRY *ATOM_MakePtr(
147                   WORD selector,  /* [in] Segment */
148                   HANDLE16 handle /* [in] Handle */
149 ) {
150     return (ATOMENTRY *)PTR_SEG_OFF_TO_LIN( selector, handle );
151 }
152
153
154 /***********************************************************************
155  *           ATOM_Hash
156  * RETURNS
157  *      The hash value for the input string
158  */
159 static WORD ATOM_Hash(
160             WORD entries, /* [in] Total number of entries */
161             LPCSTR str,   /* [in] Pointer to string to hash */
162             WORD len      /* [in] Length of string */
163 ) {
164     WORD i, hash = 0;
165
166     TRACE("%x, %s, %x\n", entries, str, len);
167     
168     for (i = 0; i < len; i++) hash ^= toupper(str[i]) + i;
169     return hash % entries;
170 }
171
172 static BOOL ATOM_IsIntAtom(LPCSTR atomstr,WORD *atomid) {
173         LPSTR   xend;
174
175         if (!HIWORD(atomstr)) {
176                 *atomid = LOWORD(atomstr);
177                 return TRUE;
178         }
179         if (atomstr[0]!='#')
180                 return FALSE;
181         *atomid=strtol(atomstr+1,&xend,10);
182         if (*xend) {
183                 FIXME("found atom named '%s'\n",atomstr);
184                 return FALSE;
185         }
186         return TRUE;
187 }
188
189
190 /***********************************************************************
191  *           ATOM_AddAtom
192  *
193  * Windows DWORD aligns the atom entry size.
194  * The remaining unused string space created by the alignment
195  * gets padded with '\0's in a certain way to ensure
196  * that at least one trailing '\0' remains.
197  *
198  * RETURNS
199  *      Atom: Success
200  *      0: Failure
201  */
202 static ATOM ATOM_AddAtom(
203             WORD selector, /* [in] Segment */
204             LPCSTR str     /* [in] Pointer to the string to add */
205 ) {
206     WORD hash;
207     HANDLE16 entry;
208     ATOMENTRY * entryPtr;
209     ATOMTABLE * table;
210     int len, ae_len;
211     WORD        iatom;
212
213     TRACE("0x%x, %s\n", selector, str);
214     
215     if (ATOM_IsIntAtom(str,&iatom))
216         return iatom;
217     if ((len = strlen( str )) > MAX_ATOM_LEN) len = MAX_ATOM_LEN;
218     if (!(table = ATOM_GetTable( selector, TRUE ))) return 0;
219     hash = ATOM_Hash( table->size, str, len );
220     entry = table->entries[hash];
221     while (entry)
222     {
223         entryPtr = ATOM_MakePtr( selector, entry );
224         if ((entryPtr->length == len) && 
225             (!lstrncmpiA( entryPtr->str, str, len )))
226         {
227             entryPtr->refCount++;
228         TRACE("-- existing 0x%x\n", entry);
229             return HANDLETOATOM( entry );
230         }
231         entry = entryPtr->next;
232     }
233
234     ae_len = (sizeof(ATOMENTRY)+len+3) & ~3;
235     entry = LOCAL_Alloc( selector, LMEM_FIXED, ae_len);
236     if (!entry) return 0;
237     /* Reload the table ptr in case it moved in linear memory */
238     table = ATOM_GetTable( selector, FALSE );
239     entryPtr = ATOM_MakePtr( selector, entry );
240     entryPtr->next = table->entries[hash];
241     entryPtr->refCount = 1;
242     entryPtr->length = len;
243     strncpy( entryPtr->str, str, ae_len - sizeof(ATOMENTRY) + 1); /* always use strncpy ('\0's padding) */
244     table->entries[hash] = entry;
245     TRACE("-- new 0x%x\n", entry);
246     return HANDLETOATOM( entry );
247 }
248
249
250 /***********************************************************************
251  *           ATOM_DeleteAtom
252  * RETURNS
253  *      0: Success
254  *      Atom: Failure
255  */
256 static ATOM ATOM_DeleteAtom(
257             WORD selector, /* [in] Segment */
258             ATOM atom      /* [in] Atom to delete */
259 ) {
260     ATOMENTRY * entryPtr;
261     ATOMTABLE * table;
262     HANDLE16 entry, *prevEntry;
263     WORD hash;
264
265     TRACE("0x%x, 0x%x\n", selector, atom);
266     
267     if (atom < MIN_STR_ATOM) return 0;  /* Integer atom */
268
269     if (!(table = ATOM_GetTable( selector, FALSE ))) return 0;
270     entry = ATOMTOHANDLE( atom );
271     entryPtr = ATOM_MakePtr( selector, entry );
272
273       /* Find previous atom */
274     hash = ATOM_Hash( table->size, entryPtr->str, entryPtr->length );
275     prevEntry = &table->entries[hash];
276     while (*prevEntry && *prevEntry != entry)
277     {
278         ATOMENTRY * prevEntryPtr = ATOM_MakePtr( selector, *prevEntry );
279         prevEntry = &prevEntryPtr->next;
280     }    
281     if (!*prevEntry) return atom;
282
283       /* Delete atom */
284     if (--entryPtr->refCount == 0)
285     {
286         *prevEntry = entryPtr->next;
287         LOCAL_Free( selector, entry );
288     }    
289     return 0;
290 }
291
292
293 /***********************************************************************
294  *           ATOM_FindAtom
295  * RETURNS
296  *      Atom: Success
297  *      0: Failure
298  */
299 static ATOM ATOM_FindAtom(
300             WORD selector, /* [in] Segment */
301             LPCSTR str     /* [in] Pointer to string to find */
302 ) {
303     ATOMTABLE * table;
304     WORD hash,iatom;
305     HANDLE16 entry;
306     int len;
307
308     TRACE("%x, %s\n", selector, str);
309     if (ATOM_IsIntAtom(str,&iatom))
310         return iatom;
311     if ((len = strlen( str )) > 255) len = 255;
312     if (!(table = ATOM_GetTable( selector, FALSE ))) return 0;
313     hash = ATOM_Hash( table->size, str, len );
314     entry = table->entries[hash];
315     while (entry)
316     {
317         ATOMENTRY * entryPtr = ATOM_MakePtr( selector, entry );
318         if ((entryPtr->length == len) && 
319             (!lstrncmpiA( entryPtr->str, str, len )))
320     {    TRACE("-- found %x\n", entry);
321             return HANDLETOATOM( entry );
322     }
323         entry = entryPtr->next;
324     }
325     TRACE("-- not found\n");
326     return 0;
327 }
328
329
330 /***********************************************************************
331  *           ATOM_GetAtomName
332  * RETURNS
333  *      Length of string copied to buffer: Success
334  *      0: Failure
335  */
336 static UINT ATOM_GetAtomName(
337               WORD selector, /* [in]  Segment */
338               ATOM atom,     /* [in]  Atom identifier */
339               LPSTR buffer,  /* [out] Pointer to buffer for atom string */
340               INT count    /* [in]  Size of buffer */
341 ) {
342     ATOMTABLE * table;
343     ATOMENTRY * entryPtr;
344     HANDLE16 entry;
345     char * strPtr;
346     UINT len;
347     char text[8];
348     
349     TRACE("%x, %x\n", selector, atom);
350     
351     if (!count) return 0;
352     if (atom < MIN_STR_ATOM)
353     {
354         sprintf( text, "#%d", atom );
355         len = strlen(text);
356         strPtr = text;
357     }
358     else
359     {
360        if (!(table = ATOM_GetTable( selector, FALSE ))) return 0;
361         entry = ATOMTOHANDLE( atom );
362         entryPtr = ATOM_MakePtr( selector, entry );
363         len = entryPtr->length;
364         strPtr = entryPtr->str;
365     }
366     if (len >= count) len = count-1;
367     memcpy( buffer, strPtr, len );
368     buffer[len] = '\0';
369     return len;
370 }
371
372
373 /***********************************************************************
374  *           InitAtomTable16   (KERNEL.68)
375  */
376 WORD WINAPI InitAtomTable16( WORD entries )
377 {
378     if (!entries) entries = DEFAULT_ATOMTABLE_SIZE;  /* sanity check */
379     return ATOM_InitTable( CURRENT_DS, entries );
380 }
381
382
383 /***********************************************************************
384  *           GetAtomHandle   (KERNEL.73)
385  */
386 HANDLE16 WINAPI GetAtomHandle16( ATOM atom )
387 {
388     if (atom < MIN_STR_ATOM) return 0;
389     return ATOMTOHANDLE( atom );
390 }
391
392
393 /***********************************************************************
394  *           AddAtom16   (KERNEL.70)
395  */
396 ATOM WINAPI AddAtom16( SEGPTR str )
397 {
398     ATOM atom;
399     HANDLE16 ds = CURRENT_DS;
400
401     if (!HIWORD(str)) return (ATOM)LOWORD(str);  /* Integer atom */
402     if (SELECTOR_TO_ENTRY(LOWORD(str)) == SELECTOR_TO_ENTRY(ds))
403     {
404         /* If the string is in the same data segment as the atom table, make */
405         /* a copy of the string to be sure it doesn't move in linear memory. */
406         char buffer[MAX_ATOM_LEN+1];
407         lstrcpynA( buffer, (char *)PTR_SEG_TO_LIN(str), sizeof(buffer) );
408         atom = ATOM_AddAtom( ds, buffer );
409     }
410     else atom = ATOM_AddAtom( ds, (LPCSTR)PTR_SEG_TO_LIN(str) );
411     return atom;
412 }
413
414
415 /***********************************************************************
416  *           AddAtom32A   (KERNEL32.0)
417  * Adds a string to the atom table and returns the atom identifying the
418  * string.
419  *
420  * RETURNS
421  *      Atom: Success
422  *      0: Failure
423  */
424 ATOM WINAPI AddAtomA(
425             LPCSTR str /* [in] Pointer to string to add */
426 ) {
427     return GlobalAddAtomA( str );  /* FIXME */
428 }
429
430
431 /***********************************************************************
432  *           AddAtom32W   (KERNEL32.1)
433  * See AddAtom32A
434  */
435 ATOM WINAPI AddAtomW( LPCWSTR str )
436 {
437     return GlobalAddAtomW( str );  /* FIXME */
438 }
439
440
441 /***********************************************************************
442  *           DeleteAtom16   (KERNEL.71)
443  */
444 ATOM WINAPI DeleteAtom16( ATOM atom )
445 {
446     return ATOM_DeleteAtom( CURRENT_DS, atom );
447 }
448
449
450 /***********************************************************************
451  *           DeleteAtom32   (KERNEL32.69)
452  * Decrements the reference count of a string atom.  If count becomes
453  * zero, the string associated with the atom is removed from the table.
454  *
455  * RETURNS
456  *      0: Success
457  *      Atom: Failure
458  */
459 ATOM WINAPI DeleteAtom(
460             ATOM atom /* [in] Atom to delete */
461 ) {
462     return GlobalDeleteAtom( atom );  /* FIXME */
463 }
464
465
466 /***********************************************************************
467  *           FindAtom16   (KERNEL.69)
468  */
469 ATOM WINAPI FindAtom16( SEGPTR str )
470 {
471     if (!HIWORD(str)) return (ATOM)LOWORD(str);  /* Integer atom */
472     return ATOM_FindAtom( CURRENT_DS, (LPCSTR)PTR_SEG_TO_LIN(str) );
473 }
474
475
476 /***********************************************************************
477  *           FindAtom32A   (KERNEL32.117)
478  * Searches the local atom table for the string and returns the atom
479  * associated with that string.
480  *
481  * RETURNS
482  *      Atom: Success
483  *      0: Failure
484  */
485 ATOM WINAPI FindAtomA(
486             LPCSTR str /* [in] Pointer to string to find */
487 ) {
488     return GlobalFindAtomA( str );  /* FIXME */
489 }
490
491
492 /***********************************************************************
493  *           FindAtom32W   (KERNEL32.118)
494  * See FindAtom32A
495  */
496 ATOM WINAPI FindAtomW( LPCWSTR str )
497 {
498     return GlobalFindAtomW( str );  /* FIXME */
499 }
500
501
502 /***********************************************************************
503  *           GetAtomName16   (KERNEL.72)
504  */
505 UINT16 WINAPI GetAtomName16( ATOM atom, LPSTR buffer, INT16 count )
506 {
507     return (UINT16)ATOM_GetAtomName( CURRENT_DS, atom, buffer, count );
508 }
509
510
511 /***********************************************************************
512  *           GetAtomName32A   (KERNEL32.149)
513  * Retrieves a copy of the string associated with the atom.
514  *
515  * RETURNS
516  *      Length of string: Success
517  *      0: Failure
518  */
519 UINT WINAPI GetAtomNameA(
520               ATOM atom,    /* [in]  Atom */
521               LPSTR buffer, /* [out] Pointer to string for atom string */
522               INT count   /* [in]  Size of buffer */
523 ) {
524     return GlobalGetAtomNameA( atom, buffer, count );  /* FIXME */
525 }
526
527
528 /***********************************************************************
529  *           GetAtomName32W   (KERNEL32.150)
530  * See GetAtomName32A
531  */
532 UINT WINAPI GetAtomNameW( ATOM atom, LPWSTR buffer, INT count )
533 {
534     return GlobalGetAtomNameW( atom, buffer, count );  /* FIXME */
535 }
536
537
538 /***********************************************************************
539  *           GlobalAddAtom16   (USER.268)
540  */
541 ATOM WINAPI GlobalAddAtom16( SEGPTR str )
542 {
543     if (!HIWORD(str)) return (ATOM)LOWORD(str);  /* Integer atom */
544     return ATOM_AddAtom( ATOM_GlobalTable, (LPCSTR)PTR_SEG_TO_LIN(str) );
545 }
546
547
548 /***********************************************************************
549  *           GlobalAddAtom32A   (KERNEL32.313)
550  * Adds a character string to the global atom table and returns a unique
551  * value identifying the string.
552  *
553  * RETURNS
554  *      Atom: Success
555  *      0: Failure
556  */
557 ATOM WINAPI GlobalAddAtomA(
558             LPCSTR str /* [in] Pointer to string to add */
559 ) {
560     if (!HIWORD(str)) return (ATOM)LOWORD(str);  /* Integer atom */
561     return ATOM_AddAtom( ATOM_GlobalTable, str );
562 }
563
564
565 /***********************************************************************
566  *           GlobalAddAtom32W   (KERNEL32.314)
567  * See GlobalAddAtom32A
568  */
569 ATOM WINAPI GlobalAddAtomW( LPCWSTR str )
570 {
571     char buffer[MAX_ATOM_LEN+1];
572     if (!HIWORD(str)) return (ATOM)LOWORD(str);  /* Integer atom */
573     lstrcpynWtoA( buffer, str, sizeof(buffer) );
574     return ATOM_AddAtom( ATOM_GlobalTable, buffer );
575 }
576
577
578 /***********************************************************************
579  *           GlobalDeleteAtom   (USER.269) (KERNEL32.317)
580  * Decrements the reference count of a string atom.  If the count is
581  * zero, the string associated with the atom is removed from the table.
582  *
583  * RETURNS
584  *      0: Success
585  *      Atom: Failure
586  */
587 ATOM WINAPI GlobalDeleteAtom(
588             ATOM atom /* [in] Atom to delete */
589 ) {
590     return ATOM_DeleteAtom( ATOM_GlobalTable, atom );
591 }
592
593
594 /***********************************************************************
595  *           GlobalFindAtom16   (USER.270)
596  */
597 ATOM WINAPI GlobalFindAtom16( SEGPTR str )
598 {
599     if (!HIWORD(str)) return (ATOM)LOWORD(str);  /* Integer atom */
600     return ATOM_FindAtom( ATOM_GlobalTable, (LPCSTR)PTR_SEG_TO_LIN(str) );
601 }
602
603
604 /***********************************************************************
605  *           GlobalFindAtom32A   (KERNEL32.318)
606  * Searches the atom table for the string and returns the atom
607  * associated with it.
608  *
609  * RETURNS
610  *      Atom: Success
611  *      0: Failure
612  */
613 ATOM WINAPI GlobalFindAtomA(
614             LPCSTR str /* [in] Pointer to string to search for */
615 ) {
616     if (!HIWORD(str)) return (ATOM)LOWORD(str);  /* Integer atom */
617     return ATOM_FindAtom( ATOM_GlobalTable, str );
618 }
619
620
621 /***********************************************************************
622  *           GlobalFindAtom32W   (KERNEL32.319)
623  * See GlobalFindAtom32A
624  */
625 ATOM WINAPI GlobalFindAtomW( LPCWSTR str )
626 {
627     char buffer[MAX_ATOM_LEN+1];
628     if (!HIWORD(str)) return (ATOM)LOWORD(str);  /* Integer atom */
629     lstrcpynWtoA( buffer, str, sizeof(buffer) );
630     return ATOM_FindAtom( ATOM_GlobalTable, buffer );
631 }
632
633
634 /***********************************************************************
635  *           GlobalGetAtomName16   (USER.271)
636  */
637 UINT16 WINAPI GlobalGetAtomName16( ATOM atom, LPSTR buffer, INT16 count )
638 {
639     return (UINT16)ATOM_GetAtomName( ATOM_GlobalTable, atom, buffer, count );
640 }
641
642
643 /***********************************************************************
644  *           GlobalGetAtomName32A   (KERNEL32.323)
645  * Retrieves a copy of the string associated with an atom.
646  *
647  * RETURNS
648  *      Length of string in characters: Success
649  *      0: Failure
650  */
651 UINT WINAPI GlobalGetAtomNameA(
652               ATOM atom,    /* [in]  Atom identifier */
653               LPSTR buffer, /* [out] Pointer to buffer for atom string */
654               INT count   /* [in]  Size of buffer */
655 ) {
656     return ATOM_GetAtomName( ATOM_GlobalTable, atom, buffer, count );
657 }
658
659
660 /***********************************************************************
661  *           GlobalGetAtomName32W   (KERNEL32.324)
662  * See GlobalGetAtomName32A
663  */
664 UINT WINAPI GlobalGetAtomNameW( ATOM atom, LPWSTR buffer, INT count )
665 {
666     char tmp[MAX_ATOM_LEN+1];
667     ATOM_GetAtomName( ATOM_GlobalTable, atom, tmp, sizeof(tmp) );
668     lstrcpynAtoW( buffer, tmp, count );
669     return lstrlenW( buffer );
670 }