atom.c 13.9 KB
Newer Older
Alexandre Julliard's avatar
Alexandre Julliard committed
1 2 3
/*
 * Atom table functions
 *
Alexandre Julliard's avatar
Alexandre Julliard committed
4
 * Copyright 1993, 1994, 1995 Alexandre Julliard
5 6 7 8 9 10 11 12 13 14 15 16 17
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * 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
Alexandre Julliard's avatar
Alexandre Julliard committed
19 20
 */

21
#include "config.h"
22
#include "wine/port.h"
23

Alexandre Julliard's avatar
Alexandre Julliard committed
24
#include <stdlib.h>
25
#include <stdarg.h>
Alexandre Julliard's avatar
Alexandre Julliard committed
26
#include <stdio.h>
Alexandre Julliard's avatar
Alexandre Julliard committed
27
#include <string.h>
Alexandre Julliard's avatar
Alexandre Julliard committed
28
#include <ctype.h>
Alexandre Julliard's avatar
Alexandre Julliard committed
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 44 45 46 47 48
/******************************************************************
 *		get_local_table
 *
 * Returns the local atom table for this process (and create it if doesn't
 * exist yet)
 */
static RTL_ATOM_TABLE get_local_table(DWORD entries)
49
{
50
    static RTL_ATOM_TABLE local_table;
51 52 53

    if (!local_table)
    {
54 55
        NTSTATUS        status;
        RTL_ATOM_TABLE  table = NULL;
56

57
        if ((status = RtlCreateAtomTable( entries, &table )))
58 59
            SetLastError( RtlNtStatusToDosError( status ) );
        else if (InterlockedCompareExchangePointer((void*)&local_table, table, NULL) != NULL)
60
            RtlDestroyAtomTable( table );
61 62
    }

63
    return local_table;
64 65 66
}


Alexandre Julliard's avatar
Alexandre Julliard committed
67
/***********************************************************************
68
 *           InitAtomTable   (KERNEL32.@)
Jon Griffiths's avatar
Jon Griffiths committed
69
 *
70
 * Initialise local atom table.
Jon Griffiths's avatar
Jon Griffiths committed
71 72 73 74 75 76 77
 *
 * PARAMS
 *  entries [I] The number of entries to reserve in the table.
 *
 * RETURNS
 *  Success: TRUE.
 *  Failure: FALSE.
Alexandre Julliard's avatar
Alexandre Julliard committed
78
 */
79 80
BOOL WINAPI InitAtomTable( DWORD entries )
{
81
    return get_local_table( entries ) != 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
82 83
}

84 85 86 87 88 89 90
/******************************************************************
 *		check_integral_atom
 *
 * Check if a string (ANSI or UNICODE) is in fact an integral atom
 * (but doesn't check the "#1234" form)
 */
static inline BOOL check_integral_atom( const void* ptr, ATOM* patom)
Alexandre Julliard's avatar
Alexandre Julliard committed
91
{
92
    if (!IS_INTATOM( ptr )) return FALSE;
93
    if ((*patom = LOWORD( ptr )) >= MAXINTATOM)
94
    {
95 96
        SetLastError( ERROR_INVALID_PARAMETER );
        *patom = 0;
97
    }
98
    return TRUE;
Alexandre Julliard's avatar
Alexandre Julliard committed
99 100
}

Alexandre Julliard's avatar
Alexandre Julliard committed
101
/***********************************************************************
102
 *           GlobalAddAtomA   (KERNEL32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
103
 *
Jon Griffiths's avatar
Jon Griffiths committed
104 105
 * Add a character string to the global atom table and return a unique
 * value identifying it.
Alexandre Julliard's avatar
Alexandre Julliard committed
106 107
 *
 * RETURNS
Jon Griffiths's avatar
Jon Griffiths committed
108 109
 *	Success: The atom allocated to str.
 *	Failure: 0.
Alexandre Julliard's avatar
Alexandre Julliard committed
110
 */
