reactos/dll/appcompat/apphelp/sdbstringtable.c

191 lines
4.1 KiB
C

/*
* PROJECT: ReactOS Application compatibility module
* LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
* PURPOSE: Shim database string table builder
* COPYRIGHT: Copyright 2016-2019 Mark Jansen (mark.jansen@reactos.org)
*/
#if !defined(SDBWRITE_HOSTTOOL)
#define WIN32_NO_STATUS
#include "windows.h"
#include <appcompat/sdbtypes.h>
#include "sdbpapi.h"
#else /* !defined(SDBWRITE_HOSTTOOL) */
#include <typedefs.h>
#include <guiddef.h>
#include "sdbtypes.h"
#include "sdbpapi.h"
#endif /* !defined(SDBWRITE_HOSTTOOL) */
#include "sdbstringtable.h"
#if !defined(offsetof)
#if defined(__GNUC__)
#define offsetof(TYPE, MEMBER) __builtin_offsetof (TYPE, MEMBER)
#else
#define offsetof(TYPE, MEMBER) ((size_t)&(((TYPE *)0)->MEMBER))
#endif
#endif // !defined(offsetof)
#define DEFAULT_TABLE_SIZE 0x100
typedef struct SdbHashEntry
{
struct SdbHashEntry* Next;
TAGID Tagid;
WCHAR Name[1];
} SdbHashEntry;
struct SdbStringHashTable
{
DWORD Size;
struct SdbHashEntry** Entries;
};
static struct SdbStringHashTable* HashCreate(void)
{
struct SdbStringHashTable* tab = SdbAlloc(sizeof(*tab));
if (!tab)
{
SHIM_ERR("Failed to allocate 8 bytes.\r\n");
return tab;
}
tab->Size = DEFAULT_TABLE_SIZE;
tab->Entries = SdbAlloc(tab->Size * sizeof(*tab->Entries));
return tab;
}
void SdbpTableDestroy(struct SdbStringHashTable** pTable)
{
struct SdbStringHashTable* table = *pTable;
struct SdbHashEntry* entry, *next;
DWORD n, depth = 0, once = 1;
*pTable = NULL;
for (n = 0; n < table->Size; ++n)
{
depth = 0;
entry = next = table->Entries[n];
while (entry)
{
next = entry->Next;
SdbFree(entry);
entry = next;
depth++;
}
if (once && depth > 3)
{
// warn
once = 0;
}
}
SdbFree(table->Entries);
SdbFree(table);
}
/* Based on RtlHashUnicodeString */
static DWORD StringHash(const WCHAR* str)
{
DWORD hash = 0;
for (; *str; str++)
{
hash = ((65599 * hash) + (ULONG)(*str));
}
return hash;
}
int Sdbwcscmp(const WCHAR* s1, const WCHAR* s2)
{
while (*s1 == *s2)
{
if (*s1 == 0)
return 0;
s1++;
s2++;
}
return *s1 - *s2;
}
// implementation taken from reactos/sdk/lib/crt/string/wcs.c
INT Sdbwcscpy(WCHAR* wcDest, size_t numElement, const WCHAR *wcSrc)
{
size_t size = 0;
if(!wcDest || !numElement)
return 22; /* EINVAL */
wcDest[0] = 0;
if(!wcSrc)
return 22; /* EINVAL */
size = SdbpStrlen(wcSrc) + 1;
if(size > numElement)
return 34; /* ERANGE */
memcpy(wcDest, wcSrc, size * sizeof(WCHAR));
return 0;
}
static struct SdbHashEntry** TableFindPtr(struct SdbStringHashTable* table, const WCHAR* str)
{
DWORD hash = StringHash(str);
struct SdbHashEntry** entry = &table->Entries[hash % table->Size];
while (*entry)
{
if (!Sdbwcscmp((*entry)->Name, str))
return entry;
entry = &(*entry)->Next;
}
return entry;
}
static BOOL HashAddString(struct SdbStringHashTable* table, struct SdbHashEntry** position, const WCHAR* str, TAGID tagid)
{
struct SdbHashEntry* entry;
SIZE_T size, len;
if (!position)
position = TableFindPtr(table, str);
len = SdbpStrlen(str) + 1;
size = offsetof(struct SdbHashEntry, Name[len]);
entry = (*position) = SdbAlloc(size);
if (!entry)
{
SHIM_ERR("Failed to allocate %u bytes.", size);
return FALSE;
}
entry->Tagid = tagid;
Sdbwcscpy(entry->Name, len, str);
return TRUE;
}
BOOL SdbpAddStringToTable(struct SdbStringHashTable** table, const WCHAR* str, TAGID* tagid)
{
struct SdbHashEntry** entry;
if (!*table)
{
*table = HashCreate();
if (!*table)
{
SHIM_ERR("Error creating hash table\n");
return FALSE;
}
}
entry = TableFindPtr(*table, str);
if (*entry)
{
*tagid = (*entry)->Tagid;
return FALSE;
}
return HashAddString(*table, entry, str, *tagid);
}