| /* | |
| * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
| */ | |
| /* | |
| * Warning: The code assumes that LocalAlloc() returns a block aligned | |
| * on a 4-bytes boundary (because of the shifting done in | |
| * HANDLETOATOM). If this is not the case, the allocation code will | |
| * have to be changed. | |
| */ | |
| #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 "wine/server.h" | |
| #include "wine/unicode.h" | |
| #include "kernel_private.h" | |
| #include "wine/debug.h" | |
| WINE_DEFAULT_DEBUG_CHANNEL(atom); | |
| #define MAX_ATOM_LEN 255 | |
| /*********************************************************************** | |
| * ATOM_IsIntAtomA | |
| */ | |
| static BOOL ATOM_IsIntAtomA(LPCSTR atomstr,WORD *atomid) | |
| { | |
| UINT atom = 0; | |
| if (!HIWORD(atomstr)) atom = LOWORD(atomstr); | |
| else | |
| { | |
| if (*atomstr++ != '#') return FALSE; | |
| while (*atomstr >= '0' && *atomstr <= '9') | |
| { | |
| atom = atom * 10 + *atomstr - '0'; | |
| atomstr++; | |
| } | |
| if (*atomstr) return FALSE; | |
| } | |
| if (atom >= MAXINTATOM) | |
| { | |
| SetLastError( ERROR_INVALID_PARAMETER ); | |
| atom = 0; | |
| } | |
| *atomid = atom; | |
| return TRUE; | |
| } | |
| /*********************************************************************** | |
| * ATOM_IsIntAtomW | |
| */ | |
| static BOOL ATOM_IsIntAtomW(LPCWSTR atomstr,WORD *atomid) | |
| { | |
| UINT atom = 0; | |
| if (!HIWORD(atomstr)) atom = LOWORD(atomstr); | |
| else | |
| { | |
| if (*atomstr++ != '#') return FALSE; | |
| while (*atomstr >= '0' && *atomstr <= '9') | |
| { | |
| atom = atom * 10 + *atomstr - '0'; | |
| atomstr++; | |
| } | |
| if (*atomstr) return FALSE; | |
| } | |
| if (atom >= MAXINTATOM) | |
| { | |
| SetLastError( ERROR_INVALID_PARAMETER ); | |
| atom = 0; | |
| } | |
| *atomid = atom; | |
| return TRUE; | |
| } | |
| /*********************************************************************** | |
| * 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 ) | |
| { | |
| BOOL ret; | |
| SERVER_START_REQ( init_atom_table ) | |
| { | |
| req->entries = entries; | |
| ret = !wine_server_call_err( req ); | |
| } | |
| SERVER_END_REQ; | |
| return ret; | |
| } | |
| static ATOM ATOM_AddAtomA( LPCSTR str, BOOL local ) | |
| { | |
| ATOM atom = 0; | |
| if (!ATOM_IsIntAtomA( 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 ); | |
| return 0; | |
| } | |
| SERVER_START_REQ( add_atom ) | |
| { | |
| wine_server_add_data( req, buffer, len * sizeof(WCHAR) ); | |
| req->local = local; | |
| if (!wine_server_call_err(req)) atom = reply->atom; | |
| } | |
| SERVER_END_REQ; | |
| } | |
| TRACE( "(%s) %s -> %x\n", local ? "local" : "global", debugstr_a(str), atom ); | |
| return atom; | |
| } | |
| /*********************************************************************** | |
| * 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 */ ) | |
| { | |
| return ATOM_AddAtomA( str, FALSE ); | |
| } | |
| /*********************************************************************** | |
| * 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 */ ) | |
| { | |
| return ATOM_AddAtomA( str, TRUE ); | |
| } | |
| static ATOM ATOM_AddAtomW( LPCWSTR str, BOOL local ) | |
| { | |
| ATOM atom = 0; | |
| if (!ATOM_IsIntAtomW( str, &atom )) | |
| { | |
| DWORD len = strlenW(str); | |
| if (len > MAX_ATOM_LEN) | |
| { | |
| SetLastError( ERROR_INVALID_PARAMETER ); | |
| return 0; | |
| } | |
| SERVER_START_REQ( add_atom ) | |
| { | |
| req->local = local; | |
| wine_server_add_data( req, str, len * sizeof(WCHAR) ); | |
| if (!wine_server_call_err(req)) atom = reply->atom; | |
| } | |
| SERVER_END_REQ; | |
| } | |
| TRACE( "(%s) %s -> %x\n", local ? "local" : "global", debugstr_w(str), atom ); | |
| return atom; | |
| } | |
| /*********************************************************************** | |
| * GlobalAddAtomW (KERNEL32.@) | |
| * | |
| * Unicode version of GlobalAddAtomA. | |
| */ | |
| ATOM WINAPI GlobalAddAtomW( LPCWSTR str ) | |
| { | |
| return ATOM_AddAtomW( str, FALSE ); | |
| } | |
| /*********************************************************************** | |
| * AddAtomW (KERNEL32.@) | |
| * | |
| * Unicode version of AddAtomA. | |
| */ | |
| ATOM WINAPI AddAtomW( LPCWSTR str ) | |
| { | |
| return ATOM_AddAtomW( str, TRUE ); | |
| } | |
| static ATOM ATOM_DeleteAtom( ATOM atom, BOOL local) | |
| { | |
| TRACE( "(%s) %x\n", local ? "local" : "global", atom ); | |
| if (atom >= MAXINTATOM) | |
| { | |
| SERVER_START_REQ( delete_atom ) | |
| { | |
| req->atom = atom; | |
| req->local = local; | |
| wine_server_call_err( req ); | |
| } | |
| SERVER_END_REQ; | |
| } | |
| return 0; | |
| } | |
| /*********************************************************************** | |
| * 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 */ ) | |
| { | |
| return ATOM_DeleteAtom( atom, FALSE); | |
| } | |
| /*********************************************************************** | |
| * 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 */ ) | |
| { | |
| return ATOM_DeleteAtom( atom, TRUE ); | |
| } | |
| static ATOM ATOM_FindAtomA( LPCSTR str, BOOL local ) | |
| { | |
| ATOM atom = 0; | |
| if (!ATOM_IsIntAtomA( 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 ); | |
| return 0; | |
| } | |
| SERVER_START_REQ( find_atom ) | |
| { | |
| req->local = local; | |
| wine_server_add_data( req, buffer, len * sizeof(WCHAR) ); | |
| if (!wine_server_call_err(req)) atom = reply->atom; | |
| } | |
| SERVER_END_REQ; | |
| } | |
| TRACE( "(%s) %s -> %x\n", local ? "local" : "global", debugstr_a(str), atom ); | |
| return atom; | |
| } | |
| /*********************************************************************** | |
| * 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 */ ) | |
| { | |
| return ATOM_FindAtomA( str, FALSE ); | |
| } | |
| /*********************************************************************** | |
| * 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 */ ) | |
| { | |
| return ATOM_FindAtomA( str, TRUE ); | |
| } | |
| static ATOM ATOM_FindAtomW( LPCWSTR str, BOOL local ) | |
| { | |
| ATOM atom = 0; | |
| if (!ATOM_IsIntAtomW( str, &atom )) | |
| { | |
| DWORD len = strlenW(str); | |
| if (len > MAX_ATOM_LEN) | |
| { | |
| SetLastError( ERROR_INVALID_PARAMETER ); | |
| return 0; | |
| } | |
| SERVER_START_REQ( find_atom ) | |
| { | |
| wine_server_add_data( req, str, len * sizeof(WCHAR) ); | |
| req->local = local; | |
| if (!wine_server_call_err( req )) atom = reply->atom; | |
| } | |
| SERVER_END_REQ; | |
| } | |
| TRACE( "(%s) %s -> %x\n", local ? "local" : "global", debugstr_w(str), atom ); | |
| return atom; | |
| } | |
| /*********************************************************************** | |
| * GlobalFindAtomW (KERNEL32.@) | |
| * | |
| * Unicode version of GlobalFindAtomA. | |
| */ | |
| ATOM WINAPI GlobalFindAtomW( LPCWSTR str ) | |
| { | |
| return ATOM_FindAtomW( str, FALSE ); | |
| } | |
| /*********************************************************************** | |
| * FindAtomW (KERNEL32.@) | |
| * | |
| * Unicode version of FindAtomA. | |
| */ | |
| ATOM WINAPI FindAtomW( LPCWSTR str ) | |
| { | |
| return ATOM_FindAtomW( str, TRUE ); | |
| } | |
| static UINT ATOM_GetAtomNameA( ATOM atom, LPSTR buffer, INT count, BOOL local ) | |
| { | |
| INT len; | |
| if (count <= 0) | |
| { | |
| SetLastError( ERROR_MORE_DATA ); | |
| return 0; | |
| } | |
| if (atom < MAXINTATOM) | |
| { | |
| char name[8]; | |
| if (!atom) | |
| { | |
| SetLastError( ERROR_INVALID_PARAMETER ); | |
| return 0; | |
| } | |
| len = sprintf( name, "#%d", atom ); | |
| lstrcpynA( buffer, name, count ); | |
| } | |
| else | |
| { | |
| WCHAR full_name[MAX_ATOM_LEN]; | |
| len = 0; | |
| SERVER_START_REQ( get_atom_name ) | |
| { | |
| req->atom = atom; | |
| req->local = local; | |
| wine_server_set_reply( req, full_name, sizeof(full_name) ); | |
| if (!wine_server_call_err( req )) | |
| { | |
| len = WideCharToMultiByte( CP_ACP, 0, full_name, | |
| wine_server_reply_size(reply) / sizeof(WCHAR), | |
| buffer, count - 1, NULL, NULL ); | |
| if (!len) len = count; /* overflow */ | |
| else buffer[len] = 0; | |
| } | |
| } | |
| SERVER_END_REQ; | |
| } | |
| if (len && count <= len) | |
| { | |
| SetLastError( ERROR_MORE_DATA ); | |
| buffer[count-1] = 0; | |
| return 0; | |
| } | |
| TRACE( "(%s) %x -> %s\n", local ? "local" : "global", atom, debugstr_a(buffer) ); | |
| return len; | |
| } | |
| /*********************************************************************** | |
| * 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 */ | |
| { | |
| return ATOM_GetAtomNameA( atom, buffer, count, FALSE ); | |
| } | |
| /*********************************************************************** | |
| * 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 */ | |
| { | |
| return ATOM_GetAtomNameA( atom, buffer, count, TRUE ); | |
| } | |
| static UINT ATOM_GetAtomNameW( ATOM atom, LPWSTR buffer, INT count, BOOL local ) | |
| { | |
| INT len; | |
| if (count <= 0) | |
| { | |
| SetLastError( ERROR_MORE_DATA ); | |
| return 0; | |
| } | |
| if (atom < MAXINTATOM) | |
| { | |
| char name[8]; | |
| if (!atom) | |
| { | |
| SetLastError( ERROR_INVALID_PARAMETER ); | |
| return 0; | |
| } | |
| sprintf( name, "#%d", atom ); | |
| len = MultiByteToWideChar( CP_ACP, 0, name, -1, buffer, count ); | |
| if (!len) buffer[count-1] = 0; /* overflow */ | |
| } | |
| else | |
| { | |
| WCHAR full_name[MAX_ATOM_LEN]; | |
| len = 0; | |
| SERVER_START_REQ( get_atom_name ) | |
| { | |
| req->atom = atom; | |
| req->local = local; | |
| wine_server_set_reply( req, full_name, sizeof(full_name) ); | |
| if (!wine_server_call_err( req )) | |
| { | |
| len = wine_server_reply_size(reply) / sizeof(WCHAR); | |
| if (count > len) count = len + 1; | |
| memcpy( buffer, full_name, (count-1) * sizeof(WCHAR) ); | |
| buffer[count-1] = 0; | |
| } | |
| } | |
| SERVER_END_REQ; | |
| if (!len) return 0; | |
| } | |
| TRACE( "(%s) %x -> %s\n", local ? "local" : "global", atom, debugstr_w(buffer) ); | |
| return len; | |
| } | |
| /*********************************************************************** | |
| * GlobalGetAtomNameW (KERNEL32.@) | |
| * | |
| * Unicode version of GlobalGetAtomNameA. | |
| */ | |
| UINT WINAPI GlobalGetAtomNameW( ATOM atom, LPWSTR buffer, INT count ) | |
| { | |
| return ATOM_GetAtomNameW( atom, buffer, count, FALSE); | |
| } | |
| /*********************************************************************** | |
| * GetAtomNameW (KERNEL32.@) | |
| * | |
| * Unicode version of GetAtomNameA. | |
| */ | |
| UINT WINAPI GetAtomNameW( ATOM atom, LPWSTR buffer, INT count ) | |
| { | |
| return ATOM_GetAtomNameW( atom, buffer, count, TRUE ); | |
| } |