Commit 8802f84c authored by Nikolay Sivov's avatar Nikolay Sivov Committed by Alexandre Julliard

setupapi: Implement a binary compatible string table.

parent 351fae12
......@@ -2,6 +2,7 @@
* 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
......@@ -19,88 +20,103 @@
*/
#include "config.h"
#include "wine/port.h"
#include <stdarg.h>
#include "windef.h"
#include "winbase.h"
#include "wingdi.h"
#include "winuser.h"
#include "winreg.h"
#include "winnls.h"
#include "setupapi.h"
#include "wine/debug.h"
#define TABLE_DEFAULT_SIZE 256
#include "wine/unicode.h"
WINE_DEFAULT_DEBUG_CHANNEL(setupapi);
DECLARE_HANDLE(HSTRING_TABLE);
typedef struct _TABLE_SLOT
{
LPWSTR pString;
LPVOID pData;
DWORD dwSize;
} TABLE_SLOT, *PTABLE_SLOT;
struct stringtable {
char *data;
ULONG nextoffset;
ULONG allocated;
DWORD_PTR unk[2];
ULONG max_extra_size;
LCID lcid;
};
typedef struct _STRING_TABLE
{
PTABLE_SLOT pSlots;
DWORD dwUsedSlots;
DWORD dwMaxSlots;
DWORD dwMaxDataSize;
} STRING_TABLE, *PSTRING_TABLE;
struct stringentry {
DWORD nextoffset;
WCHAR data[1];
};
#define BUCKET_COUNT 509
#define DEFAULT_ALLOC_SIZE 4096
/**************************************************************************
* 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)
{
PSTRING_TABLE pStringTable;
/*
String table details
TRACE("\n");
Returned string table 'handle' is a pointer to 'struct stringtable' structure.
Data itself is allocated separately, pointer is stored in 'data' field.
pStringTable = MyMalloc(sizeof(STRING_TABLE));
if (pStringTable == NULL)
{
ERR("Invalid hStringTable!\n");
return NULL;
}
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.
memset(pStringTable, 0, sizeof(STRING_TABLE));
A simple hash function is used to determine which bucket a given string belongs to (see below).
pStringTable->pSlots = MyMalloc(sizeof(TABLE_SLOT) * TABLE_DEFAULT_SIZE);
if (pStringTable->pSlots == NULL)
{
MyFree(pStringTable);
return NULL;
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++;
}
memset(pStringTable->pSlots, 0, sizeof(TABLE_SLOT) * TABLE_DEFAULT_SIZE);
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));
}
pStringTable->dwUsedSlots = 0;
pStringTable->dwMaxSlots = TABLE_DEFAULT_SIZE;
pStringTable->dwMaxDataSize = 0;
static inline WCHAR *get_string_ptr(struct stringtable *table, DWORD id)
{
return (WCHAR*)(table->data + id + sizeof(DWORD));
}
TRACE("Done\n");
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);
}
return (HSTRING_TABLE)pStringTable;
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.@]
......@@ -108,433 +124,340 @@ StringTableInitialize(VOID)
* Creates a new string table and initializes it.
*
* PARAMS
* dwMaxExtraDataSize [I] Maximum extra data size
* dwReserved [I] Unused
* max_extra_size [I] Maximum extra data size
* reserved [I] Unused
*
* RETURNS
* Success: Handle to the string table
* Failure: NULL
*/
HSTRING_TABLE WINAPI
StringTableInitializeEx(DWORD dwMaxExtraDataSize,
DWORD dwReserved)
HSTRING_TABLE WINAPI StringTableInitializeEx(ULONG max_extra_size, DWORD reserved)
{
PSTRING_TABLE pStringTable;
TRACE("\n");
struct stringtable *table;
pStringTable = MyMalloc(sizeof(STRING_TABLE));
if (pStringTable == NULL) return NULL;
TRACE("(%d %x)\n", max_extra_size, reserved);
memset(pStringTable, 0, sizeof(STRING_TABLE));
table = MyMalloc(sizeof(*table));
if (!table) return NULL;
pStringTable->pSlots = MyMalloc(sizeof(TABLE_SLOT) * TABLE_DEFAULT_SIZE);
if (pStringTable->pSlots == NULL)
{
MyFree(pStringTable);
table->allocated = get_aligned16_size(BUCKET_COUNT*sizeof(DWORD) + DEFAULT_ALLOC_SIZE);
table->data = MyMalloc(table->allocated);
if (!table->data) {
MyFree(table);
return NULL;
}
memset(pStringTable->pSlots, 0, sizeof(TABLE_SLOT) * TABLE_DEFAULT_SIZE);
pStringTable->dwUsedSlots = 0;
pStringTable->dwMaxSlots = TABLE_DEFAULT_SIZE;
pStringTable->dwMaxDataSize = dwMaxExtraDataSize;
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();
TRACE("Done\n");
/* 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)pStringTable;
return (HSTRING_TABLE)table;
}
/**************************************************************************
* StringTableDestroy [SETUPAPI.@]
* StringTableInitialize [SETUPAPI.@]
*
* Destroys a string table.
* Creates a new string table and initializes it.
*
* PARAMS
* hStringTable [I] Handle to the string table to be destroyed
* None
*
* RETURNS
* None
* Success: Handle to the string table
* Failure: NULL
*/
VOID WINAPI
StringTableDestroy(HSTRING_TABLE hStringTable)
HSTRING_TABLE WINAPI StringTableInitialize(void)
{
PSTRING_TABLE pStringTable;
DWORD i;
TRACE("%p\n", hStringTable);
pStringTable = (PSTRING_TABLE)hStringTable;
if (pStringTable == NULL)
return;
if (pStringTable->pSlots != NULL)
{
for (i = 0; i < pStringTable->dwMaxSlots; i++)
{
MyFree(pStringTable->pSlots[i].pString);
pStringTable->pSlots[i].pString = NULL;
MyFree(pStringTable->pSlots[i].pData);
pStringTable->pSlots[i].pData = NULL;
pStringTable->pSlots[i].dwSize = 0;
}
MyFree(pStringTable->pSlots);
}
MyFree(pStringTable);
return StringTableInitializeEx(0, 0);
}
/**************************************************************************
* StringTableAddStringEx [SETUPAPI.@]
* StringTableDestroy [SETUPAPI.@]
*
* Adds a new string plus extra data to the string table.
* Destroys a string table.
*
* PARAMS
* hStringTable [I] Handle to the string table
* lpString [I] String to be added to the string table
* dwFlags [I] Flags
* 1: case sensitive compare
* lpExtraData [I] Pointer to the extra data
* dwExtraDataSize [I] Size of the extra data
* hTable [I] Handle to the string table to be destroyed
*
* RETURNS
* Success: String ID
* Failure: ~0u
*
* 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.
* None
*/
DWORD WINAPI
StringTableAddStringEx(HSTRING_TABLE hStringTable, LPWSTR lpString,
DWORD dwFlags, LPVOID lpExtraData, DWORD dwExtraDataSize)
void WINAPI StringTableDestroy(HSTRING_TABLE hTable)
{
PSTRING_TABLE pStringTable;
DWORD i;
TRACE("%p %s %x %p, %u\n", hStringTable, debugstr_w(lpString), dwFlags,
lpExtraData, dwExtraDataSize);
pStringTable = (PSTRING_TABLE)hStringTable;
if (!pStringTable)
{
ERR("Invalid hStringTable!\n");
return ~0u;
}
/* Search for existing string in the string table */
for (i = 0; i < pStringTable->dwMaxSlots; i++)
{
if (pStringTable->pSlots[i].pString)
{
if (dwFlags & 1)
{
if (!lstrcmpW(pStringTable->pSlots[i].pString, lpString))
return i + 1;
}
else
{
if (!lstrcmpiW(pStringTable->pSlots[i].pString, lpString))
return i + 1;
}
}
}
struct stringtable *table = (struct stringtable*)hTable;
/* Check for filled slot table */
if (pStringTable->dwUsedSlots == pStringTable->dwMaxSlots)
{
FIXME("Resize the string table!\n");
return ~0u;
}
TRACE("%p\n", table);
/* Search for an empty slot */
for (i = 0; i < pStringTable->dwMaxSlots; i++)
{
if (!pStringTable->pSlots[i].pString)
{
pStringTable->pSlots[i].pString = MyMalloc((lstrlenW(lpString) + 1) * sizeof(WCHAR));
if (!pStringTable->pSlots[i].pString)
{
WARN("Couldn't allocate memory for a new string!\n");
return ~0u;
}
lstrcpyW(pStringTable->pSlots[i].pString, lpString);
if (!table)
return;
pStringTable->pSlots[i].pData = MyMalloc(dwExtraDataSize);
if (!pStringTable->pSlots[i].pData)
{
TRACE("Couldn't allocate memory for data!\n");
return ~0u;
}
memcpy(pStringTable->pSlots[i].pData, lpExtraData, dwExtraDataSize);
pStringTable->pSlots[i].dwSize = dwExtraDataSize;
pStringTable->dwUsedSlots++;
return i + 1;
}
}
TRACE("Couldn't find an empty slot!\n");
return ~0u;
MyFree(table->data);
MyFree(table);
}
/**************************************************************************
* StringTableAddString [SETUPAPI.@]
*
* Adds a new string to the string table.
*
* PARAMS
* hStringTable [I] Handle to the string table
* lpString [I] String to be added to the string table
* dwFlags [I] Flags
* 1: case sensitive compare
*
* RETURNS
* Success: String ID
* Failure: ~0u
*
* 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 hStringTable, LPWSTR lpString, DWORD dwFlags)
{
return StringTableAddStringEx(hStringTable, lpString, dwFlags, NULL, 0);
}
/**************************************************************************
* StringTableDuplicate [SETUPAPI.@]
*
* Duplicates a given string table.
*
* PARAMS
* hStringTable [I] Handle to the string table
* hTable [I] Handle to the string table
*
* RETURNS
* Success: Handle to the duplicated string table
* Failure: NULL
*
*/
HSTRING_TABLE WINAPI
StringTableDuplicate(HSTRING_TABLE hStringTable)
HSTRING_TABLE WINAPI StringTableDuplicate(HSTRING_TABLE hTable)
{
PSTRING_TABLE pSourceTable;
PSTRING_TABLE pDestinationTable;
DWORD i;
DWORD length;
struct stringtable *src = (struct stringtable*)hTable, *dest;
TRACE("%p\n", hStringTable);
TRACE("%p\n", src);
pSourceTable = (PSTRING_TABLE)hStringTable;
if (pSourceTable == NULL)
{
ERR("Invalid hStringTable!\n");
if (!src)
return NULL;
}
pDestinationTable = MyMalloc(sizeof(STRING_TABLE));
if (pDestinationTable == NULL)
{
ERR("Could not allocate a new string table!\n");
dest = MyMalloc(sizeof(*dest));
if (!dest)
return NULL;
}
memset(pDestinationTable, 0, sizeof(STRING_TABLE));
pDestinationTable->pSlots = MyMalloc(sizeof(TABLE_SLOT) * pSourceTable->dwMaxSlots);
if (pDestinationTable->pSlots == NULL)
{
MyFree(pDestinationTable);
*dest = *src;
dest->data = MyMalloc(src->allocated);
if (!dest->data) {
MyFree(dest);
return NULL;
}
memset(pDestinationTable->pSlots, 0, sizeof(TABLE_SLOT) * pSourceTable->dwMaxSlots);
pDestinationTable->dwUsedSlots = 0;
pDestinationTable->dwMaxSlots = pSourceTable->dwMaxSlots;
for (i = 0; i < pSourceTable->dwMaxSlots; i++)
{
if (pSourceTable->pSlots[i].pString != NULL)
{
length = (lstrlenW(pSourceTable->pSlots[i].pString) + 1) * sizeof(WCHAR);
pDestinationTable->pSlots[i].pString = MyMalloc(length);
if (pDestinationTable->pSlots[i].pString != NULL)
{
memcpy(pDestinationTable->pSlots[i].pString,
pSourceTable->pSlots[i].pString,
length);
pDestinationTable->dwUsedSlots++;
}
if (pSourceTable->pSlots[i].pData != NULL)
{
length = pSourceTable->pSlots[i].dwSize;
pDestinationTable->pSlots[i].pData = MyMalloc(length);
if (pDestinationTable->pSlots[i].pData)
{
memcpy(pDestinationTable->pSlots[i].pData,
pSourceTable->pSlots[i].pData,
length);
pDestinationTable->pSlots[i].dwSize = length;
}
}
}
}
return (HSTRING_TABLE)pDestinationTable;
memcpy(dest->data, src->data, src->allocated);
return (HSTRING_TABLE)dest;
}
/**************************************************************************
* StringTableGetExtraData [SETUPAPI.@]
*
* Retrieves extra data from a given string table entry.
*
* PARAMS
* hStringTable [I] Handle to the string table
* dwId [I] String ID
* lpExtraData [I] Pointer a buffer that receives the extra data
* dwExtraDataSize [I] Size of the buffer
* 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 hStringTable,
DWORD dwId,
LPVOID lpExtraData,
DWORD dwExtraDataSize)
BOOL WINAPI StringTableGetExtraData(HSTRING_TABLE hTable, ULONG id, void *extra, ULONG extra_size)
{
PSTRING_TABLE pStringTable;
struct stringtable *table = (struct stringtable*)hTable;
char *extraptr;
TRACE("%p %x %p %u\n",
hStringTable, dwId, lpExtraData, dwExtraDataSize);
TRACE("%p %u %p %u\n", table, id, extra, extra_size);
pStringTable = (PSTRING_TABLE)hStringTable;
if (pStringTable == NULL)
{
ERR("Invalid hStringTable!\n");
if (!table)
return FALSE;
}
if (dwId == 0 || dwId > pStringTable->dwMaxSlots)
{
ERR("Invalid Slot id!\n");
if (!is_valid_string_id(table, id))
return FALSE;
}
if (pStringTable->pSlots[dwId - 1].dwSize > dwExtraDataSize)
if (table->max_extra_size > extra_size)
{
ERR("Data size is too large!\n");
ERR("data size is too large\n");
return FALSE;
}
memcpy(lpExtraData,
pStringTable->pSlots[dwId - 1].pData,
dwExtraDataSize);
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
* hStringTable [I] Handle to the string table
* lpString [I] String to be searched for
* dwFlags [I] Flags
* hTable [I] Handle to the string table
* string [I] String to be searched for
* flags [I] Flags
* 1: case sensitive compare
* lpExtraData [O] Pointer to the buffer that receives the extra data
* dwReserved [I/O] Unused
* 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 hStringTable,
LPWSTR lpString,
DWORD dwFlags,
LPVOID lpExtraData,
DWORD dwReserved)
DWORD WINAPI StringTableLookUpStringEx(HSTRING_TABLE hTable, LPWSTR string, DWORD flags,
void *extra, ULONG extra_size)
{
PSTRING_TABLE pStringTable;
DWORD i;
TRACE("%p %s %x %p, %x\n", hStringTable, debugstr_w(lpString), dwFlags,
lpExtraData, dwReserved);
pStringTable = (PSTRING_TABLE)hStringTable;
if (pStringTable == NULL)
{
ERR("Invalid hStringTable!\n");
return ~0u;
}
/* Search for existing string in the string table */
for (i = 0; i < pStringTable->dwMaxSlots; i++)
{
if (pStringTable->pSlots[i].pString != NULL)
{
if (dwFlags & 1)
{
if (!lstrcmpW(pStringTable->pSlots[i].pString, lpString))
{
if (lpExtraData)
memcpy(lpExtraData, pStringTable->pSlots[i].pData, dwReserved);
return i + 1;
}
}
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
{
if (!lstrcmpiW(pStringTable->pSlots[i].pString, lpString))
{
if (lpExtraData)
memcpy(lpExtraData, pStringTable->pSlots[i].pData, dwReserved);
return i + 1;
}
}
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;
}
return ~0u;
}
/**************************************************************************
* StringTableLookUpString [SETUPAPI.@]
*
* Searches a string table for a given string.
*
* PARAMS
* hStringTable [I] Handle to the string table
* lpString [I] String to be searched for
* dwFlags [I] Flags
* 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: ~0u
* Failure: -1
*/
DWORD WINAPI
StringTableLookUpString(HSTRING_TABLE hStringTable,
LPWSTR lpString,
DWORD dwFlags)
DWORD WINAPI StringTableLookUpString(HSTRING_TABLE hTable, LPWSTR string, DWORD flags)
{
return StringTableLookUpStringEx(hStringTable, lpString, dwFlags, NULL, 0);
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.@]
......@@ -542,166 +465,128 @@ StringTableLookUpString(HSTRING_TABLE hStringTable,
* Sets extra data for a given string table entry.
*
* PARAMS
* hStringTable [I] Handle to the string table
* dwId [I] String ID
* lpExtraData [I] Pointer to the extra data
* dwExtraDataSize [I] Size of the extra data
* 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 hStringTable,
DWORD dwId,
LPVOID lpExtraData,
DWORD dwExtraDataSize)
BOOL WINAPI StringTableSetExtraData(HSTRING_TABLE hTable, DWORD id, void *extra, ULONG extra_size)
{
PSTRING_TABLE pStringTable;
struct stringtable *table = (struct stringtable*)hTable;
char *extraptr;
TRACE("%p %x %p %u\n",
hStringTable, dwId, lpExtraData, dwExtraDataSize);
TRACE("%p %d %p %u\n", hTable, id, extra, extra_size);
pStringTable = (PSTRING_TABLE)hStringTable;
if (pStringTable == NULL)
{
ERR("Invalid hStringTable!\n");
if (!table)
return FALSE;
}
if (dwId == 0 || dwId > pStringTable->dwMaxSlots)
{
ERR("Invalid Slot id!\n");
if (!is_valid_string_id(table, id))
return FALSE;
}
if (pStringTable->dwMaxDataSize < dwExtraDataSize)
if (table->max_extra_size < extra_size)
{
ERR("Data size is too large!\n");
ERR("data size is too large\n");
return FALSE;
}
pStringTable->pSlots[dwId - 1].pData = MyMalloc(dwExtraDataSize);
if (pStringTable->pSlots[dwId - 1].pData == NULL)
{
ERR("\n");
return FALSE;
}
memcpy(pStringTable->pSlots[dwId - 1].pData,
lpExtraData,
dwExtraDataSize);
pStringTable->pSlots[dwId - 1].dwSize = dwExtraDataSize;
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
* hStringTable [I] Handle to the string table.
* dwId [I] String ID
* hTable [I] Handle to the string table.
* id [I] String ID
*
* RETURNS
* Success: Pointer to the string
* Failure: NULL
*/
LPWSTR WINAPI
StringTableStringFromId(HSTRING_TABLE hStringTable,
DWORD dwId)
LPWSTR WINAPI StringTableStringFromId(HSTRING_TABLE hTable, ULONG id)
{
PSTRING_TABLE pStringTable;
struct stringtable *table = (struct stringtable*)hTable;
static WCHAR empty[] = {0};
TRACE("%p %x\n", hStringTable, dwId);
TRACE("%p %d\n", table, id);
pStringTable = (PSTRING_TABLE)hStringTable;
if (pStringTable == NULL)
{
ERR("Invalid hStringTable!\n");
if (!table)
return NULL;
}
if (dwId == 0 || dwId > pStringTable->dwMaxSlots)
if (!is_valid_string_id(table, id))
return empty;
return pStringTable->pSlots[dwId - 1].pString;
return get_string_ptr(table, id);
}
/**************************************************************************
* StringTableStringFromIdEx [SETUPAPI.@]
*
* Returns a string for the given string ID.
*
* PARAMS
* hStringTable [I] Handle to the string table
* dwId [I] String ID
* lpBuffer [I] Pointer to string buffer
* lpBufferSize [I/O] Pointer to the size of the string buffer
* 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 hStringTable,
DWORD dwId,
LPWSTR lpBuffer,
LPDWORD lpBufferLength)
BOOL WINAPI StringTableStringFromIdEx(HSTRING_TABLE hTable, ULONG id, LPWSTR buff, DWORD *buflen)
{
PSTRING_TABLE pStringTable;
DWORD dwLength;
BOOL bResult = FALSE;
struct stringtable *table = (struct stringtable*)hTable;
BOOL ret = TRUE;
WCHAR *ptrW;
int len;
TRACE("%p %x %p %p\n", hStringTable, dwId, lpBuffer, lpBufferLength);
TRACE("%p %x %p %p\n", table, id, buff, buflen);
pStringTable = (PSTRING_TABLE)hStringTable;
if (pStringTable == NULL)
{
ERR("Invalid hStringTable!\n");
*lpBufferLength = 0;
if (!table) {
*buflen = 0;
return FALSE;
}
if (dwId == 0 || dwId > pStringTable->dwMaxSlots ||
pStringTable->pSlots[dwId - 1].pString == NULL)
{
WARN("Invalid string ID!\n");
*lpBufferLength = 0;
if (!is_valid_string_id(table, id)) {
WARN("invalid string id\n");
*buflen = 0;
return FALSE;
}
dwLength = (lstrlenW(pStringTable->pSlots[dwId - 1].pString) + 1) * sizeof(WCHAR);
if (dwLength <= *lpBufferLength)
{
lstrcpyW(lpBuffer, pStringTable->pSlots[dwId - 1].pString);
bResult = TRUE;
}
*lpBufferLength = dwLength;
ptrW = get_string_ptr(table, id);
len = (strlenW(ptrW) + 1)*sizeof(WCHAR);
if (len <= *buflen)
strcpyW(buff, ptrW);
else
ret = FALSE;
return bResult;
*buflen = len;
return ret;
}
/**************************************************************************
* StringTableTrim [SETUPAPI.@]
*
* ...
*
* PARAMS
* hStringTable [I] Handle to the string table
* hTable [I] Handle to the string table
*
* RETURNS
* None
*/
VOID WINAPI
StringTableTrim(HSTRING_TABLE hStringTable)
void WINAPI StringTableTrim(HSTRING_TABLE hTable)
{
FIXME("%p\n", hStringTable);
FIXME("%p\n", hTable);
}
......@@ -29,11 +29,11 @@
#include "wingdi.h"
#include "winuser.h"
#include "winreg.h"
#include "winnls.h"
#include "setupapi.h"
#include "wine/test.h"
DECLARE_HANDLE(HSTRING_TABLE);
/* Flags for StringTableAddString and StringTableLookUpString */
......@@ -48,57 +48,35 @@ static HSTRING_TABLE (WINAPI *pStringTableInitializeEx)(DWORD, DWORD);
static DWORD (WINAPI *pStringTableLookUpString)(HSTRING_TABLE, LPWSTR, DWORD);
static DWORD (WINAPI *pStringTableLookUpStringEx)(HSTRING_TABLE, LPWSTR, DWORD, LPVOID, DWORD);
static LPWSTR (WINAPI *pStringTableStringFromId)(HSTRING_TABLE, DWORD);
static BOOL (WINAPI *pStringTableGetExtraData)(HSTRING_TABLE, ULONG, void*, ULONG);
static HMODULE hdll;
static WCHAR string[] = {'s','t','r','i','n','g',0};
static WCHAR String[] = {'S','t','r','i','n','g',0};
static WCHAR foo[] = {'f','o','o',0};
static void load_it_up(void)
{
hdll = GetModuleHandleA("setupapi.dll");
pStringTableInitialize = (void*)GetProcAddress(hdll, "StringTableInitialize");
if (!pStringTableInitialize)
pStringTableInitialize = (void*)GetProcAddress(hdll, "pSetupStringTableInitialize");
pStringTableInitializeEx = (void*)GetProcAddress(hdll, "StringTableInitializeEx");
if (!pStringTableInitializeEx)
pStringTableInitializeEx = (void*)GetProcAddress(hdll, "pSetupStringTableInitializeEx");
pStringTableAddString = (void*)GetProcAddress(hdll, "StringTableAddString");
if (!pStringTableAddString)
pStringTableAddString = (void*)GetProcAddress(hdll, "pSetupStringTableAddString");
pStringTableAddStringEx = (void*)GetProcAddress(hdll, "StringTableAddStringEx");
if (!pStringTableAddStringEx)
pStringTableAddStringEx = (void*)GetProcAddress(hdll, "pSetupStringTableAddStringEx");
pStringTableDuplicate = (void*)GetProcAddress(hdll, "StringTableDuplicate");
if (!pStringTableDuplicate)
pStringTableDuplicate = (void*)GetProcAddress(hdll, "pSetupStringTableDuplicate");
pStringTableDestroy = (void*)GetProcAddress(hdll, "StringTableDestroy");
if (!pStringTableDestroy)
pStringTableDestroy = (void*)GetProcAddress(hdll, "pSetupStringTableDestroy");
pStringTableLookUpString = (void*)GetProcAddress(hdll, "StringTableLookUpString");
if (!pStringTableLookUpString)
pStringTableLookUpString = (void*)GetProcAddress(hdll, "pSetupStringTableLookUpString");
pStringTableLookUpStringEx = (void*)GetProcAddress(hdll, "StringTableLookUpStringEx");
if (!pStringTableLookUpStringEx)
pStringTableLookUpStringEx = (void*)GetProcAddress(hdll, "pSetupStringTableLookUpStringEx");
pStringTableStringFromId = (void*)GetProcAddress(hdll, "StringTableStringFromId");
if (!pStringTableStringFromId)
pStringTableStringFromId = (void*)GetProcAddress(hdll, "pSetupStringTableStringFromId");
HMODULE hdll = GetModuleHandleA("setupapi.dll");
#define X(f) if (!(p##f = (void*)GetProcAddress(hdll, #f))) \
p##f = (void*)GetProcAddress(hdll, "pSetup"#f);
X(StringTableInitialize);
X(StringTableInitializeEx);
X(StringTableAddString);
X(StringTableAddStringEx);
X(StringTableDuplicate);
X(StringTableDestroy);
X(StringTableLookUpString);
X(StringTableLookUpStringEx);
X(StringTableStringFromId);
X(StringTableGetExtraData);
#undef X
}
static void test_StringTableAddString(void)
{
DWORD retval, hstring, hString, hfoo;
HANDLE table;
HSTRING_TABLE table;
table = pStringTableInitialize();
ok(table != NULL, "failed to initialize string table\n");
......@@ -124,22 +102,23 @@ static void test_StringTableAddString(void)
static void test_StringTableAddStringEx(void)
{
DWORD retval, hstring, hString, hfoo;
DWORD retval, hstring, hString, hfoo, extra;
HANDLE table;
BOOL ret;
table = pStringTableInitialize();
ok(table != NULL,"Failed to Initialize String Table\n");
/* case insensitive */
hstring = pStringTableAddStringEx(table, string, 0, NULL, 0);
ok(hstring != ~0u, "Failed to add string to String Table\n");
ok(hstring != -1, "Failed to add string to String Table\n");
retval = pStringTableAddStringEx(table, String, 0, NULL, 0);
ok(retval != ~0u, "Failed to add String to String Table\n");
ok(retval != -1, "Failed to add String to String Table\n");
ok(hstring == retval, "string handle %x != String handle %x in String Table\n", hstring, retval);
hfoo = pStringTableAddStringEx(table, foo, 0, NULL, 0);
ok(hfoo != ~0u, "Failed to add foo to String Table\n");
ok(hfoo != -1, "Failed to add foo to String Table\n");
ok(hfoo != hstring, "foo and string share the same ID %x in String Table\n", hfoo);
/* case sensitive */
......@@ -147,11 +126,33 @@ static void test_StringTableAddStringEx(void)
ok(hstring != hString, "String handle and string share same ID %x in Table\n", hstring);
pStringTableDestroy(table);
/* set same string twice but with different extra */
table = pStringTableInitializeEx(4, 0);
ok(table != NULL, "Failed to Initialize String Table\n");
extra = 10;
hstring = pStringTableAddStringEx(table, string, 0, &extra, 4);
ok(hstring != -1, "failed to add string, %d\n", hstring);
extra = 0;
ret = pStringTableGetExtraData(table, hstring, &extra, 4);
ok(ret && extra == 10, "got %d, extra %d\n", ret, extra);
extra = 11;
hstring = pStringTableAddStringEx(table, string, 0, &extra, 4);
ok(hstring != -1, "failed to add string, %d\n", hstring);
extra = 0;
ret = pStringTableGetExtraData(table, hstring, &extra, 4);
ok(ret && extra == 10, "got %d, extra %d\n", ret, extra);
pStringTableDestroy(table);
}
static void test_StringTableDuplicate(void)
{
HANDLE table, table2;
HSTRING_TABLE table, table2;
table = pStringTableInitialize();
ok(table != NULL,"Failed to Initialize String Table\n");
......@@ -166,7 +167,7 @@ static void test_StringTableDuplicate(void)
static void test_StringTableLookUpString(void)
{
DWORD retval, retval2, hstring, hString, hfoo;
HANDLE table, table2;
HSTRING_TABLE table, table2;
table = pStringTableInitialize();
ok(table != NULL,"failed to initialize string table\n");
......@@ -224,7 +225,7 @@ static void test_StringTableLookUpStringEx(void)
{
static WCHAR uilevel[] = {'U','I','L','E','V','E','L',0};
DWORD retval, retval2, hstring, hString, hfoo, data;
HANDLE table, table2;
HSTRING_TABLE table, table2;
char buffer[4];
table = pStringTableInitialize();
......@@ -305,23 +306,55 @@ static void test_StringTableLookUpStringEx(void)
static void test_StringTableStringFromId(void)
{
HANDLE table;
DWORD hstring;
HSTRING_TABLE table;
WCHAR *string2;
int result;
DWORD id, id2;
table = pStringTableInitialize();
ok(table != NULL,"Failed to Initialize String Table\n");
ok(table != NULL, "Failed to Initialize String Table\n");
hstring = pStringTableAddString(table, string, 0);
ok(hstring != ~0u,"failed to add 'string' to string table\n");
id = pStringTableAddString(table, string, 0);
ok(id != -1, "failed to add 'string' to string table\n");
/* correct */
string2=pStringTableStringFromId(table,pStringTableLookUpString(table,string,0));
ok(string2!=NULL,"Failed to look up string by ID from String Table\n");
id2 = pStringTableLookUpString(table, string, 0);
ok(id2 == id, "got %d and %d\n", id2, id);
string2 = pStringTableStringFromId(table, id2);
ok(string2 != NULL, "failed to lookup string %d\n", id2);
ok(!lstrcmpiW(string, string2), "got %s, expected %s\n", wine_dbgstr_w(string2), wine_dbgstr_w(string));
pStringTableDestroy(table);
}
struct stringtable {
char *data;
ULONG nextoffset;
ULONG allocated;
DWORD_PTR unk[2];
ULONG max_extra_size;
LCID lcid;
};
static void test_stringtable_layout(void)
{
struct stringtable *ptr;
HSTRING_TABLE table;
result=lstrcmpiW(string, string2);
ok(result==0,"StringID %p does not match requested StringID %p\n",string,string2);
table = pStringTableInitialize();
ok(table != NULL,"failed to initialize string table\n");
ptr = (struct stringtable*)table;
ok(ptr->data != NULL, "got %p\n", ptr->data);
/* first data offset is right after bucket area */
ok(ptr->nextoffset == 509*sizeof(DWORD), "got %d\n", ptr->nextoffset);
ok(ptr->allocated != 0, "got %d\n", ptr->allocated);
todo_wine {
ok(ptr->unk[0] != 0, "got %lx\n", ptr->unk[0]);
ok(ptr->unk[1] != 0, "got %lx\n", ptr->unk[1]);
}
ok(ptr->max_extra_size == 0, "got %d\n", ptr->max_extra_size);
ok(ptr->lcid == GetThreadLocale(), "got %x, thread lcid %x\n", ptr->lcid, GetThreadLocale());
pStringTableDestroy(table);
}
......@@ -336,4 +369,5 @@ START_TEST(stringtable)
test_StringTableLookUpString();
test_StringTableLookUpStringEx();
test_StringTableStringFromId();
test_stringtable_layout();
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment