2 * Copyright 2011 André Hentschel
3 * Copyright 2013 Mislav Bla\9eevic
4 * Copyright 2015-2017 Mark Jansen (mark.jansen@reactos.org)
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.
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.
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
25 DWORD WINAPI
SdbGetTagDataSize(PDB pdb
, TAGID tagid
);
28 BOOL WINAPI
SdbpReadData(PDB pdb
, PVOID dest
, DWORD offset
, DWORD num
)
30 DWORD size
= offset
+ num
;
32 /* Either overflow or no data to read */
40 memcpy(dest
, pdb
->data
+ offset
, num
);
44 static DWORD WINAPI
SdbpGetTagSize(PDB pdb
, TAGID tagid
)
49 type
= SdbGetTagFromTagID(pdb
, tagid
) & TAG_TYPE_MASK
;
53 size
= SdbGetTagDataSize(pdb
, tagid
);
54 if (type
<= TAG_TYPE_STRINGREF
)
55 return size
+= sizeof(TAG
);
56 else size
+= (sizeof(TAG
) + sizeof(DWORD
));
61 static LPWSTR WINAPI
SdbpGetString(PDB pdb
, TAGID tagid
, PDWORD size
)
66 tag
= SdbGetTagFromTagID(pdb
, tagid
);
70 if ((tag
& TAG_TYPE_MASK
) == TAG_TYPE_STRINGREF
)
72 /* No stringtable; all references are invalid */
73 if (pdb
->stringtable
== TAGID_NULL
)
76 /* TAG_TYPE_STRINGREF contains offset of string relative to stringtable */
77 if (!SdbpReadData(pdb
, &tagid
, tagid
+ sizeof(TAG
), sizeof(TAGID
)))
80 offset
= pdb
->stringtable
+ tagid
+ sizeof(TAG
) + sizeof(TAGID
);
82 else if ((tag
& TAG_TYPE_MASK
) == TAG_TYPE_STRING
)
84 offset
= tagid
+ sizeof(TAG
) + sizeof(TAGID
);
88 SHIM_ERR("Tag 0x%u at tagid %u is neither a string or reference to string\n", tag
, tagid
);
92 /* Optionally read string size */
93 if (size
&& !SdbpReadData(pdb
, size
, tagid
+ sizeof(TAG
), sizeof(*size
)))
96 return (LPWSTR
)(&pdb
->data
[offset
]);
100 * Searches shim database for the tag associated with specified tagid.
102 * @param [in] pdb Handle to the shim database.
103 * @param [in] tagid The TAGID of the tag.
105 * @return Success: The tag associated with specified tagid, Failure: TAG_NULL.
107 TAG WINAPI
SdbGetTagFromTagID(PDB pdb
, TAGID tagid
)
110 if (!SdbpReadData(pdb
, &data
, tagid
, sizeof(data
)))
116 * Retrieves size of data at specified tagid.
118 * @param [in] pdb Handle to the shim database.
119 * @param [in] tagid Tagid of tag whose size is queried.
121 * @return Success: Size of data at specified tagid, Failure: 0.
123 DWORD WINAPI
SdbGetTagDataSize(PDB pdb
, TAGID tagid
)
125 /* sizes of data types with fixed size */
126 static const SIZE_T sizes
[6] = {
127 0, /* NULL */ 1, /* BYTE */
128 2, /* WORD */ 4, /* DWORD */
129 8, /* QWORD */ 4 /* STRINGREF */
134 type
= SdbGetTagFromTagID(pdb
, tagid
) & TAG_TYPE_MASK
;
135 if (type
== TAG_NULL
)
138 if (type
<= TAG_TYPE_STRINGREF
)
139 return sizes
[(type
>> 12) - 1];
141 /* tag with dynamic size (e.g. list): must read size */
142 if (!SdbpReadData(pdb
, &size
, tagid
+ sizeof(TAG
), sizeof(size
)))
149 * Searches shim database for a child of specified parent tag.
151 * @param [in] pdb Handle to the shim database.
152 * @param [in] parent TAGID of parent.
154 * @return Success: TAGID of child tag, Failure: TAGID_NULL.
156 TAGID WINAPI
SdbGetFirstChild(PDB pdb
, TAGID parent
)
158 /* if we are at beginning of database */
159 if (parent
== TAGID_ROOT
)
161 /* header only database: no tags */
162 if (pdb
->size
<= _TAGID_ROOT
)
164 /* return *real* root tagid */
165 else return _TAGID_ROOT
;
168 /* only list tag can have children */
169 if ((SdbGetTagFromTagID(pdb
, parent
) & TAG_TYPE_MASK
) != TAG_TYPE_LIST
)
172 /* first child is sizeof(TAG) + sizeof(DWORD) bytes after beginning of list */
173 return parent
+ sizeof(TAG
) + sizeof(DWORD
);
177 * Searches shim database for next child of specified parent tag.
179 * @param [in] pdb Handle to the shim database.
180 * @param [in] parent TAGID of parent.
181 * @param [in] prev_child TAGID of previous child.
183 * @return Success: TAGID of next child tag, Failure: TAGID_NULL.
185 TAGID WINAPI
SdbGetNextChild(PDB pdb
, TAGID parent
, TAGID prev_child
)
188 DWORD prev_child_size
, parent_size
;
190 prev_child_size
= SdbpGetTagSize(pdb
, prev_child
);
191 if (prev_child_size
== 0)
195 next_child
= prev_child
+ prev_child_size
;
196 if (next_child
>= pdb
->size
)
199 if (parent
== TAGID_ROOT
)
202 parent_size
= SdbpGetTagSize(pdb
, parent
);
203 if (parent_size
== 0)
206 /* Specified parent has no more children */
207 if (next_child
>= parent
+ parent_size
)
214 * Searches shim database for a tag within specified domain.
216 * @param [in] pdb Handle to the shim database.
217 * @param [in] parent TAGID of parent.
218 * @param [in] tag TAG to be located.
220 * @return Success: TAGID of first matching tag, Failure: TAGID_NULL.
222 TAGID WINAPI
SdbFindFirstTag(PDB pdb
, TAGID parent
, TAG tag
)
226 iter
= SdbGetFirstChild(pdb
, parent
);
227 while (iter
!= TAGID_NULL
)
229 if (SdbGetTagFromTagID(pdb
, iter
) == tag
)
231 iter
= SdbGetNextChild(pdb
, parent
, iter
);
237 * Searches shim database for a next tag which matches prev_child within parent's domain.
239 * @param [in] pdb Handle to the shim database.
240 * @param [in] parent TAGID of parent.
241 * @param [in] prev_child TAGID of previous match.
243 * @return Success: TAGID of next match, Failure: TAGID_NULL.
245 TAGID WINAPI
SdbFindNextTag(PDB pdb
, TAGID parent
, TAGID prev_child
)
250 tag
= SdbGetTagFromTagID(pdb
, prev_child
);
251 iter
= SdbGetNextChild(pdb
, parent
, prev_child
);
253 while (iter
!= TAGID_NULL
)
255 if (SdbGetTagFromTagID(pdb
, iter
) == tag
)
257 iter
= SdbGetNextChild(pdb
, parent
, iter
);
263 * Searches shim database for string associated with specified tagid and copies string into a
266 * If size parameter is less than number of characters in string, this function shall fail and
267 * no data shall be copied.
269 * @param [in] pdb Handle to the shim database.
270 * @param [in] tagid TAGID of string or stringref associated with the string.
271 * @param [out] buffer Buffer in which string will be copied.
272 * @param [in] size Number of characters to copy.
274 * @return TRUE if string was successfully copied to the buffer FALSE if string was not copied
277 BOOL WINAPI
SdbReadStringTag(PDB pdb
, TAGID tagid
, LPWSTR buffer
, DWORD size
)
282 string
= SdbpGetString(pdb
, tagid
, &string_size
);
286 /* Check if buffer is too small */
287 if (size
* sizeof(WCHAR
) < string_size
)
290 memcpy(buffer
, string
, string_size
);
295 * Reads WORD value at specified tagid.
297 * @param [in] pdb Handle to the shim database.
298 * @param [in] tagid TAGID of WORD value.
299 * @param [in] ret Default return value in case function fails.
301 * @return Success: WORD value at specified tagid, or ret on failure.
303 WORD WINAPI
SdbReadWORDTag(PDB pdb
, TAGID tagid
, WORD ret
)
305 if (SdbpCheckTagIDType(pdb
, tagid
, TAG_TYPE_WORD
))
306 SdbpReadData(pdb
, &ret
, tagid
+ 2, sizeof(WORD
));
311 * Reads DWORD value at specified tagid.
313 * @param [in] pdb Handle to the shim database.
314 * @param [in] tagid TAGID of DWORD value.
315 * @param [in] ret Default return value in case function fails.
317 * @return Success: DWORD value at specified tagid, otherwise ret.
319 DWORD WINAPI
SdbReadDWORDTag(PDB pdb
, TAGID tagid
, DWORD ret
)
321 if (SdbpCheckTagIDType(pdb
, tagid
, TAG_TYPE_DWORD
))
322 SdbpReadData(pdb
, &ret
, tagid
+ 2, sizeof(DWORD
));
327 * Reads QWORD value at specified tagid.
329 * @param [in] pdb Handle to the shim database.
330 * @param [in] tagid TAGID of QWORD value.
331 * @param [in] ret Default return value in case function fails.
333 * @return Success: QWORD value at specified tagid, otherwise ret.
335 QWORD WINAPI
SdbReadQWORDTag(PDB pdb
, TAGID tagid
, QWORD ret
)
337 if (SdbpCheckTagIDType(pdb
, tagid
, TAG_TYPE_QWORD
))
338 SdbpReadData(pdb
, &ret
, tagid
+ sizeof(TAG
), sizeof(QWORD
));
343 * Reads binary data at specified tagid.
345 * @param [in] pdb Handle to the shim database.
346 * @param [in] tagid TAGID of binary data.
347 * @param [out] buffer Buffer in which data will be copied.
348 * @param [in] size Size of the buffer.
350 * @return TRUE if data was successfully written, or FALSE otherwise.
352 BOOL WINAPI
SdbReadBinaryTag(PDB pdb
, TAGID tagid
, PBYTE buffer
, DWORD size
)
356 if (SdbpCheckTagIDType(pdb
, tagid
, TAG_TYPE_BINARY
))
358 SdbpReadData(pdb
, &data_size
, tagid
+ sizeof(TAG
), sizeof(data_size
));
359 if (size
>= data_size
)
360 return SdbpReadData(pdb
, buffer
, tagid
+ sizeof(TAG
) + sizeof(data_size
), data_size
);
367 * Retrieves binary data at specified tagid.
369 * @param [in] pdb Handle to the shim database.
370 * @param [in] tagid TAGID of binary data.
372 * @return Success: Pointer to binary data at specified tagid, or NULL on failure.
374 PVOID WINAPI
SdbGetBinaryTagData(PDB pdb
, TAGID tagid
)
376 if (!SdbpCheckTagIDType(pdb
, tagid
, TAG_TYPE_BINARY
))
378 return &pdb
->data
[tagid
+ sizeof(TAG
) + sizeof(DWORD
)];
382 * Searches shim database for string associated with specified tagid.
384 * @param [in] pdb Handle to the shim database.
385 * @param [in] tagid TAGID of string or stringref associated with the string.
387 * @return the LPWSTR associated with specified tagid, or NULL on failure.
389 LPWSTR WINAPI
SdbGetStringTagPtr(PDB pdb
, TAGID tagid
)
391 return SdbpGetString(pdb
, tagid
, NULL
);
395 * Reads binary data at specified tagid.
397 * @param [in] pdb Handle to the shim database.
398 * @param [out] Guid Database ID.
400 * @return true if the ID was found FALSE otherwise.
402 BOOL WINAPI
SdbGetDatabaseID(PDB pdb
, GUID
* Guid
)
404 if(SdbIsNullGUID(&pdb
->database_id
))
406 TAGID root
= SdbFindFirstTag(pdb
, TAGID_ROOT
, TAG_DATABASE
);
407 if(root
!= TAGID_NULL
)
409 TAGID id
= SdbFindFirstTag(pdb
, root
, TAG_DATABASE_ID
);
412 if(!SdbReadBinaryTag(pdb
, id
, (PBYTE
)&pdb
->database_id
, sizeof(pdb
->database_id
)))
414 memset(&pdb
->database_id
, 0, sizeof(pdb
->database_id
));
419 /* Should we silence this if we are opening a system db? */
420 SHIM_ERR("Failed to get the database id\n");
425 /* Should we silence this if we are opening a system db? */
426 SHIM_ERR("Failed to get root tag\n");
429 if(!SdbIsNullGUID(&pdb
->database_id
))
431 memcpy(Guid
, &pdb
->database_id
, sizeof(pdb
->database_id
));