Check for failed allocation
[reactos.git] / reactos / lib / kernel32 / misc / atom.c
1 /* $Id: atom.c,v 1.12 2001/03/31 01:17:29 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 =
285 (ATOMENTRY*) RtlAllocateHeap(GetProcessHeap(),
286 HEAP_GENERATE_EXCEPTIONS|HEAP_ZERO_MEMORY,
287 sizeof(ATOMENTRY));
288 at->TableSize = 1;
289 lp = at->AtomTable;
290 index = 0;
291 }
292 else
293 {
294 at->TableSize++;
295 at->AtomTable =
296 (ATOMENTRY*) RtlReAllocateHeap(GetProcessHeap(),0,
297 (LPVOID) at->AtomTable,
298 at->TableSize * sizeof(ATOMENTRY));
299 lp = &at->AtomTable[at->TableSize - 1];
300 }
301
302 /* set in the entry */
303 lp->refcnt = 1;
304 lp->q = q;
305 lp->idsize = atomlen;
306 lp->idx = 0;
307
308 /* add an entry if not intatom... */
309 if(atomlen) {
310 newlen = at->DataSize + atomlen;
311
312 if(at->AtomData == 0) {
313 at->AtomData =
314 (WCHAR*)RtlAllocateHeap(GetProcessHeap(),
315 HEAP_GENERATE_EXCEPTIONS|HEAP_ZERO_MEMORY,
316 newlen*2);
317 if (at->AtomData == NULL)
318 {
319 return(0);
320 }
321 lp->idx = 0;
322 } else {
323
324 at->AtomData =
325 (WCHAR*)RtlReAllocateHeap(GetProcessHeap(), 0, at->AtomData, newlen*2);
326 if (at->AtomData == NULL)
327 {
328 return(0);
329 }
330 lp->idx = at->DataSize;
331 }
332
333 lstrcpyW(&at->AtomData[lp->idx],lpString);
334 at->DataSize = newlen;
335 }
336
337 return index + ATOMBASE;
338 }
339
340
341
342
343
344
345
346
347
348
349 ATOM
350 AWGLFindAtom(ATOMTABLE *at, const WCHAR *lpString)
351 {
352
353 ATOMID q;
354 LPATOMENTRY lp;
355 int index;
356 int atomlen;
357
358
359 /* convert string to 'q', and get length */
360 q = AtomHashString(lpString,&atomlen);
361
362 /* find the q value, note: this could be INTATOM */
363 /* if q matches, then do case insensitive compare*/
364 for(index = 0;(lp = GetAtomPointer(at,index));index++) {
365 if(lp->q == q) {
366 if(HIWORD(lpString) == 0)
367 return ATOMBASE + index;
368 if(lstrcmpiW(&at->AtomData[lp->idx],lpString) == 0)
369 return ATOMBASE + index;
370 }
371 }
372 return 0;
373 }
374
375
376 UINT
377 AWGLGetAtomName(ATOMTABLE *at, ATOM atom, WCHAR *lpString,int len)
378 {
379
380 ATOMENTRY *lp;
381 WCHAR *atomstr;
382 int atomlen;
383
384
385
386 /* return the atom name, or create the INTATOM */
387 if((lp = GetAtomPointer(at,atom - ATOMBASE))) {
388 if(lp->idsize) {
389 atomlen = lstrlenW(atomstr = &at->AtomData[lp->idx]);
390 if (atomlen < len)
391 lstrcpyW(lpString,atomstr);
392 else {
393 lstrcpynW(lpString,atomstr,len-1);
394 lpString[len-1] = '\0';
395 }
396 return (UINT)lstrlenW(lpString);
397 } else {
398 //wsprintf((wchar *)lpString,"#%d",lp->q);
399 return (UINT)lstrlenW(lpString);
400 }
401 }
402 return 0;
403 }
404
405
406 /********************************************************/
407 /* convert alphanumeric string to a 'q' value. */
408 /* 'q' values do not need to be unique, they just limit */
409 /* the search we need to make to find a string */
410 /********************************************************/
411
412 static ATOMID
413 AtomHashString(const WCHAR * lp,int *lplen)
414 {
415 ATOMID q;
416 WCHAR *p,ch;
417 int len;
418
419 /* if we have an intatom... */
420 if(HIWORD(lp) == 0) {
421 if(lplen) *lplen = 0;
422 return (ATOMID)lp;
423 }
424
425 /* convert the string to an internal representation */
426 for(p=(WCHAR *)lp,q=0,len=0;(p++,ch=*p++);len++)
427 q = (q<<1) + iswlower(ch)?towupper(ch):ch;
428
429 /* 0 is reserved for empty slots */
430 if(q == 0)
431 q++;
432
433 /* avoid strlen later */
434 /* check out with unicode */
435 if(lplen) {
436 *lplen = ++len;
437 }
438 return q;
439 }
440
441 /********************************************************/
442 /* convert an atom index into a pointer into an */
443 /* atom table. This validates the pointer is in */
444 /* range, and that the data is accessible */
445 /********************************************************/
446
447 static ATOMENTRY *
448 GetAtomPointer(ATOMTABLE *at,int index)
449 {
450 ATOMENTRY *lp;
451
452 /* if no table, then no pointers */
453 if(at->AtomTable == 0)
454 return 0;
455
456 /* bad index */
457 if((index < 0) || (index >= at->TableSize))
458 return 0;
459
460 /* we have a pointer */
461 lp = &at->AtomTable[index];
462
463
464 /* is the index past stored data, validity check */
465 /* LATER: is the size of the entry within the available space */
466 if(lp->idx > at->DataSize)
467 return 0;
468
469 return lp;
470 }
471
472 int ansi2unicode( WCHAR *uni,const char *ansi, int s)
473 {
474 register int i;
475
476 for(i=0;i<=s;i++)
477 uni[i] = (WCHAR)ansi[i];
478 return i;
479 }
480
481 int
482 unicode2ansi( char *ansi,const WCHAR *uni, int s)
483 {
484 register int i;
485
486 for(i=0;i<=s;i++)
487 ansi[i] = (char)uni[i];
488 return i;
489 }
490
491
492 #endif
493
494 /* EOF */