[APPHELP_APITEST][APPHELP] Add new tests showing that SdbWriteStringTag and SdbEndWri...
[reactos.git] / reactos / dll / appcompat / apphelp / sdbwrite.c
1 /*
2 * Copyright 2011 André Hentschel
3 * Copyright 2013 Mislav Bla\9eevic
4 * Copyright 2015,2016 Mark Jansen
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
23 #define WIN32_NO_STATUS
24 #include "windows.h"
25 #include "ntndk.h"
26 #include "apphelp.h"
27 #include "wine/unicode.h"
28
29 #else
30
31 #include <typedefs.h>
32 #include <guiddef.h>
33
34 #include "sdbtypes.h"
35 #include "sdbpapi.h"
36 #include "sdbtagid.h"
37
38 #endif
39
40 BOOL WINAPI SdbWriteStringRefTag(PDB db, TAG tag, TAGID tagid);
41 TAGID WINAPI SdbBeginWriteListTag(PDB db, TAG tag);
42 BOOL WINAPI SdbEndWriteListTag(PDB db, TAGID tagid);
43
44
45 static void WINAPI SdbpWrite(PDB db, const void* data, DWORD size)
46 {
47 if (db->write_iter + size > db->size)
48 {
49 /* Round to powers of two to prevent too many reallocations */
50 while (db->size < db->write_iter + size) db->size <<= 1;
51 db->data = SdbReAlloc(db->data, db->size);
52 }
53
54 memcpy(db->data + db->write_iter, data, size);
55 db->write_iter += size;
56 }
57
58 static BOOL WINAPI SdbpGetOrAddStringRef(PDB db, LPCWSTR string, TAGID* tagid)
59 {
60 /* TODO:
61 - Insert or find in stringtable
62 - return TAGID
63 */
64
65 return FALSE;
66 }
67
68 static void WINAPI SdbpWriteStringtable(PDB db)
69 {
70 TAGID table = SdbBeginWriteListTag(db, TAG_STRINGTABLE);
71 /* TODO: Write out all strings*/
72 SdbEndWriteListTag(db, table);
73 }
74
75 /**
76 * Creates new shim database file
77 *
78 * If a file already exists on specified path, that file shall be overwritten.
79 *
80 * @note Use SdbCloseDatabasWrite to close the database opened with this function.
81 *
82 * @param [in] path Path to the new shim database.
83 * @param [in] type Type of path. Either DOS_PATH or NT_PATH.
84 *
85 * @return Success: Handle to the newly created shim database, NULL otherwise.
86 */
87 PDB WINAPI SdbCreateDatabase(LPCWSTR path, PATH_TYPE type)
88 {
89 static const DWORD version_major = 2, version_minor = 1;
90 static const char* magic = "sdbf";
91 PDB db;
92
93 db = SdbpCreate(path, type, TRUE);
94 if (!db)
95 return NULL;
96
97 db->size = sizeof(DWORD) + sizeof(DWORD) + strlen(magic);
98 db->data = SdbAlloc(db->size);
99
100 SdbpWrite(db, &version_major, sizeof(DWORD));
101 SdbpWrite(db, &version_minor, sizeof(DWORD));
102 SdbpWrite(db, magic, strlen(magic));
103
104 return db;
105 }
106
107 /**
108 * Closes specified database and writes data to file.
109 *
110 * @param [in] db Handle to the shim database.
111 */
112 void WINAPI SdbCloseDatabaseWrite(PDB db)
113 {
114 SdbpWriteStringtable(db);
115 SdbpFlush(db);
116 SdbCloseDatabase(db);
117 }
118
119 /**
120 * Writes a tag-only (NULL) entry to the specified shim database.
121 *
122 * @param [in] db Handle to the shim database.
123 * @param [in] tag A tag for the entry.
124 *
125 * @return TRUE if it succeeds, FALSE if it fails.
126 */
127 BOOL WINAPI SdbWriteNULLTag(PDB db, TAG tag)
128 {
129 if (!SdbpCheckTagType(tag, TAG_TYPE_NULL))
130 return FALSE;
131
132 SdbpWrite(db, &tag, sizeof(TAG));
133 return TRUE;
134 }
135
136 /**
137 * Writes a WORD entry to the specified shim database.
138 *
139 * @param [in] db Handle to the shim database.
140 * @param [in] tag A tag for the entry.
141 * @param [in] data WORD entry which will be written to the database.
142 *
143 * @return TRUE if it succeeds, FALSE if it fails.
144 */
145 BOOL WINAPI SdbWriteWORDTag(PDB db, TAG tag, WORD data)
146 {
147 if (!SdbpCheckTagType(tag, TAG_TYPE_WORD))
148 return FALSE;
149
150 SdbpWrite(db, &tag, sizeof(TAG));
151 SdbpWrite(db, &data, sizeof(data));
152 return TRUE;
153 }
154
155 /**
156 * Writes a DWORD entry to the specified shim database.
157 *
158 * @param [in] db Handle to the shim database.
159 * @param [in] tag A tag for the entry.
160 * @param [in] data DWORD entry which will be written to the database.
161 *
162 * @return TRUE if it succeeds, FALSE if it fails.
163 */
164 BOOL WINAPI SdbWriteDWORDTag(PDB db, TAG tag, DWORD data)
165 {
166 if (!SdbpCheckTagType(tag, TAG_TYPE_DWORD))
167 return FALSE;
168
169 SdbpWrite(db, &tag, sizeof(TAG));
170 SdbpWrite(db, &data, sizeof(data));
171 return TRUE;
172 }
173
174 /**
175 * Writes a DWORD entry to the specified shim database.
176 *
177 * @param [in] db Handle to the shim database.
178 * @param [in] tag A tag for the entry.
179 * @param [in] data QWORD entry which will be written to the database.
180 *
181 * @return TRUE if it succeeds, FALSE if it fails.
182 */
183 BOOL WINAPI SdbWriteQWORDTag(PDB db, TAG tag, QWORD data)
184 {
185 if (!SdbpCheckTagType(tag, TAG_TYPE_QWORD))
186 return FALSE;
187
188 SdbpWrite(db, &tag, sizeof(TAG));
189 SdbpWrite(db, &data, sizeof(data));
190 return TRUE;
191 }
192
193 /**
194 * Writes a wide string entry to the specified shim database.
195 *
196 * @param [in] db Handle to the shim database.
197 * @param [in] tag A tag for the entry.
198 * @param [in] string Wide string entry which will be written to the database.
199 *
200 * @return TRUE if it succeeds, FALSE if it fails.
201 */
202 BOOL WINAPI SdbWriteStringTag(PDB db, TAG tag, LPCWSTR string)
203 {
204 DWORD size;
205
206 if (SdbpCheckTagType(tag, TAG_TYPE_STRINGREF))
207 {
208 TAGID tagid = 0;
209 if (!SdbpGetOrAddStringRef(db, string, &tagid))
210 return FALSE;
211
212 return SdbWriteStringRefTag(db, tag, tagid);
213 }
214
215 if (!SdbpCheckTagType(tag, TAG_TYPE_STRING))
216 return FALSE;
217
218 size = SdbpStrsize(string);
219 SdbpWrite(db, &tag, sizeof(TAG));
220 SdbpWrite(db, &size, sizeof(size));
221 SdbpWrite(db, string, size);
222 return TRUE;
223 }
224
225 /**
226 * Writes a stringref tag to specified database
227 * @note Reference (tagid) is not checked for validity.
228 *
229 * @param [in] db Handle to the shim database.
230 * @param [in] tag TAG which will be written.
231 * @param [in] tagid TAGID of the string tag refers to.
232 *
233 * @return TRUE if it succeeds, FALSE if it fails.
234 */
235 BOOL WINAPI SdbWriteStringRefTag(PDB db, TAG tag, TAGID tagid)
236 {
237 if (!SdbpCheckTagType(tag, TAG_TYPE_STRINGREF))
238 return FALSE;
239
240 SdbpWrite(db, &tag, sizeof(TAG));
241 SdbpWrite(db, &tagid, sizeof(tagid));
242 return TRUE;
243 }
244
245 /**
246 * Writes data the specified shim database.
247 *
248 * @param [in] db Handle to the shim database.
249 * @param [in] tag A tag for the entry.
250 * @param [in] data Pointer to data.
251 * @param [in] size Number of bytes to write.
252 *
253 * @return TRUE if it succeeds, FALSE if it fails.
254 */
255 BOOL WINAPI SdbWriteBinaryTag(PDB db, TAG tag, BYTE* data, DWORD size)
256 {
257 if (!SdbpCheckTagType(tag, TAG_TYPE_BINARY))
258 return FALSE;
259
260 SdbpWrite(db, &tag, sizeof(TAG));
261 SdbpWrite(db, &size, sizeof(size));
262 SdbpWrite(db, data, size);
263 return TRUE;
264 }
265
266 #if !defined(SDBWRITE_HOSTTOOL)
267 /**
268 * Writes data from a file to the specified shim database.
269 *
270 * @param [in] db Handle to the shim database.
271 * @param [in] tag A tag for the entry.
272 * @param [in] path Path of the input file.
273 *
274 * @return TRUE if it succeeds, FALSE if it fails.
275 */
276 BOOL WINAPI SdbWriteBinaryTagFromFile(PDB db, TAG tag, LPCWSTR path)
277 {
278 MEMMAPPED mapped;
279
280 if (!SdbpCheckTagType(tag, TAG_TYPE_BINARY))
281 return FALSE;
282
283 if (!SdbpOpenMemMappedFile(path, &mapped))
284 return FALSE;
285
286 SdbWriteBinaryTag(db, tag, mapped.view, mapped.size);
287 SdbpCloseMemMappedFile(&mapped);
288 return TRUE;
289 }
290 #endif
291
292 /**
293 * Writes a list tag to specified database All subsequent SdbWrite* functions shall write to
294 * newly created list untill TAGID of that list is passed to SdbEndWriteListTag.
295 *
296 * @param [in] db Handle to the shim database.
297 * @param [in] tag TAG for the list
298 *
299 * RETURNS Success: TAGID of the newly created list, or TAGID_NULL on failure.
300 *
301 * @return A TAGID.
302 */
303 TAGID WINAPI SdbBeginWriteListTag(PDB db, TAG tag)
304 {
305 TAGID list_id;
306 DWORD dum = 0;
307
308 if (!SdbpCheckTagType(tag, TAG_TYPE_LIST))
309 return TAGID_NULL;
310
311 list_id = db->write_iter;
312 SdbpWrite(db, &tag, sizeof(TAG));
313 SdbpWrite(db, &dum, sizeof(dum)); /* reserve some memory for storing list size */
314 return list_id;
315 }
316
317 /**
318 * Marks end of the specified list.
319 *
320 * @param [in] db Handle to the shim database.
321 * @param [in] tagid TAGID of the list.
322 *
323 * @return TRUE if it succeeds, FALSE if it fails.
324 */
325 BOOL WINAPI SdbEndWriteListTag(PDB db, TAGID tagid)
326 {
327 if (!SdbpCheckTagIDType(db, tagid, TAG_TYPE_LIST))
328 return FALSE;
329
330 /* Write size of list to list tag header */
331 *(DWORD*)&db->data[tagid + sizeof(TAG)] = db->write_iter - tagid - sizeof(TAG) - sizeof(TAGID);
332 return TRUE;
333 }
334