Reactos
at master 191 lines 4.2 kB view raw
1/* 2 * PROJECT: ReactOS Application compatibility module 3 * LICENSE: MIT (https://spdx.org/licenses/MIT) 4 * PURPOSE: Shim database string table builder 5 * COPYRIGHT: Copyright 2016-2025 Mark Jansen <mark.jansen@reactos.org> 6 */ 7 8#if !defined(SDBWRITE_HOSTTOOL) 9#define WIN32_NO_STATUS 10#include "windows.h" 11#include <appcompat/sdbtypes.h> 12#include "sdbpapi.h" 13#else /* !defined(SDBWRITE_HOSTTOOL) */ 14#include <typedefs.h> 15#include <guiddef.h> 16#include "sdbtypes.h" 17#include "sdbpapi.h" 18#endif /* !defined(SDBWRITE_HOSTTOOL) */ 19 20#include "sdbstringtable.h" 21 22#if !defined(offsetof) 23#if defined(__GNUC__) 24#define offsetof(TYPE, MEMBER) __builtin_offsetof (TYPE, MEMBER) 25#else 26#define offsetof(TYPE, MEMBER) ((size_t)&(((TYPE *)0)->MEMBER)) 27#endif 28#endif // !defined(offsetof) 29 30#define DEFAULT_TABLE_SIZE 0x100 31 32typedef struct SdbHashEntry 33{ 34 struct SdbHashEntry* Next; 35 TAGID Tagid; 36 WCHAR Name[1]; 37} SdbHashEntry; 38 39struct SdbStringHashTable 40{ 41 DWORD Size; 42 struct SdbHashEntry** Entries; 43}; 44 45 46static struct SdbStringHashTable* HashCreate(void) 47{ 48 struct SdbStringHashTable* tab = SdbAlloc(sizeof(*tab)); 49 if (!tab) 50 { 51 SHIM_ERR("Failed to allocate 8 bytes.\r\n"); 52 return tab; 53 } 54 tab->Size = DEFAULT_TABLE_SIZE; 55 tab->Entries = SdbAlloc(tab->Size * sizeof(*tab->Entries)); 56 return tab; 57} 58 59 60void SdbpTableDestroy(struct SdbStringHashTable** pTable) 61{ 62 struct SdbStringHashTable* table = *pTable; 63 struct SdbHashEntry* entry, *next; 64 DWORD n, depth = 0, once = 1; 65 66 *pTable = NULL; 67 for (n = 0; n < table->Size; ++n) 68 { 69 depth = 0; 70 entry = next = table->Entries[n]; 71 while (entry) 72 { 73 next = entry->Next; 74 SdbFree(entry); 75 entry = next; 76 depth++; 77 } 78 if (once && depth > 3) 79 { 80 // warn 81 once = 0; 82 } 83 } 84 SdbFree(table->Entries); 85 SdbFree(table); 86} 87 88/* Based on RtlHashUnicodeString */ 89static DWORD StringHash(const WCHAR* str) 90{ 91 DWORD hash = 0; 92 for (; *str; str++) 93 { 94 hash = ((65599 * hash) + (ULONG)(*str)); 95 } 96 return hash; 97} 98 99int Sdbwcscmp(const WCHAR* s1, const WCHAR* s2) 100{ 101 while (*s1 == *s2) 102 { 103 if (*s1 == 0) 104 return 0; 105 s1++; 106 s2++; 107 } 108 return *s1 - *s2; 109} 110 111 112// implementation taken from reactos/sdk/lib/crt/string/wcs.c 113INT Sdbwcscpy(WCHAR* wcDest, size_t numElement, const WCHAR *wcSrc) 114{ 115 size_t size = 0; 116 if(!wcDest || !numElement) 117 return 22; /* EINVAL */ 118 119 wcDest[0] = 0; 120 121 if(!wcSrc) 122 return 22; /* EINVAL */ 123 124 size = SdbpStrlen(wcSrc) + 1; 125 126 if(size > numElement) 127 return 34; /* ERANGE */ 128 129 memcpy(wcDest, wcSrc, size * sizeof(WCHAR)); 130 131 return 0; 132} 133 134static struct SdbHashEntry** TableFindPtr(struct SdbStringHashTable* table, const WCHAR* str) 135{ 136 DWORD hash = StringHash(str); 137 struct SdbHashEntry** entry = &table->Entries[hash % table->Size]; 138 while (*entry) 139 { 140 if (!Sdbwcscmp((*entry)->Name, str)) 141 return entry; 142 entry = &(*entry)->Next; 143 } 144 return entry; 145} 146 147static BOOL HashAddString(struct SdbStringHashTable* table, struct SdbHashEntry** position, const WCHAR* str, TAGID tagid) 148{ 149 struct SdbHashEntry* entry; 150 SIZE_T size, len; 151 152 if (!position) 153 position = TableFindPtr(table, str); 154 155 len = SdbpStrlen(str) + 1; 156 size = offsetof(struct SdbHashEntry, Name[len]); 157 entry = (*position) = SdbAlloc(size); 158 if (!entry) 159 { 160 SHIM_ERR("Failed to allocate %u bytes.\n", size); 161 return FALSE; 162 } 163 entry->Tagid = tagid; 164 Sdbwcscpy(entry->Name, len, str); 165 return TRUE; 166} 167 168 169BOOL SdbpAddStringToTable(struct SdbStringHashTable** table, const WCHAR* str, TAGID* tagid) 170{ 171 struct SdbHashEntry** entry; 172 173 if (!*table) 174 { 175 *table = HashCreate(); 176 if (!*table) 177 { 178 SHIM_ERR("Error creating hash table\n"); 179 return FALSE; 180 } 181 } 182 183 entry = TableFindPtr(*table, str); 184 if (*entry) 185 { 186 *tagid = (*entry)->Tagid; 187 return FALSE; 188 } 189 return HashAddString(*table, entry, str, *tagid); 190} 191