Add implementation for RtlQueryRegistryValues, RtlCheckRegistryKey and
[wine] / dlls / kernel / atom.c
1 /*
2  * Atom table functions
3  *
4  * Copyright 1993, 1994, 1995 Alexandre Julliard
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  */
20
21 /*
22  * Warning: The code assumes that LocalAlloc() returns a block aligned
23  * on a 4-bytes boundary (because of the shifting done in
24  * HANDLETOATOM).  If this is not the case, the allocation code will
25  * have to be changed.
26  */
27
28 #include "config.h"
29 #include "wine/port.h"
30
31 #include <stdlib.h>
32 #include <stdarg.h>
33 #include <stdio.h>
34 #include <string.h>
35 #include <ctype.h>
36
37 #include "windef.h"
38 #include "winbase.h"
39 #include "winerror.h"
40
41 #include "wine/server.h"
42 #include "wine/unicode.h"
43 #include "kernel_private.h"
44
45 #include "wine/debug.h"
46
47 WINE_DEFAULT_DEBUG_CHANNEL(atom);
48
49 #define MAX_ATOM_LEN 255
50
51 /***********************************************************************
52  *           ATOM_IsIntAtomA
53  */
54 static BOOL ATOM_IsIntAtomA(LPCSTR atomstr,WORD *atomid)
55 {
56     UINT atom = 0;
57     if (!HIWORD(atomstr)) atom = LOWORD(atomstr);
58     else
59     {
60         if (*atomstr++ != '#') return FALSE;
61         while (*atomstr >= '0' && *atomstr <= '9')
62         {
63             atom = atom * 10 + *atomstr - '0';
64             atomstr++;
65         }
66         if (*atomstr) return FALSE;
67     }
68     if (atom >= MAXINTATOM)
69     {
70         SetLastError( ERROR_INVALID_PARAMETER );
71         atom = 0;
72     }
73     *atomid = atom;
74     return TRUE;
75 }
76
77
78 /***********************************************************************
79  *           ATOM_IsIntAtomW
80  */
81 static BOOL ATOM_IsIntAtomW(LPCWSTR atomstr,WORD *atomid)
82 {
83     UINT atom = 0;
84     if (!HIWORD(atomstr)) atom = LOWORD(atomstr);
85     else
86     {
87         if (*atomstr++ != '#') return FALSE;
88         while (*atomstr >= '0' && *atomstr <= '9')
89         {
90             atom = atom * 10 + *atomstr - '0';
91             atomstr++;
92         }
93         if (*atomstr) return FALSE;
94     }
95     if (atom >= MAXINTATOM)
96     {
97         SetLastError( ERROR_INVALID_PARAMETER );
98         atom = 0;
99     }
100     *atomid = atom;
101     return TRUE;
102 }
103
104
105 /***********************************************************************
106  *           InitAtomTable   (KERNEL32.@)
107  *
108  * Initialise the global atom table.
109  *
110  * PARAMS
111  *  entries [I] The number of entries to reserve in the table.
112  *
113  * RETURNS
114  *  Success: TRUE.
115  *  Failure: FALSE.
116  */
117 BOOL WINAPI InitAtomTable( DWORD entries )
118 {
119     BOOL ret;
120     SERVER_START_REQ( init_atom_table )
121     {
122         req->entries = entries;
123         ret = !wine_server_call_err( req );
124     }
125     SERVER_END_REQ;
126     return ret;
127 }
128
129
130 static ATOM ATOM_AddAtomA( LPCSTR str, BOOL local )
131 {
132     ATOM atom = 0;
133     if (!ATOM_IsIntAtomA( str, &atom ))
134     {
135         WCHAR buffer[MAX_ATOM_LEN];
136
137         DWORD len = MultiByteToWideChar( CP_ACP, 0, str, strlen(str), buffer, MAX_ATOM_LEN );
138         if (!len)
139         {
140             SetLastError( ERROR_INVALID_PARAMETER );
141             return 0;
142         }
143         SERVER_START_REQ( add_atom )
144         {
145             wine_server_add_data( req, buffer, len * sizeof(WCHAR) );
146             req->local = local;
147             if (!wine_server_call_err(req)) atom = reply->atom;
148         }
149         SERVER_END_REQ;
150     }
151     TRACE( "(%s) %s -> %x\n", local ? "local" : "global", debugstr_a(str), atom );
152     return atom;
153 }
154
155
156 /***********************************************************************
157  *           GlobalAddAtomA   (KERNEL32.@)
158  *
159  * Add a character string to the global atom table and return a unique
160  * value identifying it.
161  *
162  * RETURNS
163  *      Success: The atom allocated to str.
164  *      Failure: 0.
165  */
166 ATOM WINAPI GlobalAddAtomA( LPCSTR str /* [in] String to add */ )
167 {
168     return ATOM_AddAtomA( str, FALSE );
169 }
170
171
172 /***********************************************************************
173  *           AddAtomA   (KERNEL32.@)
174  *
175  * Add a character string to the global atom table and return a unique
176  * value identifying it.
177  *
178  * RETURNS
179  *      Success: The atom allocated to str.
180  *      Failure: 0.
181  */
182 ATOM WINAPI AddAtomA( LPCSTR str /* [in] String to add */ )
183 {
184     return ATOM_AddAtomA( str, TRUE );
185 }
186
187
188 static ATOM ATOM_AddAtomW( LPCWSTR str, BOOL local )
189 {
190     ATOM atom = 0;
191     if (!ATOM_IsIntAtomW( str, &atom ))
192     {
193         DWORD len = strlenW(str);
194         if (len > MAX_ATOM_LEN)
195         {
196             SetLastError( ERROR_INVALID_PARAMETER );
197             return 0;
198         }
199         SERVER_START_REQ( add_atom )
200         {
201             req->local = local;
202             wine_server_add_data( req, str, len * sizeof(WCHAR) );
203             if (!wine_server_call_err(req)) atom = reply->atom;
204         }
205         SERVER_END_REQ;
206     }
207     TRACE( "(%s) %s -> %x\n", local ? "local" : "global", debugstr_w(str), atom );
208     return atom;
209 }
210
211
212 /***********************************************************************
213  *           GlobalAddAtomW   (KERNEL32.@)
214  *
215  * Unicode version of GlobalAddAtomA.
216  */
217 ATOM WINAPI GlobalAddAtomW( LPCWSTR str )
218 {
219     return ATOM_AddAtomW( str, FALSE );
220 }
221
222
223 /***********************************************************************
224  *           AddAtomW   (KERNEL32.@)
225  *
226  * Unicode version of AddAtomA.          
227  */
228 ATOM WINAPI AddAtomW( LPCWSTR str )
229 {
230     return ATOM_AddAtomW( str, TRUE );
231 }
232
233
234 static ATOM ATOM_DeleteAtom( ATOM atom,  BOOL local)
235 {
236     TRACE( "(%s) %x\n", local ? "local" : "global", atom );
237     if (atom >= MAXINTATOM)
238     {
239         SERVER_START_REQ( delete_atom )
240         {
241             req->atom = atom;
242             req->local = local;
243             wine_server_call_err( req );
244         }
245         SERVER_END_REQ;
246     }
247     return 0;
248 }
249
250
251 /***********************************************************************
252  *           GlobalDeleteAtom   (KERNEL32.@)
253  *
254  * Decrement the reference count of a string atom.  If the count is
255  * zero, the string associated with the atom is removed from the table.
256  *
257  * RETURNS
258  *      Success: 0.
259  *      Failure: atom.
260  */
261 ATOM WINAPI GlobalDeleteAtom( ATOM atom /* [in] Atom to delete */ )
262 {
263     return ATOM_DeleteAtom( atom, FALSE);
264 }
265
266
267 /***********************************************************************
268  *           DeleteAtom   (KERNEL32.@)
269  *
270  * Decrement the reference count of a string atom.  If the count becomes
271  * zero, the string associated with the atom is removed from the table.
272  *
273  * RETURNS
274  *      Success: 0.
275  *      Failure: atom
276  */
277 ATOM WINAPI DeleteAtom( ATOM atom /* [in] Atom to delete */ )
278 {
279     return ATOM_DeleteAtom( atom, TRUE );
280 }
281
282
283 static ATOM ATOM_FindAtomA( LPCSTR str, BOOL local )
284 {
285     ATOM atom = 0;
286     if (!ATOM_IsIntAtomA( str, &atom ))
287     {
288         WCHAR buffer[MAX_ATOM_LEN];
289
290         DWORD len = MultiByteToWideChar( CP_ACP, 0, str, strlen(str), buffer, MAX_ATOM_LEN );
291         if (!len)
292         {
293             SetLastError( ERROR_INVALID_PARAMETER );
294             return 0;
295         }
296         SERVER_START_REQ( find_atom )
297         {
298             req->local = local;
299             wine_server_add_data( req, buffer, len * sizeof(WCHAR) );
300             if (!wine_server_call_err(req)) atom = reply->atom;
301         }
302         SERVER_END_REQ;
303     }
304     TRACE( "(%s) %s -> %x\n", local ? "local" : "global", debugstr_a(str), atom );
305     return atom;
306 }
307
308
309 /***********************************************************************
310  *           GlobalFindAtomA   (KERNEL32.@)
311  *
312  * Get the atom associated with a string.
313  *
314  * RETURNS
315  *      Success: The associated atom.
316  *      Failure: 0.
317  */
318 ATOM WINAPI GlobalFindAtomA( LPCSTR str /* [in] Pointer to string to search for */ )
319 {
320     return ATOM_FindAtomA( str, FALSE );
321 }
322
323 /***********************************************************************
324  *           FindAtomA   (KERNEL32.@)
325  *
326  * Get the atom associated with a string.
327  *
328  * RETURNS
329  *      Success: The associated atom.
330  *      Failure: 0.
331  */
332 ATOM WINAPI FindAtomA( LPCSTR str /* [in] Pointer to string to find */ )
333 {
334     return ATOM_FindAtomA( str, TRUE );
335 }
336
337
338 static ATOM ATOM_FindAtomW( LPCWSTR str, BOOL local )
339 {
340     ATOM atom = 0;
341     if (!ATOM_IsIntAtomW( str, &atom ))
342     {
343         DWORD len = strlenW(str);
344         if (len > MAX_ATOM_LEN)
345         {
346             SetLastError( ERROR_INVALID_PARAMETER );
347             return 0;
348         }
349         SERVER_START_REQ( find_atom )
350         {
351             wine_server_add_data( req, str, len * sizeof(WCHAR) );
352             req->local = local;
353             if (!wine_server_call_err( req )) atom = reply->atom;
354         }
355         SERVER_END_REQ;
356     }
357     TRACE( "(%s) %s -> %x\n", local ? "local" : "global", debugstr_w(str), atom );
358     return atom;
359 }
360
361
362 /***********************************************************************
363  *           GlobalFindAtomW   (KERNEL32.@)
364  *
365  * Unicode version of GlobalFindAtomA.
366  */
367 ATOM WINAPI GlobalFindAtomW( LPCWSTR str )
368 {
369     return ATOM_FindAtomW( str, FALSE );
370 }
371
372
373 /***********************************************************************
374  *           FindAtomW   (KERNEL32.@)
375  *
376  * Unicode version of FindAtomA.
377  */
378 ATOM WINAPI FindAtomW( LPCWSTR str )
379 {
380     return ATOM_FindAtomW( str, TRUE );
381 }
382
383
384 static UINT ATOM_GetAtomNameA( ATOM atom, LPSTR buffer, INT count, BOOL local )
385 {
386     INT len;
387
388     if (count <= 0)
389     {
390         SetLastError( ERROR_MORE_DATA );
391         return 0;
392     }
393     if (atom < MAXINTATOM)
394     {
395         char name[8];
396         if (!atom)
397         {
398             SetLastError( ERROR_INVALID_PARAMETER );
399             return 0;
400         }
401         len = sprintf( name, "#%d", atom );
402         lstrcpynA( buffer, name, count );
403     }
404     else
405     {
406         WCHAR full_name[MAX_ATOM_LEN];
407
408         len = 0;
409         SERVER_START_REQ( get_atom_name )
410         {
411             req->atom = atom;
412             req->local = local;
413             wine_server_set_reply( req, full_name, sizeof(full_name) );
414             if (!wine_server_call_err( req ))
415             {
416                 len = WideCharToMultiByte( CP_ACP, 0, full_name,
417                                            wine_server_reply_size(reply) / sizeof(WCHAR),
418                                            buffer, count - 1, NULL, NULL );
419                 if (!len) len = count; /* overflow */
420                 else buffer[len] = 0;
421             }
422         }
423         SERVER_END_REQ;
424     }
425
426     if (len && count <= len)
427     {
428         SetLastError( ERROR_MORE_DATA );
429         buffer[count-1] = 0;
430         return 0;
431     }
432     TRACE( "(%s) %x -> %s\n", local ? "local" : "global", atom, debugstr_a(buffer) );
433     return len;
434 }
435
436
437 /***********************************************************************
438  *           GlobalGetAtomNameA   (KERNEL32.@)
439  *
440  * Get a copy of the string associated with an atom.
441  *
442  * RETURNS
443  *      Success: The length of the returned string in characters.
444  *      Failure: 0.
445  */
446 UINT WINAPI GlobalGetAtomNameA(
447               ATOM atom,    /* [in]  Atom identifier */
448               LPSTR buffer, /* [out] Pointer to buffer for atom string */
449               INT count )   /* [in]  Size of buffer */
450 {
451     return ATOM_GetAtomNameA( atom, buffer, count, FALSE );
452 }
453
454
455 /***********************************************************************
456  *           GetAtomNameA   (KERNEL32.@)
457  *
458  * Get a copy of the string associated with an atom.
459  *
460  * RETURNS
461  *      Success: The length of the returned string in characters.
462  *      Failure: 0.
463  */
464 UINT WINAPI GetAtomNameA(
465               ATOM atom,    /* [in]  Atom */
466               LPSTR buffer, /* [out] Pointer to string for atom string */
467               INT count)    /* [in]  Size of buffer */
468 {
469     return ATOM_GetAtomNameA( atom, buffer, count, TRUE );
470 }
471
472
473 static UINT ATOM_GetAtomNameW( ATOM atom, LPWSTR buffer, INT count, BOOL local )
474 {
475     INT len;
476
477     if (count <= 0)
478     {
479         SetLastError( ERROR_MORE_DATA );
480         return 0;
481     }
482     if (atom < MAXINTATOM)
483     {
484         char name[8];
485         if (!atom)
486         {
487             SetLastError( ERROR_INVALID_PARAMETER );
488             return 0;
489         }
490         sprintf( name, "#%d", atom );
491         len = MultiByteToWideChar( CP_ACP, 0, name, -1, buffer, count );
492         if (!len) buffer[count-1] = 0;  /* overflow */
493     }
494     else
495     {
496         WCHAR full_name[MAX_ATOM_LEN];
497
498         len = 0;
499         SERVER_START_REQ( get_atom_name )
500         {
501             req->atom = atom;
502             req->local = local;
503             wine_server_set_reply( req, full_name, sizeof(full_name) );
504             if (!wine_server_call_err( req ))
505             {
506                 len = wine_server_reply_size(reply) / sizeof(WCHAR);
507                 if (count > len) count = len + 1;
508                 memcpy( buffer, full_name, (count-1) * sizeof(WCHAR) );
509                 buffer[count-1] = 0;
510             }
511         }
512         SERVER_END_REQ;
513         if (!len) return 0;
514     }
515     TRACE( "(%s) %x -> %s\n", local ? "local" : "global", atom, debugstr_w(buffer) );
516     return len;
517 }
518
519
520 /***********************************************************************
521  *           GlobalGetAtomNameW   (KERNEL32.@)
522  *
523  * Unicode version of GlobalGetAtomNameA.
524  */
525 UINT WINAPI GlobalGetAtomNameW( ATOM atom, LPWSTR buffer, INT count )
526 {
527     return ATOM_GetAtomNameW( atom, buffer, count, FALSE);
528 }
529
530
531 /***********************************************************************
532  *           GetAtomNameW   (KERNEL32.@)
533  *
534  * Unicode version of GetAtomNameA.
535  */
536 UINT WINAPI GetAtomNameW( ATOM atom, LPWSTR buffer, INT count )
537 {
538     return ATOM_GetAtomNameW( atom, buffer, count, TRUE );
539 }