Jon Griffiths's avatar
Jon Griffiths committed
111
ATOM WINAPI GlobalAddAtomA( LPCSTR str /* [in] String to add */ )
Alexandre Julliard's avatar
Alexandre Julliard committed
112
{
113
    ATOM atom = 0;
114 115
    __TRY
    {
116 117 118 119 120 121 122 123 124 125 126 127 128 129 130
        if (!check_integral_atom( str, &atom ))
	{
	    WCHAR buffer[MAX_ATOM_LEN];
	    DWORD len = MultiByteToWideChar( CP_ACP, 0, str, strlen(str), buffer, MAX_ATOM_LEN );
	    if (!len) SetLastError( ERROR_INVALID_PARAMETER );
	    else
	    {
	        NTSTATUS status = NtAddAtom( buffer, len * sizeof(WCHAR), &atom );
		if (status)
		{
		    SetLastError( RtlNtStatusToDosError( status ) );
		    atom = 0;
		}
	    }
	}
131
    }
132
    __EXCEPT_PAGE_FAULT
133 134
    {
        SetLastError( ERROR_INVALID_PARAMETER );
135
        atom = 0;
136 137
    }
    __ENDTRY
138
    return atom;
Alexandre Julliard's avatar
Alexandre Julliard committed
139 140 141 142
}


/***********************************************************************
143
 *           AddAtomA   (KERNEL32.@)
Jon Griffiths's avatar
Jon Griffiths committed
144
 *
145
 * Add a character string to local atom table and return a unique
Jon Griffiths's avatar
Jon Griffiths committed
146
 * value identifying it.
Alexandre Julliard's avatar
Alexandre Julliard committed
147 148
 *
 * RETURNS
Jon Griffiths's avatar
Jon Griffiths committed
149 150
 *      Success: The atom allocated to str.
 *      Failure: 0.
Alexandre Julliard's avatar
Alexandre Julliard committed
151
 */
Jon Griffiths's avatar
Jon Griffiths committed
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 159 160 161 162 163 164
        WCHAR           buffer[MAX_ATOM_LEN + 1];
        DWORD           len;
        RTL_ATOM_TABLE  table;

        len = MultiByteToWideChar( CP_ACP, 0, str, -1, buffer, MAX_ATOM_LEN + 1 );
        if (!len) SetLastError( ERROR_INVALID_PARAMETER );
        else if ((table = get_local_table( 0 )))
165
        {
166 167 168 169 170 171
            NTSTATUS status = RtlAddAtomToAtomTable( table, buffer, &atom );
            if (status)
            {
                SetLastError( RtlNtStatusToDosError( status ) );
                atom = 0;
            }
172
        }
173 174
    }
    return atom;
Alexandre Julliard's avatar
Alexandre Julliard committed
175 176 177
}

/***********************************************************************
178
 *           GlobalAddAtomW   (KERNEL32.@)
Jon Griffiths's avatar
Jon Griffiths committed
179 180
 *
 * Unicode version of GlobalAddAtomA.
Alexandre Julliard's avatar
Alexandre Julliard committed
181
 */
182
ATOM WINAPI GlobalAddAtomW( LPCWSTR str )
Alexandre Julliard's avatar
Alexandre Julliard committed
183
{
184 185 186 187 188 189 190 191 192 193
    ATOM        atom = 0;
    NTSTATUS    status;

    if (!check_integral_atom( str, &atom ) && 
        (status = NtAddAtom( str, strlenW( str ) * sizeof(WCHAR), &atom )))
    {
        SetLastError( RtlNtStatusToDosError( status ) );
        atom = 0;
    }
    return atom;
194 195 196 197
}


/***********************************************************************
198
 *           AddAtomW   (KERNEL32.@)
Jon Griffiths's avatar
Jon Griffiths committed
199 200
 *
 * Unicode version of AddAtomA.          
201 202 203
 */
ATOM WINAPI AddAtomW( LPCWSTR str )
{
204 205
    ATOM                atom = 0;
    RTL_ATOM_TABLE      table;
206

207
    if (!check_integral_atom( str, &atom ) && (table = get_local_table( 0 )))
208
    {
209 210
        NTSTATUS status = RtlAddAtomToAtomTable( table, str, &atom );
        if (status)
211
        {
212 213
            SetLastError( RtlNtStatusToDosError( status ) );
            atom = 0;
214
        }
215
    }
216
    return atom;
Alexandre Julliard's avatar
Alexandre Julliard committed
217 218 219 220
}


