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