windows-nt/Source/XPSP1/NT/windows/appcompat/sdbapi/read.c
2020-09-26 16:20:57 +08:00

774 lines
22 KiB
C

/*++
Copyright (c) 1989-2000 Microsoft Corporation
Module Name:
read.c
Abstract:
This module implements primitives used for reading the database.
Author:
dmunsil created sometime in 1999
Revision History:
several people contributed (vadimb, clupu, ...)
--*/
#include "sdbp.h"
#if defined(KERNEL_MODE) && defined(ALLOC_PRAGMA)
#pragma alloc_text(PAGE, SdbpGetTagHeadSize)
#pragma alloc_text(PAGE, SdbReadBYTETag)
#pragma alloc_text(PAGE, SdbReadWORDTag)
#pragma alloc_text(PAGE, SdbReadDWORDTag)
#pragma alloc_text(PAGE, SdbReadQWORDTag)
#pragma alloc_text(PAGE, SdbReadBYTETagRef)
#pragma alloc_text(PAGE, SdbReadWORDTagRef)
#pragma alloc_text(PAGE, SdbReadDWORDTagRef)
#pragma alloc_text(PAGE, SdbReadQWORDTagRef)
#pragma alloc_text(PAGE, SdbGetTagDataSize)
#pragma alloc_text(PAGE, SdbpGetTagRefDataSize)
#pragma alloc_text(PAGE, SdbpReadTagData)
#pragma alloc_text(PAGE, SdbReadStringTagRef)
#pragma alloc_text(PAGE, SdbpReadBinaryTagRef)
#pragma alloc_text(PAGE, SdbpGetMappedTagData)
#pragma alloc_text(PAGE, SdbpGetStringRefLength)
#pragma alloc_text(PAGE, SdbpReadStringRef)
#pragma alloc_text(PAGE, SdbReadStringTag)
#pragma alloc_text(PAGE, SdbGetStringTagPtr)
#pragma alloc_text(PAGE, SdbpReadStringFromTable)
#pragma alloc_text(PAGE, SdbpGetMappedStringFromTable)
#pragma alloc_text(PAGE, SdbReadBinaryTag)
#pragma alloc_text(PAGE, SdbGetBinaryTagData)
#endif // KERNEL_MODE && ALLOC_PRAGMA
DWORD
SdbpGetTagHeadSize(
PDB pdb, // IN - pdb to use
TAGID tiWhich // IN - record to get info on
)
/*++
Return: The size of the non-data (TAG & SIZE) portion of the record.
Desc: Returns the size of the non-data part of a tag in the DB, which is
to say the tag itself (a WORD), and possibly the size (a DWORD).
So this function will return 2 if the tag has an implied size,
6 if the tag has a size after it, and 0 if there was an error.
--*/
{
TAG tWhich;
DWORD dwRetOffset;
DWORD dwOffset = (DWORD)tiWhich;
if (!SdbpReadMappedData(pdb, (DWORD)tiWhich, &tWhich, sizeof(TAG))) {
DBGPRINT((sdlError, "SdbpGetTagHeadSize", "Error reading tag.\n"));
return 0;
}
dwRetOffset = sizeof(TAG);
if (GETTAGTYPE(tWhich) >= TAG_TYPE_LIST) {
dwRetOffset += sizeof(DWORD);
}
return dwRetOffset;
}
//
// This macro is used by the *ReadTypeTag primitives.
//
#define READDATATAG(dataType, tagType, dtDefault) \
{ \
dataType dtReturn = dtDefault; \
\
assert(pdb); \
\
if (GETTAGTYPE(SdbGetTagFromTagID(pdb, tiWhich)) != tagType) { \
DBGPRINT((sdlError, \
"READDATATAG", \
"TagID 0x%X, Tag 0x%X not of the expected type.\n", \
tiWhich, \
(DWORD)SdbGetTagFromTagID(pdb, tiWhich))); \
return dtDefault; \
} \
\
if (!SdbpReadTagData(pdb, tiWhich, &dtReturn, sizeof(dataType))) { \
return dtDefault; \
} \
\
return dtReturn; \
}
BYTE
SdbReadBYTETag(PDB pdb, TAGID tiWhich, BYTE jDefault)
{
READDATATAG(BYTE, TAG_TYPE_BYTE, jDefault);
}
WORD SdbReadWORDTag(PDB pdb, TAGID tiWhich, WORD wDefault)
{
READDATATAG(WORD, TAG_TYPE_WORD, wDefault);
}
DWORD SdbReadDWORDTag(PDB pdb, TAGID tiWhich, DWORD dwDefault)
{
READDATATAG(DWORD, TAG_TYPE_DWORD, dwDefault);
}
ULONGLONG SdbReadQWORDTag(PDB pdb, TAGID tiWhich, ULONGLONG qwDefault)
{
READDATATAG(ULONGLONG, TAG_TYPE_QWORD, qwDefault);
}
//
// This macro is used by the *ReadTypeTag primitives.
//
#define READTYPETAGREF(fnReadTypeTag, dtDefault) \
{ \
PDB pdb; \
TAGID tiWhich; \
\
if (!SdbTagRefToTagID(hSDB, trWhich, &pdb, &tiWhich)) { \
DBGPRINT((sdlError, "READTYPETAGREF", "Can't convert tag ref.\n")); \
return dtDefault; \
} \
\
return fnReadTypeTag(pdb, tiWhich, dtDefault); \
}
BYTE SdbReadBYTETagRef(HSDB hSDB, TAGREF trWhich, BYTE jDefault)
{
READTYPETAGREF(SdbReadBYTETag, jDefault);
}
WORD SdbReadWORDTagRef(HSDB hSDB, TAGREF trWhich, WORD wDefault)
{
READTYPETAGREF(SdbReadWORDTag, wDefault);
}
DWORD SdbReadDWORDTagRef(HSDB hSDB, TAGREF trWhich, DWORD dwDefault)
{
READTYPETAGREF(SdbReadDWORDTag, dwDefault);
}
ULONGLONG SdbReadQWORDTagRef(HSDB hSDB, TAGREF trWhich, ULONGLONG qwDefault)
{
READTYPETAGREF(SdbReadQWORDTag, qwDefault);
}
DWORD
SdbGetTagDataSize(
IN PDB pdb, // DB to use
IN TAGID tiWhich // record to get size of
)
/*++
Return: The size of the data portion of the record.
Desc: Returns the size of the data portion of the given tag, i.e. the
part after the tag WORD and the (possible) size DWORD.
--*/
{
TAG tWhich;
DWORD dwSize;
DWORD dwOffset = (DWORD)tiWhich;
assert(pdb);
tWhich = SdbGetTagFromTagID(pdb, tiWhich);
switch (GETTAGTYPE(tWhich)) {
case TAG_TYPE_NULL:
dwSize = 0;
break;
case TAG_TYPE_BYTE:
dwSize = 1;
break;
case TAG_TYPE_WORD:
dwSize = 2;
break;
case TAG_TYPE_DWORD:
dwSize = 4;
break;
case TAG_TYPE_QWORD:
dwSize = 8;
break;
case TAG_TYPE_STRINGREF:
dwSize = 4;
break;
default:
dwSize = 0;
if (!SdbpReadMappedData(pdb, dwOffset + sizeof(TAG), &dwSize, sizeof(DWORD))) {
DBGPRINT((sdlError, "SdbGetTagDataSize", "Error reading size data\n"));
}
break;
}
return dwSize;
}
DWORD
SdbpGetTagRefDataSize(
IN HSDB hSDB,
IN TAGREF trWhich
)
/*++
Return: The size of the data portion of the record.
Desc: Returns the data size of the tag pointed to by TAGREF.
Useful for finding out how much to allocate before
calling SdbpReadBinaryTagRef.
--*/
{
PDB pdb;
TAGID tiWhich;
try {
if (!SdbTagRefToTagID(hSDB, trWhich, &pdb, &tiWhich)) {
DBGPRINT((sdlError, "SdbpGetTagRefDataSize", "Can't convert tag ref.\n"));
return 0;
}
return SdbGetTagDataSize(pdb, tiWhich);
} except (SHIM_EXCEPT_HANDLER) {
;
}
return 0;
}
BOOL
SdbpReadTagData(
IN PDB pdb, // DB to use
IN TAGID tiWhich, // record to read
OUT PVOID pBuffer, // buffer to fill
IN DWORD dwBufferSize // size of buffer
)
/*++
Return: TRUE if the data was read, FALSE if not.
Desc: An internal function used to read the data from a tag into a buffer.
It does not check the type of the TAG, and should only be used internally.
--*/
{
DWORD dwOffset;
DWORD dwSize;
assert(pdb && pBuffer);
dwSize = SdbGetTagDataSize(pdb, tiWhich);
if (dwSize > dwBufferSize) {
DBGPRINT((sdlError,
"SdbpReadTagData",
"Buffer too small. Avail: %d, Need: %d.\n",
dwBufferSize,
dwSize));
return FALSE;
}
dwOffset = tiWhich + SdbpGetTagHeadSize(pdb, tiWhich);
if (!SdbpReadMappedData(pdb, dwOffset, pBuffer, dwSize)) {
DBGPRINT((sdlError,
"SdbpReadTagData",
"Error reading tag data.\n"));
return FALSE;
}
return TRUE;
}
BOOL
SdbReadStringTagRef(
IN HSDB hSDB, // handle to the database channel
IN TAGREF trWhich, // string or stringref tag to read
OUT LPTSTR pwszBuffer, // buffer to fill
IN DWORD dwBufferSize // size of passed-in buffer
)
/*++
Return: TRUE if the string was read, FALSE if not.
Desc: Reads a tag of type STRING or STRINGREF into a buffer. If the
type is STRING, the data is read directly from the tag.
If the type is STRINGREF, the string is read from the string
table at the end of the file. Which one it is should be
transparent to the caller.
--*/
{
PDB pdb;
TAGID tiWhich;
try {
if (!SdbTagRefToTagID(hSDB, trWhich, &pdb, &tiWhich)) {
DBGPRINT((sdlError, "SdbReadStringTagRef", "Can't convert tag ref.\n"));
return FALSE;
}
return SdbReadStringTag(pdb, tiWhich, pwszBuffer, dwBufferSize);
} except (SHIM_EXCEPT_HANDLER) {
;
}
return FALSE;
}
BOOL
SdbpReadBinaryTagRef(
IN HSDB hSDB, // handle to the database channel
IN TAGREF trWhich, // BINARY tag to read
OUT PBYTE pBuffer, // buffer to fill
IN DWORD dwBufferSize // size of passed-in buffer
)
/*++
Return: TRUE if the buffer was read, FALSE if not.
Desc: Reads a tag of type BINARY into pBuffer. Use SdbpGetTagRefDataSize
to get the size of the buffer before calling this routine.
--*/
{
PDB pdb;
TAGID tiWhich;
try {
if (!SdbTagRefToTagID(hSDB, trWhich, &pdb, &tiWhich)) {
DBGPRINT((sdlError, "SdbpReadBinaryTagRef", "Can't convert tag ref.\n"));
return FALSE;
}
return SdbReadBinaryTag(pdb, tiWhich, pBuffer, dwBufferSize);
} except (SHIM_EXCEPT_HANDLER) {
}
return FALSE;
}
PVOID
SdbpGetMappedTagData(
IN PDB pdb, // DB to use
IN TAGID tiWhich // record to read
)
/*++
Return: The data pointer or NULL on failure.
Desc: An internal function used to get a pointer to the tag data.
It works only if the DB is mapped.
--*/
{
PVOID pReturn;
DWORD dwOffset;
assert(pdb);
dwOffset = tiWhich + SdbpGetTagHeadSize(pdb, tiWhich);
pReturn = SdbpGetMappedData(pdb, dwOffset);
if (pReturn == NULL) {
DBGPRINT((sdlError, "SdbpGetMappedTagData", "Error getting ptr to tag data.\n"));
}
return pReturn;
}
DWORD
SdbpGetStringRefLength(
IN HSDB hSDB,
IN TAGREF trString
)
/*++
Return: BUGBUG: ?
Desc: BUGBUG: ?
--*/
{
PDB pdb = NULL;
TAGID tiString = TAGID_NULL;
DWORD dwLength = 0;
LPCTSTR lpszString;
if (!SdbTagRefToTagID(hSDB, trString, &pdb, &tiString)) {
DBGPRINT((sdlError,
"SdbGetStringRefLength",
"Failed to convert tag 0x%x to tagid\n",
trString));
return dwLength;
}
lpszString = SdbGetStringTagPtr(pdb, tiString);
if (lpszString != NULL) {
dwLength = _tcslen(lpszString);
}
return dwLength;
}
LPCTSTR
SdbpGetStringRefPtr(
IN HSDB hSDB,
IN TAGREF trString
)
{
PDB pdb = NULL;
TAGID tiString = TAGID_NULL;
if (!SdbTagRefToTagID(hSDB, trString, &pdb, &tiString)) {
DBGPRINT((sdlError, "SdbGetStringRefPtr",
"Failed to convert tag 0x%x to tagid\n", trString));
return NULL;
}
return SdbGetStringTagPtr(pdb, tiString);
}
STRINGREF
SdbpReadStringRef(
IN PDB pdb, // PDB to use
IN TAGID tiWhich // record of type STRINGREF
)
/*++
Return: Returns the stringref, or STRINGREF_NULL on failure.
Desc: Used to read a stringref tag directly; normally one would just read
it like a string, and let the DB fix up string refs. But a low-level
tool may need to know exactly what it's reading.
--*/
{
STRINGREF srReturn = STRINGREF_NULL;
assert(pdb);
if (GETTAGTYPE(SdbGetTagFromTagID(pdb, tiWhich)) != TAG_TYPE_STRINGREF) {
DBGPRINT((sdlError,
"SdbpReadStringRef",
"TagID 0x%08X, Tag %04X not STRINGREF type.\n",
tiWhich,
(DWORD)SdbGetTagFromTagID(pdb, tiWhich)));
return STRINGREF_NULL;
}
if (!SdbpReadTagData(pdb, tiWhich, &srReturn, sizeof(STRINGREF))) {
DBGPRINT((sdlError, "SdbpReadStringRef", "Error reading data.\n"));
return STRINGREF_NULL;
}
return srReturn;
}
BOOL
SdbReadStringTag(
IN PDB pdb, // DB to use
IN TAGID tiWhich, // record of type STRING or STRINGREF
OUT LPTSTR pwszBuffer, // buffer to fill
IN DWORD dwBufferSize // size in characters of buffer (leave room for zero!)
)
/*++
Return: TRUE if successful, or FALSE if the string can't be found or the
buffer is too small.
Desc: Reads a string from the DB into szBuffer. If the tag is of
type STRING, the string is just read from the data portion of
the tag. If the tag is of type STRINGREF, the db reads the STRINGREF,
then uses it to read the string from the string table at the end of
the file. Either way, it's transparent to the caller.
--*/
{
TAG tWhich;
BOOL bSuccess;
assert(pdb && pwszBuffer);
tWhich = SdbGetTagFromTagID(pdb, tiWhich);
if (GETTAGTYPE(tWhich) == TAG_TYPE_STRING) {
//
// Read an actual string.
//
return(READ_STRING(pdb, tiWhich, pwszBuffer, dwBufferSize));
} else if (GETTAGTYPE(tWhich) == TAG_TYPE_STRINGREF) {
//
// Read a string reference, then get the string out of the table
//
STRINGREF srWhich = SdbpReadStringRef(pdb, tiWhich);
if (srWhich == 0) {
DBGPRINT((sdlError, "SdbReadStringTag", "Error getting StringRef.\n"));
return FALSE;
}
return SdbpReadStringFromTable(pdb, srWhich, pwszBuffer, dwBufferSize);
}
//
// This ain't no kind of string at all
//
return FALSE;
}
LPTSTR
SdbGetStringTagPtr(
IN PDB pdb, // DB to use
IN TAGID tiWhich // record of type STRING or STRINGREF
)
/*++
Return: Returns a pointer if successful, or NULL if the string can't be found.
Desc: Gets a pointer to the string. If the tag is of type STRING,
the string is just obtained from the data portion of the tag.
If the tag is of type STRINGREF, the db reads the STRINGREF,
then uses it to get the string from the string table at the end
of the file. Either way, it's transparent to the caller.
--*/
{
TAG tWhich;
LPTSTR pszReturn = NULL;
assert(pdb);
tWhich = SdbGetTagFromTagID(pdb, tiWhich);
if (GETTAGTYPE(tWhich) == TAG_TYPE_STRING) {
//
// Read an actual string.
//
pszReturn = CONVERT_STRINGPTR(pdb,
SdbpGetMappedTagData(pdb, tiWhich),
TAG_TYPE_STRING,
tiWhich);
} else if (GETTAGTYPE(tWhich) == TAG_TYPE_STRINGREF) {
//
// Read a string reference, then get the string out of the table.
//
STRINGREF srWhich = SdbpReadStringRef(pdb, tiWhich);
if (srWhich == 0) {
DBGPRINT((sdlError, "SdbReadStringTag", "Error getting StringRef.\n"));
return NULL;
}
pszReturn = CONVERT_STRINGPTR(pdb,
SdbpGetMappedStringFromTable(pdb, srWhich),
TAG_TYPE_STRINGREF,
srWhich);
}
//
// This ain't no kind of string at all.
//
return pszReturn;
}
BOOL
SdbpReadStringFromTable(
IN PDB pdb, // DB to use
IN STRINGREF srData, // STRINGREF to get
OUT LPTSTR szBuffer, // buffer to fill
IN DWORD dwBufferSize // size of buffer
)
/*++
Return: TRUE if the string was read, FALSE if not.
Desc: Reads a string out of the string table, given a STRINGREF.
The STRINGREF is a direct offset from the beginning of the
STRINGTABLE tag that should exist at the end of the db.
--*/
{
TAGID tiWhich;
TAG tWhich;
PDB pdbString = NULL;
assert(pdb && srData && szBuffer);
if (pdb->bWrite) {
//
// When we're writing, the string table is in a separate DB.
//
if (!pdb->pdbStringTable) {
DBGPRINT((sdlError, "SdbpReadStringFromTable", "No stringtable in DB.\n"));
return FALSE;
}
//
// Adjust for the slightly different offsets in the other DB.
//
tiWhich = srData - sizeof(TAG) - sizeof(DWORD) + sizeof(DB_HEADER);
pdbString = pdb->pdbStringTable;
} else {
//
// The STRINGREF is an offset from the beginning of the string table.
//
if (pdb->tiStringTable == TAGID_NULL) {
pdb->tiStringTable = SdbFindFirstTag(pdb, TAGID_ROOT, TAG_STRINGTABLE);
if (pdb->tiStringTable == TAGID_NULL) {
DBGPRINT((sdlError, "SdbpReadStringFromTable", "No stringtable in DB.\n"));
return FALSE;
}
}
tiWhich = pdb->tiStringTable + srData;
pdbString = pdb;
}
tWhich = SdbGetTagFromTagID(pdbString, tiWhich);
if (tWhich != TAG_STRINGTABLE_ITEM) {
DBGPRINT((sdlError, "SdbpReadStringFromTable", "Pulled out a non-stringtable item.\n"));
return FALSE;
}
return READ_STRING(pdbString, tiWhich, szBuffer, dwBufferSize);
}
WCHAR*
SdbpGetMappedStringFromTable(
IN PDB pdb, // DB to use
IN STRINGREF srData // STRINGREF to get
)
/*++
Return: A pointer to a string or NULL.
Desc: Gets a pointer to a string in the string table, given a STRINGREF.
The STRINGREF is a direct offset from the beginning of the STRINGTABLE
tag that should exist at the end of the db.
--*/
{
TAGID tiWhich;
TAG tWhich;
PDB pdbString = NULL;
assert(pdb && srData);
if (pdb->bWrite) {
//
// When we're writing, the string table is in a separate DB.
//
if (pdb->pdbStringTable == NULL) {
DBGPRINT((sdlError, "SdbpGetMappedStringFromTable", "No stringtable in DB.\n"));
return NULL;
}
//
// Adjust for the slightly different offsets in the other DB
//
tiWhich = srData - sizeof(TAG) - sizeof(DWORD) + sizeof(DB_HEADER);
pdbString = pdb->pdbStringTable;
} else {
if (pdb->tiStringTable == TAGID_NULL) {
pdb->tiStringTable = SdbFindFirstTag(pdb, TAGID_ROOT, TAG_STRINGTABLE);
if (pdb->tiStringTable == TAGID_NULL) {
DBGPRINT((sdlError, "SdbpGetMappedStringFromTable", "No stringtable in DB.\n"));
return NULL;
}
}
//
// The STRINGREF is an offset from the beginning of the string table.
//
tiWhich = pdb->tiStringTable + srData;
pdbString = pdb;
}
tWhich = SdbGetTagFromTagID(pdbString, tiWhich);
if (tWhich != TAG_STRINGTABLE_ITEM) {
DBGPRINT((sdlError,
"SdbpGetMappedStringFromTable",
"Pulled out a non-stringtable item.\n"));
return NULL;
}
return (WCHAR*)SdbpGetMappedTagData(pdbString, tiWhich);
}
BOOL
SdbReadBinaryTag(
IN PDB pdb, // DB to use
IN TAGID tiWhich, // record of BASIC TYPE BINARY
OUT PBYTE pBuffer, // buffer to fill
IN DWORD dwBufferSize // buffer size
)
/*++
Return: TRUE if the data was read, FALSE if not.
Desc: Reads data from a tag of type BINARY into pBuffer.
Returns FALSE if the tag is not type BINARY, or the buffer is too small.
--*/
{
assert(pdb);
if (GETTAGTYPE(SdbGetTagFromTagID(pdb, tiWhich)) != TAG_TYPE_BINARY) {
DBGPRINT((sdlError,
"SdbReadBinaryTag",
"TagID 0x%08X, Tag %04X not BINARY type.\n",
tiWhich,
(DWORD)SdbGetTagFromTagID(pdb, tiWhich)));
return FALSE;
}
if (!SdbpReadTagData(pdb, tiWhich, pBuffer, dwBufferSize)) {
DBGPRINT((sdlError, "SdbReadBinaryTag", "Error reading buffer.\n"));
return FALSE;
}
return TRUE;
}
PVOID
SdbGetBinaryTagData(
IN PDB pdb, // pointer to the database to use
IN TAGID tiWhich // tagid of the binary tag
)
/*++
Return: pointer to the binary data referenced by tiWhich or NULL if
tiWhich does not refer to the binary tag or if tiWhich is invalid.
Desc: Function returns pointer to the [mapped] binary data referred to by
tiWhich parameter in the database pdb.
--*/
{
assert(pdb);
if (GETTAGTYPE(SdbGetTagFromTagID(pdb, tiWhich)) != TAG_TYPE_BINARY) {
DBGPRINT((sdlError,
"SdbGetBinaryTagData",
"TagID 0x%08X, Tag %04X not BINARY type.\n",
tiWhich,
(DWORD)SdbGetTagFromTagID(pdb, tiWhich)));
return NULL;
}
return SdbpGetMappedTagData(pdb, tiWhich);
}