/***********************************************************************
221
 *           GlobalDeleteAtom   (KERNEL32.@)
Jon Griffiths's avatar
Jon Griffiths committed
222 223
 *
 * Decrement the reference count of a string atom.  If the count is
Alexandre Julliard's avatar
Alexandre Julliard committed
224 225 226
 * zero, the string associated with the atom is removed from the table.
 *
 * RETURNS
Jon Griffiths's avatar
Jon Griffiths committed
227 228
 *	Success: 0.
 *	Failure: atom.
Alexandre Julliard's avatar
Alexandre Julliard committed
229
 */
230
ATOM WINAPI GlobalDeleteAtom( ATOM atom /* [in] Atom to delete */ )
Alexandre Julliard's avatar
Alexandre Julliard committed
231
{
232 233 234 235 236 237 238 239 240 241
    if (atom >= MAXINTATOM)
    {
        NTSTATUS status = NtDeleteAtom( atom );
        if (status)
        {
            SetLastError( RtlNtStatusToDosError( status ) );
            return atom;
        }
    }
    return 0;
242 243 244 245
}


/***********************************************************************
246
 *           DeleteAtom   (KERNEL32.@)
Jon Griffiths's avatar
Jon Griffiths committed
247 248
 *
 * Decrement the reference count of a string atom.  If the count becomes
249 250 251
 * zero, the string associated with the atom is removed from the table.
 *
 * RETURNS
Jon Griffiths's avatar
Jon Griffiths committed
252 253
 *	Success: 0.
 *	Failure: atom
254 255 256
 */
ATOM WINAPI DeleteAtom( ATOM atom /* [in] Atom to delete */ )
{
257 258
    NTSTATUS            status;
    RTL_ATOM_TABLE      table;
259

260
    if (atom >= MAXINTATOM)
261
    {
262 263 264
        if (!(table = get_local_table( 0 ))) return atom;
        status = RtlDeleteAtomFromAtomTable( table, atom );
        if (status)
265
        {
266 267
            SetLastError( RtlNtStatusToDosError( status ) );
            return atom;
268
        }
269
    }
270
    return 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
271 272 273 274
}


/***********************************************************************
275
 *           GlobalFindAtomA   (KERNEL32.@)
276
 *
Jon Griffiths's avatar
Jon Griffiths committed
277
 * Get the atom associated with a string.
Alexandre Julliard's avatar
Alexandre Julliard committed
278 279
 *
 * RETURNS
Jon Griffiths's avatar
Jon Griffiths committed
280 281
 *	Success: The associated atom.
 *	Failure: 0.
Alexandre Julliard's avatar
Alexandre Julliard committed
282
 */
283
ATOM WINAPI GlobalFindAtomA( LPCSTR str /* [in] Pointer to string to search for */ )
284
{
285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303
    ATOM atom = 0;

    if (!check_integral_atom( str, &atom ))
    {
        WCHAR buffer[MAX_ATOM_LEN];
        DWORD len = MultiByteToWideChar( CP_ACP, 0, str, strlen(str), buffer, MAX_ATOM_LEN );

        if (!len) SetLastError( ERROR_INVALID_PARAMETER );
        else
        {
            NTSTATUS status = NtFindAtom( buffer, len * sizeof(WCHAR), &atom );
            if (status)
            {
                SetLastError( RtlNtStatusToDosError( status ) );
                atom = 0;
            }
        }
    }
    return atom;
304 305 306
}

/***********************************************************************
307
 *           FindAtomA   (KERNEL32.@)
Jon Griffiths's avatar
Jon Griffiths committed
308 309
 *
 * Get the atom associated with a string.
310 311
 *
 * RETURNS
Jon Griffiths's avatar
Jon Griffiths committed
312 313
 *	Success: The associated atom.
 *	Failure: 0.
314 315
 */
