/* * 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 #define IS_INTATOM(x) (((ULONG_PTR)(x) >> 16) == 0) /****************************************************************** * 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 (!IS_INTATOM( 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; }