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