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