ATOM WINAPI FindAtomA( LPCSTR str /* [in] Pointer to string to find */ )
Alexandre Julliard's avatar
Alexandre Julliard committed
316
{
317
    ATOM atom = 0;
318 319

    if (!check_integral_atom( str, &atom ))
320
    {
321 322 323 324 325 326 327
        WCHAR           buffer[MAX_ATOM_LEN + 1];
        DWORD           len;
        RTL_ATOM_TABLE  table;

        len = MultiByteToWideChar( CP_ACP, 0, str, -1, buffer, MAX_ATOM_LEN + 1 );
        if (!len) SetLastError( ERROR_INVALID_PARAMETER );
        else if ((table = get_local_table( 0 )))
328
        {
329 330 331 332 333 334
            NTSTATUS status = RtlLookupAtomInAtomTable( table, buffer, &atom );
            if (status)
            {
                SetLastError( RtlNtStatusToDosError( status ) );
                atom = 0;
            }
335
        }
336 337
    }
    return atom;
Alexandre Julliard's avatar
Alexandre Julliard committed
338 339 340 341
}


/***********************************************************************
342
 *           GlobalFindAtomW   (KERNEL32.@)
Jon Griffiths's avatar
Jon Griffiths committed
343 344
 *
 * Unicode version of GlobalFindAtomA.
Alexandre Julliard's avatar
Alexandre Julliard committed
345
 */
346
ATOM WINAPI GlobalFindAtomW( LPCWSTR str )
Alexandre Julliard's avatar
Alexandre Julliard committed
347
{
348 349 350 351 352 353 354 355 356 357 358 359
    ATOM atom = 0;

    if (!check_integral_atom( str, &atom ))
    {
        NTSTATUS status = NtFindAtom( str, strlenW( str ) * sizeof(WCHAR), &atom );
        if (status)
        {
            SetLastError( RtlNtStatusToDosError( status ) );
            atom = 0;
        }
    }
    return atom;
Alexandre Julliard's avatar
Alexandre Julliard committed
360 361 362 363
}


/***********************************************************************
364
 *           FindAtomW   (KERNEL32.@)
Jon Griffiths's avatar
Jon Griffiths committed
365 366
 *
 * Unicode version of FindAtomA.
Alexandre Julliard's avatar
Alexandre Julliard committed
367
 */
368 369
ATOM WINAPI FindAtomW( LPCWSTR str )
{
370 371 372 373 374 375 376 377 378 379 380 381 382 383
    ATOM                atom = 0;
    NTSTATUS            status;
    RTL_ATOM_TABLE      table;

    if ((table = get_local_table( 0 )))
    {
        status = RtlLookupAtomInAtomTable( table, str, &atom );
        if (status)
        {
            SetLastError( RtlNtStatusToDosError( status ) );
            atom = 0;
        }
    }
    return atom;
384 385 386
}


Alexandre Julliard's avatar
Alexandre Julliard committed
387
/***********************************************************************
388
 *           GlobalGetAtomNameA   (KERNEL32.@)
389
 *
Jon Griffiths's avatar
Jon Griffiths committed
390
 * Get a copy of the string associated with an atom.
391 392
 *
 * RETURNS
Jon Griffiths's avatar
Jon Griffiths committed
393 394
 *	Success: The length of the returned string in characters.
 *	Failure: 0.
Alexandre Julliard's avatar
Alexandre Julliard committed
395
 */
396 397 398 399 400
UINT WINAPI GlobalGetAtomNameA(
              ATOM atom,    /* [in]  Atom identifier */
              LPSTR buffer, /* [out] Pointer to buffer for atom string */
              INT count )   /* [in]  Size of buffer */
{
401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419
    WCHAR       tmpW[MAX_ATOM_LEN + 1];
    UINT        wlen, len = 0, c;

    if (count <= 0) SetLastError( ERROR_MORE_DATA );
    else if ((wlen = GlobalGetAtomNameW( atom, tmpW, MAX_ATOM_LEN + 1 )))
    {
        char    tmp[MAX_ATOM_LEN + 1];

        len = WideCharToMultiByte( CP_ACP, 0, tmpW, wlen, tmp, MAX_ATOM_LEN + 1, NULL, NULL );
        c = min(len, count - 1);
        memcpy(buffer, tmp, c);
        buffer[c] = '\0';
        if (len >= count)
        {
            len = 0;
            SetLastError( ERROR_MORE_DATA );
        }
    }
    return len;
420 421 422 423
}


/***********************************************************************
424
 *           GetAtomNameA   (KERNEL32.@)
Jon Griffiths's avatar
Jon Griffiths committed
425 426
 *
 * Get a copy of the string associated with an atom.
427 428
 *
 * RETURNS
Jon Griffiths's avatar
Jon Griffiths committed
429 430
 *	Success: The length of the returned string in characters.
 *	Failure: 0.
431 432 433 434 435 436
 */
