1f68c2fb01182cb683a0be2f35d9395010a377a2
[reactos.git] / reactos / dll / appcompat / apphelp / sdbwrite.c
1 /*
2 * Copyright 2011 André Hentschel
3 * Copyright 2013 Mislav Blažević
4 * Copyright 2015-2017 Mark Jansen (mark.jansen@reactos.org)
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19 */
20
21 #if !defined(SDBWRITE_HOSTTOOL)
22 #define WIN32_NO_STATUS
23 #include "windows.h"
24 #include "ntndk.h"
25 #else
26 #include <typedefs.h>
27 #include <guiddef.h>
28 #endif
29
30 #include "sdbtypes.h"
31 #include "sdbpapi.h"
32 #include "sdbtagid.h"
33 #include "sdbstringtable.h"
34
35
36 /* Local functions */
37 BOOL WINAPI SdbWriteStringRefTag(PDB db, TAG tag, TAGID tagid);
38 BOOL WINAPI SdbWriteStringTag(PDB db, TAG tag, LPCWSTR string);
39 TAGID WINAPI SdbBeginWriteListTag(PDB db, TAG tag);
40 BOOL WINAPI SdbEndWriteListTag(PDB db, TAGID tagid);
41
42 /* sdbapi.c */
43 void WINAPI SdbCloseDatabase(PDB);
44
45
46 static void WINAPI SdbpWrite(PDB db, const void* data, DWORD size)
47 {
48 if (db->write_iter + size > db->size)
49 {
50 DWORD oldSize = db->size;
51 /* Round to powers of two to prevent too many reallocations */
52 while (db->size < db->write_iter + size) db->size <<= 1;
53 db->data = SdbReAlloc(db->data, db->size, oldSize);
54 }
55
56 memcpy(db->data + db->write_iter, data, size);
57 db->write_iter += size;
58 }
59
60 static BOOL WINAPI SdbpGetOrAddStringRef(PDB db, LPCWSTR string, TAGID* tagid)
61 {
62 PDB buf = db->string_buffer;
63 if (db->string_buffer == NULL)
64 {
65 db->string_buffer = buf = SdbAlloc(sizeof(DB));
66 if (buf == NULL)
67 return FALSE;
68 buf->size = 128;
69 buf->data = SdbAlloc(buf->size);
70 if (buf->data == NULL)
71 return FALSE;
72 }
73
74 *tagid = buf->write_iter + sizeof(TAG) + sizeof(DWORD);
75 if (SdbpAddStringToTable(&db->string_lookup, string, tagid))
76 return SdbWriteStringTag(buf, TAG_STRINGTABLE_ITEM, string);
77
78 return db->string_lookup != NULL;
79 }
80
81 static BOOL WINAPI SdbpWriteStringtable(PDB db)
82 {
83 TAGID table;
84 PDB buf = db->string_buffer;
85 if (buf == NULL || db->string_lookup == NULL)
86 return FALSE;
87
88 table = SdbBeginWriteListTag(db, TAG_STRINGTABLE);
89 SdbpWrite(db, buf->data, buf->write_iter);
90 return SdbEndWriteListTag(db, table);
91 }
92
93 /**
94 * Creates new shim database file
95 *
96 * If a file already exists on specified path, that file shall be overwritten.
97 *
98 * @note Use SdbCloseDatabaseWrite to close the database opened with this function.
99 *
100 * @param [in] path Path to the new shim database.
101 * @param [in] type Type of path. Either DOS_PATH or NT_PATH.
102 *
103 * @return Success: Handle to the newly created shim database, NULL otherwise.
104 */
105 PDB WINAPI SdbCreateDatabase(LPCWSTR path, PATH_TYPE type)
106 {
107 static const DWORD version_major = 2, version_minor = 1;
108 static const char* magic = "sdbf";
109 PDB db;
110
111 db = SdbpCreate(path, type, TRUE);
112 if (!db)
113 return NULL;
114
115 db->size = sizeof(DWORD) + sizeof(DWORD) + strlen(magic);
116 db->data = SdbAlloc(db->size);
117
118 SdbpWrite(db, &version_major, sizeof(DWORD));
119 SdbpWrite(db, &version_minor, sizeof(DWORD));
120 SdbpWrite(db, magic, strlen(magic));
121
122 return db;
123 }
124
125 /**
126 * Closes specified database and writes data to file.
127 *
128 * @param [in] db Handle to the shim database.
129 */
130 void WINAPI SdbCloseDatabaseWrite(PDB db)
131 {
132 SdbpWriteStringtable(db);
133 SdbpFlush(db);
134 SdbCloseDatabase(db);
135 }
136
137 /**
138 * Writes a tag-only (NULL) entry to the specified shim database.
139 *
140 * @param [in] db Handle to the shim database.
141 * @param [in] tag A tag for the entry.
142 *
143 * @return TRUE if it succeeds, FALSE if it fails.
144 */
145 BOOL WINAPI SdbWriteNULLTag(PDB db, TAG tag)
146 {
147 if (!SdbpCheckTagType(tag, TAG_TYPE_NULL))
148 return FALSE;
149
150 SdbpWrite(db, &tag, sizeof(TAG));
151 return TRUE;
152 }
153
154 /**
155 * Writes a WORD entry to the specified shim database.
156 *
157 * @param [in] db Handle to the shim database.
158 * @param [in] tag A tag for the entry.
159 * @param [in] data WORD entry which will be written to the database.
160 *
161 * @return TRUE if it succeeds, FALSE if it fails.
162 */
163 BOOL WINAPI SdbWriteWORDTag(PDB db, TAG tag, WORD data)
164 {
165 if (!SdbpCheckTagType(tag, TAG_TYPE_WORD))
166 return FALSE;
167
168 SdbpWrite(db, &tag, sizeof(TAG));
169 SdbpWrite(db, &data, sizeof(data));
170 return TRUE;
171 }
172
173 /**
174 * Writes a DWORD entry to the specified shim database.
175 *
176 * @param [in] db Handle to the shim database.
177 * @param [in] tag A tag for the entry.
178 * @param [in] data DWORD entry which will be written to the database.
179 *
180 * @return TRUE if it succeeds, FALSE if it fails.
181 */
182 BOOL WINAPI SdbWriteDWORDTag(PDB db, TAG tag, DWORD data)
183 {
184 if (!SdbpCheckTagType(tag, TAG_TYPE_DWORD))
185 return FALSE;
186
187 SdbpWrite(db, &tag, sizeof(TAG));
188 SdbpWrite(db, &data, sizeof(data));
189 return TRUE;
190 }
191
192 /**
193 * Writes a DWORD entry to the specified shim database.
194 *
195 * @param [in] db Handle to the shim database.
196 * @param [in] tag A tag for the entry.
197 * @param [in] data QWORD entry which will be written to the database.
198 *
199 * @return TRUE if it succeeds, FALSE if it fails.
200 */
201 BOOL WINAPI SdbWriteQWORDTag(PDB db, TAG tag, QWORD data)
202 {
203 if (!SdbpCheckTagType(tag, TAG_TYPE_QWORD))
204 return FALSE;
205
206 SdbpWrite(db, &tag, sizeof(TAG));
207 SdbpWrite(db, &data, sizeof(data));
208 return TRUE;
209 }
210
211 /**
212 * Writes a wide string entry to the specified shim database.
213 *
214 * @param [in] db Handle to the shim database.
215 * @param [in] tag A tag for the entry.
216 * @param [in] string Wide string entry which will be written to the database.
217 *
218 * @return TRUE if it succeeds, FALSE if it fails.
219 */
220 BOOL WINAPI SdbWriteStringTag(PDB db, TAG tag, LPCWSTR string)
221 {
222 DWORD size;
223
224 if (SdbpCheckTagType(tag, TAG_TYPE_STRINGREF))
225 {
226 TAGID tagid = 0;
227 if (!SdbpGetOrAddStringRef(db, string, &tagid))
228 return FALSE;
229
230 return SdbWriteStringRefTag(db, tag, tagid);
231 }
232
233 if (!SdbpCheckTagType(tag, TAG_TYPE_STRING))
234 return FALSE;
235
236 size = SdbpStrsize(string);
237 SdbpWrite(db, &tag, sizeof(TAG));
238 SdbpWrite(db, &size, sizeof(size));
239 SdbpWrite(db, string, size);
240 return TRUE;
241 }
242
243 /**
244 * Writes a stringref tag to specified database
245 * @note Reference (tagid) is not checked for validity.
246 *
247 * @param [in] db Handle to the shim database.
248 * @param [in] tag TAG which will be written.
249 * @param [in] tagid TAGID of the string tag refers to.
250 *
251 * @return TRUE if it succeeds, FALSE if it fails.
252 */
253 BOOL WINAPI SdbWriteStringRefTag(PDB db, TAG tag, TAGID tagid)
254 {
255 if (!SdbpCheckTagType(tag, TAG_TYPE_STRINGREF))
256 return FALSE;
257
258 SdbpWrite(db, &tag, sizeof(TAG));
259 SdbpWrite(db, &tagid, sizeof(tagid));
260 return TRUE;
261 }
262
263 /**
264 * Writes data the specified shim database.
265 *
266 * @param [in] db Handle to the shim database.
267 * @param [in] tag A tag for the entry.
268 * @param [in] data Pointer to data.
269 * @param [in] size Number of bytes to write.
270 *
271 * @return TRUE if it succeeds, FALSE if it fails.
272 */
273 BOOL WINAPI SdbWriteBinaryTag(PDB db, TAG tag, const BYTE* data, DWORD size)
274 {
275 if (!SdbpCheckTagType(tag, TAG_TYPE_BINARY))
276 return FALSE;
277
278 SdbpWrite(db, &tag, sizeof(TAG));
279 SdbpWrite(db, &size, sizeof(size));
280 SdbpWrite(db, data, size);
281 return TRUE;
282 }
283
284 #if !defined(SDBWRITE_HOSTTOOL)
285 /**
286 * Writes data from a file to the specified shim database.
287 *
288 * @param [in] db Handle to the shim database.
289 * @param [in] tag A tag for the entry.
290 * @param [in] path Path of the input file.
291 *
292 * @return TRUE if it succeeds, FALSE if it fails.
293 */
294 BOOL WINAPI SdbWriteBinaryTagFromFile(PDB db, TAG tag, LPCWSTR path)
295 {
296 MEMMAPPED mapped;
297
298 if (!SdbpCheckTagType(tag, TAG_TYPE_BINARY))
299 return FALSE;
300
301 if (!SdbpOpenMemMappedFile(path, &mapped))
302 return FALSE;
303
304 SdbWriteBinaryTag(db, tag, mapped.view, mapped.size);
305 SdbpCloseMemMappedFile(&mapped);
306 return TRUE;
307 }
308 #endif
309
310 /**
311 * Writes a list tag to specified database All subsequent SdbWrite* functions shall write to
312 * newly created list untill TAGID of that list is passed to SdbEndWriteListTag.
313 *
314 * @param [in] db Handle to the shim database.
315 * @param [in] tag TAG for the list
316 *
317 * RETURNS Success: TAGID of the newly created list, or TAGID_NULL on failure.
318 *
319 * @return A TAGID.
320 */
321 TAGID WINAPI SdbBeginWriteListTag(PDB db, TAG tag)
322 {
323 TAGID list_id;
324 DWORD dum = 0;
325
326 if (!SdbpCheckTagType(tag, TAG_TYPE_LIST))
327 return TAGID_NULL;
328
329 list_id = db->write_iter;
330 SdbpWrite(db, &tag, sizeof(TAG));
331 SdbpWrite(db, &dum, sizeof(dum)); /* reserve some memory for storing list size */
332 return list_id;
333 }
334
335 /**
336 * Marks end of the specified list.
337 *
338 * @param [in] db Handle to the shim database.
339 * @param [in] tagid TAGID of the list.
340 *
341 * @return TRUE if it succeeds, FALSE if it fails.
342 */
343 BOOL WINAPI SdbEndWriteListTag(PDB db, TAGID tagid)
344 {
345 if (!SdbpCheckTagIDType(db, tagid, TAG_TYPE_LIST))
346 return FALSE;
347
348 /* Write size of list to list tag header */
349 *(DWORD*)&db->data[tagid + sizeof(TAG)] = db->write_iter - tagid - sizeof(TAG) - sizeof(TAGID);
350 return TRUE;
351 }
352