| /* | |
| * Atom table functions | |
| * | |
| * Copyright 1993, 1994, 1995 Alexandre Julliard | |
| * | |
| * 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 | |
| * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA | |
| */ | |
| #include "config.h" | |
| #include "wine/port.h" | |
| #include <stdlib.h> | |
| #include <stdarg.h> | |
| #include <stdio.h> | |
| #include <string.h> | |
| #include <ctype.h> | |
| #include "windef.h" | |
| #include "winbase.h" | |
| #include "winerror.h" | |
| #include "winternl.h" | |
| #include "wine/exception.h" | |
| #include "wine/unicode.h" | |
| #include "kernel_private.h" | |
| #define MAX_ATOM_LEN 255 | |
| /****************************************************************** | |
| * 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) | |
| { | |
| static RTL_ATOM_TABLE local_table; | |
| if (!local_table) | |
| { | |
| NTSTATUS status; | |
| RTL_ATOM_TABLE table = NULL; | |
| if ((status = RtlCreateAtomTable( entries, &table ))) | |
| SetLastError( RtlNtStatusToDosError( status ) ); | |
| else if (InterlockedCompareExchangePointer((void*)&local_table, table, NULL) != NULL) | |
| RtlDestroyAtomTable( table ); | |
| } | |
| return local_table; | |
| } | |
| /*********************************************************************** | |
| * InitAtomTable (KERNEL32.@) | |
| * | |
| * Initialise the global atom table. | |
| * | |
| * PARAMS | |
| * entries [I] The number of entries to reserve in the table. | |
| * | |
| * RETURNS | |
| * Success: TRUE. | |
| * Failure: FALSE. | |
| */ | |
| BOOL WINAPI InitAtomTable( DWORD entries ) | |
| { | |
| return get_local_table( entries ) ? TRUE : FALSE; | |
| } | |
| /****************************************************************** | |
| * 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) | |
| { | |
| if (HIWORD( ptr )) return FALSE; | |
| if ((*patom = LOWORD( ptr )) >= MAXINTATOM) | |
| { | |
| SetLastError( ERROR_INVALID_PARAMETER ); | |
| *patom = 0; | |
| } | |
| return TRUE; | |
| } | |
| /*********************************************************************** | |
| * GlobalAddAtomA (KERNEL32.@) | |
| * | |
| * Add a character string to the global atom table and return a unique | |
| * value identifying it. | |
| * | |
| * RETURNS | |
| * Success: The atom allocated to str. | |
| * Failure: 0. | |
| */ | |
| ATOM WINAPI GlobalAddAtomA( LPCSTR str /* [in] String to add */ ) | |
| { | |
| ATOM atom = 0; | |
| __TRY | |
| { | |
| 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; | |
| } | |
| } | |
| } | |
| } | |
| __EXCEPT_PAGE_FAULT | |
| { | |
| SetLastError( ERROR_INVALID_PARAMETER ); | |
| atom = 0; | |
| } | |
| __ENDTRY | |
| return atom; | |
| } | |
| /*********************************************************************** | |
| * AddAtomA (KERNEL32.@) | |
| * | |
| * Add a character string to the global atom table and return a unique | |
| * value identifying it. | |
| * | |
| * RETURNS | |
| * Success: The atom allocated to str. | |
| * Failure: 0. | |
| */ | |
| ATOM WINAPI AddAtomA( LPCSTR str /* [in] String to add */ ) | |
| { | |
| ATOM atom = 0; | |
| if (!check_integral_atom( str, &atom )) | |
| { | |
| 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 ))) | |
| { | |
| NTSTATUS status = RtlAddAtomToAtomTable( table, buffer, &atom ); | |
| if (status) | |
| { | |
| SetLastError( RtlNtStatusToDosError( status ) ); | |
| atom = 0; | |
| } | |
| } | |
| } | |
| return atom; | |
| } | |
| /*********************************************************************** | |
| * GlobalAddAtomW (KERNEL32.@) | |
| * | |
| * Unicode version of GlobalAddAtomA. | |
| */ | |
| ATOM WINAPI GlobalAddAtomW( LPCWSTR str ) | |
| { | |
| 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; | |
| } | |
| /*********************************************************************** | |
| * AddAtomW (KERNEL32.@) | |
| * | |
| * Unicode version of AddAtomA. | |
| */ | |
| ATOM WINAPI AddAtomW( LPCWSTR str ) | |
| { | |
| ATOM atom = 0; | |
| RTL_ATOM_TABLE table; | |
| if (!check_integral_atom( str, &atom ) && (table = get_local_table( 0 ))) | |
| { | |
| NTSTATUS status = RtlAddAtomToAtomTable( table, str, &atom ); | |
| if (status) | |
| { | |
| SetLastError( RtlNtStatusToDosError( status ) ); | |
| atom = 0; | |
| } | |
| } | |
| return atom; | |
| } | |
| /*********************************************************************** | |
| * GlobalDeleteAtom (KERNEL32.@) | |
| * | |
| * Decrement the reference count of a string atom. If the count is | |
| * zero, the string associated with the atom is removed from the table. | |
| * | |
| * RETURNS | |
| * Success: 0. | |
| * Failure: atom. | |
| */ | |
| ATOM WINAPI GlobalDeleteAtom( ATOM atom /* [in] Atom to delete */ ) | |
| { | |
| if (atom >= MAXINTATOM) | |
| { | |
| NTSTATUS status = NtDeleteAtom( atom ); | |
| if (status) | |
| { | |
| SetLastError( RtlNtStatusToDosError( status ) ); | |
| return atom; | |
| } | |
| } | |
| return 0; | |
| } | |
| /*********************************************************************** | |
| * DeleteAtom (KERNEL32.@) | |
| * | |
| * Decrement the reference count of a string atom. If the count becomes | |
| * zero, the string associated with the atom is removed from the table. | |
| * | |
| * RETURNS | |
| * Success: 0. | |
| * Failure: atom | |
| */ | |
| ATOM WINAPI DeleteAtom( ATOM atom /* [in] Atom to delete */ ) | |
| { | |
| NTSTATUS status; | |
| RTL_ATOM_TABLE table; | |
| if (atom >= MAXINTATOM) | |
| { | |
| if (!(table = get_local_table( 0 ))) return atom; | |
| status = RtlDeleteAtomFromAtomTable( table, atom ); | |
| if (status) | |
| { | |
| SetLastError( RtlNtStatusToDosError( status ) ); | |
| return atom; | |
| } | |
| } | |
| return 0; | |
| } | |
| /*********************************************************************** | |
| * GlobalFindAtomA (KERNEL32.@) | |
| * | |
| * Get the atom associated with a string. | |
| * | |
| * RETURNS | |
| * Success: The associated atom. | |
| * Failure: 0. | |
| */ | |
| ATOM WINAPI GlobalFindAtomA( LPCSTR str /* [in] Pointer to string to search for */ ) | |
| { | |
| 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; | |
| } | |
| /*********************************************************************** | |
| * FindAtomA (KERNEL32.@) | |
| * | |
| * Get the atom associated with a string. | |
| * | |
| * RETURNS | |
| * Success: The associated atom. | |
| * Failure: 0. | |
| */ | |
| ATOM WINAPI FindAtomA( LPCSTR str /* [in] Pointer to string to find */ ) | |
| { | |
| ATOM atom = 0; | |
| if (!check_integral_atom( str, &atom )) | |
| { | |
| 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 ))) | |
| { | |
| NTSTATUS status = RtlLookupAtomInAtomTable( table, buffer, &atom ); | |
| if (status) | |
| { | |
| SetLastError( RtlNtStatusToDosError( status ) ); | |
| atom = 0; | |
| } | |
| } | |
| } | |
| return atom; | |
| } | |
| /*********************************************************************** | |
| * GlobalFindAtomW (KERNEL32.@) | |
| * | |
| * Unicode version of GlobalFindAtomA. | |
| */ | |
| ATOM WINAPI GlobalFindAtomW( LPCWSTR str ) | |
| { | |
| 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; | |
| } | |
| /*********************************************************************** | |
| * FindAtomW (KERNEL32.@) | |
| * | |
| * Unicode version of FindAtomA. | |
| */ | |
| ATOM WINAPI FindAtomW( LPCWSTR str ) | |
| { | |
| 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; | |
| } | |
| /*********************************************************************** | |
| * GlobalGetAtomNameA (KERNEL32.@) | |
| * | |
| * Get a copy of the string associated with an atom. | |
| * | |
| * RETURNS | |
| * Success: The length of the returned string in characters. | |
| * Failure: 0. | |
| */ | |
| UINT WINAPI GlobalGetAtomNameA( | |
| ATOM atom, /* [in] Atom identifier */ | |
| LPSTR buffer, /* [out] Pointer to buffer for atom string */ | |
| INT count ) /* [in] Size of buffer */ | |
| { | |
| 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; | |
| } | |
| /*********************************************************************** | |
| * GetAtomNameA (KERNEL32.@) | |
| * | |
| * Get a copy of the string associated with an atom. | |
| * | |
| * RETURNS | |
| * Success: The length of the returned string in characters. | |
| * Failure: 0. | |
| */ | |
| UINT WINAPI GetAtomNameA( | |
| ATOM atom, /* [in] Atom */ | |
| LPSTR buffer, /* [out] Pointer to string for atom string */ | |
| INT count) /* [in] Size of buffer */ | |
| { | |
| WCHAR tmpW[MAX_ATOM_LEN + 1]; | |
| UINT wlen, len = 0, c; | |
| if (count <= 0) SetLastError( ERROR_MORE_DATA ); | |
| else if ((wlen = GetAtomNameW( 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 = c; | |
| SetLastError( ERROR_MORE_DATA ); | |
| } | |
| } | |
| return len; | |
| } | |
| /*********************************************************************** | |
| * GlobalGetAtomNameW (KERNEL32.@) | |
| * | |
| * Unicode version of GlobalGetAtomNameA. | |
| */ | |
| UINT WINAPI GlobalGetAtomNameW( ATOM atom, LPWSTR buffer, INT count ) | |
| { | |
| 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) ); | |
| /* yes, the string will not be null terminated if the passed buffer | |
| * is one WCHAR too small (and it's not an error) | |
| */ | |
| if (length < abi->NameLength / sizeof(WCHAR)) | |
| { | |
| SetLastError( ERROR_MORE_DATA ); | |
| length = count; | |
| } | |
| else if (length < count) buffer[length] = '\0'; | |
| } | |
| return length; | |
| } | |
| /*********************************************************************** | |
| * GetAtomNameW (KERNEL32.@) | |
| * | |
| * Unicode version of GetAtomNameA. | |
| */ | |
| UINT WINAPI GetAtomNameW( ATOM atom, LPWSTR buffer, INT count ) | |
| { | |
| 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; | |
| } |