2 * PROJECT: ReactOS Application compatibility module
3 * LICENSE: GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+)
4 * PURPOSE: Shim database query functions
5 * COPYRIGHT: Copyright 2011 André Hentschel
6 * Copyright 2013 Mislav Blaževic
7 * Copyright 2015-2018 Mark Jansen (mark.jansen@reactos.org)
14 BOOL WINAPI
SdbpReadData(PDB pdb
, PVOID dest
, DWORD offset
, DWORD num
)
16 DWORD size
= offset
+ num
;
18 /* Either overflow or no data to read */
26 memcpy(dest
, pdb
->data
+ offset
, num
);
30 static DWORD WINAPI
SdbpGetTagSize(PDB pdb
, TAGID tagid
)
35 type
= SdbGetTagFromTagID(pdb
, tagid
) & TAG_TYPE_MASK
;
39 size
= SdbGetTagDataSize(pdb
, tagid
);
40 if (type
<= TAG_TYPE_STRINGREF
)
41 return size
+= sizeof(TAG
);
42 else size
+= (sizeof(TAG
) + sizeof(DWORD
));
47 LPWSTR WINAPI
SdbpGetString(PDB pdb
, TAGID tagid
, PDWORD size
)
52 tag
= SdbGetTagFromTagID(pdb
, tagid
);
56 if ((tag
& TAG_TYPE_MASK
) == TAG_TYPE_STRINGREF
)
58 /* No stringtable; all references are invalid */
59 if (pdb
->stringtable
== TAGID_NULL
)
62 /* TAG_TYPE_STRINGREF contains offset of string relative to stringtable */
63 if (!SdbpReadData(pdb
, &tagid
, tagid
+ sizeof(TAG
), sizeof(TAGID
)))
66 offset
= pdb
->stringtable
+ tagid
+ sizeof(TAG
) + sizeof(TAGID
);
68 else if ((tag
& TAG_TYPE_MASK
) == TAG_TYPE_STRING
)
70 offset
= tagid
+ sizeof(TAG
) + sizeof(TAGID
);
74 SHIM_ERR("Tag 0x%u at tagid %u is neither a string or reference to string\n", tag
, tagid
);
78 /* Optionally read string size */
79 if (size
&& !SdbpReadData(pdb
, size
, offset
- sizeof(TAGID
), sizeof(*size
)))
82 return (LPWSTR
)(&pdb
->data
[offset
]);
86 * Searches shim database for the tag associated with specified tagid.
88 * @param [in] pdb Handle to the shim database.
89 * @param [in] tagid The TAGID of the tag.
91 * @return Success: The tag associated with specified tagid, Failure: TAG_NULL.
93 TAG WINAPI
SdbGetTagFromTagID(PDB pdb
, TAGID tagid
)
96 if (!SdbpReadData(pdb
, &data
, tagid
, sizeof(data
)))
102 * Retrieves size of data at specified tagid.
104 * @param [in] pdb Handle to the shim database.
105 * @param [in] tagid Tagid of tag whose size is queried.
107 * @return Success: Size of data at specified tagid, Failure: 0.
109 DWORD WINAPI
SdbGetTagDataSize(PDB pdb
, TAGID tagid
)
111 /* sizes of data types with fixed size */
112 static const SIZE_T sizes
[6] = {
113 0, /* NULL */ 1, /* BYTE */
114 2, /* WORD */ 4, /* DWORD */
115 8, /* QWORD */ 4 /* STRINGREF */
120 type
= SdbGetTagFromTagID(pdb
, tagid
) & TAG_TYPE_MASK
;
121 if (type
== TAG_NULL
)
124 if (type
<= TAG_TYPE_STRINGREF
)
125 return sizes
[(type
>> 12) - 1];
127 /* tag with dynamic size (e.g. list): must read size */
128 if (!SdbpReadData(pdb
, &size
, tagid
+ sizeof(TAG
), sizeof(size
)))
135 * Searches shim database for a child of specified parent tag.
137 * @param [in] pdb Handle to the shim database.
138 * @param [in] parent TAGID of parent.
140 * @return Success: TAGID of child tag, Failure: TAGID_NULL.
142 TAGID WINAPI
SdbGetFirstChild(PDB pdb
, TAGID parent
)
144 /* if we are at beginning of database */
145 if (parent
== TAGID_ROOT
)
147 /* header only database: no tags */
148 if (pdb
->size
<= _TAGID_ROOT
)
150 /* return *real* root tagid */
151 else return _TAGID_ROOT
;
154 /* only list tag can have children */
155 if ((SdbGetTagFromTagID(pdb
, parent
) & TAG_TYPE_MASK
) != TAG_TYPE_LIST
)
158 /* first child is sizeof(TAG) + sizeof(DWORD) bytes after beginning of list */
159 return parent
+ sizeof(TAG
) + sizeof(DWORD
);
163 * Searches shim database for next child of specified parent tag.
165 * @param [in] pdb Handle to the shim database.
166 * @param [in] parent TAGID of parent.
167 * @param [in] prev_child TAGID of previous child.
169 * @return Success: TAGID of next child tag, Failure: TAGID_NULL.
171 TAGID WINAPI
SdbGetNextChild(PDB pdb
, TAGID parent
, TAGID prev_child
)
174 DWORD prev_child_size
, parent_size
;
176 prev_child_size
= SdbpGetTagSize(pdb
, prev_child
);
177 if (prev_child_size
== 0)
181 next_child
= prev_child
+ prev_child_size
;
182 if (next_child
>= pdb
->size
)
185 if (parent
== TAGID_ROOT
)
188 parent_size
= SdbpGetTagSize(pdb
, parent
);
189 if (parent_size
== 0)
192 /* Specified parent has no more children */
193 if (next_child
>= parent
+ parent_size
)
200 * Searches shim database for a tag within specified domain.
202 * @param [in] pdb Handle to the shim database.
203 * @param [in] parent TAGID of parent.
204 * @param [in] tag TAG to be located.
206 * @return Success: TAGID of first matching tag, Failure: TAGID_NULL.
208 TAGID WINAPI
SdbFindFirstTag(PDB pdb
, TAGID parent
, TAG tag
)
212 iter
= SdbGetFirstChild(pdb
, parent
);
213 while (iter
!= TAGID_NULL
)
215 if (SdbGetTagFromTagID(pdb
, iter
) == tag
)
217 iter
= SdbGetNextChild(pdb
, parent
, iter
);
223 * Searches shim database for a next tag which matches prev_child within parent's domain.
225 * @param [in] pdb Handle to the shim database.
226 * @param [in] parent TAGID of parent.
227 * @param [in] prev_child TAGID of previous match.
229 * @return Success: TAGID of next match, Failure: TAGID_NULL.
231 TAGID WINAPI
SdbFindNextTag(PDB pdb
, TAGID parent
, TAGID prev_child
)
236 tag
= SdbGetTagFromTagID(pdb
, prev_child
);
237 iter
= SdbGetNextChild(pdb
, parent
, prev_child
);
239 while (iter
!= TAGID_NULL
)
241 if (SdbGetTagFromTagID(pdb
, iter
) == tag
)
243 iter
= SdbGetNextChild(pdb
, parent
, iter
);
249 * Searches shim database for string associated with specified tagid and copies string into a
252 * If size parameter is less than number of characters in string, this function shall fail and
253 * no data shall be copied.
255 * @param [in] pdb Handle to the shim database.
256 * @param [in] tagid TAGID of string or stringref associated with the string.
257 * @param [out] buffer Buffer in which string will be copied.
258 * @param [in] size Number of characters to copy.
260 * @return TRUE if string was successfully copied to the buffer FALSE if string was not copied
263 BOOL WINAPI
SdbReadStringTag(PDB pdb
, TAGID tagid
, LPWSTR buffer
, DWORD size
)
268 string
= SdbpGetString(pdb
, tagid
, &string_size
);
272 /* Check if buffer is too small */
273 if (size
* sizeof(WCHAR
) < string_size
)
276 memcpy(buffer
, string
, string_size
);
281 * Reads WORD value at specified tagid.
283 * @param [in] pdb Handle to the shim database.
284 * @param [in] tagid TAGID of WORD value.
285 * @param [in] ret Default return value in case function fails.
287 * @return Success: WORD value at specified tagid, or ret on failure.
289 WORD WINAPI
SdbReadWORDTag(PDB pdb
, TAGID tagid
, WORD ret
)
291 if (SdbpCheckTagIDType(pdb
, tagid
, TAG_TYPE_WORD
))
292 SdbpReadData(pdb
, &ret
, tagid
+ 2, sizeof(WORD
));
297 * Reads DWORD value at specified tagid.
299 * @param [in] pdb Handle to the shim database.
300 * @param [in] tagid TAGID of DWORD value.
301 * @param [in] ret Default return value in case function fails.
303 * @return Success: DWORD value at specified tagid, otherwise ret.
305 DWORD WINAPI
SdbReadDWORDTag(PDB pdb
, TAGID tagid
, DWORD ret
)
307 if (SdbpCheckTagIDType(pdb
, tagid
, TAG_TYPE_DWORD
))
308 SdbpReadData(pdb
, &ret
, tagid
+ 2, sizeof(DWORD
));
313 * Reads QWORD value at specified tagid.
315 * @param [in] pdb Handle to the shim database.
316 * @param [in] tagid TAGID of QWORD value.
317 * @param [in] ret Default return value in case function fails.
319 * @return Success: QWORD value at specified tagid, otherwise ret.
321 QWORD WINAPI
SdbReadQWORDTag(PDB pdb
, TAGID tagid
, QWORD ret
)
323 if (SdbpCheckTagIDType(pdb
, tagid
, TAG_TYPE_QWORD
))
324 SdbpReadData(pdb
, &ret
, tagid
+ sizeof(TAG
), sizeof(QWORD
));
329 * Reads binary data at specified tagid.
331 * @param [in] pdb Handle to the shim database.
332 * @param [in] tagid TAGID of binary data.
333 * @param [out] buffer Buffer in which data will be copied.
334 * @param [in] size Size of the buffer.
336 * @return TRUE if data was successfully written, or FALSE otherwise.
338 BOOL WINAPI
SdbReadBinaryTag(PDB pdb
, TAGID tagid
, PBYTE buffer
, DWORD size
)
342 if (SdbpCheckTagIDType(pdb
, tagid
, TAG_TYPE_BINARY
))
344 SdbpReadData(pdb
, &data_size
, tagid
+ sizeof(TAG
), sizeof(data_size
));
345 if (size
>= data_size
)
346 return SdbpReadData(pdb
, buffer
, tagid
+ sizeof(TAG
) + sizeof(data_size
), data_size
);
353 * Retrieves binary data at specified tagid.
355 * @param [in] pdb Handle to the shim database.
356 * @param [in] tagid TAGID of binary data.
358 * @return Success: Pointer to binary data at specified tagid, or NULL on failure.
360 PVOID WINAPI
SdbGetBinaryTagData(PDB pdb
, TAGID tagid
)
362 if (!SdbpCheckTagIDType(pdb
, tagid
, TAG_TYPE_BINARY
))
364 return &pdb
->data
[tagid
+ sizeof(TAG
) + sizeof(DWORD
)];
368 * Searches shim database for string associated with specified tagid.
370 * @param [in] pdb Handle to the shim database.
371 * @param [in] tagid TAGID of string or stringref associated with the string.
373 * @return the LPWSTR associated with specified tagid, or NULL on failure.
375 LPWSTR WINAPI
SdbGetStringTagPtr(PDB pdb
, TAGID tagid
)
377 return SdbpGetString(pdb
, tagid
, NULL
);
381 * Reads binary data at specified tagid.
383 * @param [in] pdb Handle to the shim database.
384 * @param [out] Guid Database ID.
386 * @return true if the ID was found FALSE otherwise.
388 BOOL WINAPI
SdbGetDatabaseID(PDB pdb
, GUID
* Guid
)
390 if(SdbIsNullGUID(&pdb
->database_id
))
392 TAGID root
= SdbFindFirstTag(pdb
, TAGID_ROOT
, TAG_DATABASE
);
393 if(root
!= TAGID_NULL
)
395 TAGID id
= SdbFindFirstTag(pdb
, root
, TAG_DATABASE_ID
);
398 if(!SdbReadBinaryTag(pdb
, id
, (PBYTE
)&pdb
->database_id
, sizeof(pdb
->database_id
)))
400 memset(&pdb
->database_id
, 0, sizeof(pdb
->database_id
));
405 /* Should we silence this if we are opening a system db? */
406 SHIM_ERR("Failed to get the database id\n");
411 /* Should we silence this if we are opening a system db? */
412 SHIM_ERR("Failed to get root tag\n");
415 if(!SdbIsNullGUID(&pdb
->database_id
))
417 memcpy(Guid
, &pdb
->database_id
, sizeof(pdb
->database_id
));