1463 lines
37 KiB
C
1463 lines
37 KiB
C
/*++
|
|
|
|
Copyright (c) 1989-2000 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
index.c
|
|
|
|
Abstract:
|
|
|
|
This module implements the APIs and internal functions used to access and build
|
|
indexes in the database.
|
|
|
|
Author:
|
|
|
|
dmunsil created sometime in 1999
|
|
|
|
Revision History:
|
|
|
|
several people contributed (vadimb, clupu, ...)
|
|
|
|
--*/
|
|
|
|
#include "sdbp.h"
|
|
|
|
#if defined(KERNEL_MODE) && defined(ALLOC_DATA_PRAGMA)
|
|
#pragma data_seg()
|
|
#endif // KERNEL_MODE && ALLOC_DATA_PRAGMA
|
|
|
|
|
|
#if defined(KERNEL_MODE) && defined(ALLOC_PRAGMA)
|
|
#pragma alloc_text(PAGE, SdbFindFirstGUIDIndexedTag)
|
|
#pragma alloc_text(PAGE, SdbFindNextGUIDIndexedTag)
|
|
#pragma alloc_text(PAGE, SdbFindFirstDWORDIndexedTag)
|
|
#pragma alloc_text(PAGE, SdbFindNextDWORDIndexedTag)
|
|
#pragma alloc_text(PAGE, SdbFindFirstStringIndexedTag)
|
|
#pragma alloc_text(PAGE, SdbFindNextStringIndexedTag)
|
|
#pragma alloc_text(PAGE, SdbpBinarySearchUnique)
|
|
#pragma alloc_text(PAGE, SdbpBinarySearchFirst)
|
|
#pragma alloc_text(PAGE, SdbpGetFirstIndexedRecord)
|
|
#pragma alloc_text(PAGE, SdbpGetNextIndexedRecord)
|
|
#pragma alloc_text(PAGE, SdbpPatternMatch)
|
|
#pragma alloc_text(PAGE, SdbpPatternMatchAnsi)
|
|
#pragma alloc_text(PAGE, SdbpKeyToAnsiString)
|
|
#pragma alloc_text(PAGE, SdbpFindFirstIndexedWildCardTag)
|
|
#pragma alloc_text(PAGE, SdbpFindNextIndexedWildCardTag)
|
|
#pragma alloc_text(PAGE, SdbGetIndex)
|
|
#pragma alloc_text(PAGE, SdbpScanIndexes)
|
|
#pragma alloc_text(PAGE, SdbpGetIndex)
|
|
#pragma alloc_text(PAGE, SdbMakeIndexKeyFromString)
|
|
#pragma alloc_text(PAGE, SdbpTagToKey)
|
|
#endif // KERNEL_MODE && ALLOC_PRAGMA
|
|
|
|
TAGID
|
|
SdbFindFirstGUIDIndexedTag(
|
|
IN PDB pdb,
|
|
IN TAG tWhich,
|
|
IN TAG tKey,
|
|
IN GUID* pguidName,
|
|
OUT FIND_INFO* pFindInfo
|
|
)
|
|
/*++
|
|
Return: void
|
|
|
|
Desc: This function locates the first matching entry indexed by GUID id
|
|
--*/
|
|
{
|
|
TAGID tiReturn;
|
|
DWORD dwFlags = 0;
|
|
|
|
pFindInfo->tiIndex = SdbGetIndex(pdb, tWhich, tKey, &dwFlags);
|
|
|
|
if (pFindInfo->tiIndex == TAGID_NULL) {
|
|
DBGPRINT((sdlError,
|
|
"SdbFindFirstGUIDIndexedTag",
|
|
"Failed to find index 0x%lx key 0x%lx\n",
|
|
tWhich, tKey));
|
|
|
|
return TAGID_NULL;
|
|
}
|
|
|
|
pFindInfo->tName = tKey;
|
|
pFindInfo->pguidName = pguidName;
|
|
pFindInfo->dwFlags = dwFlags;
|
|
pFindInfo->ullKey = MAKEKEYFROMGUID(pguidName);
|
|
|
|
tiReturn = SdbpGetFirstIndexedRecord(pdb, pFindInfo->tiIndex, pFindInfo->ullKey, pFindInfo);
|
|
|
|
if (tiReturn == TAGID_NULL) {
|
|
//
|
|
// While this is handled properly in FindMatchingGUID we return here since
|
|
// the record was not found in the index. It is not an abnormal condition.
|
|
// We have just failed to find the match. Likewise, DBGPRINT is not warranted
|
|
//
|
|
return tiReturn;
|
|
}
|
|
|
|
return SdbpFindMatchingGUID(pdb, tiReturn, pFindInfo);
|
|
}
|
|
|
|
TAGID
|
|
SdbFindNextGUIDIndexedTag(
|
|
IN PDB pdb,
|
|
OUT FIND_INFO* pFindInfo
|
|
)
|
|
/*++
|
|
Return: The TAGID of the next GUID-indexed tag.
|
|
|
|
Desc: This function finds the next entry matching a guid provided in a
|
|
previous call to SdbFindNextGUIDIndexedTag
|
|
--*/
|
|
{
|
|
TAGID tiReturn;
|
|
|
|
//
|
|
// Get a preliminary match from the index.
|
|
//
|
|
tiReturn = SdbpGetNextIndexedRecord(pdb, pFindInfo->tiIndex, pFindInfo);
|
|
|
|
if (tiReturn == TAGID_NULL) {
|
|
//
|
|
// This case is handled properly in SdbpFindMatchingGUID
|
|
// we return here however for simplicity.
|
|
// DBGPRINT is not needed since it's not an abnormal condition
|
|
//
|
|
return tiReturn;
|
|
}
|
|
|
|
return SdbpFindMatchingGUID(pdb, tiReturn, pFindInfo);
|
|
}
|
|
|
|
TAGID
|
|
SdbFindFirstDWORDIndexedTag(
|
|
IN PDB pdb,
|
|
IN TAG tWhich,
|
|
IN TAG tKey,
|
|
IN DWORD dwName,
|
|
OUT FIND_INFO* pFindInfo
|
|
)
|
|
/*++
|
|
Return: BUGBUG: ?
|
|
|
|
Desc: BUGBUG: what does this do ?
|
|
--*/
|
|
{
|
|
|
|
TAGID tiReturn;
|
|
DWORD dwFlags = 0;
|
|
|
|
pFindInfo->tiIndex = SdbGetIndex(pdb, tWhich, tKey, &dwFlags);
|
|
|
|
if (pFindInfo->tiIndex == TAGID_NULL) {
|
|
DBGPRINT((sdlError,
|
|
"SdbFindFirstDWORDIndexedTag",
|
|
"Failed to find index 0x%lx key 0x%lx\n",
|
|
tWhich, tKey));
|
|
|
|
return TAGID_NULL;
|
|
}
|
|
|
|
pFindInfo->tName = tKey;
|
|
pFindInfo->dwName = dwName;
|
|
pFindInfo->dwFlags = dwFlags;
|
|
pFindInfo->ullKey = MAKEKEYFROMDWORD(dwName);
|
|
|
|
tiReturn = SdbpGetFirstIndexedRecord(pdb, pFindInfo->tiIndex, pFindInfo->ullKey, pFindInfo);
|
|
|
|
if (tiReturn == TAGID_NULL) {
|
|
//
|
|
// While this is handled properly in FindMatchingGUID we return here since
|
|
// the record was not found in the index. It is not an abnormal condition.
|
|
// We have just failed to find the match. Likewise, DBGPRINT is not warranted
|
|
//
|
|
return tiReturn;
|
|
}
|
|
|
|
return SdbpFindMatchingDWORD(pdb, tiReturn, pFindInfo);
|
|
}
|
|
|
|
TAGID
|
|
SdbFindNextDWORDIndexedTag(
|
|
IN PDB pdb,
|
|
OUT FIND_INFO* pFindInfo
|
|
)
|
|
/*++
|
|
Return: BUGBUG: ?
|
|
|
|
Desc: BUGBUG: ?
|
|
--*/
|
|
{
|
|
TAGID tiReturn;
|
|
|
|
//
|
|
// Get a preliminary match from the index.
|
|
//
|
|
tiReturn = SdbpGetNextIndexedRecord(pdb, pFindInfo->tiIndex, pFindInfo);
|
|
|
|
if (tiReturn == TAGID_NULL) {
|
|
//
|
|
// This case is handled properly in SdbpFindMatchingDWORD
|
|
// we return here however for simplicity.
|
|
// DBGPRINT is not needed since it's not an abnormal condition
|
|
//
|
|
return tiReturn;
|
|
}
|
|
|
|
return SdbpFindMatchingDWORD(pdb, tiReturn, pFindInfo);
|
|
|
|
}
|
|
|
|
TAGID
|
|
SdbFindFirstStringIndexedTag(
|
|
IN PDB pdb,
|
|
IN TAG tWhich,
|
|
IN TAG tKey,
|
|
IN LPCTSTR pszName,
|
|
OUT FIND_INFO* pFindInfo
|
|
)
|
|
/*++
|
|
Return: BUGBUG: ?
|
|
|
|
Desc: BUGBUG: ?
|
|
--*/
|
|
{
|
|
TAGID tiReturn;
|
|
DWORD dwFlags = 0;
|
|
|
|
pFindInfo->tiIndex = SdbGetIndex(pdb, tWhich, tKey, &dwFlags);
|
|
|
|
if (pFindInfo->tiIndex == TAGID_NULL) {
|
|
|
|
DBGPRINT((sdlError,
|
|
"SdbFindFirstStringIndexedTag",
|
|
"Index not found 0x%lx Key 0x%lx\n",
|
|
tWhich,
|
|
tKey));
|
|
|
|
return TAGID_NULL;
|
|
}
|
|
|
|
pFindInfo->tName = tKey;
|
|
pFindInfo->szName = (LPTSTR)pszName;
|
|
pFindInfo->dwFlags = dwFlags;
|
|
pFindInfo->ullKey = SdbMakeIndexKeyFromString(pszName);
|
|
|
|
//
|
|
// Get a preliminary match from the index.
|
|
//
|
|
tiReturn = SdbpGetFirstIndexedRecord(pdb, pFindInfo->tiIndex, pFindInfo->ullKey, pFindInfo);
|
|
|
|
if (tiReturn == TAGID_NULL) {
|
|
//
|
|
// This is not a bug, tag was not found
|
|
//
|
|
return tiReturn;
|
|
}
|
|
|
|
DBGPRINT((sdlInfo, "SdbFindFirstStringIndexedTag", "Found tagid 0x%x\n", tiReturn));
|
|
|
|
return SdbpFindMatchingName(pdb, tiReturn, pFindInfo);
|
|
}
|
|
|
|
|
|
TAGID
|
|
SdbFindNextStringIndexedTag(
|
|
IN PDB pdb,
|
|
OUT FIND_INFO* pFindInfo
|
|
)
|
|
/*++
|
|
Return: BUGBUG: ?
|
|
|
|
Desc: BUGBUG: ?
|
|
--*/
|
|
{
|
|
TAGID tiReturn;
|
|
|
|
//
|
|
// Get a preliminary match from the index.
|
|
//
|
|
tiReturn = SdbpGetNextIndexedRecord(pdb, pFindInfo->tiIndex, pFindInfo);
|
|
|
|
if (tiReturn == TAGID_NULL) {
|
|
//
|
|
// This is not a bug, this item was not found
|
|
//
|
|
return tiReturn;
|
|
}
|
|
|
|
return SdbpFindMatchingName(pdb, tiReturn, pFindInfo);
|
|
|
|
}
|
|
|
|
BOOL
|
|
SdbpBinarySearchUnique(
|
|
IN PINDEX_RECORD pRecords, // index record ptr
|
|
IN DWORD nRecords, // number of records
|
|
IN ULONGLONG ullKey, // key to search for
|
|
OUT DWORD* pdwIndex // index to the item
|
|
)
|
|
/*++
|
|
Return: TRUE if the index to the item is found.
|
|
|
|
Desc: BUGBUG: comment ?
|
|
--*/
|
|
{
|
|
int iLeft = 0;
|
|
int iRight = (int)nRecords - 1;
|
|
int i = -1;
|
|
ULONGLONG ullKeyIndex;
|
|
BOOL bFound = FALSE;
|
|
|
|
if (iRight >= 0) {
|
|
do {
|
|
i = (iLeft + iRight) / 2; // middle
|
|
|
|
READ_INDEX_KEY(pRecords, i, &ullKeyIndex);
|
|
|
|
if (ullKey <= ullKeyIndex) {
|
|
iRight = i - 1;
|
|
}
|
|
|
|
if (ullKey >= ullKeyIndex) {
|
|
iLeft = i + 1;
|
|
}
|
|
} while (iRight >= iLeft);
|
|
}
|
|
|
|
bFound = (iLeft - iRight > 1);
|
|
|
|
if (bFound) {
|
|
*pdwIndex = (DWORD)i;
|
|
}
|
|
return bFound;
|
|
}
|
|
|
|
BOOL
|
|
SdbpBinarySearchFirst(
|
|
IN PINDEX_RECORD pRecords,
|
|
IN DWORD nRecords,
|
|
IN ULONGLONG ullKey,
|
|
OUT DWORD* pdwIndex
|
|
)
|
|
{
|
|
int iLeft = 0;
|
|
int iRight = (int)nRecords - 1;
|
|
int i = -1;
|
|
|
|
ULONGLONG ullKeyIndex = 0;
|
|
ULONGLONG ullKeyIndexPrev = 0;
|
|
BOOL bFound = FALSE;
|
|
|
|
if (iRight < 0) {
|
|
return FALSE;
|
|
}
|
|
|
|
do {
|
|
|
|
i= (iLeft + iRight) / 2; // middle
|
|
READ_INDEX_KEY(pRecords, i, &ullKeyIndex);
|
|
|
|
if (ullKey == ullKeyIndex) {
|
|
if (i == 0 || READ_INDEX_KEY_VAL(pRecords, i - 1, &ullKeyIndexPrev) != ullKey) {
|
|
//
|
|
// we are done, thank you
|
|
//
|
|
bFound = TRUE;
|
|
break;
|
|
} else {
|
|
//
|
|
// look in the previous record
|
|
//
|
|
iRight = i - 1;
|
|
}
|
|
|
|
} else {
|
|
|
|
if (ullKey < ullKeyIndex) {
|
|
iRight = i - 1;
|
|
} else {
|
|
iLeft = i + 1;
|
|
}
|
|
}
|
|
|
|
} while (iRight >= iLeft);
|
|
|
|
if (bFound) {
|
|
*pdwIndex = (DWORD)i;
|
|
}
|
|
return bFound;
|
|
|
|
}
|
|
|
|
TAGID
|
|
SdbpGetFirstIndexedRecord(
|
|
IN PDB pdb, // the DB to use
|
|
IN TAGID tiIndex, // the index to use
|
|
IN ULONGLONG ullKey, // the key to search for
|
|
OUT FIND_INFO* pFindInfo // search context
|
|
)
|
|
/*++
|
|
Return: the record found, or TAGID_NULL.
|
|
|
|
Desc: Looks through an index for the first record that matches the key. It
|
|
returns the index record position for subsequent calls to SdbpGetNextIndexedRecord.
|
|
--*/
|
|
{
|
|
PINDEX_RECORD pIndexRecords;
|
|
DWORD dwRecords;
|
|
BOOL bFound;
|
|
|
|
if (SdbGetTagFromTagID(pdb, tiIndex) != TAG_INDEX_BITS) {
|
|
|
|
DBGPRINT((sdlError,
|
|
"SdbpGetFirstIndexedRecord",
|
|
"The tag 0x%lx is not an index tag\n",
|
|
tiIndex));
|
|
|
|
return TAGID_NULL;
|
|
}
|
|
|
|
dwRecords = SdbGetTagDataSize(pdb, tiIndex) / sizeof(INDEX_RECORD);
|
|
|
|
pIndexRecords = (INDEX_RECORD*)SdbpGetMappedTagData(pdb, tiIndex);
|
|
|
|
if (pIndexRecords == NULL) {
|
|
|
|
DBGPRINT((sdlError,
|
|
"SdbpGetFirstIndexedRecord",
|
|
"Failed to get the pointer to index data, index tagid 0x%lx\n",
|
|
tiIndex));
|
|
|
|
return TAGID_NULL;
|
|
}
|
|
|
|
//
|
|
// Check to see whether our index is "unique", if so use our search proc.
|
|
//
|
|
if (pFindInfo->dwFlags & SHIMDB_INDEX_UNIQUE_KEY) {
|
|
bFound = SdbpBinarySearchUnique(pIndexRecords,
|
|
dwRecords,
|
|
ullKey,
|
|
&pFindInfo->dwIndexRec);
|
|
|
|
if (bFound && pFindInfo->dwIndexRec < (dwRecords - 1)) {
|
|
//
|
|
// We have the next rec -- retrieve the next tagid.
|
|
//
|
|
pFindInfo->tiEndIndex = pIndexRecords[pFindInfo->dwIndexRec + 1].tiRef;
|
|
} else {
|
|
//
|
|
// We will have to search until eof.
|
|
//
|
|
pFindInfo->tiEndIndex = TAGID_NULL;
|
|
}
|
|
pFindInfo->tiCurrent = TAGID_NULL;
|
|
|
|
} else {
|
|
bFound = SdbpBinarySearchFirst(pIndexRecords,
|
|
dwRecords,
|
|
ullKey,
|
|
&pFindInfo->dwIndexRec);
|
|
}
|
|
|
|
return bFound ? pIndexRecords[pFindInfo->dwIndexRec].tiRef : TAGID_NULL;
|
|
}
|
|
|
|
TAGID
|
|
SdbpGetNextIndexedRecord(
|
|
IN PDB pdb, // the DB to use
|
|
IN TAGID tiIndex, // the index to use
|
|
OUT FIND_INFO* pFindInfo // the find context
|
|
)
|
|
/*++
|
|
Return: the record found, or TAGID_NULL.
|
|
|
|
Desc: Gets the next record that matches the one found by a previous call to
|
|
SdbpGetFirstIndexedRecord.
|
|
--*/
|
|
{
|
|
ULONGLONG ullKey;
|
|
ULONGLONG ullKeyNext;
|
|
PINDEX_RECORD pIndexRecords;
|
|
DWORD dwRecords;
|
|
TAGID tiRef = TAGID_NULL;
|
|
TAGID tiThis;
|
|
TAG tag, tagThis;
|
|
|
|
if (SdbGetTagFromTagID(pdb, tiIndex) != TAG_INDEX_BITS) {
|
|
DBGPRINT((sdlError,
|
|
"SdbpGetNextIndexedRecord",
|
|
"The tag 0x%lx is not an index tag\n",
|
|
tiIndex));
|
|
|
|
return TAGID_NULL;
|
|
}
|
|
|
|
pIndexRecords = (PINDEX_RECORD)SdbpGetMappedTagData(pdb, tiIndex);
|
|
|
|
if (pIndexRecords == NULL) {
|
|
|
|
DBGPRINT((sdlError,
|
|
"SdbpGetNextIndexedRecord",
|
|
"Failed to get pointer to the index data tagid x%lx\n",
|
|
tiIndex));
|
|
|
|
return TAGID_NULL;
|
|
}
|
|
|
|
if (pFindInfo->dwFlags & SHIMDB_INDEX_UNIQUE_KEY) {
|
|
//
|
|
// There are 2 cases:
|
|
// - this is the very first call to SdbpGetNextIndexedrecord
|
|
// - this is one of the subsequent calls
|
|
//
|
|
// In the first case, we will have tiCurrent member of the FIND_INFO
|
|
// structure set to TAGID_NULL. We use then the reference to the
|
|
// index table contained in pFindInfo->dwIndexRec to obtain the reference
|
|
// to the next eligible entry in the database.
|
|
// In the second case we use the stored tiCurrent to obtain the current tag
|
|
//
|
|
if (pFindInfo->tiCurrent == TAGID_NULL) {
|
|
tiThis = pIndexRecords[pFindInfo->dwIndexRec].tiRef;
|
|
} else {
|
|
tiThis = pFindInfo->tiCurrent;
|
|
}
|
|
|
|
//
|
|
// The tag tiThis which we just obtained was the one we previously looked at
|
|
// we need to step to the next tag, the call below does that. Entries are sorted
|
|
// since we're using "unique" index
|
|
//
|
|
tiRef = SdbpGetNextTagId(pdb, tiThis);
|
|
|
|
//
|
|
// Now check the tag for corruption, eof and other calamities.
|
|
//
|
|
tagThis = SdbGetTagFromTagID(pdb, tiThis);
|
|
tag = SdbGetTagFromTagID(pdb, tiRef);
|
|
|
|
if (tag == TAG_NULL || GETTAGTYPE(tag) != TAG_TYPE_LIST || tag != tagThis) {
|
|
|
|
//
|
|
// This is NOT a bug, but a special condition when the tag happened to be
|
|
// the very last tag in the index, thus we have to walk until we hit either
|
|
// the end of the file - or a tag of a different type
|
|
|
|
return TAGID_NULL;
|
|
}
|
|
|
|
//
|
|
// Also check for the endtag. It will be a check for TAGID_NULL if we're
|
|
// looking for eof but this condition has already been caught by the code above.
|
|
//
|
|
if (tiRef == pFindInfo->tiEndIndex) {
|
|
|
|
//
|
|
// This is not an error condition. We have walked all the matching entries until
|
|
// we hit the very last entry, as denoted by tiEndIndex
|
|
//
|
|
|
|
return TAGID_NULL;
|
|
}
|
|
|
|
//
|
|
// Also here check whether the key still has the same
|
|
// value for this entry as it did for the previous entry.
|
|
// This would have been easy but keys are not immediately available
|
|
// for this entry therefore we just return the tiRef. The caller will
|
|
// verify whether the entry is valid and whether the search should continue.
|
|
//
|
|
pFindInfo->tiCurrent = tiRef;
|
|
|
|
} else {
|
|
|
|
dwRecords = SdbGetTagDataSize(pdb, tiIndex) / sizeof(INDEX_RECORD);
|
|
|
|
//
|
|
// Get out if this is the last record.
|
|
//
|
|
if (pFindInfo->dwIndexRec == dwRecords - 1) {
|
|
//
|
|
// This is not a bug, record not found
|
|
//
|
|
return TAGID_NULL;
|
|
}
|
|
|
|
//
|
|
// we check the next index record to see if it has the same key
|
|
//
|
|
READ_INDEX_KEY(pIndexRecords, pFindInfo->dwIndexRec, &ullKey);
|
|
READ_INDEX_KEY(pIndexRecords, pFindInfo->dwIndexRec + 1, &ullKeyNext);
|
|
|
|
if (ullKey != ullKeyNext) {
|
|
|
|
//
|
|
// This is not a bug, record not found
|
|
//
|
|
return TAGID_NULL;
|
|
}
|
|
|
|
++pFindInfo->dwIndexRec;
|
|
tiRef = pIndexRecords[pFindInfo->dwIndexRec].tiRef;
|
|
}
|
|
|
|
return tiRef;
|
|
}
|
|
|
|
BOOL
|
|
SdbpPatternMatch(
|
|
IN LPCTSTR pszPattern,
|
|
IN LPCTSTR pszTestString)
|
|
/*++
|
|
Return: TRUE if pszTestString matches pszPattern
|
|
FALSE if not
|
|
|
|
Desc: This function does a case-insensitive comparison of
|
|
pszTestString against pszPattern. pszPattern can
|
|
include asterisks to do wildcard matches.
|
|
|
|
Any complaints about this function should be directed
|
|
toward MarkDer.
|
|
--*/
|
|
{
|
|
//
|
|
// March through pszTestString. Each time through the loop,
|
|
// pszTestString is advanced one character.
|
|
//
|
|
while (TRUE) {
|
|
|
|
//
|
|
// If pszPattern and pszTestString are both sitting on a NULL,
|
|
// then they reached the end at the same time and the strings
|
|
// must be equal.
|
|
//
|
|
if (*pszPattern == TEXT('\0') && *pszTestString == TEXT('\0')) {
|
|
return TRUE;
|
|
}
|
|
|
|
if (*pszPattern != TEXT('*')) {
|
|
|
|
//
|
|
// Non-asterisk mode. Look for a match on this character.
|
|
// If equal, continue traversing. Otherwise, the strings
|
|
// cannot be equal so return FALSE.
|
|
//
|
|
if (UPCASE_CHAR(*pszPattern) == UPCASE_CHAR(*pszTestString)) {
|
|
pszPattern++;
|
|
} else {
|
|
return FALSE;
|
|
}
|
|
|
|
} else {
|
|
|
|
//
|
|
// Asterisk mode. Look for a match on the character directly
|
|
// after the asterisk.
|
|
//
|
|
if (*(pszPattern + 1) == TEXT('*')) {
|
|
//
|
|
// Asterisks exist side by side. Advance the pattern pointer
|
|
// and go through loop again.
|
|
//
|
|
pszPattern++;
|
|
continue;
|
|
}
|
|
|
|
if (*(pszPattern + 1) == TEXT('\0')) {
|
|
//
|
|
// Asterisk exists at the end of the pattern string. Any
|
|
// remaining part of pszTestString matches so we can
|
|
// immediately return TRUE.
|
|
//
|
|
return TRUE;
|
|
}
|
|
|
|
if (UPCASE_CHAR(*(pszPattern + 1)) == UPCASE_CHAR(*pszTestString)) {
|
|
//
|
|
// Characters match. If the remaining parts of
|
|
// pszPattern and pszTestString match, then the entire
|
|
// string matches. Otherwise, keep advancing the
|
|
// pszTestString pointer.
|
|
//
|
|
if (SdbpPatternMatch(pszPattern + 1, pszTestString)) {
|
|
return TRUE;
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// No more pszTestString left. Must not be a match.
|
|
//
|
|
if (!*pszTestString) {
|
|
return FALSE;
|
|
}
|
|
|
|
pszTestString++;
|
|
}
|
|
}
|
|
|
|
BOOL
|
|
SdbpPatternMatchAnsi(
|
|
IN LPCSTR pszPattern,
|
|
IN LPCSTR pszTestString)
|
|
{
|
|
//
|
|
// March through pszTestString. Each time through the loop,
|
|
// pszTestString is advanced one character.
|
|
//
|
|
while (TRUE) {
|
|
|
|
//
|
|
// If pszPattern and pszTestString are both sitting on a NULL,
|
|
// then they reached the end at the same time and the strings
|
|
// must be equal.
|
|
//
|
|
if (*pszPattern == '\0' && *pszTestString == '\0') {
|
|
return TRUE;
|
|
}
|
|
|
|
if (*pszPattern != '*') {
|
|
|
|
//
|
|
// Non-asterisk mode. Look for a match on this character.
|
|
// If equal, continue traversing. Otherwise, the strings
|
|
// cannot be equal so return FALSE.
|
|
//
|
|
if (toupper(*pszPattern) == toupper(*pszTestString)) {
|
|
pszPattern++;
|
|
} else {
|
|
return FALSE;
|
|
}
|
|
|
|
} else {
|
|
|
|
//
|
|
// Asterisk mode. Look for a match on the character directly
|
|
// after the asterisk.
|
|
//
|
|
|
|
if (*(pszPattern + 1) == '*') {
|
|
//
|
|
// Asterisks exist side by side. Advance the pattern pointer
|
|
// and go through loop again.
|
|
//
|
|
pszPattern++;
|
|
continue;
|
|
}
|
|
|
|
if (*(pszPattern + 1) == '\0') {
|
|
//
|
|
// Asterisk exists at the end of the pattern string. Any
|
|
// remaining part of pszTestString matches so we can
|
|
// immediately return TRUE.
|
|
//
|
|
return TRUE;
|
|
}
|
|
|
|
if (toupper(*(pszPattern + 1)) == toupper(*pszTestString)) {
|
|
//
|
|
// Characters match. If the remaining parts of
|
|
// pszPattern and pszTestString match, then the entire
|
|
// string matches. Otherwise, keep advancing the
|
|
// pszTestString pointer.
|
|
//
|
|
if (SdbpPatternMatchAnsi(pszPattern + 1, pszTestString)) {
|
|
return TRUE;
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// No more pszTestString left. Must not be a match.
|
|
//
|
|
if (!*pszTestString) {
|
|
return FALSE;
|
|
}
|
|
|
|
pszTestString++;
|
|
}
|
|
}
|
|
|
|
char*
|
|
SdbpKeyToAnsiString(
|
|
ULONGLONG ullKey,
|
|
char* szString
|
|
)
|
|
/*++
|
|
Return: ?
|
|
|
|
Desc: ?
|
|
--*/
|
|
{
|
|
char* szRevString = (char*)&ullKey;
|
|
int i;
|
|
|
|
for (i = 0; i < 8; ++i) {
|
|
szString[i] = szRevString[7 - i];
|
|
}
|
|
szString[8] = 0;
|
|
|
|
return szString;
|
|
}
|
|
|
|
TAGID
|
|
SdbpFindFirstIndexedWildCardTag(
|
|
PDB pdb,
|
|
TAG tWhich,
|
|
TAG tKey,
|
|
LPCTSTR szName,
|
|
FIND_INFO* pFindInfo
|
|
)
|
|
/*++
|
|
Return: ?
|
|
|
|
Desc: ?
|
|
--*/
|
|
{
|
|
char szAnsiName[MAX_PATH];
|
|
char szAnsiKey[10];
|
|
PINDEX_RECORD pIndex = NULL;
|
|
DWORD dwRecs;
|
|
NTSTATUS status;
|
|
DWORD dwFlags = 0;
|
|
DWORD i, j;
|
|
|
|
pFindInfo->tiIndex = SdbGetIndex(pdb, tWhich, tKey, &dwFlags);
|
|
|
|
if (pFindInfo->tiIndex == TAGID_NULL) {
|
|
DBGPRINT((sdlError,
|
|
"SdbpFindFirstIndexedWilCardTag",
|
|
"Failed to get an index for tag 0x%lx key 0x%lx\n",
|
|
(DWORD)tWhich,
|
|
(DWORD)tKey));
|
|
|
|
return TAGID_NULL;
|
|
}
|
|
|
|
pFindInfo->tName = tKey;
|
|
pFindInfo->szName = szName;
|
|
pFindInfo->dwFlags = dwFlags;
|
|
|
|
RtlZeroMemory(szAnsiName, MAX_PATH);
|
|
RtlZeroMemory(szAnsiKey, 10);
|
|
|
|
//
|
|
// Get the uppercase ANSI version of this search string so
|
|
// it will match the keys in the index.
|
|
//
|
|
status = UPCASE_UNICODETOMULTIBYTEN(szAnsiName,
|
|
CHARCOUNT(szAnsiName), // this is size in characters
|
|
pFindInfo->szName);
|
|
if (!NT_SUCCESS(status)) {
|
|
|
|
DBGPRINT((sdlError,
|
|
"SdbpFindFirstIndexedWildCardTag",
|
|
"Failed to convert name to multi-byte\n"));
|
|
return TAGID_NULL;
|
|
}
|
|
|
|
//
|
|
// Get the index.
|
|
//
|
|
pIndex = SdbpGetIndex(pdb, pFindInfo->tiIndex, &dwRecs);
|
|
|
|
if (pIndex == NULL) {
|
|
DBGPRINT((sdlError,
|
|
"SdbpFindFirstIndexedWildCardTag",
|
|
"Failed to get index by tag id 0x%lx\n",
|
|
pFindInfo->tiIndex));
|
|
return TAGID_NULL;
|
|
}
|
|
|
|
//
|
|
// Walk through the whole index sequentially, doing a first pass check of the key
|
|
// so we can avoid getting the whole record if the name clearly isn't a match.
|
|
//
|
|
for (i = 0; i < dwRecs; ++i) {
|
|
|
|
TAGID tiMatch;
|
|
TAGID tiKey;
|
|
LPTSTR szDBName;
|
|
ULONGLONG ullKey;
|
|
|
|
READ_INDEX_KEY(pIndex, i, &ullKey);
|
|
|
|
//
|
|
// the call below never fails, so we don't check return value
|
|
//
|
|
SdbpKeyToAnsiString(pIndex[i].ullKey, szAnsiKey);
|
|
|
|
//
|
|
// If the original pattern match is more than eight characters, we have
|
|
// to plant an asterisk at the eighth character so that proper wildcard
|
|
// matching occurs.
|
|
//
|
|
szAnsiKey[8] = '*';
|
|
|
|
//
|
|
// Quick check of the string that's in the key.
|
|
//
|
|
if (!SdbpPatternMatchAnsi(szAnsiKey, szAnsiName)) {
|
|
continue;
|
|
}
|
|
|
|
//
|
|
// We found a tentative match, now pull the full record and
|
|
// see if it's real.
|
|
//
|
|
tiMatch = pIndex[i].tiRef;
|
|
|
|
//
|
|
// Get the key field.
|
|
//
|
|
tiKey = SdbFindFirstTag(pdb, tiMatch, pFindInfo->tName);
|
|
|
|
if (tiKey == TAGID_NULL) {
|
|
//
|
|
// This is not a bug, but rather continue searching
|
|
//
|
|
continue;
|
|
}
|
|
|
|
szDBName = SdbGetStringTagPtr(pdb, tiKey);
|
|
|
|
if (szDBName == NULL) {
|
|
// BUGBUG: what if this fails ?
|
|
continue;
|
|
}
|
|
|
|
//
|
|
// Is this really a match?
|
|
//
|
|
if (SdbpPatternMatch(szDBName, pFindInfo->szName)) {
|
|
pFindInfo->dwIndexRec = i;
|
|
return tiMatch;
|
|
}
|
|
}
|
|
|
|
// BUGBUG: DPF
|
|
return TAGID_NULL;
|
|
}
|
|
|
|
TAGID
|
|
SdbpFindNextIndexedWildCardTag(
|
|
PDB pdb,
|
|
FIND_INFO* pFindInfo
|
|
)
|
|
/*++
|
|
Return: ?
|
|
|
|
Desc: ?
|
|
--*/
|
|
{
|
|
char szAnsiName[MAX_PATH];
|
|
char szAnsiKey[10];
|
|
PINDEX_RECORD pIndex = NULL;
|
|
DWORD dwRecs;
|
|
NTSTATUS status;
|
|
DWORD i, j;
|
|
|
|
RtlZeroMemory(szAnsiName, MAX_PATH);
|
|
RtlZeroMemory(szAnsiKey, 10);
|
|
|
|
//
|
|
// Get the uppercase ANSI version of this search string so
|
|
// it will match the keys in the index.
|
|
//
|
|
status = UPCASE_UNICODETOMULTIBYTEN(szAnsiName,
|
|
CHARCOUNT(szAnsiName),
|
|
pFindInfo->szName);
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
// BUGBUG: DPF
|
|
return TAGID_NULL;
|
|
}
|
|
|
|
//
|
|
// Get the index.
|
|
//
|
|
pIndex = SdbpGetIndex(pdb, pFindInfo->tiIndex, &dwRecs);
|
|
|
|
if (pIndex == NULL) {
|
|
// BUGBUG: DPF
|
|
return TAGID_NULL;
|
|
}
|
|
|
|
//
|
|
// Walk through the rest of the index sequentially, doing a first pass
|
|
// check of the key so we can avoid getting the whole record if the
|
|
// name clearly isn't a match.
|
|
//
|
|
for (i = pFindInfo->dwIndexRec + 1; i < dwRecs; ++i) {
|
|
|
|
TAGID tiMatch;
|
|
TAGID tiKey;
|
|
LPTSTR pszDBName;
|
|
ULONGLONG ullKey;
|
|
|
|
READ_INDEX_KEY(pIndex, i, &ullKey);
|
|
|
|
SdbpKeyToAnsiString(ullKey, szAnsiKey);
|
|
|
|
//
|
|
// If the original pattern match is more than eight characters, we have
|
|
// to plant an asterisk at the eighth character so that proper wildcard
|
|
// matching occurs.
|
|
//
|
|
szAnsiKey[8] = '*';
|
|
|
|
//
|
|
// Quick check of the string that's in the key.
|
|
//
|
|
if (!SdbpPatternMatchAnsi(szAnsiKey, szAnsiName)) {
|
|
// BUGBUG: DPF
|
|
continue;
|
|
}
|
|
|
|
//
|
|
// We found a tentative match, now pull the full record and
|
|
// see if it's real.
|
|
//
|
|
tiMatch = pIndex[i].tiRef;
|
|
|
|
//
|
|
// Get the key field.
|
|
//
|
|
tiKey = SdbFindFirstTag(pdb, tiMatch, pFindInfo->tName);
|
|
|
|
if (tiKey == TAGID_NULL) {
|
|
// BUGBUG: DPF
|
|
continue;
|
|
}
|
|
|
|
pszDBName = SdbGetStringTagPtr(pdb, tiKey);
|
|
|
|
if (pszDBName == NULL) {
|
|
// BUGBUG: DPF
|
|
continue;
|
|
}
|
|
|
|
//
|
|
// Is this really a match?
|
|
//
|
|
if (SdbpPatternMatch(pszDBName, pFindInfo->szName)) {
|
|
pFindInfo->dwIndexRec = i;
|
|
return tiMatch;
|
|
}
|
|
}
|
|
|
|
// BUGBUG: DPF
|
|
return TAGID_NULL;
|
|
}
|
|
|
|
//
|
|
// Index access functions (for reading) -- better to use tiFindFirstIndexedTag, above
|
|
//
|
|
|
|
TAGID
|
|
SdbGetIndex(
|
|
IN PDB pdb, // db to use
|
|
IN TAG tWhich, // tag we'd like an index for
|
|
IN TAG tKey, // the kind of tag used as a key for this index
|
|
OUT LPDWORD lpdwFlags // index record flags (e.g. indicator whether the index
|
|
// is "unique" style
|
|
)
|
|
/*++
|
|
Return: TAGID of index, or TAGID_NULL.
|
|
|
|
Desc: Retrieves a TAGID ptr to the index bits for a specific
|
|
tag, if one exists.
|
|
--*/
|
|
{
|
|
TAGID tiReturn = TAGID_NULL;
|
|
int i;
|
|
|
|
//
|
|
// Scan the indexes if not done already.
|
|
//
|
|
if (!pdb->bIndexesScanned) {
|
|
SdbpScanIndexes(pdb);
|
|
}
|
|
|
|
for (i = 0; i < MAX_INDEXES; ++i) {
|
|
|
|
if (!pdb->aIndexes[i].tWhich) {
|
|
|
|
DBGPRINT((sdlInfo,
|
|
"SdbGetIndex",
|
|
"index 0x%x(0x%x) was not found in the index table\n",
|
|
tWhich,
|
|
tKey));
|
|
|
|
return TAGID_NULL;
|
|
}
|
|
|
|
if (pdb->aIndexes[i].tWhich == tWhich && pdb->aIndexes[i].tKey == tKey) {
|
|
|
|
tiReturn = pdb->aIndexes[i].tiIndex;
|
|
|
|
if (lpdwFlags != NULL) {
|
|
*lpdwFlags = pdb->aIndexes[i].dwFlags;
|
|
}
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
return tiReturn;
|
|
}
|
|
|
|
void
|
|
SdbpScanIndexes(
|
|
IN PDB pdb // db to use
|
|
)
|
|
/*++
|
|
|
|
Params: described above.
|
|
|
|
Return: void. No failure case.
|
|
|
|
Desc: Scans the initial tags in the DB and gets the index pointer info.
|
|
--*/
|
|
{
|
|
TAGID tiFirst;
|
|
TAGID tiIndex;
|
|
|
|
if (pdb->bIndexesScanned && !pdb->bWrite) {
|
|
//
|
|
// This is not an error condition
|
|
//
|
|
return;
|
|
}
|
|
|
|
RtlZeroMemory(pdb->aIndexes, sizeof(pdb->aIndexes));
|
|
|
|
pdb->bIndexesScanned = TRUE;
|
|
|
|
//
|
|
// The indexes must be the first tag.
|
|
//
|
|
tiFirst = SdbGetFirstChild(pdb, TAGID_ROOT);
|
|
|
|
if (tiFirst == TAGID_NULL) {
|
|
DBGPRINT((sdlError,
|
|
"SdbpScanIndexes",
|
|
"Failed to get the child index from root\n"));
|
|
return;
|
|
}
|
|
|
|
if (SdbGetTagFromTagID(pdb, tiFirst) != TAG_INDEXES) {
|
|
DBGPRINT((sdlError,
|
|
"SdbpScanIndexes",
|
|
"Root child tag is not index tagid 0x%lx\n",
|
|
tiFirst));
|
|
return;
|
|
}
|
|
|
|
pdb->dwIndexes = 0;
|
|
tiIndex = SdbFindFirstTag(pdb, tiFirst, TAG_INDEX);
|
|
|
|
while (tiIndex != TAGID_NULL) {
|
|
|
|
TAGID tiIndexTag;
|
|
TAGID tiIndexKey;
|
|
TAGID tiIndexBits;
|
|
TAGID tiIndexFlags;
|
|
|
|
if (pdb->dwIndexes == MAX_INDEXES) {
|
|
DBGPRINT((sdlError,
|
|
"SdbpScanIndexes",
|
|
"Too many indexes in file. Recompile and increase MAX_INDEXES.\n"));
|
|
return;
|
|
}
|
|
|
|
tiIndexTag = SdbFindFirstTag(pdb, tiIndex, TAG_INDEX_TAG);
|
|
|
|
if (tiIndexTag == TAGID_NULL) {
|
|
DBGPRINT((sdlError,
|
|
"SdbpScanIndexes",
|
|
"Index missing TAG_INDEX_TAG.\n"));
|
|
return;
|
|
}
|
|
|
|
pdb->aIndexes[pdb->dwIndexes].tWhich = SdbReadWORDTag(pdb, tiIndexTag, TAG_NULL);
|
|
|
|
tiIndexKey = SdbFindFirstTag(pdb, tiIndex, TAG_INDEX_KEY);
|
|
|
|
if (tiIndexKey == TAGID_NULL) {
|
|
DBGPRINT((sdlError, "SdbpScanIndexes", "Index missing TAG_INDEX_KEY.\n"));
|
|
return;
|
|
}
|
|
pdb->aIndexes[pdb->dwIndexes].tKey = SdbReadWORDTag(pdb, tiIndexKey, TAG_NULL);
|
|
|
|
tiIndexFlags = SdbFindFirstTag(pdb, tiIndex, TAG_INDEX_FLAGS);
|
|
|
|
if (tiIndexFlags != TAGID_NULL) {
|
|
pdb->aIndexes[pdb->dwIndexes].dwFlags = SdbReadDWORDTag(pdb, tiIndexFlags, 0);
|
|
} else {
|
|
pdb->aIndexes[pdb->dwIndexes].dwFlags = 0;
|
|
}
|
|
|
|
tiIndexBits = SdbFindFirstTag(pdb, tiIndex, TAG_INDEX_BITS);
|
|
|
|
if (tiIndexBits == TAGID_NULL) {
|
|
pdb->aIndexes[pdb->dwIndexes].tWhich = TAG_NULL;
|
|
DBGPRINT((sdlError, "SdbpScanIndexes", "Index missing TAG_INDEX_BITS.\n"));
|
|
return;
|
|
}
|
|
pdb->aIndexes[pdb->dwIndexes].tiIndex = tiIndexBits;
|
|
|
|
pdb->dwIndexes++;
|
|
|
|
tiIndex = SdbFindNextTag(pdb, tiFirst, tiIndex);
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
PINDEX_RECORD
|
|
SdbpGetIndex(
|
|
IN PDB pdb,
|
|
IN TAGID tiIndex,
|
|
OUT DWORD* pdwNumRecs
|
|
)
|
|
/*++
|
|
Return: ?
|
|
|
|
Desc: ?
|
|
--*/
|
|
{
|
|
if (SdbGetTagFromTagID(pdb, tiIndex) != TAG_INDEX_BITS) {
|
|
DBGPRINT((sdlError,
|
|
"SdbpGetIndex",
|
|
"Index tagid 0x%lx is not referring to the index bits\n",
|
|
tiIndex));
|
|
return NULL;
|
|
}
|
|
|
|
*pdwNumRecs = SdbGetTagDataSize(pdb, tiIndex) / sizeof(INDEX_RECORD);
|
|
|
|
return (PINDEX_RECORD)SdbpGetMappedTagData(pdb, tiIndex);
|
|
}
|
|
|
|
#if defined(_WIN64)
|
|
|
|
ULONGLONG
|
|
SdbMakeIndexKeyFromGUID(
|
|
IN GUID* pGuid
|
|
)
|
|
/*
|
|
Return: a 64-bit key to use for searching
|
|
|
|
Desc: The standard index key is created for a Guid
|
|
using the xor operation on a first and second half
|
|
of guid
|
|
*/
|
|
{
|
|
ULONGLONG ullPart1 = 0,
|
|
ullPart2 = 0;
|
|
|
|
RtlMoveMemory(&ullPart1, pGuid, sizeof(ULONGLONG));
|
|
RtlMoveMemory(&ullPart2, (PBYTE)pGuid + sizeof(ULONGLONG), sizeof(ULONGLONG));
|
|
|
|
return (ullPart1 ^ ullPart2);
|
|
}
|
|
|
|
#endif // _WIN64
|
|
|
|
|
|
#define SDB_KEY_LENGTH_BYTES 8
|
|
#define SDB_KEY_LENGTH 8
|
|
|
|
ULONGLONG
|
|
SdbMakeIndexKeyFromString(
|
|
IN LPCTSTR szKey
|
|
)
|
|
/*++
|
|
Return: a 64-bit key to use for searching.
|
|
|
|
Desc: The standard index key for a Unicode string is the
|
|
first 8 characters of the string, converted to uppercase ansi,
|
|
then cast to a ULONGLONG (64 bit unsigned int).
|
|
--*/
|
|
{
|
|
char szFlippedKey[SDB_KEY_LENGTH_BYTES]; // flipped to deal with little-endian issues
|
|
char* pszKey = &szFlippedKey[SDB_KEY_LENGTH_BYTES-1]; // points to the last char
|
|
NTSTATUS status;
|
|
int i;
|
|
WCHAR ch;
|
|
int nLength;
|
|
|
|
#ifndef WIN32A_MODE
|
|
|
|
UNICODE_STRING ustrKey;
|
|
UNICODE_STRING ustrKeySrc; // truncated string
|
|
UNICODE_STRING ustrKeySrcUpcased;
|
|
WCHAR Buffer[SDB_KEY_LENGTH];
|
|
WCHAR BufferUpcased[SDB_KEY_LENGTH];
|
|
LPCWSTR pKeyBuffer = BufferUpcased;
|
|
NTSTATUS Status;
|
|
|
|
RtlInitUnicodeString(&ustrKey, szKey);
|
|
|
|
//
|
|
// Call below copies upto maximum length of the destination string
|
|
//
|
|
ustrKeySrc.Buffer = Buffer;
|
|
ustrKeySrc.MaximumLength = sizeof(Buffer);
|
|
RtlCopyUnicodeString(&ustrKeySrc, &ustrKey);
|
|
|
|
//
|
|
// Upcase what we have created
|
|
//
|
|
ustrKeySrcUpcased.Buffer = BufferUpcased;
|
|
ustrKeySrcUpcased.MaximumLength = sizeof(BufferUpcased);
|
|
|
|
Status = RtlUpcaseUnicodeString(&ustrKeySrcUpcased, &ustrKeySrc, FALSE);
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
DBGPRINT((sdlError,
|
|
"SdbMakeIndexKeyFromString",
|
|
"Failed to upcase unicode string \"%s\"\n",
|
|
szKey));
|
|
return 0;
|
|
}
|
|
|
|
//
|
|
// Now we have an upper-case unicode string which is of max. 8 characters length
|
|
//
|
|
nLength = ustrKeySrcUpcased.Length / sizeof(WCHAR);
|
|
|
|
#else // WIN32A_MODE
|
|
|
|
WCHAR Buffer[SDB_KEY_LENGTH + 1];
|
|
LPCWSTR pKeyBuffer = Buffer;
|
|
|
|
nLength = mbstowcs(Buffer, szKey, CHARCOUNT(Buffer));
|
|
|
|
if (nLength < 0) {
|
|
DBGPRINT((sdlError,
|
|
"SdbMakeIndexKeyFromString",
|
|
"Failed to convert string \"%s\" to unicode\n",
|
|
szKey));
|
|
return 0;
|
|
}
|
|
|
|
Buffer[nLength] = TEXT('\0'); // zero-terminate
|
|
|
|
//
|
|
// Upcase now. Buffer is always 0-terminated.
|
|
//
|
|
_wcsupr(Buffer);
|
|
|
|
#endif // WIN32A_MODE
|
|
|
|
assert(nLength <= SDB_KEY_LENGTH);
|
|
|
|
RtlZeroMemory(szFlippedKey , sizeof(szFlippedKey));
|
|
|
|
//
|
|
// To be compatible with the old (ANSI) scheme of making keys, we
|
|
// construct the key using all non-null bytes in the string, up to 8
|
|
//
|
|
for (i = 0; i < nLength; ++i) {
|
|
|
|
ch = *pKeyBuffer++;
|
|
*pszKey-- = (unsigned char)ch;
|
|
|
|
//
|
|
// ch is a unicode char, whatever it is, see if it has 2 bytes or just one
|
|
//
|
|
if (HIBYTE(ch) && i < (SDB_KEY_LENGTH - 1)) {
|
|
//
|
|
// Two bytes, store both
|
|
//
|
|
*pszKey-- = (unsigned char)HIBYTE(ch);
|
|
++i;
|
|
}
|
|
}
|
|
|
|
return *((ULONGLONG*)szFlippedKey);
|
|
}
|
|
|
|
|
|
ULONGLONG
|
|
SdbpTagToKey(
|
|
IN PDB pdb,
|
|
IN TAGID tiTag
|
|
)
|
|
/*++
|
|
Return: ?
|
|
|
|
Desc: ?
|
|
--*/
|
|
{
|
|
TAG_TYPE ttType;
|
|
ULONGLONG ullReturn = 0;
|
|
DWORD dwSize;
|
|
PVOID pData;
|
|
LPTSTR szTemp = NULL;
|
|
|
|
ttType = GETTAGTYPE(SdbGetTagFromTagID(pdb, tiTag));
|
|
|
|
switch (ttType) {
|
|
|
|
case TAG_TYPE_STRING:
|
|
case TAG_TYPE_STRINGREF:
|
|
|
|
szTemp = SdbGetStringTagPtr(pdb, tiTag);
|
|
|
|
if (!szTemp) {
|
|
ullReturn = 0;
|
|
} else {
|
|
ullReturn = SdbMakeIndexKeyFromString(szTemp);
|
|
}
|
|
|
|
break;
|
|
|
|
case TAG_TYPE_NULL:
|
|
ullReturn = 1;
|
|
break;
|
|
|
|
case TAG_TYPE_BINARY: // indexing binary data
|
|
// check that the size of the data is sizeof(GUID)
|
|
if (sizeof(GUID) == SdbGetTagDataSize(pdb, tiTag)) {
|
|
//
|
|
// Special case.
|
|
//
|
|
pData = SdbpGetMappedTagData(pdb, tiTag);
|
|
|
|
if (pData == NULL) {
|
|
return 0;
|
|
}
|
|
|
|
ullReturn = MAKEKEYFROMGUID((GUID*)pData);
|
|
break;
|
|
}
|
|
//
|
|
// Fall through to the general binary data case.
|
|
//
|
|
|
|
default:
|
|
|
|
dwSize = SdbGetTagDataSize(pdb, tiTag);
|
|
|
|
if (dwSize > sizeof(ULONGLONG)) {
|
|
dwSize = sizeof(ULONGLONG);
|
|
}
|
|
|
|
pData = SdbpGetMappedTagData(pdb, tiTag);
|
|
|
|
if (pData == NULL) {
|
|
return 0;
|
|
}
|
|
|
|
memcpy(&ullReturn, pData, dwSize);
|
|
break;
|
|
}
|
|
|
|
return ullReturn;
|
|
}
|
|
|