Avoid using deprecated openldap functions.
[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 #include "config.h"
22 #include "wine/port.h"
23
24 #include <stdlib.h>
25 #include <stdarg.h>
26 #include <stdio.h>
27 #include <string.h>
28 #include <ctype.h>
29
30 #include "windef.h"
31 #include "winbase.h"
32 #include "winerror.h"
33 #include "winreg.h"
34 #include "winternl.h"
35
36 #include "wine/exception.h"
37 #include "excpt.h"
38 #include "wine/server.h"
39 #include "wine/unicode.h"
40 #include "kernel_private.h"
41
42 #include "wine/debug.h"
43
44 WINE_DEFAULT_DEBUG_CHANNEL(atom);
45
46 #define MAX_ATOM_LEN 255
47
48 /* filter for page-fault exceptions */
49 static WINE_EXCEPTION_FILTER(page_fault)
50 {
51     if (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION)
52         return EXCEPTION_EXECUTE_HANDLER;
53     return EXCEPTION_CONTINUE_SEARCH;
54 }
55
56 /******************************************************************
57  *              get_local_table
58  *
59  * Returns the local atom table for this process (and create it if doesn't
60  * exist yet)
61  */
62 static RTL_ATOM_TABLE get_local_table(DWORD entries)
63 {
64     static RTL_ATOM_TABLE local_table;
65
66     if (!local_table)
67     {
68         NTSTATUS        status;
69         RTL_ATOM_TABLE  table = NULL;
70
71         if ((status = RtlCreateAtomTable( entries, &table )))
72             SetLastError( RtlNtStatusToDosError( status ) );
73         else if (InterlockedCompareExchangePointer((void*)&local_table, table, NULL) != NULL)
74             RtlDestroyAtomTable( table );
75     }
76
77     return local_table;
78 }
79
80
81 /***********************************************************************
82  *           InitAtomTable   (KERNEL32.@)
83  *
84  * Initialise the global atom table.
85  *
86  * PARAMS
87  *  entries [I] The number of entries to reserve in the table.
88  *
89  * RETURNS
90  *  Success: TRUE.
91  *  Failure: FALSE.
92  */
93 BOOL WINAPI InitAtomTable( DWORD entries )
94 {
95     return get_local_table( entries ) ? TRUE : FALSE;
96 }
97
98 /******************************************************************
99  *              check_integral_atom
100  *
101  * Check if a string (ANSI or UNICODE) is in fact an integral atom
102  * (but doesn't check the "#1234" form)
103  */
104 static inline BOOL check_integral_atom( const void* ptr, ATOM* patom)
105 {
106     if (HIWORD( ptr )) return FALSE;
107     if ((*patom = LOWORD( ptr )) >= MAXINTATOM)
108     {
109         SetLastError( ERROR_INVALID_PARAMETER );
110         *patom = 0;
111     }
112     return TRUE;
113 }
114
115 /***********************************************************************
116  *           GlobalAddAtomA   (KERNEL32.@)
117  *
118  * Add a character string to the global atom table and return a unique
119  * value identifying it.
120  *
121  * RETURNS
122  *      Success: The atom allocated to str.
123  *      Failure: 0.
124  */
125 ATOM WINAPI GlobalAddAtomA( LPCSTR str /* [in] String to add */ )
126 {
127     ATOM atom = 0;
128     __TRY
129     {
130         if (!check_integral_atom( str, &atom ))
131         {
132             WCHAR buffer[MAX_ATOM_LEN];
133             DWORD len = MultiByteToWideChar( CP_ACP, 0, str, strlen(str), buffer, MAX_ATOM_LEN );
134             if (!len) SetLastError( ERROR_INVALID_PARAMETER );
135             else
136             {
137                 NTSTATUS status = NtAddAtom( buffer, len * sizeof(WCHAR), &atom );
138                 if (status)
139                 {
140                     SetLastError( RtlNtStatusToDosError( status ) );
141                     atom = 0;
142                 }
143             }
144         }
145     }
146     __EXCEPT(page_fault)
147     {
148         SetLastError( ERROR_INVALID_PARAMETER );
149         atom = 0;
150     }
151     __ENDTRY
152     return atom;
153 }
154
155
156 /***********************************************************************
157  *           AddAtomA   (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 AddAtomA( LPCSTR str /* [in] String to add */ )
167 {
168     ATOM atom = 0;
169
170     if (!check_integral_atom( str, &atom ))
171     {
172         WCHAR           buffer[MAX_ATOM_LEN + 1];
173         DWORD           len;
174         RTL_ATOM_TABLE  table;
175
176         len = MultiByteToWideChar( CP_ACP, 0, str, -1, buffer, MAX_ATOM_LEN + 1 );
177         if (!len) SetLastError( ERROR_INVALID_PARAMETER );
178         else if ((table = get_local_table( 0 )))
179         {
180             NTSTATUS status = RtlAddAtomToAtomTable( table, buffer, &atom );
181             if (status)
182             {
183                 SetLastError( RtlNtStatusToDosError( status ) );
184                 atom = 0;
185             }
186         }
187     }
188     return atom;
189 }
190
191 /***********************************************************************
192  *           GlobalAddAtomW   (KERNEL32.@)
193  *
194  * Unicode version of GlobalAddAtomA.
195  */
196 ATOM WINAPI GlobalAddAtomW( LPCWSTR str )
197 {
198     ATOM        atom = 0;
199     NTSTATUS    status;
200
201     if (!check_integral_atom( str, &atom ) && 
202         (status = NtAddAtom( str, strlenW( str ) * sizeof(WCHAR), &atom )))
203     {
204         SetLastError( RtlNtStatusToDosError( status ) );
205         atom = 0;
206     }
207     return atom;
208 }
209
210
211 /***********************************************************************
212  *           AddAtomW   (KERNEL32.@)
213  *
214  * Unicode version of AddAtomA.          
215  */
216 ATOM WINAPI AddAtomW( LPCWSTR str )
217 {
218     ATOM                atom = 0;
219     RTL_ATOM_TABLE      table;
220
221     if (!check_integral_atom( str, &atom ) && (table = get_local_table( 0 )))
222     {
223         NTSTATUS status = RtlAddAtomToAtomTable( table, str, &atom );
224         if (status)
225         {
226             SetLastError( RtlNtStatusToDosError( status ) );
227             atom = 0;
228         }
229     }
230     return atom;
231 }
232
233
234 /***********************************************************************
235  *           GlobalDeleteAtom   (KERNEL32.@)
236  *
237  * Decrement the reference count of a string atom.  If the count is
238  * zero, the string associated with the atom is removed from the table.
239  *
240  * RETURNS
241  *      Success: 0.
242  *      Failure: atom.
243  */
244 ATOM WINAPI GlobalDeleteAtom( ATOM atom /* [in] Atom to delete */ )
245 {
246     if (atom >= MAXINTATOM)
247     {
248         NTSTATUS status = NtDeleteAtom( atom );
249         if (status)
250         {
251             SetLastError( RtlNtStatusToDosError( status ) );
252             return atom;
253         }
254     }
255     return 0;
256 }
257
258
259 /***********************************************************************
260  *           DeleteAtom   (KERNEL32.@)
261  *
262  * Decrement the reference count of a string atom.  If the count becomes
263  * zero, the string associated with the atom is removed from the table.
264  *
265  * RETURNS
266  *      Success: 0.
267  *      Failure: atom
268  */
269 ATOM WINAPI DeleteAtom( ATOM atom /* [in] Atom to delete */ )
270 {
271     NTSTATUS            status;
272     RTL_ATOM_TABLE      table;
273
274     if (atom >= MAXINTATOM)
275     {
276         if (!(table = get_local_table( 0 ))) return atom;
277         status = RtlDeleteAtomFromAtomTable( table, atom );
278         if (status)
279         {
280             SetLastError( RtlNtStatusToDosError( status ) );
281             return atom;
282         }
283     }
284     return 0;
285 }
286
287
288 /***********************************************************************
289  *           GlobalFindAtomA   (KERNEL32.@)
290  *
291  * Get the atom associated with a string.
292  *
293  * RETURNS
294  *      Success: The associated atom.
295  *      Failure: 0.
296  */
297 ATOM WINAPI GlobalFindAtomA( LPCSTR str /* [in] Pointer to string to search for */ )
298 {
299     ATOM atom = 0;
300
301     if (!check_integral_atom( str, &atom ))
302     {
303         WCHAR buffer[MAX_ATOM_LEN];
304         DWORD len = MultiByteToWideChar( CP_ACP, 0, str, strlen(str), buffer, MAX_ATOM_LEN );
305
306         if (!len) SetLastError( ERROR_INVALID_PARAMETER );
307         else
308         {
309             NTSTATUS status = NtFindAtom( buffer, len * sizeof(WCHAR), &atom );
310             if (status)
311             {
312                 SetLastError( RtlNtStatusToDosError( status ) );
313                 atom = 0;
314             }
315         }
316     }
317     return atom;
318 }
319
320 /***********************************************************************
321  *           FindAtomA   (KERNEL32.@)
322  *
323  * Get the atom associated with a string.
324  *
325  * RETURNS
326  *      Success: The associated atom.
327  *      Failure: 0.
328  */
329 ATOM WINAPI FindAtomA( LPCSTR str /* [in] Pointer to string to find */ )
330 {
331     ATOM atom = 0;
332
333     if (!check_integral_atom( str, &atom ))
334     {
335         WCHAR           buffer[MAX_ATOM_LEN + 1];
336         DWORD           len;
337         RTL_ATOM_TABLE  table;
338
339         len = MultiByteToWideChar( CP_ACP, 0, str, -1, buffer, MAX_ATOM_LEN + 1 );
340         if (!len) SetLastError( ERROR_INVALID_PARAMETER );
341         else if ((table = get_local_table( 0 )))
342         {
343             NTSTATUS status = RtlLookupAtomInAtomTable( table, buffer, &atom );
344             if (status)
345             {
346                 SetLastError( RtlNtStatusToDosError( status ) );
347                 atom = 0;
348             }
349         }
350     }
351     return atom;
352 }
353
354
355 /***********************************************************************
356  *           GlobalFindAtomW   (KERNEL32.@)
357  *
358  * Unicode version of GlobalFindAtomA.
359  */
360 ATOM WINAPI GlobalFindAtomW( LPCWSTR str )
361 {
362     ATOM atom = 0;
363
364     if (!check_integral_atom( str, &atom ))
365     {
366         NTSTATUS status = NtFindAtom( str, strlenW( str ) * sizeof(WCHAR), &atom );
367         if (status)
368         {
369             SetLastError( RtlNtStatusToDosError( status ) );
370             atom = 0;
371         }
372     }
373     return atom;
374 }
375
376
377 /***********************************************************************
378  *           FindAtomW   (KERNEL32.@)
379  *
380  * Unicode version of FindAtomA.
381  */
382 ATOM WINAPI FindAtomW( LPCWSTR str )
383 {
384     ATOM                atom = 0;
385     NTSTATUS            status;
386     RTL_ATOM_TABLE      table;
387
388     if ((table = get_local_table( 0 )))
389     {
390         status = RtlLookupAtomInAtomTable( table, str, &atom );
391         if (status)
392         {
393             SetLastError( RtlNtStatusToDosError( status ) );
394             atom = 0;
395         }
396     }
397     return atom;
398 }
399
400
401 static UINT ATOM_GetAtomNameA( ATOM atom, LPSTR buffer, INT count, struct atom_table* table )
402 {
403     INT len;
404
405     if (count <= 0)
406     {
407         SetLastError( ERROR_MORE_DATA );
408         return 0;
409     }
410     if (atom < MAXINTATOM)
411     {
412         char name[8];
413         if (!atom)
414         {
415             SetLastError( ERROR_INVALID_PARAMETER );
416             return 0;
417         }
418         len = sprintf( name, "#%d", atom );
419         lstrcpynA( buffer, name, count );
420     }
421     else
422     {
423         WCHAR full_name[MAX_ATOM_LEN];
424
425         len = 0;
426         SERVER_START_REQ( get_atom_information )
427         {
428             req->atom = atom;
429             req->table = table;
430             wine_server_set_reply( req, full_name, sizeof(full_name) );
431             if (!wine_server_call_err( req ))
432             {
433                 len = WideCharToMultiByte( CP_ACP, 0, full_name,
434                                            wine_server_reply_size(reply) / sizeof(WCHAR),
435                                            buffer, count - 1, NULL, NULL );
436                 if (!len) len = count; /* overflow */
437                 else buffer[len] = 0;
438             }
439         }
440         SERVER_END_REQ;
441     }
442
443     if (len && count <= len)
444     {
445         SetLastError( ERROR_MORE_DATA );
446         buffer[count-1] = 0;
447         return 0;
448     }
449     TRACE( "(%s) %x -> %s\n", table ? "local" : "global", atom, debugstr_a(buffer) );
450     return len;
451 }
452
453
454 /***********************************************************************
455  *           GlobalGetAtomNameA   (KERNEL32.@)
456  *
457  * Get a copy of the string associated with an atom.
458  *
459  * RETURNS
460  *      Success: The length of the returned string in characters.
461  *      Failure: 0.
462  */
463 UINT WINAPI GlobalGetAtomNameA(
464               ATOM atom,    /* [in]  Atom identifier */
465               LPSTR buffer, /* [out] Pointer to buffer for atom string */
466               INT count )   /* [in]  Size of buffer */
467 {
468     return ATOM_GetAtomNameA( atom, buffer, count, NULL );
469 }
470
471
472 /***********************************************************************
473  *           GetAtomNameA   (KERNEL32.@)
474  *
475  * Get a copy of the string associated with an atom.
476  *
477  * RETURNS
478  *      Success: The length of the returned string in characters.
479  *      Failure: 0.
480  */
481 UINT WINAPI GetAtomNameA(
482               ATOM atom,    /* [in]  Atom */
483               LPSTR buffer, /* [out] Pointer to string for atom string */
484               INT count)    /* [in]  Size of buffer */
485 {
486     return ATOM_GetAtomNameA( atom, buffer, count, get_local_table(0) );
487 }
488
489
490 static UINT ATOM_GetAtomNameW( ATOM atom, LPWSTR buffer, INT count, struct atom_table* table )
491 {
492     INT len;
493
494     if (count <= 0)
495     {
496         SetLastError( ERROR_MORE_DATA );
497         return 0;
498     }
499     if (atom < MAXINTATOM)
500     {
501         char name[8];
502         if (!atom)
503         {
504             SetLastError( ERROR_INVALID_PARAMETER );
505             return 0;
506         }
507         sprintf( name, "#%d", atom );
508         len = MultiByteToWideChar( CP_ACP, 0, name, -1, buffer, count );
509         if (!len) buffer[count-1] = 0;  /* overflow */
510     }
511     else
512     {
513         WCHAR full_name[MAX_ATOM_LEN];
514
515         len = 0;
516         SERVER_START_REQ( get_atom_information )
517         {
518             req->atom = atom;
519             req->table = table;
520             wine_server_set_reply( req, full_name, sizeof(full_name) );
521             if (!wine_server_call_err( req ))
522             {
523                 len = wine_server_reply_size(reply) / sizeof(WCHAR);
524                 if (count > len) count = len + 1;
525                 memcpy( buffer, full_name, (count-1) * sizeof(WCHAR) );
526                 buffer[count-1] = 0;
527             }
528         }
529         SERVER_END_REQ;
530         if (!len) return 0;
531     }
532     TRACE( "(%s) %x -> %s\n", table ? "local" : "global", atom, debugstr_w(buffer) );
533     return len;
534 }
535
536
537 /***********************************************************************
538  *           GlobalGetAtomNameW   (KERNEL32.@)
539  *
540  * Unicode version of GlobalGetAtomNameA.
541  */
542 UINT WINAPI GlobalGetAtomNameW( ATOM atom, LPWSTR buffer, INT count )
543 {
544     return ATOM_GetAtomNameW( atom, buffer, count, NULL);
545 }
546
547
548 /***********************************************************************
549  *           GetAtomNameW   (KERNEL32.@)
550  *
551  * Unicode version of GetAtomNameA.
552  */
553 UINT WINAPI GetAtomNameW( ATOM atom, LPWSTR buffer, INT count )
554 {
555     return ATOM_GetAtomNameW( atom, buffer, count, get_local_table(0) );
556 }