[APPCOMPAT] Move sdbtagid.h and sdbtypes.h to a shared location
[reactos.git] / dll / appcompat / apphelp / sdbstringtable.c
1 /*
2 * PROJECT: ReactOS Application compatibility module
3 * LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
4 * PURPOSE: Shim database string table builder
5 * COPYRIGHT: Copyright 2016-2019 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
32 typedef struct SdbHashEntry
33 {
34 struct SdbHashEntry* Next;
35 TAGID Tagid;
36 WCHAR Name[1];
37 } SdbHashEntry;
38
39 struct SdbStringHashTable
40 {
41 DWORD Size;
42 struct SdbHashEntry** Entries;
43 };
44
45
46 static 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
60 void 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 */
89 static 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
99 int 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
113 INT 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
134 static 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
147 static 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.", size);
161 return FALSE;
162 }
163 entry->Tagid = tagid;
164 Sdbwcscpy(entry->Name, len, str);
165 return TRUE;
166 }
167
168
169 BOOL 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