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