From 378ff5bb6b360f8b0762c92b1751681a6ee94334 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Herm=C3=A8s=20B=C3=A9lusca-Ma=C3=AFto?= Date: Thu, 14 Sep 2023 12:58:21 +0200 Subject: [PATCH] [WINESYNC] setupapi: Implement a binary compatible string table. wine commit id 8802f84c8cc473d5617c134c16973b1cb2c4b53e by Nikolay Sivov + Compile wine's stringtable.c , but keep ours around for the time being. --- dll/win32/setupapi/CMakeLists.txt | 2 +- dll/win32/setupapi/stringtable_wine.c | 595 ++++++++++++++++++++++++++ sdk/tools/winesync/setupapi.cfg | 2 +- 3 files changed, 597 insertions(+), 2 deletions(-) create mode 100644 dll/win32/setupapi/stringtable_wine.c diff --git a/dll/win32/setupapi/CMakeLists.txt b/dll/win32/setupapi/CMakeLists.txt index 2b3b4bae4a9..967f77922c7 100644 --- a/dll/win32/setupapi/CMakeLists.txt +++ b/dll/win32/setupapi/CMakeLists.txt @@ -25,7 +25,7 @@ list(APPEND SOURCE query.c queue.c setupcab.c - stringtable.c + stringtable_wine.c stubs.c rpc.c) diff --git a/dll/win32/setupapi/stringtable_wine.c b/dll/win32/setupapi/stringtable_wine.c new file mode 100644 index 00000000000..f51bb9e4ed8 --- /dev/null +++ b/dll/win32/setupapi/stringtable_wine.c @@ -0,0 +1,595 @@ +/* + * Setupapi string table functions + * + * Copyright 2005 Eric Kohl + * Copyright 2014 Nikolay Sivov for CodeWeavers + * + * 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 "setupapi_private.h" +#include + + +#define _PSETUP(func) pSetup ## func + +#define StringTableInitialize _PSETUP(StringTableInitialize) +#define StringTableInitializeEx _PSETUP(StringTableInitializeEx) +#define StringTableDestroy _PSETUP(StringTableDestroy) +#define StringTableAddString _PSETUP(StringTableAddString) +#define StringTableAddStringEx _PSETUP(StringTableAddStringEx) +#define StringTableDuplicate _PSETUP(StringTableDuplicate) +#define StringTableGetExtraData _PSETUP(StringTableGetExtraData) +#define StringTableLookUpString _PSETUP(StringTableLookUpString) +#define StringTableLookUpStringEx _PSETUP(StringTableLookUpStringEx) +#define StringTableSetExtraData _PSETUP(StringTableSetExtraData) +#define StringTableStringFromId _PSETUP(StringTableStringFromId) +#define StringTableStringFromIdEx _PSETUP(StringTableStringFromIdEx) +#define StringTableTrim _PSETUP(StringTableTrim) + + +struct stringtable { + char *data; + ULONG nextoffset; + ULONG allocated; + DWORD_PTR unk[2]; + ULONG max_extra_size; + LCID lcid; +}; + +struct stringentry { + DWORD nextoffset; + WCHAR data[1]; +}; + +#define BUCKET_COUNT 509 +#define DEFAULT_ALLOC_SIZE 4096 + +/* + String table details + + Returned string table 'handle' is a pointer to 'struct stringtable' structure. + Data itself is allocated separately, pointer is stored in 'data' field. + + Data starts with array of 509 DWORDs - lookup table. Initially all offsets in that + array are set to -1. Right after lookup table goes data itself, stored in linked lists. + Lookup table offset points to first record of 'struct stringentry' type. When more + than one record is present in a bucket, first record links to next one with 'nextoffset' + field. Last record has nextoffset == -1, same when there's only one record. String data + is placed right after offset, and is followed by extra data. Each record has reserved + 'max_extra_size' bytes to store extra data, it's not compacted in any way. + + A simple hash function is used to determine which bucket a given string belongs to (see below). + + All offsets including returned string ids are relative to 'data' pointer. When table + needs to grow 'allocated' size is doubled, but offsets are always valid and preserved. + +*/ + +static inline DWORD get_string_hash(const WCHAR *str, BOOL case_sensitive) +{ + DWORD hash = 0; + + while (*str) { + WCHAR ch = case_sensitive ? *str : tolowerW(*str); + hash += ch; + if (ch & ~0xff) + hash |= 1; + str++; + } + + return hash % BUCKET_COUNT; +} + +static inline DWORD *get_bucket_ptr(struct stringtable *table, const WCHAR *string, BOOL case_sensitive) +{ + DWORD hash = get_string_hash(string, case_sensitive); + return (DWORD*)(table->data + hash*sizeof(DWORD)); +} + +static inline WCHAR *get_string_ptr(struct stringtable *table, DWORD id) +{ + return (WCHAR*)(table->data + id + sizeof(DWORD)); +} + +static inline char *get_extradata_ptr(struct stringtable *table, DWORD id) +{ + WCHAR *ptrW = get_string_ptr(table, id); + /* skip string itself */ + return (char*)(ptrW + strlenW(ptrW) + 1); +} + +static inline BOOL is_valid_string_id(struct stringtable *table, DWORD id) +{ + return (id >= BUCKET_COUNT*sizeof(DWORD)) && (id < table->allocated); +} + +static inline int get_aligned16_size(int size) +{ + return (size + 15) & ~15; +} + +/************************************************************************** + * StringTableInitializeEx [SETUPAPI.@] + * + * Creates a new string table and initializes it. + * + * PARAMS + * max_extra_size [I] Maximum extra data size + * reserved [I] Unused + * + * RETURNS + * Success: Handle to the string table + * Failure: NULL + */ +HSTRING_TABLE WINAPI StringTableInitializeEx(ULONG max_extra_size, DWORD reserved) +{ + struct stringtable *table; + + TRACE("(%d %x)\n", max_extra_size, reserved); + + table = MyMalloc(sizeof(*table)); + if (!table) return NULL; + + table->allocated = get_aligned16_size(BUCKET_COUNT*sizeof(DWORD) + DEFAULT_ALLOC_SIZE); + table->data = MyMalloc(table->allocated); + if (!table->data) { + MyFree(table); + return NULL; + } + + table->nextoffset = BUCKET_COUNT*sizeof(DWORD); + /* FIXME: actually these two are not zero */ + table->unk[0] = table->unk[1] = 0; + table->max_extra_size = max_extra_size; + table->lcid = GetThreadLocale(); + + /* bucket area is filled with 0xff, actual string data area is zeroed */ + memset(table->data, 0xff, table->nextoffset); + memset(table->data + table->nextoffset, 0, table->allocated - table->nextoffset); + + return (HSTRING_TABLE)table; +} + +/************************************************************************** + * StringTableInitialize [SETUPAPI.@] + * + * Creates a new string table and initializes it. + * + * PARAMS + * None + * + * RETURNS + * Success: Handle to the string table + * Failure: NULL + */ +HSTRING_TABLE WINAPI StringTableInitialize(void) +{ + return StringTableInitializeEx(0, 0); +} + +/************************************************************************** + * StringTableDestroy [SETUPAPI.@] + * + * Destroys a string table. + * + * PARAMS + * hTable [I] Handle to the string table to be destroyed + * + * RETURNS + * None + */ +void WINAPI StringTableDestroy(HSTRING_TABLE hTable) +{ + struct stringtable *table = (struct stringtable*)hTable; + + TRACE("%p\n", table); + + if (!table) + return; + + MyFree(table->data); + MyFree(table); +} + +/************************************************************************** + * StringTableDuplicate [SETUPAPI.@] + * + * Duplicates a given string table. + * + * PARAMS + * hTable [I] Handle to the string table + * + * RETURNS + * Success: Handle to the duplicated string table + * Failure: NULL + * + */ +HSTRING_TABLE WINAPI StringTableDuplicate(HSTRING_TABLE hTable) +{ + struct stringtable *src = (struct stringtable*)hTable, *dest; + + TRACE("%p\n", src); + + if (!src) + return NULL; + + dest = MyMalloc(sizeof(*dest)); + if (!dest) + return NULL; + + *dest = *src; + dest->data = MyMalloc(src->allocated); + if (!dest->data) { + MyFree(dest); + return NULL; + } + + memcpy(dest->data, src->data, src->allocated); + return (HSTRING_TABLE)dest; +} + +/************************************************************************** + * StringTableGetExtraData [SETUPAPI.@] + * + * Retrieves extra data from a given string table entry. + * + * PARAMS + * hTable [I] Handle to the string table + * id [I] String ID + * extra [I] Pointer a buffer that receives the extra data + * extra_size [I] Size of the buffer + * + * RETURNS + * Success: TRUE + * Failure: FALSE + */ +BOOL WINAPI StringTableGetExtraData(HSTRING_TABLE hTable, ULONG id, void *extra, ULONG extra_size) +{ + struct stringtable *table = (struct stringtable*)hTable; + char *extraptr; + + TRACE("%p %u %p %u\n", table, id, extra, extra_size); + + if (!table) + return FALSE; + + if (!is_valid_string_id(table, id)) + return FALSE; + + if (table->max_extra_size > extra_size) + { + ERR("data size is too large\n"); + return FALSE; + } + + extraptr = get_extradata_ptr(table, id); + memcpy(extra, extraptr, extra_size); + return TRUE; +} + +/************************************************************************** + * StringTableLookUpStringEx [SETUPAPI.@] + * + * Searches a string table and extra data for a given string. + * + * PARAMS + * hTable [I] Handle to the string table + * string [I] String to be searched for + * flags [I] Flags + * 1: case sensitive compare + * extra [O] Pointer to the buffer that receives the extra data + * extra_size [I/O] Unused + * + * RETURNS + * Success: String ID + * Failure: -1 + */ +DWORD WINAPI StringTableLookUpStringEx(HSTRING_TABLE hTable, LPWSTR string, DWORD flags, + void *extra, ULONG extra_size) +{ + struct stringtable *table = (struct stringtable*)hTable; + BOOL case_sensitive = flags & 1; + struct stringentry *entry; + DWORD offset; + int cmp; + + TRACE("%p->%p %s %x %p, %x\n", table, table->data, debugstr_w(string), flags, extra, extra_size); + + if (!table) + return -1; + + /* get corresponding offset */ + offset = *get_bucket_ptr(table, string, case_sensitive); + if (offset == -1) + return -1; + + /* now we're at correct bucket, do linear search for string */ + while (1) { + entry = (struct stringentry*)(table->data + offset); + if (case_sensitive) + cmp = lstrcmpW(entry->data, string); + else + cmp = lstrcmpiW(entry->data, string); + if (!cmp) { + if (extra) + memcpy(extra, get_extradata_ptr(table, offset), extra_size); + return offset; + } + + /* last entry */ + if (entry->nextoffset == -1) + return -1; + + offset = entry->nextoffset; + if (offset > table->allocated) + return -1; + } +} + +/************************************************************************** + * StringTableLookUpString [SETUPAPI.@] + * + * Searches a string table for a given string. + * + * PARAMS + * hTable [I] Handle to the string table + * string [I] String to be searched for + * flags [I] Flags + * 1: case sensitive compare + * + * RETURNS + * Success: String ID + * Failure: -1 + */ +DWORD WINAPI StringTableLookUpString(HSTRING_TABLE hTable, LPWSTR string, DWORD flags) +{ + return StringTableLookUpStringEx(hTable, string, flags, NULL, 0); +} + +/************************************************************************** + * StringTableAddStringEx [SETUPAPI.@] + * + * Adds a new string plus extra data to the string table. + * + * PARAMS + * hTable [I] Handle to the string table + * string [I] String to be added to the string table + * flags [I] Flags + * 1: case sensitive compare + * extra [I] Pointer to the extra data + * extra_size [I] Size of the extra data + * + * RETURNS + * Success: String ID + * Failure: -1 + * + * NOTES + * If the given string already exists in the string table it will not + * be added again. The ID of the existing string will be returned in + * this case. + */ +DWORD WINAPI StringTableAddStringEx(HSTRING_TABLE hTable, LPWSTR string, + DWORD flags, void *extra, DWORD extra_size) +{ + struct stringtable *table = (struct stringtable*)hTable; + BOOL case_sensitive = flags & 1; + struct stringentry *entry; + DWORD id, *offset; + WCHAR *ptrW; + int len; + + TRACE("%p %s %x %p, %u\n", hTable, debugstr_w(string), flags, extra, extra_size); + + if (!table) + return -1; + + id = StringTableLookUpStringEx(hTable, string, flags, NULL, 0); + if (id != -1) + return id; + + /* needed space for new record */ + len = sizeof(DWORD) + (strlenW(string)+1)*sizeof(WCHAR) + table->max_extra_size; + if (table->nextoffset + len >= table->allocated) { + table->allocated <<= 1; + table->data = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, table->data, table->allocated); + } + + /* hash string */ + offset = get_bucket_ptr(table, string, case_sensitive); + if (*offset == -1) + /* bucket used for a very first time */ + *offset = table->nextoffset; + else { + entry = (struct stringentry*)(table->data + *offset); + /* link existing last entry to newly added */ + while (entry->nextoffset != -1) + entry = (struct stringentry*)(table->data + entry->nextoffset); + entry->nextoffset = table->nextoffset; + } + entry = (struct stringentry*)(table->data + table->nextoffset); + entry->nextoffset = -1; + id = table->nextoffset; + + /* copy string */ + ptrW = get_string_ptr(table, id); + strcpyW(ptrW, string); + if (!case_sensitive) + strlwrW(ptrW); + + /* copy extra data */ + if (extra) + memcpy(get_extradata_ptr(table, id), extra, extra_size); + + table->nextoffset += len; + return id; +} + +/************************************************************************** + * StringTableAddString [SETUPAPI.@] + * + * Adds a new string to the string table. + * + * PARAMS + * hTable [I] Handle to the string table + * string [I] String to be added to the string table + * flags [I] Flags + * 1: case sensitive compare + * + * RETURNS + * Success: String ID + * Failure: -1 + * + * NOTES + * If the given string already exists in the string table it will not + * be added again. The ID of the existing string will be returned in + * this case. + */ +DWORD WINAPI StringTableAddString(HSTRING_TABLE hTable, LPWSTR string, DWORD flags) +{ + return StringTableAddStringEx(hTable, string, flags, NULL, 0); +} + +/************************************************************************** + * StringTableSetExtraData [SETUPAPI.@] + * + * Sets extra data for a given string table entry. + * + * PARAMS + * hTable [I] Handle to the string table + * id [I] String ID + * extra [I] Pointer to the extra data + * extra_size [I] Size of the extra data + * + * RETURNS + * Success: TRUE + * Failure: FALSE + */ +BOOL WINAPI StringTableSetExtraData(HSTRING_TABLE hTable, DWORD id, void *extra, ULONG extra_size) +{ + struct stringtable *table = (struct stringtable*)hTable; + char *extraptr; + + TRACE("%p %d %p %u\n", hTable, id, extra, extra_size); + + if (!table) + return FALSE; + + if (!is_valid_string_id(table, id)) + return FALSE; + + if (table->max_extra_size < extra_size) + { + ERR("data size is too large\n"); + return FALSE; + } + + extraptr = get_extradata_ptr(table, id); + memset(extraptr, 0, table->max_extra_size); + memcpy(extraptr, extra, extra_size); + + return TRUE; +} + +/************************************************************************** + * StringTableStringFromId [SETUPAPI.@] + * + * Returns a pointer to a string for the given string ID. + * + * PARAMS + * hTable [I] Handle to the string table. + * id [I] String ID + * + * RETURNS + * Success: Pointer to the string + * Failure: NULL + */ +LPWSTR WINAPI StringTableStringFromId(HSTRING_TABLE hTable, ULONG id) +{ + struct stringtable *table = (struct stringtable*)hTable; + static WCHAR empty[] = {0}; + + TRACE("%p %d\n", table, id); + + if (!table) + return NULL; + + if (!is_valid_string_id(table, id)) + return empty; + + return get_string_ptr(table, id); +} + +/************************************************************************** + * StringTableStringFromIdEx [SETUPAPI.@] + * + * Returns a string for the given string ID. + * + * PARAMS + * hTable [I] Handle to the string table + * id [I] String ID + * buff [I] Pointer to string buffer + * buflen [I/O] Pointer to the size of the string buffer + * + * RETURNS + * Success: TRUE + * Failure: FALSE + */ +BOOL WINAPI StringTableStringFromIdEx(HSTRING_TABLE hTable, ULONG id, LPWSTR buff, DWORD *buflen) +{ + struct stringtable *table = (struct stringtable*)hTable; + BOOL ret = TRUE; + WCHAR *ptrW; + int len; + + TRACE("%p %x %p %p\n", table, id, buff, buflen); + + if (!table) { + *buflen = 0; + return FALSE; + } + + if (!is_valid_string_id(table, id)) { + WARN("invalid string id\n"); + *buflen = 0; + return FALSE; + } + + ptrW = get_string_ptr(table, id); + len = (strlenW(ptrW) + 1)*sizeof(WCHAR); + if (len <= *buflen) + strcpyW(buff, ptrW); + else + ret = FALSE; + + *buflen = len; + return ret; +} + +/************************************************************************** + * StringTableTrim [SETUPAPI.@] + * + * ... + * + * PARAMS + * hTable [I] Handle to the string table + * + * RETURNS + * None + */ +void WINAPI StringTableTrim(HSTRING_TABLE hTable) +{ + FIXME("%p\n", hTable); +} diff --git a/sdk/tools/winesync/setupapi.cfg b/sdk/tools/winesync/setupapi.cfg index af142af1799..f8f252e461c 100644 --- a/sdk/tools/winesync/setupapi.cfg +++ b/sdk/tools/winesync/setupapi.cfg @@ -3,4 +3,4 @@ files: dlls/setupapi/queue.c: dll/win32/setupapi/queue.c dlls/setupapi/stringtable.c: dll/win32/setupapi/stringtable_wine.c tags: - wine: wine-1.7.18 + wine: 8802f84c8cc473d5617c134c16973b1cb2c4b53e