progman: Added Hebrew translation.
[wine] / dlls / ntdll / atom.c
1 /*
2  * Atom table functions
3  *
4  * Copyright 1993, 1994, 1995 Alexandre Julliard
5  * Copyright 2004,2005 Eric Pouech
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20  */
21
22 #include "config.h"
23 #include "wine/port.h"
24
25 #include <stdlib.h>
26 #include <stdarg.h>
27 #include <stdio.h>
28 #include <string.h>
29 #include <ctype.h>
30
31 #include "ntstatus.h"
32 #define WIN32_NO_STATUS
33 #include "windef.h"
34
35 #include "wine/server.h"
36 #include "wine/unicode.h"
37
38 #include "wine/debug.h"
39
40 WINE_DEFAULT_DEBUG_CHANNEL(atom);
41
42 #define MAX_ATOM_LEN    255
43 #define IS_INTATOM(x)   (((ULONG_PTR)(x) >> 16) == 0)
44
45 /******************************************************************
46  *              is_integral_atom
47  * Returns STATUS_SUCCESS if integral atom and 'pAtom' is filled
48  *         STATUS_INVALID_PARAMETER if 'atomstr' is too long
49  *         STATUS_MORE_ENTRIES otherwise
50  */
51 static NTSTATUS is_integral_atom( LPCWSTR atomstr, size_t len, RTL_ATOM* pAtom )
52 {
53     RTL_ATOM atom;
54
55     if (!IS_INTATOM( atomstr ))
56     {
57         const WCHAR* ptr = atomstr;
58         if (!len) return STATUS_OBJECT_NAME_INVALID;
59
60         if (*ptr++ == '#')
61         {
62             atom = 0;
63             while (ptr < atomstr + len && *ptr >= '0' && *ptr <= '9')
64             {
65                 atom = atom * 10 + *ptr++ - '0';
66             }
67             if (ptr > atomstr + 1 && ptr == atomstr + len) goto done;
68         }
69         if (len > MAX_ATOM_LEN) return STATUS_INVALID_PARAMETER;
70         return STATUS_MORE_ENTRIES;
71     }
72     else atom = LOWORD( atomstr );
73 done:
74     if (!atom || atom >= MAXINTATOM) return STATUS_INVALID_PARAMETER;
75     *pAtom = atom;
76     return STATUS_SUCCESS;
77 }
78
79 /******************************************************************
80  *              RtlDeleteAtomFromAtomTable (NTDLL.@)
81  */
82 NTSTATUS WINAPI RtlDeleteAtomFromAtomTable( RTL_ATOM_TABLE table, RTL_ATOM atom )
83 {
84     NTSTATUS    status;
85
86     TRACE( "%p %x\n", table, atom );
87     if (!table) status = STATUS_INVALID_PARAMETER;
88     else
89     {
90         SERVER_START_REQ( delete_atom )
91         {
92             req->atom = atom;
93             req->table = wine_server_obj_handle( table );
94             status = wine_server_call( req );
95         }
96         SERVER_END_REQ;
97     }
98     return status;
99 }
100
101 /******************************************************************
102  *              integral_atom_name (internal)
103  *
104  * Helper for fetching integral (local/global) atoms names.
105  */
106 static ULONG integral_atom_name(WCHAR* buffer, ULONG len, RTL_ATOM atom)
107 {
108     static const WCHAR fmt[] = {'#','%','u',0};
109     WCHAR tmp[16];
110     int ret;
111
112     ret = sprintfW( tmp, fmt, atom );
113     if (!len) return ret * sizeof(WCHAR);
114     if (len <= ret) ret = len - 1;
115     memcpy( buffer, tmp, ret * sizeof(WCHAR) );
116     buffer[ret] = 0;
117     return ret * sizeof(WCHAR);
118 }
119
120 /******************************************************************
121  *              RtlQueryAtomInAtomTable (NTDLL.@)
122  */
123 NTSTATUS WINAPI RtlQueryAtomInAtomTable( RTL_ATOM_TABLE table, RTL_ATOM atom, ULONG* ref,
124                                          ULONG* pin, WCHAR* name, ULONG* len )
125 {
126     NTSTATUS    status = STATUS_SUCCESS;
127     DWORD       wlen = 0;
128
129     if (!table) status = STATUS_INVALID_PARAMETER;
130     else if (atom < MAXINTATOM)
131     {
132         if (!atom) return STATUS_INVALID_PARAMETER;
133         if (len) wlen = integral_atom_name( name, *len, atom);
134         if (ref) *ref = 1;
135         if (pin) *pin = 1;
136     }
137     else
138     {
139         SERVER_START_REQ( get_atom_information )
140         {
141             req->atom = atom;
142             req->table = wine_server_obj_handle( table );
143             if (len && *len && name)
144                 wine_server_set_reply( req, name, *len );
145             status = wine_server_call( req );
146             if (status == STATUS_SUCCESS)
147             {
148                 wlen = reply->total;
149                 if (ref) *ref = reply->count;
150                 if (pin) *pin = reply->pinned;
151             }
152         }
153         SERVER_END_REQ;
154     }
155     if (status == STATUS_SUCCESS && len)
156     {
157         if (*len)
158         {
159             wlen = min( *len - sizeof(WCHAR), wlen );
160             if (name) name[wlen / sizeof(WCHAR)] = 0;
161         }
162         else status = STATUS_BUFFER_TOO_SMALL;
163         *len = wlen;
164     }
165
166     TRACE( "%p %x -> %s (%x)\n",
167            table, atom, len ? debugstr_wn(name, wlen / sizeof(WCHAR)) : NULL, status );
168     return status;
169 }
170
171 /******************************************************************
172  *              RtlCreateAtomTable (NTDLL.@)
173  */
174 NTSTATUS WINAPI RtlCreateAtomTable( ULONG size, RTL_ATOM_TABLE* table )
175 {
176     NTSTATUS    status;
177
178     if (*table)
179     {
180         if (size) status = STATUS_INVALID_PARAMETER;
181         else status = STATUS_SUCCESS;
182     }
183     else
184     {
185         SERVER_START_REQ( init_atom_table )
186         {
187             req->entries = size;
188             status = wine_server_call( req );
189             *table = wine_server_ptr_handle( reply->table );
190         }
191         SERVER_END_REQ;
192     }
193     return status;
194 }
195
196 /******************************************************************
197  *              RtlDestroyAtomTable (NTDLL.@)
198  */
199 NTSTATUS WINAPI RtlDestroyAtomTable( RTL_ATOM_TABLE table )
200 {
201     if (!table) return STATUS_INVALID_PARAMETER;
202     return NtClose( table );
203 }
204
205 /******************************************************************
206  *              RtlAddAtomToAtomTable (NTDLL.@)
207  */
208 NTSTATUS WINAPI RtlAddAtomToAtomTable( RTL_ATOM_TABLE table, const WCHAR* name, RTL_ATOM* atom )
209 {
210     NTSTATUS    status;
211
212     if (!table) status = STATUS_INVALID_PARAMETER;
213     else
214     {
215         size_t len = HIWORD(name) ? strlenW(name) : 0;
216         status = is_integral_atom( name, len, atom );
217         if (status == STATUS_MORE_ENTRIES)
218         {
219             SERVER_START_REQ( add_atom )
220             {
221                 wine_server_add_data( req, name, len * sizeof(WCHAR) );
222                 req->table = wine_server_obj_handle( table );
223                 status = wine_server_call( req );
224                 *atom = reply->atom;
225             }
226             SERVER_END_REQ;
227         }
228     }
229     TRACE( "%p %s -> %x\n",
230            table, debugstr_w(name), status == STATUS_SUCCESS ? *atom : 0 );
231
232     return status;
233 }
234
235 /******************************************************************
236  *              RtlLookupAtomInAtomTable (NTDLL.@)
237  */
238 NTSTATUS WINAPI RtlLookupAtomInAtomTable( RTL_ATOM_TABLE table, const WCHAR* name, RTL_ATOM* atom )
239 {
240     NTSTATUS    status;
241
242     if (!table) status = STATUS_INVALID_PARAMETER;
243     else
244     {
245         size_t len = HIWORD(name) ? strlenW(name) : 0;
246         status = is_integral_atom( name, len, atom );
247         if (status == STATUS_MORE_ENTRIES)
248         {
249             SERVER_START_REQ( find_atom )
250             {
251                 wine_server_add_data( req, name, len * sizeof(WCHAR) );
252                 req->table = wine_server_obj_handle( table );
253                 status = wine_server_call( req );
254                 *atom = reply->atom;
255             }
256             SERVER_END_REQ;
257         }
258     }
259     TRACE( "%p %s -> %x\n",
260            table, debugstr_w(name), status == STATUS_SUCCESS ? *atom : 0 );
261     return status;
262 }
263
264 /******************************************************************
265  *              RtlEmptyAtomTable (NTDLL.@)
266  */
267 NTSTATUS WINAPI RtlEmptyAtomTable( RTL_ATOM_TABLE table, BOOLEAN delete_pinned )
268 {
269     NTSTATUS    status;
270
271     if (!table) status = STATUS_INVALID_PARAMETER;
272     else
273     {
274         SERVER_START_REQ( empty_atom_table )
275         {
276             req->table = wine_server_obj_handle( table );
277             req->if_pinned = delete_pinned;
278             status = wine_server_call( req );
279         }
280         SERVER_END_REQ;
281     }
282     return status;
283 }
284
285 /******************************************************************
286  *              RtlPinAtomInAtomTable (NTDLL.@)
287  */
288 NTSTATUS WINAPI RtlPinAtomInAtomTable( RTL_ATOM_TABLE table, RTL_ATOM atom )
289 {
290     NTSTATUS status;
291
292     if (!table) return STATUS_INVALID_PARAMETER;
293     if (atom < MAXINTATOM) return STATUS_SUCCESS;
294
295     SERVER_START_REQ( set_atom_information )
296     {
297         req->table = wine_server_obj_handle( table );
298         req->atom = atom;
299         req->pinned = TRUE;
300         status = wine_server_call( req );
301     }
302     SERVER_END_REQ;
303
304     return status;
305 }
306
307 /*************************************************
308  *        Global handle table management
309  *************************************************/
310
311 /******************************************************************
312  *              NtAddAtom (NTDLL.@)
313  */
314 NTSTATUS WINAPI NtAddAtom( const WCHAR* name, ULONG length, RTL_ATOM* atom )
315 {
316     NTSTATUS    status;
317
318     status = is_integral_atom( name, length / sizeof(WCHAR), atom );
319     if (status == STATUS_MORE_ENTRIES)
320     {
321         SERVER_START_REQ( add_atom )
322         {
323             wine_server_add_data( req, name, length );
324             req->table = 0;
325             status = wine_server_call( req );
326             *atom = reply->atom;
327         }
328         SERVER_END_REQ;
329     }
330     TRACE( "%s -> %x\n",
331            debugstr_wn(name, length/sizeof(WCHAR)), status == STATUS_SUCCESS ? *atom : 0 );
332     return status;
333 }
334
335 /******************************************************************
336  *              NtDeleteAtom (NTDLL.@)
337  */
338 NTSTATUS WINAPI NtDeleteAtom(RTL_ATOM atom)
339 {
340     NTSTATUS    status;
341
342     SERVER_START_REQ( delete_atom )
343     {
344         req->atom = atom;
345         req->table = 0;
346         status = wine_server_call( req );
347     }
348     SERVER_END_REQ;
349     return status;
350 }
351
352 /******************************************************************
353  *              NtFindAtom (NTDLL.@)
354  */
355 NTSTATUS WINAPI NtFindAtom( const WCHAR* name, ULONG length, RTL_ATOM* atom )
356 {
357     NTSTATUS    status;
358
359     status = is_integral_atom( name, length / sizeof(WCHAR), atom );
360     if (status == STATUS_MORE_ENTRIES)
361     {
362         SERVER_START_REQ( find_atom )
363         {
364             wine_server_add_data( req, name, length );
365             req->table = 0;
366             status = wine_server_call( req );
367             *atom = reply->atom;
368         }
369         SERVER_END_REQ;
370     }
371     TRACE( "%s -> %x\n",
372            debugstr_wn(name, length/sizeof(WCHAR)), status == STATUS_SUCCESS ? *atom : 0 );
373     return status;
374 }
375
376 /******************************************************************
377  *              NtQueryInformationAtom (NTDLL.@)
378  */
379 NTSTATUS WINAPI NtQueryInformationAtom( RTL_ATOM atom, ATOM_INFORMATION_CLASS class,
380                                         PVOID ptr, ULONG size, PULONG psize )
381 {
382     NTSTATUS status;
383
384     switch (class)
385     {
386     case AtomBasicInformation:
387         {
388             ULONG name_len;
389             ATOM_BASIC_INFORMATION* abi = ptr;
390
391             if (size < sizeof(ATOM_BASIC_INFORMATION))
392                 return STATUS_INVALID_PARAMETER;
393             name_len = size - sizeof(ATOM_BASIC_INFORMATION);
394
395             if (atom < MAXINTATOM)
396             {
397                 if (atom)
398                 {
399                     abi->NameLength = integral_atom_name( abi->Name, name_len, atom );
400                     status = (name_len) ? STATUS_SUCCESS : STATUS_BUFFER_TOO_SMALL;
401                     abi->ReferenceCount = 1;
402                     abi->Pinned = 1;
403                 }
404                 else status = STATUS_INVALID_PARAMETER;
405             }
406             else
407             {
408                 SERVER_START_REQ( get_atom_information )
409                 {
410                     req->atom = atom;
411                     req->table = 0;
412                     if (name_len) wine_server_set_reply( req, abi->Name, name_len );
413                     status = wine_server_call( req );
414                     if (status == STATUS_SUCCESS)
415                     {
416                         name_len = wine_server_reply_size( reply );
417                         if (name_len)
418                         {
419                             abi->NameLength = name_len;
420                             abi->Name[name_len / sizeof(WCHAR)] = '\0';
421                         }
422                         else
423                         {
424                             name_len = reply->total;
425                             abi->NameLength = name_len;
426                             status = STATUS_BUFFER_TOO_SMALL;
427                         }
428                         abi->ReferenceCount = reply->count;
429                         abi->Pinned = reply->pinned;
430                     }
431                     else name_len = 0;
432                 }
433                 SERVER_END_REQ;
434             }
435             TRACE( "%x -> %s (%u)\n", 
436                    atom, debugstr_wn(abi->Name, abi->NameLength / sizeof(WCHAR)),
437                    status );
438             if (psize)
439                 *psize = sizeof(ATOM_BASIC_INFORMATION) + name_len;
440         }
441         break;
442     default:
443         FIXME( "Unsupported class %u\n", class );
444         status = STATUS_INVALID_INFO_CLASS;
445         break;
446     }
447     return status;
448 }