Boudewjin's massive work on kernel32 and crtdll and a console driver.
[reactos.git] / reactos / lib / kernel32 / misc / atom.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS system libraries
4 * FILE: lib/kernel32/misc/atom.c
5 * PURPOSE: Atom functions
6 * PROGRAMMER: Ariadne ( ariadne@xs4all.nl)
7 modified from WINE [ Onno Hovers, (onno@stack.urc.tue.nl) ]
8 * UPDATE HISTORY:
9 * Created 01/11/98
10 */
11
12 #include <kernel32\atom.h>
13 #include <kernel32\proc.h>
14 #include <kernel32\thread.h>
15 #include <wstring.h>
16 #include <string.h>
17 //#include <stdlib.h>
18
19
20
21
22
23
24 /* system global and local atom tables */
25
26 static ATOMTABLE GlobalAtomTable;
27
28 /* internal functions */
29 ATOM GLDeleteAtom(ATOMTABLE *at, ATOM nAtom);
30 ATOM AWGLAddAtom( ATOMTABLE *at, const WCHAR *lpString);
31 ATOM AWGLFindAtom(ATOMTABLE *at, const WCHAR *lpString);
32 UINT AWGLGetAtomName(ATOMTABLE *at,ATOM atom, WCHAR *lpString, int nSize);
33
34 static ATOMENTRY *GetAtomPointer(ATOMTABLE *,int);
35 static ATOMID AtomHashString(const WCHAR *,int *);
36
37 #define ATOMBASE 0xcc00
38
39 int unicode2ansi( char *ansi,const WCHAR *uni, int s);
40 int ansi2unicode( WCHAR *uni,const char *ansi, int s);
41
42
43 ATOM
44 STDCALL
45 GlobalDeleteAtom(
46 ATOM nAtom
47 )
48 {
49 return GLDeleteAtom(&GlobalAtomTable, nAtom);
50 }
51
52
53 BOOL
54 STDCALL
55 InitAtomTable(
56 DWORD nSize
57 )
58 {
59 // nSize should be a prime number
60
61 if ( nSize < 4 || nSize >= 512 ) {
62 nSize = 37;
63 }
64
65 if ( (GetCurrentPeb()->LocalAtomTable).lpDrvData == NULL ) {
66 (GetCurrentPeb()->LocalAtomTable).lpDrvData = HeapAlloc(GetProcessHeap(),HEAP_GENERATE_EXCEPTIONS|HEAP_ZERO_MEMORY,nSize*sizeof(ATOMENTRY));
67 }
68
69
70 return TRUE;
71 }
72
73
74 ATOM
75 STDCALL
76 DeleteAtom(
77 ATOM nAtom
78 )
79 {
80 return GLDeleteAtom(&GetCurrentPeb()->LocalAtomTable, nAtom);
81
82 }
83
84
85
86
87 ATOM
88 STDCALL
89 GlobalAddAtomA(
90 LPCSTR lpString
91 )
92 {
93
94 UINT BufLen = strlen(lpString);
95 WCHAR *lpBuffer = (WCHAR *)HeapAlloc(GetProcessHeap(),HEAP_GENERATE_EXCEPTIONS|HEAP_ZERO_MEMORY,BufLen*sizeof(WCHAR));
96 ATOM atom;
97 ansi2unicode(lpBuffer, lpString,BufLen);
98 atom = AWGLAddAtom(&GlobalAtomTable,lpBuffer );
99 HeapFree(GetProcessHeap(),0,lpBuffer);
100 return atom;
101 }
102
103
104
105
106
107 ATOM
108 STDCALL
109 GlobalAddAtomW(
110 LPCWSTR lpString
111 )
112 {
113 return AWGLAddAtom(&GlobalAtomTable, lpString);
114 }
115
116
117 ATOM
118 STDCALL
119 GlobalFindAtomA(
120 LPCSTR lpString
121 )
122 {
123 ATOM a;
124 UINT BufLen = strlen(lpString);
125 WCHAR *lpBuffer = (WCHAR *)HeapAlloc(GetProcessHeap(),HEAP_GENERATE_EXCEPTIONS|HEAP_ZERO_MEMORY,BufLen*sizeof(WCHAR));
126 ansi2unicode(lpBuffer, lpString,BufLen);
127 a = AWGLFindAtom(&GlobalAtomTable, lpBuffer);
128 HeapFree(GetProcessHeap(),0,lpBuffer);
129 return a;
130 }
131
132
133 ATOM
134 STDCALL
135 GlobalFindAtomW(
136 const WCHAR *lpString
137 )
138 {
139 return AWGLFindAtom(&GlobalAtomTable, lpString);
140 }
141
142
143
144 UINT
145 STDCALL
146 GlobalGetAtomNameA(
147 ATOM nAtom,
148 char *lpBuffer,
149 int nSize
150 )
151 {
152
153 WCHAR *lpUnicode = (WCHAR *)HeapAlloc(GetProcessHeap(),HEAP_GENERATE_EXCEPTIONS|HEAP_ZERO_MEMORY,nSize *sizeof(WCHAR));
154 UINT x = AWGLGetAtomName(&GlobalAtomTable,nAtom, lpUnicode,nSize);
155 unicode2ansi(lpBuffer,lpUnicode,nSize);
156 HeapFree(GetProcessHeap(),0,lpUnicode);
157 return x;
158 }
159
160
161 UINT
162 STDCALL
163 GlobalGetAtomNameW(
164 ATOM nAtom,
165 WCHAR * lpBuffer,
166 int nSize
167 )
168 {
169 return AWGLGetAtomName(&GlobalAtomTable, nAtom, lpBuffer, nSize);
170 }
171
172
173 ATOM
174 STDCALL
175 AddAtomA(
176 const char *lpString
177 )
178 {
179 UINT BufLen = strlen(lpString);
180 WCHAR *lpBuffer = (WCHAR*)HeapAlloc(GetProcessHeap(),HEAP_GENERATE_EXCEPTIONS|HEAP_ZERO_MEMORY,BufLen*2);
181 ATOM a;
182 ansi2unicode(lpBuffer, lpString,BufLen);
183 a = AWGLAddAtom(&GetCurrentPeb()->LocalAtomTable, lpBuffer);
184 HeapFree(GetProcessHeap(),0,lpBuffer);
185 return a;
186
187 }
188
189
190 ATOM
191 STDCALL
192 AddAtomW(
193 const WCHAR * lpString
194 )
195 {
196 return AWGLAddAtom(&GetCurrentPeb()->LocalAtomTable, lpString);
197 }
198
199
200
201
202 ATOM
203 STDCALL
204 FindAtomA(
205 const char *lpString
206 )
207 {
208 UINT BufLen = strlen(lpString);
209 WCHAR *lpBuffer = (WCHAR *)HeapAlloc(GetProcessHeap(),HEAP_GENERATE_EXCEPTIONS|HEAP_ZERO_MEMORY,BufLen*2);
210 ATOM a;
211 ansi2unicode(lpBuffer, lpString,BufLen);
212 a = AWGLFindAtom(&GetCurrentPeb()->LocalAtomTable, lpBuffer);
213 HeapFree(GetProcessHeap(),0,lpBuffer);
214 return a;
215 }
216
217
218 ATOM
219 STDCALL
220 FindAtomW(
221 const WCHAR * lpString
222 )
223 {
224 return AWGLFindAtom(&GetCurrentPeb()->LocalAtomTable, lpString);
225 }
226
227
228
229 UINT
230 STDCALL
231 GetAtomNameA(
232 ATOM nAtom,
233 char *lpBuffer,
234 int nSize
235 )
236 {
237 LPWSTR lpUnicode = (WCHAR *)HeapAlloc(GetProcessHeap(),HEAP_GENERATE_EXCEPTIONS|HEAP_ZERO_MEMORY,nSize *2);
238 UINT x = AWGLGetAtomName(&GlobalAtomTable, nAtom,lpUnicode,nSize);
239 unicode2ansi(lpBuffer,lpUnicode,nSize);
240 HeapFree(GetProcessHeap(),0,lpUnicode);
241 return x;
242 }
243
244
245 UINT
246 STDCALL
247 GetAtomNameW(
248 ATOM nAtom,
249 WCHAR * lpBuffer,
250 int nSize
251 )
252 {
253 return AWGLGetAtomName(&GetCurrentPeb()->LocalAtomTable,nAtom,lpBuffer, nSize);
254 }
255
256 ATOM
257 GLDeleteAtom(
258 ATOMTABLE *at, ATOM nAtom
259 )
260 {
261
262 ATOMENTRY *lp;
263
264 /* a free slot has q == 0 && refcnt == 0 */
265 if((lp = GetAtomPointer(at,nAtom - ATOMBASE))) {
266 if(lp->idsize)
267 lp->refcnt--;
268
269 if(lp->refcnt == 0) {
270 HeapFree(GetProcessHeap(),0,at->AtomTable);
271 at->AtomTable = NULL;
272 HeapFree(GetProcessHeap(),0,at->AtomData);
273 at->AtomData = NULL;
274 return lp->q = 0;
275 }
276 }
277 return nAtom;
278
279
280
281 }
282
283
284 ATOM
285 AWGLAddAtom(
286 ATOMTABLE *at, const WCHAR *lpString
287 )
288 {
289 ATOM atom;
290 ATOMID q;
291 LPATOMENTRY lp,lpfree;
292 int index,freeindex;
293 int atomlen;
294 int newlen;
295
296
297
298 /* if we already have it, bump refcnt */
299 if((atom = AWGLFindAtom(at, lpString ))) {
300 lp = GetAtomPointer(at,atom - ATOMBASE);
301 if(lp->idsize) lp->refcnt++;
302 return atom;
303 }
304
305 /* add to a free slot */
306 q = AtomHashString(lpString,&atomlen);
307
308 lpfree = 0;
309 freeindex = 0;
310
311 for(index = 0;(lp = GetAtomPointer(at,index));index++) {
312 if(lp->q == 0 && lp->refcnt == 0) {
313 if(lp->idsize > atomlen) {
314 if ((lpfree == 0) ||
315 (lpfree->idsize > lp->idsize)) {
316 lpfree = lp;
317 freeindex = index;
318 }
319 }
320 }
321 }
322 /* intatoms do not take space in data, but do get new entries */
323 /* an INTATOM will have length of 0 */
324 if(lpfree && atomlen) {
325 lpfree->q = q;
326 lpfree->refcnt = 1;
327 lstrcpynW(&at->AtomData[lpfree->idx],lpString,atomlen);
328 return freeindex + ATOMBASE;
329 }
330
331 /* no space was available, or we have an INTATOM */
332 /* so expand or create the table */
333 if(at->AtomTable == 0) {
334 at->AtomTable = (ATOMENTRY *) HeapAlloc(GetProcessHeap(),HEAP_GENERATE_EXCEPTIONS|HEAP_ZERO_MEMORY,sizeof(ATOMENTRY));
335 at->TableSize = 1;
336 lp = at->AtomTable;
337 index = 0;
338 } else {
339 at->TableSize++;
340 at->AtomTable = (ATOMENTRY *) HeapReAlloc(GetProcessHeap(),0,
341 (LPVOID) at->AtomTable,
342 at->TableSize * sizeof(ATOMENTRY));
343 lp = &at->AtomTable[at->TableSize - 1];
344 }
345
346 /* set in the entry */
347 lp->refcnt = 1;
348 lp->q = q;
349 lp->idsize = atomlen;
350 lp->idx = 0;
351
352 /* add an entry if not intatom... */
353 if(atomlen) {
354 newlen = at->DataSize + atomlen;
355
356 if(at->AtomData == 0) {
357 at->AtomData = (WCHAR *) HeapAlloc(GetProcessHeap(),HEAP_GENERATE_EXCEPTIONS|HEAP_ZERO_MEMORY,newlen*2);
358 lp->idx = 0;
359 } else {
360
361 at->AtomData = (WCHAR *) HeapReAlloc(GetProcessHeap(),0,at->AtomData,newlen*2);
362 lp->idx = at->DataSize;
363 }
364
365 lstrcpyW(&at->AtomData[lp->idx],lpString);
366 at->DataSize = newlen;
367 }
368
369 return index + ATOMBASE;
370 }
371
372
373
374
375
376
377
378
379
380
381 ATOM
382 AWGLFindAtom(
383 ATOMTABLE *at, const WCHAR *lpString
384 )
385 {
386
387 ATOMID q;
388 LPATOMENTRY lp;
389 int index;
390 int atomlen;
391
392
393
394
395 /* convert string to 'q', and get length */
396 q = AtomHashString(lpString,&atomlen);
397
398 /* find the q value, note: this could be INTATOM */
399 /* if q matches, then do case insensitive compare*/
400 for(index = 0;(lp = GetAtomPointer(at,index));index++) {
401 if(lp->q == q) {
402 if(HIWORD(lpString) == 0)
403 return ATOMBASE + index;
404 if(lstrcmpiW(&at->AtomData[lp->idx],lpString) == 0)
405 return ATOMBASE + index;
406 }
407 }
408 return 0;
409 }
410
411
412 UINT
413 AWGLGetAtomName(ATOMTABLE *at, ATOM atom, WCHAR *lpString,int len)
414 {
415
416 ATOMENTRY *lp;
417 WCHAR *atomstr;
418 int atomlen;
419
420
421
422 /* return the atom name, or create the INTATOM */
423 if((lp = GetAtomPointer(at,atom - ATOMBASE))) {
424 if(lp->idsize) {
425 atomlen = lstrlenW(atomstr = &at->AtomData[lp->idx]);
426 if (atomlen < len)
427 lstrcpyW(lpString,atomstr);
428 else {
429 lstrcpynW(lpString,atomstr,len-1);
430 lpString[len-1] = '\0';
431 }
432 return (UINT)lstrlenW(lpString);
433 } else {
434 //wsprintf((wchar *)lpString,"#%d",lp->q);
435 return (UINT)lstrlenW(lpString);
436 }
437 }
438 return 0;
439 }
440
441
442 /********************************************************/
443 /* convert alphanumeric string to a 'q' value. */
444 /* 'q' values do not need to be unique, they just limit */
445 /* the search we need to make to find a string */
446 /********************************************************/
447
448 static ATOMID
449 AtomHashString(const WCHAR * lp,int *lplen)
450 {
451 ATOMID q;
452 WCHAR *p,ch;
453 int len;
454
455 /* if we have an intatom... */
456 if(HIWORD(lp) == 0) {
457 if(lplen) *lplen = 0;
458 return (ATOMID)lp;
459 }
460
461 /* convert the string to an internal representation */
462 for(p=(WCHAR *)lp,q=0,len=0;(p++,ch=*p++);len++)
463 q = (q<<1) + iswlower(ch)?towupper(ch):ch;
464
465 /* 0 is reserved for empty slots */
466 if(q == 0)
467 q++;
468
469 /* avoid strlen later */
470 /* check out with unicode */
471 if(lplen) {
472 *lplen = ++len;
473 }
474 return q;
475 }
476
477 /********************************************************/
478 /* convert an atom index into a pointer into an */
479 /* atom table. This validates the pointer is in */
480 /* range, and that the data is accessible */
481 /********************************************************/
482
483 static ATOMENTRY *
484 GetAtomPointer(ATOMTABLE *at,int index)
485 {
486 ATOMENTRY *lp;
487
488 /* if no table, then no pointers */
489 if(at->AtomTable == 0)
490 return 0;
491
492 /* bad index */
493 if((index < 0) || (index >= at->TableSize))
494 return 0;
495
496 /* we have a pointer */
497 lp = &at->AtomTable[index];
498
499
500 /* is the index past stored data, validity check */
501 /* LATER: is the size of the entry within the available space */
502 if(lp->idx > at->DataSize)
503 return 0;
504
505 return lp;
506 }
507
508 int ansi2unicode( WCHAR *uni,const char *ansi, int s)
509 {
510 register int i;
511
512 for(i=0;i<=s;i++)
513 uni[i] = (WCHAR)ansi[i];
514 return i;
515 }
516
517 int unicode2ansi( char *ansi,const WCHAR *uni, int s)
518 {
519 register int i;
520
521 for(i=0;i<=s;i++)
522 ansi[i] = (char)uni[i];
523 return i;
524 }
525
526
527
528
529