Fix NtQueryDirectoryObject prototype, documentation, and the
[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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  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 "windef.h"
32 #include "ntstatus.h"
33
34 #include "wine/server.h"
35 #include "wine/unicode.h"
36
37 #include "wine/debug.h"
38
39 WINE_DEFAULT_DEBUG_CHANNEL(atom);
40
41 #define MAX_ATOM_LEN              255
42
43 /******************************************************************
44  *              is_integral_atom
45  * Returns STATUS_SUCCESS if integral atom and 'pAtom' is filled
46  *         STATUS_INVALID_PARAMETER if 'atomstr' is too long
47  *         STATUS_MORE_ENTRIES otherwise
48  */
49 static NTSTATUS is_integral_atom( LPCWSTR atomstr, size_t len, RTL_ATOM* pAtom )
50 {
51     RTL_ATOM atom;
52
53     if (HIWORD( atomstr ))
54     {
55         const WCHAR* ptr = atomstr;
56         if (!len) return STATUS_OBJECT_NAME_INVALID;
57
58         if (*ptr++ == '#')
59         {
60             atom = 0;
61             while (ptr < atomstr + len && *ptr >= '0' && *ptr <= '9')
62             {
63                 atom = atom * 10 + *ptr++ - '0';
64             }
65             if (ptr > atomstr + 1 && ptr == atomstr + len) goto done;
66         }
67         if (len > MAX_ATOM_LEN) return STATUS_INVALID_PARAMETER;
68         return STATUS_MORE_ENTRIES;
69     }
70     else atom = LOWORD( atomstr );
71 done:
72     if (!atom || atom >= MAXINTATOM) return STATUS_INVALID_PARAMETER;
73     *pAtom = atom;
74     return STATUS_SUCCESS;
75 }
76
77 /******************************************************************
78  *              RtlDeleteAtomFromAtomTable (NTDLL.@)
79  */
80 NTSTATUS WINAPI RtlDeleteAtomFromAtomTable( RTL_ATOM_TABLE table, RTL_ATOM atom )
81 {
82     NTSTATUS    status;
83
84     TRACE( "%p %x\n", table, atom );
85     if (!table) status = STATUS_INVALID_PARAMETER;
86     else
87     {
88         SERVER_START_REQ( delete_atom )
89         {
90             req->atom = atom;
91             req->table = table;
92             status = wine_server_call( req );
93         }
94         SERVER_END_REQ;
95     }
96     return status;
97 }
98
99 /******************************************************************
100  *              RtlQueryAtomInAtomTable (NTDLL.@)
101  */
102 NTSTATUS WINAPI RtlQueryAtomInAtomTable( RTL_ATOM_TABLE table, RTL_ATOM atom, ULONG* ref,
103                                          ULONG* pin, WCHAR* name, ULONG* len )
104 {
105     NTSTATUS    status = STATUS_SUCCESS;
106     WCHAR       full_name[MAX_ATOM_LEN];
107     DWORD       wlen = 0;
108
109     if (!table) status = STATUS_INVALID_PARAMETER;
110     else if (atom < MAXINTATOM)
111     {
112         if (!atom) return STATUS_INVALID_PARAMETER;
113         if (len)
114         {
115             static WCHAR fmt[] = {'#','%','d',0};
116             wlen = sprintfW( full_name, fmt, atom ) * sizeof(WCHAR);
117         }
118         if (ref) *ref = 1;
119         if (pin) *pin = 1;
120     }
121     else
122     {
123         SERVER_START_REQ( get_atom_information )
124         {
125             req->atom = atom;
126             req->table = table;
127             if (len) wine_server_set_reply( req, full_name, sizeof(full_name) );
128             status = wine_server_call( req );
129             if (status == STATUS_SUCCESS)
130             {
131                 wlen = wine_server_reply_size( reply );
132                 if (ref) *ref = reply->count;
133                 if (pin) *pin = reply->pinned;
134             }
135         }
136         SERVER_END_REQ;
137     }
138     if (status == STATUS_SUCCESS && len)
139     {
140         if (*len > wlen)
141         {
142             memcpy( name, full_name, wlen );
143             name[wlen / sizeof(WCHAR)] = 0;
144         }
145         else status = STATUS_BUFFER_TOO_SMALL;
146         *len = wlen;
147     }
148
149     TRACE( "%p %x -> %s (%lu)\n",
150            table, atom, len ? debugstr_w(name) : NULL, status );
151     return status;
152 }
153
154 /******************************************************************
155  *              RtlCreateAtomTable (NTDLL.@)
156  */
157 NTSTATUS WINAPI RtlCreateAtomTable( ULONG size, RTL_ATOM_TABLE* table )
158 {
159     NTSTATUS    status;
160
161     if (*table)
162     {
163         if (size) status = STATUS_INVALID_PARAMETER;
164         else status = STATUS_SUCCESS;
165     }
166     else
167     {
168         SERVER_START_REQ( init_atom_table )
169         {
170             req->entries = size;
171             status = wine_server_call( req );
172             *table = reply->table;
173         }
174         SERVER_END_REQ;
175     }
176     return status;
177 }
178
179 /******************************************************************
180  *              RtlDestroyAtomTable (NTDLL.@)
181  */
182 NTSTATUS WINAPI RtlDestroyAtomTable( RTL_ATOM_TABLE table )
183 {
184     if (!table) return STATUS_INVALID_PARAMETER;
185     return NtClose( (HANDLE)table );
186 }
187
188 /******************************************************************
189  *              RtlAddAtomToAtomTable (NTDLL.@)
190  */
191 NTSTATUS WINAPI RtlAddAtomToAtomTable( RTL_ATOM_TABLE table, const WCHAR* name, RTL_ATOM* atom )
192 {
193     NTSTATUS    status;
194
195     if (!table) status = STATUS_INVALID_PARAMETER;
196     else
197     {
198         size_t len = HIWORD(name) ? strlenW(name) : 0;
199         status = is_integral_atom( name, len, atom );
200         if (status == STATUS_MORE_ENTRIES)
201         {
202             SERVER_START_REQ( add_atom )
203             {
204                 wine_server_add_data( req, name, len * sizeof(WCHAR) );
205                 req->table = table;
206                 status = wine_server_call( req );
207                 *atom = reply->atom;
208             }
209             SERVER_END_REQ;
210         }
211     }
212     TRACE( "%p %s -> %x\n",
213            table, debugstr_w(name), status == STATUS_SUCCESS ? *atom : 0 );
214
215     return status;
216 }
217
218 /******************************************************************
219  *              RtlLookupAtomInAtomTable (NTDLL.@)
220  */
221 NTSTATUS WINAPI RtlLookupAtomInAtomTable( RTL_ATOM_TABLE table, const WCHAR* name, RTL_ATOM* atom )
222 {
223     NTSTATUS    status;
224
225     if (!table) status = STATUS_INVALID_PARAMETER;
226     else
227     {
228         size_t len = HIWORD(name) ? strlenW(name) : 0;
229         status = is_integral_atom( name, len, atom );
230         if (status == STATUS_MORE_ENTRIES)
231         {
232             SERVER_START_REQ( find_atom )
233             {
234                 wine_server_add_data( req, name, len * sizeof(WCHAR) );
235                 req->table = table;
236                 status = wine_server_call( req );
237                 *atom = reply->atom;
238             }
239             SERVER_END_REQ;
240         }
241     }
242     TRACE( "%p %s -> %x\n",
243            table, debugstr_w(name), status == STATUS_SUCCESS ? *atom : 0 );
244     return status;
245 }
246
247 /******************************************************************
248  *              RtlEmptyAtomTable (NTDLL.@)
249  */
250 NTSTATUS WINAPI RtlEmptyAtomTable( RTL_ATOM_TABLE table, BOOLEAN delete_pinned )
251 {
252     NTSTATUS    status;
253
254     if (!table) status = STATUS_INVALID_PARAMETER;
255     else
256     {
257         SERVER_START_REQ( empty_atom_table )
258         {
259             req->table = table;
260             req->if_pinned = delete_pinned;
261             status = wine_server_call( req );
262         }
263         SERVER_END_REQ;
264     }
265     return status;
266 }
267
268 /******************************************************************
269  *              RtlPinAtomInAtomTable (NTDLL.@)
270  */
271 NTSTATUS WINAPI RtlPinAtomInAtomTable( RTL_ATOM_TABLE table, RTL_ATOM atom )
272 {
273     NTSTATUS status;
274
275     if (!table) return STATUS_INVALID_PARAMETER;
276     if (atom < MAXINTATOM) return STATUS_SUCCESS;
277
278     SERVER_START_REQ( set_atom_information )
279     {
280         req->table = table;
281         req->atom = atom;
282         req->pinned = TRUE;
283         status = wine_server_call( req );
284     }
285     SERVER_END_REQ;
286
287     return status;
288 }
289
290 /*************************************************
291  *        Global handle table management
292  *************************************************/
293
294 /******************************************************************
295  *              NtAddAtom (NTDLL.@)
296  */
297 NTSTATUS WINAPI NtAddAtom( const WCHAR* name, ULONG length, RTL_ATOM* atom )
298 {
299     NTSTATUS    status;
300
301     status = is_integral_atom( name, length / sizeof(WCHAR), atom );
302     if (status == STATUS_MORE_ENTRIES)
303     {
304         SERVER_START_REQ( add_atom )
305         {
306             wine_server_add_data( req, name, length );
307             req->table = NULL;
308             status = wine_server_call( req );
309             *atom = reply->atom;
310         }
311         SERVER_END_REQ;
312     }
313     TRACE( "%s -> %x\n",
314            debugstr_wn(name, length/sizeof(WCHAR)), status == STATUS_SUCCESS ? *atom : 0 );
315     return status;
316 }
317
318 /******************************************************************
319  *              NtDeleteAtom (NTDLL.@)
320  */
321 NTSTATUS WINAPI NtDeleteAtom(RTL_ATOM atom)
322 {
323     NTSTATUS    status;
324
325     SERVER_START_REQ( delete_atom )
326     {
327         req->atom = atom;
328         req->table = NULL;
329         status = wine_server_call( req );
330     }
331     SERVER_END_REQ;
332     return status;
333 }
334
335 /******************************************************************
336  *              NtFindAtom (NTDLL.@)
337  */
338 NTSTATUS WINAPI NtFindAtom( const WCHAR* name, ULONG length, RTL_ATOM* atom )
339 {
340     NTSTATUS    status;
341
342     status = is_integral_atom( name, length / sizeof(WCHAR), atom );
343     if (status == STATUS_MORE_ENTRIES)
344     {
345         SERVER_START_REQ( find_atom )
346         {
347             wine_server_add_data( req, name, length );
348             req->table = NULL;
349             status = wine_server_call( req );
350             *atom = reply->atom;
351         }
352         SERVER_END_REQ;
353     }
354     TRACE( "%s -> %x\n",
355            debugstr_wn(name, length/sizeof(WCHAR)), status == STATUS_SUCCESS ? *atom : 0 );
356     return status;
357 }
358
359 /******************************************************************
360  *              NtQueryInformationAtom (NTDLL.@)
361  */
362 NTSTATUS WINAPI NtQueryInformationAtom( RTL_ATOM atom, ATOM_INFORMATION_CLASS class,
363                                         PVOID ptr, ULONG size, PULONG psize )
364 {
365     NTSTATUS status;
366
367     switch (class)
368     {
369     case AtomBasicInformation:
370         {
371             ULONG name_len;
372             ATOM_BASIC_INFORMATION* abi = (ATOM_BASIC_INFORMATION*)ptr;
373
374             name_len = size - (sizeof(ATOM_BASIC_INFORMATION) - sizeof(WCHAR));
375
376             if (atom < MAXINTATOM)
377             {
378                 if (!atom) status = STATUS_INVALID_PARAMETER;
379                 else if (name_len >= 7 * sizeof(WCHAR))
380                 {
381                     static WCHAR fmt[] = {'#','%','d',0};
382                     abi->NameLength = snprintfW( abi->Name, name_len / sizeof(WCHAR), fmt, atom ) * sizeof(WCHAR);
383                     abi->ReferenceCount = 1;
384                     abi->Pinned = 1;
385                     status = STATUS_SUCCESS;
386                 }
387                 else status = STATUS_BUFFER_TOO_SMALL;
388             }
389             else
390             {
391                 SERVER_START_REQ( get_atom_information )
392                 {
393                     req->atom = atom;
394                     req->table = NULL;
395                     if (name_len) wine_server_set_reply( req, abi->Name, name_len );
396                     status = wine_server_call( req );
397                     name_len = wine_server_reply_size( reply );
398                     if (status == STATUS_SUCCESS)
399                     {
400                         abi->NameLength = name_len;
401                         abi->ReferenceCount = reply->count;
402                         abi->Pinned = reply->pinned;
403                     }
404                 }
405                 SERVER_END_REQ;
406             }
407             TRACE( "%x -> %s (%lu)\n", atom, debugstr_wn(abi->Name, name_len/sizeof(WCHAR)), status );
408             if (psize)
409                 *psize = sizeof(ATOM_BASIC_INFORMATION) - sizeof(WCHAR) + name_len;
410         }
411         break;
412     default:
413         FIXME( "Unsupported class %u\n", class );
414         status = STATUS_INVALID_INFO_CLASS;
415         break;
416     }
417     return status;
418 }