2 * PROJECT: ReactOS Application compatibility module
3 * LICENSE: GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+)
4 * PURPOSE: Shim database manipulation functions
5 * COPYRIGHT: Copyright 2011 André Hentschel
6 * Copyright 2013 Mislav Blažević
7 * Copyright 2015-2017 Mark Jansen (mark.jansen@reactos.org)
10 #if !defined(SDBWRITE_HOSTTOOL)
11 #define WIN32_NO_STATUS
22 #include "sdbstringtable.h"
26 BOOL WINAPI
SdbWriteStringRefTag(PDB pdb
, TAG tag
, TAGID tagid
);
27 BOOL WINAPI
SdbWriteStringTag(PDB pdb
, TAG tag
, LPCWSTR string
);
28 TAGID WINAPI
SdbBeginWriteListTag(PDB pdb
, TAG tag
);
29 BOOL WINAPI
SdbEndWriteListTag(PDB pdb
, TAGID tagid
);
32 void WINAPI
SdbCloseDatabase(PDB
);
34 /* Copy data to the allocated database */
35 static void WINAPI
SdbpWrite(PDB pdb
, const void* data
, DWORD size
)
37 ASSERT(pdb
->for_write
);
38 if (pdb
->write_iter
+ size
> pdb
->size
)
40 DWORD oldSize
= pdb
->size
;
41 /* Round to powers of two to prevent too many reallocations */
42 while (pdb
->size
< pdb
->write_iter
+ size
) pdb
->size
<<= 1;
43 pdb
->data
= SdbReAlloc(pdb
->data
, pdb
->size
, oldSize
);
46 memcpy(pdb
->data
+ pdb
->write_iter
, data
, size
);
47 pdb
->write_iter
+= size
;
50 /* Add a string to the string table (creating it when it did not exist yet),
51 returning if it succeeded or not */
52 static BOOL WINAPI
SdbpGetOrAddStringRef(PDB pdb
, LPCWSTR string
, TAGID
* tagid
)
54 PDB buf
= pdb
->string_buffer
;
55 ASSERT(pdb
->for_write
);
57 if (pdb
->string_buffer
== NULL
)
59 pdb
->string_buffer
= buf
= SdbAlloc(sizeof(DB
));
63 buf
->data
= SdbAlloc(buf
->size
);
64 buf
->for_write
= TRUE
;
65 if (buf
->data
== NULL
)
69 *tagid
= buf
->write_iter
+ sizeof(TAG
) + sizeof(DWORD
);
70 if (SdbpAddStringToTable(&pdb
->string_lookup
, string
, tagid
))
71 return SdbWriteStringTag(buf
, TAG_STRINGTABLE_ITEM
, string
);
73 return pdb
->string_lookup
!= NULL
;
76 /* Write the in-memory stringtable to the specified db */
77 static BOOL WINAPI
SdbpWriteStringtable(PDB pdb
)
80 PDB buf
= pdb
->string_buffer
;
81 if (buf
== NULL
|| pdb
->string_lookup
== NULL
)
84 table
= SdbBeginWriteListTag(pdb
, TAG_STRINGTABLE
);
85 SdbpWrite(pdb
, buf
->data
, buf
->write_iter
);
86 return SdbEndWriteListTag(pdb
, table
);
90 * Creates new shim database file
92 * If a file already exists on specified path, that file shall be overwritten.
94 * @note Use SdbCloseDatabaseWrite to close the database opened with this function.
96 * @param [in] path Path to the new shim database.
97 * @param [in] type Type of path. Either DOS_PATH or NT_PATH.
99 * @return Success: Handle to the newly created shim database, NULL otherwise.
101 PDB WINAPI
SdbCreateDatabase(LPCWSTR path
, PATH_TYPE type
)
103 static const DWORD version_major
= 2, version_minor
= 1;
104 static const char* magic
= "sdbf";
107 pdb
= SdbpCreate(path
, type
, TRUE
);
111 pdb
->size
= sizeof(DWORD
) + sizeof(DWORD
) + strlen(magic
);
112 pdb
->data
= SdbAlloc(pdb
->size
);
114 SdbpWrite(pdb
, &version_major
, sizeof(DWORD
));
115 SdbpWrite(pdb
, &version_minor
, sizeof(DWORD
));
116 SdbpWrite(pdb
, magic
, strlen(magic
));
122 * Closes specified database and writes data to file.
124 * @param [in] pdb Handle to the shim database.
126 void WINAPI
SdbCloseDatabaseWrite(PDB pdb
)
128 ASSERT(pdb
->for_write
);
129 SdbpWriteStringtable(pdb
);
131 SdbCloseDatabase(pdb
);
135 * Writes a tag-only (NULL) entry to the specified shim database.
137 * @param [in] pdb Handle to the shim database.
138 * @param [in] tag A tag for the entry.
140 * @return TRUE if it succeeds, FALSE if it fails.
142 BOOL WINAPI
SdbWriteNULLTag(PDB pdb
, TAG tag
)
144 if (!SdbpCheckTagType(tag
, TAG_TYPE_NULL
))
147 SdbpWrite(pdb
, &tag
, sizeof(TAG
));
152 * Writes a WORD entry to the specified shim database.
154 * @param [in] pdb Handle to the shim database.
155 * @param [in] tag A tag for the entry.
156 * @param [in] data WORD entry which will be written to the database.
158 * @return TRUE if it succeeds, FALSE if it fails.
160 BOOL WINAPI
SdbWriteWORDTag(PDB pdb
, TAG tag
, WORD data
)
162 if (!SdbpCheckTagType(tag
, TAG_TYPE_WORD
))
165 SdbpWrite(pdb
, &tag
, sizeof(TAG
));
166 SdbpWrite(pdb
, &data
, sizeof(data
));
171 * Writes a DWORD entry to the specified shim database.
173 * @param [in] pdb Handle to the shim database.
174 * @param [in] tag A tag for the entry.
175 * @param [in] data DWORD entry which will be written to the database.
177 * @return TRUE if it succeeds, FALSE if it fails.
179 BOOL WINAPI
SdbWriteDWORDTag(PDB pdb
, TAG tag
, DWORD data
)
181 if (!SdbpCheckTagType(tag
, TAG_TYPE_DWORD
))
184 SdbpWrite(pdb
, &tag
, sizeof(TAG
));
185 SdbpWrite(pdb
, &data
, sizeof(data
));
190 * Writes a DWORD entry to the specified shim database.
192 * @param [in] pdb Handle to the shim database.
193 * @param [in] tag A tag for the entry.
194 * @param [in] data QWORD entry which will be written to the database.
196 * @return TRUE if it succeeds, FALSE if it fails.
198 BOOL WINAPI
SdbWriteQWORDTag(PDB pdb
, TAG tag
, QWORD data
)
200 if (!SdbpCheckTagType(tag
, TAG_TYPE_QWORD
))
203 SdbpWrite(pdb
, &tag
, sizeof(TAG
));
204 SdbpWrite(pdb
, &data
, sizeof(data
));
209 * Writes a wide string entry to the specified shim database.
211 * @param [in] pdb Handle to the shim database.
212 * @param [in] tag A tag for the entry.
213 * @param [in] string Wide string entry which will be written to the database.
215 * @return TRUE if it succeeds, FALSE if it fails.
217 BOOL WINAPI
SdbWriteStringTag(PDB pdb
, TAG tag
, LPCWSTR string
)
221 if (SdbpCheckTagType(tag
, TAG_TYPE_STRINGREF
))
224 if (!SdbpGetOrAddStringRef(pdb
, string
, &tagid
))
227 return SdbWriteStringRefTag(pdb
, tag
, tagid
);
230 if (!SdbpCheckTagType(tag
, TAG_TYPE_STRING
))
233 size
= SdbpStrsize(string
);
234 SdbpWrite(pdb
, &tag
, sizeof(TAG
));
235 SdbpWrite(pdb
, &size
, sizeof(size
));
236 SdbpWrite(pdb
, string
, size
);
241 * Writes a stringref tag to specified database
242 * @note Reference (tagid) is not checked for validity.
244 * @param [in] pdb Handle to the shim database.
245 * @param [in] tag TAG which will be written.
246 * @param [in] tagid TAGID of the string tag refers to.
248 * @return TRUE if it succeeds, FALSE if it fails.
250 BOOL WINAPI
SdbWriteStringRefTag(PDB pdb
, TAG tag
, TAGID tagid
)
252 if (!SdbpCheckTagType(tag
, TAG_TYPE_STRINGREF
))
255 SdbpWrite(pdb
, &tag
, sizeof(TAG
));
256 SdbpWrite(pdb
, &tagid
, sizeof(tagid
));
261 * Writes data the specified shim database.
263 * @param [in] pdb Handle to the shim database.
264 * @param [in] tag A tag for the entry.
265 * @param [in] data Pointer to data.
266 * @param [in] size Number of bytes to write.
268 * @return TRUE if it succeeds, FALSE if it fails.
270 BOOL WINAPI
SdbWriteBinaryTag(PDB pdb
, TAG tag
, const BYTE
* data
, DWORD size
)
272 if (!SdbpCheckTagType(tag
, TAG_TYPE_BINARY
))
275 SdbpWrite(pdb
, &tag
, sizeof(TAG
));
276 SdbpWrite(pdb
, &size
, sizeof(size
));
277 SdbpWrite(pdb
, data
, size
);
281 #if !defined(SDBWRITE_HOSTTOOL)
283 * Writes data from a file to the specified shim database.
285 * @param [in] pdb Handle to the shim database.
286 * @param [in] tag A tag for the entry.
287 * @param [in] path Path of the input file.
289 * @return TRUE if it succeeds, FALSE if it fails.
291 BOOL WINAPI
SdbWriteBinaryTagFromFile(PDB pdb
, TAG tag
, LPCWSTR path
)
295 if (!SdbpCheckTagType(tag
, TAG_TYPE_BINARY
))
298 if (!SdbpOpenMemMappedFile(path
, &mapped
))
301 SdbWriteBinaryTag(pdb
, tag
, mapped
.view
, mapped
.size
);
302 SdbpCloseMemMappedFile(&mapped
);
308 * Writes a list tag to specified database All subsequent SdbWrite* functions shall write to
309 * newly created list untill TAGID of that list is passed to SdbEndWriteListTag.
311 * @param [in] pdb Handle to the shim database.
312 * @param [in] tag TAG for the list
314 * RETURNS Success: TAGID of the newly created list, or TAGID_NULL on failure.
318 TAGID WINAPI
SdbBeginWriteListTag(PDB pdb
, TAG tag
)
323 if (!SdbpCheckTagType(tag
, TAG_TYPE_LIST
))
326 list_id
= pdb
->write_iter
;
327 SdbpWrite(pdb
, &tag
, sizeof(TAG
));
328 SdbpWrite(pdb
, &dum
, sizeof(dum
)); /* reserve some memory for storing list size */
333 * Marks end of the specified list.
335 * @param [in] pdb Handle to the shim database.
336 * @param [in] tagid TAGID of the list.
338 * @return TRUE if it succeeds, FALSE if it fails.
340 BOOL WINAPI
SdbEndWriteListTag(PDB pdb
, TAGID tagid
)
342 ASSERT(pdb
->for_write
);
344 if (!SdbpCheckTagIDType(pdb
, tagid
, TAG_TYPE_LIST
))
347 /* Write size of list to list tag header */
348 *(DWORD
*)&pdb
->data
[tagid
+ sizeof(TAG
)] = pdb
->write_iter
- tagid
- sizeof(TAG
) - sizeof(TAGID
);