wine/dlls/ntdll/atom.c
2006-05-23 14:11:13 +02:00

448 lines
13 KiB
C

/*
* Atom table functions
*
* Copyright 1993, 1994, 1995 Alexandre Julliard
* Copyright 2004,2005 Eric Pouech
*
* 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 "ntstatus.h"
#define WIN32_NO_STATUS
#include "windef.h"
#include "wine/server.h"
#include "wine/unicode.h"
#include "wine/debug.h"
WINE_DEFAULT_DEBUG_CHANNEL(atom);
#define MAX_ATOM_LEN 255
/******************************************************************
* is_integral_atom
* Returns STATUS_SUCCESS if integral atom and 'pAtom' is filled
* STATUS_INVALID_PARAMETER if 'atomstr' is too long
* STATUS_MORE_ENTRIES otherwise
*/
static NTSTATUS is_integral_atom( LPCWSTR atomstr, size_t len, RTL_ATOM* pAtom )
{
RTL_ATOM atom;
if (HIWORD( atomstr ))
{
const WCHAR* ptr = atomstr;
if (!len) return STATUS_OBJECT_NAME_INVALID;
if (*ptr++ == '#')
{
atom = 0;
while (ptr < atomstr + len && *ptr >= '0' && *ptr <= '9')
{
atom = atom * 10 + *ptr++ - '0';
}
if (ptr > atomstr + 1 && ptr == atomstr + len) goto done;
}
if (len > MAX_ATOM_LEN) return STATUS_INVALID_PARAMETER;
return STATUS_MORE_ENTRIES;
}
else atom = LOWORD( atomstr );
done:
if (!atom || atom >= MAXINTATOM) return STATUS_INVALID_PARAMETER;
*pAtom = atom;
return STATUS_SUCCESS;
}
/******************************************************************
* RtlDeleteAtomFromAtomTable (NTDLL.@)
*/
NTSTATUS WINAPI RtlDeleteAtomFromAtomTable( RTL_ATOM_TABLE table, RTL_ATOM atom )
{
NTSTATUS status;
TRACE( "%p %x\n", table, atom );
if (!table) status = STATUS_INVALID_PARAMETER;
else
{
SERVER_START_REQ( delete_atom )
{
req->atom = atom;
req->table = table;
status = wine_server_call( req );
}
SERVER_END_REQ;
}
return status;
}
/******************************************************************
* integral_atom_name (internal)
*
* Helper for fetching integral (local/global) atoms names.
*/
static ULONG integral_atom_name(WCHAR* buffer, ULONG len, RTL_ATOM atom)
{
static const WCHAR fmt[] = {'#','%','u',0};
WCHAR tmp[16];
int ret;
ret = sprintfW( tmp, fmt, atom );
if (!len) return ret * sizeof(WCHAR);
if (len <= ret) ret = len - 1;
memcpy( buffer, tmp, ret * sizeof(WCHAR) );
buffer[ret] = 0;
return ret * sizeof(WCHAR);
}
/******************************************************************
* RtlQueryAtomInAtomTable (NTDLL.@)
*/
NTSTATUS WINAPI RtlQueryAtomInAtomTable( RTL_ATOM_TABLE table, RTL_ATOM atom, ULONG* ref,
ULONG* pin, WCHAR* name, ULONG* len )
{
NTSTATUS status = STATUS_SUCCESS;
DWORD wlen = 0;
if (!table) status = STATUS_INVALID_PARAMETER;
else if (atom < MAXINTATOM)
{
if (!atom) return STATUS_INVALID_PARAMETER;
if (len) wlen = integral_atom_name( name, *len, atom);
if (ref) *ref = 1;
if (pin) *pin = 1;
}
else
{
SERVER_START_REQ( get_atom_information )
{
req->atom = atom;
req->table = table;
if (len && *len && name)
wine_server_set_reply( req, name, *len );
status = wine_server_call( req );
if (status == STATUS_SUCCESS)
{
wlen = reply->total;
if (ref) *ref = reply->count;
if (pin) *pin = reply->pinned;
}
}
SERVER_END_REQ;
}
if (status == STATUS_SUCCESS && len)
{
if (*len)
{
wlen = min( *len - sizeof(WCHAR), wlen );
if (name) name[wlen / sizeof(WCHAR)] = 0;
}
else status = STATUS_BUFFER_TOO_SMALL;
*len = wlen;
}
TRACE( "%p %x -> %s (%lx)\n",
table, atom, len ? debugstr_wn(name, wlen / sizeof(WCHAR)) : NULL, status );
return status;
}
/******************************************************************
* RtlCreateAtomTable (NTDLL.@)
*/
NTSTATUS WINAPI RtlCreateAtomTable( ULONG size, RTL_ATOM_TABLE* table )
{
NTSTATUS status;
if (*table)
{
if (size) status = STATUS_INVALID_PARAMETER;
else status = STATUS_SUCCESS;
}
else
{
SERVER_START_REQ( init_atom_table )
{
req->entries = size;
status = wine_server_call( req );
*table = reply->table;
}
SERVER_END_REQ;
}
return status;
}
/******************************************************************
* RtlDestroyAtomTable (NTDLL.@)
*/
NTSTATUS WINAPI RtlDestroyAtomTable( RTL_ATOM_TABLE table )
{
if (!table) return STATUS_INVALID_PARAMETER;
return NtClose( (HANDLE)table );
}
/******************************************************************
* RtlAddAtomToAtomTable (NTDLL.@)
*/
NTSTATUS WINAPI RtlAddAtomToAtomTable( RTL_ATOM_TABLE table, const WCHAR* name, RTL_ATOM* atom )
{
NTSTATUS status;
if (!table) status = STATUS_INVALID_PARAMETER;
else
{
size_t len = HIWORD(name) ? strlenW(name) : 0;
status = is_integral_atom( name, len, atom );
if (status == STATUS_MORE_ENTRIES)
{
SERVER_START_REQ( add_atom )
{
wine_server_add_data( req, name, len * sizeof(WCHAR) );
req->table = table;
status = wine_server_call( req );
*atom = reply->atom;
}
SERVER_END_REQ;
}
}
TRACE( "%p %s -> %x\n",
table, debugstr_w(name), status == STATUS_SUCCESS ? *atom : 0 );
return status;
}
/******************************************************************
* RtlLookupAtomInAtomTable (NTDLL.@)
*/
NTSTATUS WINAPI RtlLookupAtomInAtomTable( RTL_ATOM_TABLE table, const WCHAR* name, RTL_ATOM* atom )
{
NTSTATUS status;
if (!table) status = STATUS_INVALID_PARAMETER;
else
{
size_t len = HIWORD(name) ? strlenW(name) : 0;
status = is_integral_atom( name, len, atom );
if (status == STATUS_MORE_ENTRIES)
{
SERVER_START_REQ( find_atom )
{
wine_server_add_data( req, name, len * sizeof(WCHAR) );
req->table = table;
status = wine_server_call( req );
*atom = reply->atom;
}
SERVER_END_REQ;
}
}
TRACE( "%p %s -> %x\n",
table, debugstr_w(name), status == STATUS_SUCCESS ? *atom : 0 );
return status;
}
/******************************************************************
* RtlEmptyAtomTable (NTDLL.@)
*/
NTSTATUS WINAPI RtlEmptyAtomTable( RTL_ATOM_TABLE table, BOOLEAN delete_pinned )
{
NTSTATUS status;
if (!table) status = STATUS_INVALID_PARAMETER;
else
{
SERVER_START_REQ( empty_atom_table )
{
req->table = table;
req->if_pinned = delete_pinned;
status = wine_server_call( req );
}
SERVER_END_REQ;
}
return status;
}
/******************************************************************
* RtlPinAtomInAtomTable (NTDLL.@)
*/
NTSTATUS WINAPI RtlPinAtomInAtomTable( RTL_ATOM_TABLE table, RTL_ATOM atom )
{
NTSTATUS status;
if (!table) return STATUS_INVALID_PARAMETER;
if (atom < MAXINTATOM) return STATUS_SUCCESS;
SERVER_START_REQ( set_atom_information )
{
req->table = table;
req->atom = atom;
req->pinned = TRUE;
status = wine_server_call( req );
}
SERVER_END_REQ;
return status;
}
/*************************************************
* Global handle table management
*************************************************/
/******************************************************************
* NtAddAtom (NTDLL.@)
*/
NTSTATUS WINAPI NtAddAtom( const WCHAR* name, ULONG length, RTL_ATOM* atom )
{
NTSTATUS status;
status = is_integral_atom( name, length / sizeof(WCHAR), atom );
if (status == STATUS_MORE_ENTRIES)
{
SERVER_START_REQ( add_atom )
{
wine_server_add_data( req, name, length );
req->table = NULL;
status = wine_server_call( req );
*atom = reply->atom;
}
SERVER_END_REQ;
}
TRACE( "%s -> %x\n",
debugstr_wn(name, length/sizeof(WCHAR)), status == STATUS_SUCCESS ? *atom : 0 );
return status;
}
/******************************************************************
* NtDeleteAtom (NTDLL.@)
*/
NTSTATUS WINAPI NtDeleteAtom(RTL_ATOM atom)
{
NTSTATUS status;
SERVER_START_REQ( delete_atom )
{
req->atom = atom;
req->table = NULL;
status = wine_server_call( req );
}
SERVER_END_REQ;
return status;
}
/******************************************************************
* NtFindAtom (NTDLL.@)
*/
NTSTATUS WINAPI NtFindAtom( const WCHAR* name, ULONG length, RTL_ATOM* atom )
{
NTSTATUS status;
status = is_integral_atom( name, length / sizeof(WCHAR), atom );
if (status == STATUS_MORE_ENTRIES)
{
SERVER_START_REQ( find_atom )
{
wine_server_add_data( req, name, length );
req->table = NULL;
status = wine_server_call( req );
*atom = reply->atom;
}
SERVER_END_REQ;
}
TRACE( "%s -> %x\n",
debugstr_wn(name, length/sizeof(WCHAR)), status == STATUS_SUCCESS ? *atom : 0 );
return status;
}
/******************************************************************
* NtQueryInformationAtom (NTDLL.@)
*/
NTSTATUS WINAPI NtQueryInformationAtom( RTL_ATOM atom, ATOM_INFORMATION_CLASS class,
PVOID ptr, ULONG size, PULONG psize )
{
NTSTATUS status;
switch (class)
{
case AtomBasicInformation:
{
ULONG name_len;
ATOM_BASIC_INFORMATION* abi = (ATOM_BASIC_INFORMATION*)ptr;
if (size < sizeof(ATOM_BASIC_INFORMATION))
return STATUS_INVALID_PARAMETER;
name_len = size - sizeof(ATOM_BASIC_INFORMATION);
if (atom < MAXINTATOM)
{
if (atom)
{
abi->NameLength = integral_atom_name( abi->Name, name_len, atom );
status = (name_len) ? STATUS_SUCCESS : STATUS_BUFFER_TOO_SMALL;
abi->ReferenceCount = 1;
abi->Pinned = 1;
}
else status = STATUS_INVALID_PARAMETER;
}
else
{
SERVER_START_REQ( get_atom_information )
{
req->atom = atom;
req->table = NULL;
if (name_len) wine_server_set_reply( req, abi->Name, name_len );
status = wine_server_call( req );
if (status == STATUS_SUCCESS)
{
name_len = wine_server_reply_size( reply );
if (name_len)
{
abi->NameLength = name_len;
abi->Name[name_len / sizeof(WCHAR)] = '\0';
}
else
{
name_len = reply->total;
abi->NameLength = name_len;
status = STATUS_BUFFER_TOO_SMALL;
}
abi->ReferenceCount = reply->count;
abi->Pinned = reply->pinned;
}
else name_len = 0;
}
SERVER_END_REQ;
}
TRACE( "%x -> %s (%lu)\n",
atom, debugstr_wn(abi->Name, abi->NameLength / sizeof(WCHAR)),
status );
if (psize)
*psize = sizeof(ATOM_BASIC_INFORMATION) + name_len;
}
break;
default:
FIXME( "Unsupported class %u\n", class );
status = STATUS_INVALID_INFO_CLASS;
break;
}
return status;
}