UINT WINAPI GetAtomNameA(
              ATOM atom,    /* [in]  Atom */
              LPSTR buffer, /* [out] Pointer to string for atom string */
              INT count)    /* [in]  Size of buffer */
{
437 438
    WCHAR       tmpW[MAX_ATOM_LEN + 1];
    UINT        wlen, len = 0, c;
439

440 441
    if (count <= 0) SetLastError( ERROR_MORE_DATA );
    else if ((wlen = GetAtomNameW( atom, tmpW, MAX_ATOM_LEN + 1 )))
442
    {
443
        char    tmp[MAX_ATOM_LEN + 1];
444

445 446 447 448 449
        len = WideCharToMultiByte( CP_ACP, 0, tmpW, wlen, tmp, MAX_ATOM_LEN + 1, NULL, NULL );
        c = min(len, count - 1);
        memcpy(buffer, tmp, c);
        buffer[c] = '\0';
        if (len >= count)
450
        {
451 452
            len = c;
            SetLastError( ERROR_MORE_DATA );
453
        }
454 455
    }
    return len;
Alexandre Julliard's avatar
Alexandre Julliard committed
456
}
457 458 459


/***********************************************************************
460
 *           GlobalGetAtomNameW   (KERNEL32.@)
Jon Griffiths's avatar
Jon Griffiths committed
461 462
 *
 * Unicode version of GlobalGetAtomNameA.
463 464 465
 */
UINT WINAPI GlobalGetAtomNameW( ATOM atom, LPWSTR buffer, INT count )
{
466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482
    char        ptr[sizeof(ATOM_BASIC_INFORMATION) + MAX_ATOM_LEN * sizeof(WCHAR)];
    ATOM_BASIC_INFORMATION*     abi = (ATOM_BASIC_INFORMATION*)ptr;
    ULONG       ptr_size = sizeof(ATOM_BASIC_INFORMATION) + MAX_ATOM_LEN * sizeof(WCHAR);
    NTSTATUS    status;
    UINT        length = 0;

    if (count <= 0)
    {
        SetLastError( ERROR_MORE_DATA );
        return 0;
    }
    status = NtQueryInformationAtom( atom, AtomBasicInformation, (void*)ptr, ptr_size, NULL );
    if (status) SetLastError( RtlNtStatusToDosError( status ) );
    else
    {
        length = min( abi->NameLength / sizeof(WCHAR), count);
        memcpy( buffer, abi->Name, length * sizeof(WCHAR) );
483 484 485
        /* yes, the string will not be null terminated if the passed buffer
         * is one WCHAR too small (and it's not an error)
         */
486 487 488 489 490
        if (length < abi->NameLength / sizeof(WCHAR))
        {
            SetLastError( ERROR_MORE_DATA );
            length = count;
        }
491
        else if (length < count) buffer[length] = '\0';
492 493
    }
    return length;
494 495 496 497
}


/***********************************************************************
498
 *           GetAtomNameW   (KERNEL32.@)
Jon Griffiths's avatar
Jon Griffiths committed
499 500
 *
 * Unicode version of GetAtomNameA.
501 502 503
 */
UINT WINAPI GetAtomNameW( ATOM atom, LPWSTR buffer, INT count )
{
504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527
    NTSTATUS            status;
    RTL_ATOM_TABLE      table;
    DWORD               length;
    WCHAR               tmp[MAX_ATOM_LEN + 1];

    if (count <= 0)
    {
        SetLastError( ERROR_MORE_DATA );
        return 0;
    }
    if (!(table = get_local_table( 0 ))) return 0;
    length = sizeof(tmp);
    status = RtlQueryAtomInAtomTable( table, atom, NULL, NULL, tmp, &length );
    if (status)
    {
        SetLastError( RtlNtStatusToDosError( status ) );
        return 0;
    }
    length = min(length, (count - 1) * sizeof(WCHAR));
    if (length) memcpy(buffer, tmp, length);
    else SetLastError( ERROR_INSUFFICIENT_BUFFER );
    length /= sizeof(WCHAR);
    buffer[length] = '\0';
    return length;
528
}