windows-nt/Source/XPSP1/NT/enduser/stuff/itircl/wrdwheel/wwheel.cpp
2020-09-26 16:20:57 +08:00

858 lines
22 KiB
C++

#include <mvopsys.h>
#ifdef _DEBUG
static char s_aszModule[] = __FILE__; /* For error report */
#endif
#include <comdef.h>
#include <wwheel.h>
#include <groups.h>
#include <iterror.h>
#include <ccfiles.h>
#include <itww.h>
#include <itdb.h>
#include <itsort.h>
#include <itsortid.h>
BOOL static IsInFilter(_LPGROUP qFilter, LONG lOffset);
/*****************************************************************************
*
* WordWheelOpen
*
* @doc EXTERNAL
*
* @api HWHEEL | WordWheelOpen | This function opens a word wheel.
*
*
* @parm LPCSTR | lpszName | Specifies the name of the word wheel. This name
* should match the name used on the left side of the word-wheel entries
* specified in the [WWHEEL] section of the project file.
*
* @parm PHRESULT | phr | Error return value if failed.
*
* @rdesc Returns a handle to the specified word wheel, or NULL if the
* function fails.
*
*
* Keyword indexes are stored as word wheels in the file system. Word wheels
* for keyword indexes are named using the convention "\|c", where "c" is
* the identification character specified in the "key=" entry in the
* KEYINDEX section of the project file. For example, the default keyword
* index is named "\|0".
*
* @xref WordWheelClose
*
*/
HWHEEL FAR PASCAL EXPORT_API WordWheelOpen(IITDatabase* lpITDB,
IStorage* pWWStorage, PHRESULT phr)
{
HWHEEL hWheel = NULL; // handle to the new structure
PWHEEL pWheel = NULL; // pointer to locked-down structure
BOOL fSuccess= FALSE;
char szBtreeFormat[wMaxFormat + 1];
PWHEELINFO pInfo = NULL;
WORD t;
WORD wCount = 1;
DWORD cbSize;
DWORD cbRead;
LARGE_INTEGER dlibMove;
ULARGE_INTEGER libNewPos;
HF pHdr = NULL;
BTREE_PARAMS btp;
BOOL fReadOnly = TRUE;
ERRB errb;
*phr = S_OK; // Assume success
// allocate the structure. must be 0 initialized
if ((hWheel = _GLOBALALLOC(GMEM_MOVEABLE|GMEM_ZEROINIT, sizeof(WHEEL)+sizeof(WHEELINFO)*(wCount-1)))==NULL)
{
*phr = E_OUTOFMEMORY;
return NULL;
}
pWheel = (PWHEEL)_GLOBALLOCK(hWheel);
pWheel->magic = WHEEL_MAGIC;
pWheel->pIITGroup = NULL;
for (t = 0; t < wCount; t++)
{
pInfo = pWheel->pInfo + pWheel->wNumWheels;
// just make sure these are NULL
pInfo->pKeyHdr = NULL;
pInfo->pOccHdr = NULL;
pWheel->wNumWheels++;
pInfo->magic = WHEEL_INFO_MAGIC;
// open the subfiles
if ((pInfo->hmapbt=HmapbtOpenHfs(pWWStorage, SZ_WORDWHEEL_MAP, &errb))==NULL)
{
SetErrCode(phr, errb);
goto ignore_wheel;
}
if ((pInfo->hbt=HbtOpenBtreeSz(SZ_BTREE_BTREE, pWWStorage, fFSOpenReadOnly, &errb))==NULL)
{
SetErrCode(phr, errb);
goto ignore_wheel;
}
GetBtreeParams(pInfo->hbt, &btp);
if (btp.rgchFormat[0] == KT_EXTSORT)
{
IITSortKey *pITSortKey;
ITASSERT(btp.dwExtSortInstID != IITDB_OBJINST_NULL);
if (FAILED(*phr = lpITDB->GetObject(btp.dwExtSortInstID, IID_IITSortKey,
(LPVOID *) &pITSortKey)))
{
goto ignore_wheel;
}
BtreeSetExtSort(pInfo->hbt, pITSortKey);
// We release pITSortKey because BtreeSetExtSort
// should've AddRef'ed it.
pITSortKey->Release();
}
// Open header and save out key/occurrence
if ((pHdr = HfOpenHfs(pWWStorage, SZ_BTREE_HEADER, fFSOpenReadOnly, phr))==hfNil)
goto ignore_wheel;
// read global size and seek ahead to key header
*phr = pHdr->Read(&cbSize, sizeof(DWORD), &cbRead);
if (FAILED(*phr)) goto cleanup;
dlibMove.QuadPart = cbSize;
*phr = pHdr->Seek(dlibMove, STREAM_SEEK_CUR, &libNewPos);
if (FAILED(*phr)) goto cleanup;
// read key header size and read in key header info
*phr = pHdr->Read(&cbSize, sizeof(DWORD), &cbRead);
if (FAILED(*phr)) goto cleanup;
// ALLOCATE memory
if (cbSize)
{
if (NULL == (pInfo->pKeyHdr = new BYTE[cbSize]))
goto cleanup;
*phr = pHdr->Read(pInfo->pKeyHdr, cbSize, &cbRead);
if (FAILED(*phr)) goto cleanup;
}
// read key def. data size and seek ahead to occurrence hdr. size
*phr = pHdr->Read(&cbSize, sizeof(DWORD), &cbRead);
if (FAILED(*phr)) goto cleanup;
dlibMove.QuadPart = cbSize;
*phr = pHdr->Seek(dlibMove, STREAM_SEEK_CUR, &libNewPos);
if (FAILED(*phr)) goto cleanup;
// read occ. header size and read in key header info
*phr = pHdr->Read(&cbSize, sizeof(DWORD), &cbRead);
if (FAILED(*phr)) goto cleanup;
// ALLOCATE memory
if (cbSize)
{
if (NULL == (pInfo->pOccHdr = new BYTE[cbSize]))
goto cleanup;
*phr = pHdr->Read(pInfo->pOccHdr, cbSize, &cbRead);
if (FAILED(*phr)) goto cleanup;
}
// close header
RcCloseHf(pHdr);
// Open data file
if ((pInfo->hf = HfOpenHfs(pWWStorage, SZ_BTREE_DATA, fFSOpenReadOnly,phr))==hfNil)
goto ignore_wheel;
// erinfox: comment out full-text index support temporarily
// REVIEW(billa): If this is re-enabled, then the correct way to open an index
// will be through IITIndex obtained from CoCreateInstance on CLSID_IITIndexLocal.
// Any stop word information will get loaded automatically as part of the breaker
// instance that was associated with the index at build time.
#if 0
// if the index isn't there, that is okay.
pInfo->lpIndex = MVIndexOpen(pTitle->hfpbSysFile, pstrI, phr);
if (pInfo->lpIndex)
{ // if the stop file isn't there, that is okay.
pWheel->lpsipb = MVStopListInitiate (0, phr);
// If lpsipb is NULL MVStopListIndexLoad will
// simply return ERR_BADARG, so we don't need to check it
if (S_OK != MVStopListIndexLoad
(pTitle->hfpbSysFile, pWheel->lpsipb, pstrS))
{
MVStopListDispose (pWheel->lpsipb);
pWheel->lpsipb = NULL;
}
}
#endif
// cache the number of keywords
RcGetBtreeInfo(pInfo->hbt, (unsigned char*)szBtreeFormat, &pInfo->lNumKws, NULL);
continue;
ignore_wheel:
// close the subfiles
if (pHdr != NULL)
RcCloseHf(pHdr);
if (pInfo->hmapbt!=NULL)
RcCloseHmapbt(pInfo->hmapbt);
if (pInfo->hbt!=NULL)
RcCloseBtreeHbt(pInfo->hbt);
if (pInfo->hf != hfNil)
RcCloseHf (pInfo->hf);
#if 0
if (pInfo->lpIndex)
MVIndexClose(pInfo->lpIndex);
#endif
pInfo->magic=0;
pWheel->wNumWheels--;
}
if (!pWheel->wNumWheels)
{
// This can happen when we are looking for a-non existing word wheel
goto cleanup;
}
if (pWheel->wNumWheels > 2)
{
*phr = E_TOOMANYTITLES;
warning_abort;
}
if (pWheel->wNumWheels == 2)
{
*phr = E_NOMERGEDDATA;
warning_abort;
}
else if (pWheel->wNumWheels==1)
{
// May STILL need to load from merge file!!!!
pWheel->lNumRealEntries = pWheel->lNumEntries = pWheel->pInfo->lNumKws;
}
fSuccess = TRUE;
cleanup:
if (pWheel != NULL)
_GLOBALUNLOCK(hWheel);
// if we failed, then cleanup.
if (!fSuccess && hWheel != NULL)
{
WordWheelClose(hWheel);
hWheel = NULL;
}
return (hWheel);
}
/*****************************************************************************
*
* WordWheelClose
*
*
* @doc EXTERNAL
*
* @api void | WordWheelClose | This function closes a word wheel.
*
* @parm HWHEEL | hWheel | Specifies the handle to the word wheel.
*
* @comm After a word wheel is closed, the <p hWheel> handle is invalid and
* should not be used.
*
* @xref WordWheelOpen
*
*
*****************************************************************************/
PUBLIC VOID FAR PASCAL EXPORT_API WordWheelClose(HWHEEL hWheel)
{
PWHEEL pWheel = NULL; // pointer to locked-down structure
WORD t;
if (hWheel == NULL)
return;
// validate the parameters and lock down the structure
if ((pWheel = (PWHEEL)_GLOBALLOCK(hWheel))==NULL)
warning_abort;
if (!PWHEEL_OK(pWheel))
warning_abort;
for (t = 0; t < pWheel->wNumWheels; t++)
{
if (pWheel->pInfo[t].magic == WHEEL_INFO_MAGIC)
{
if (NULL != pWheel->pInfo[t].pOccHdr)
delete pWheel->pInfo[t].pOccHdr;
if (NULL != pWheel->pInfo[t].pKeyHdr)
delete pWheel->pInfo[t].pKeyHdr;
// close the subfiles and the file system
if (pWheel->pInfo[t].hmapbt!=NULL)
RcCloseHmapbt(pWheel->pInfo[t].hmapbt);
if (pWheel->pInfo[t].hbt!=NULL)
RcCloseBtreeHbt(pWheel->pInfo[t].hbt);
if (pWheel->pInfo[t].hf != hfNil)
RcCloseHf (pWheel->pInfo[t].hf);
#if 0
// REVIEW(billa): If this is re-enabled, then the correct way
// to close an index will be through IITIndex obtained from
// CoCreateInstance on CLSID_IITIndexLocal at open time.
// Any stop word information will get discarded automatically
// when the index object releases its associated breaker.
if (pWheel->pInfo[t].lpIndex)
MVIndexClose(pWheel->pInfo[t].lpIndex);
#endif
pWheel->pInfo[t].magic=0;
}
}
if (pWheel->hCacheData)
_GLOBALFREE(pWheel->hCacheData);
if (pWheel->lpszCacheData)
DisposeMemory(pWheel->lpszCacheData);
if (pWheel->hMergeData)
_GLOBALFREE(pWheel->hMergeData);
pWheel->magic = 0;
#if 0
if (pWheel->lpsipb)
MVStopListDispose (pWheel->lpsipb);
#endif
_GLOBALUNLOCK(hWheel);
// release the memory used for the structure.
_GLOBALFREE(hWheel);
cleanup:
return;
}
/*****************************************************************************
*
* WordWheelLength
*
*
* @doc EXTERNAL
*
* @api long | WordWheelLength | This function returns the number of entries
* in the word wheel.
*
* @parm HWHEEL | hWheel | Specifies the handle to the word wheel.
*
* @parm PHRESULT | lpErrb | Error return value if failed.
*
* @rdesc Returns the number of entries in the word wheel, or -1 if an
* error occurs.
*
* @xref WordWheelOpen
*
*
*****************************************************************************/
PUBLIC long FAR PASCAL EXPORT_API WordWheelLength(HWHEEL hWheel, PHRESULT phr)
{
PWHEEL pWheel = NULL; // pointer to locked-down structure.
long lRval = -1L; // -1 is the error condition.
PWHEELINFO pInfo = NULL;
// validate the parameters and lock down the structure
if ((pWheel = (PWHEEL)_GLOBALLOCK(hWheel))==NULL)
{
*phr = E_HANDLE;
warning_abort;
}
if (!PWHEEL_OK(pWheel))
{
*phr = E_INVALIDARG;
warning_abort;
}
lRval = pWheel->lNumEntries;
//DPF3("...WordWheelLength returns, %ld\n", lRval);
*phr = S_OK;
cleanup:
if (pWheel!=NULL)
_GLOBALUNLOCK(hWheel);
return lRval;
}
/*****************************************************************************
*
* WordWheelLookup
*
*
* @doc EXTERNAL
*
* @api HRESULT | WordWheelLookup | This function gets a string from a word
* wheel.
*
* @parm HWHEEL | hWheel | Specifies the handle to the word wheel.
*
* @parm long | lIndex | Specifies an index to the word-wheel entry.
*
* @parm LPVOID | lpvKeyBuf | Specifies a far pointer to the buffer to
* receive the text of the word-wheel entry.
*
* @parm DWORD | cbKeyBuf | Specifies the length of the buffer in bytes.
*
* @rdesc Returns S_OK if successful; otherwise returns error code
*
* @comm Word-wheel entries are numbered starting at zero.
*
* @xref WordWheelLength WordWheelOpen
*
*
*****************************************************************************/
PUBLIC HRESULT FAR PASCAL EXPORT_API WordWheelLookup(HWHEEL hWheel, long lIndex,
LPVOID lpvKeyBuf, DWORD cbKeyBuf)
{
PWHEEL pWheel = NULL; // pointer to locked-down structure
HRESULT hr = E_INVALIDARG; // assume failure
BYTE rgbKeyBuf[ITWW_CBKEY_MAX];
// validate the parameters and lock down the structure
if ((pWheel = (PWHEEL)_GLOBALLOCK(hWheel))==NULL) warning_abort;
if (!PWHEEL_OK(pWheel)) warning_abort;
if (lIndex >= 0 && lIndex < pWheel->lNumEntries)
{
PWHEELINFO pInfo = NULL;
LONG lWheelNum = 0;
IITSortKey *pITSortKey = NULL;
#ifdef MERGE_UPDATE
VirtualToReal(lIndex,pWheel,&lIndex,&lWheelNum);
#endif
pInfo = pWheel->pInfo + lWheelNum;
// If there's a filter, let's get the proper entry in the WW.
if (pWheel->pIITGroup)
{
hr = (pWheel->pIITGroup)->FindTopicNum((DWORD)lIndex, (DWORD*)(&lIndex));
if (FAILED(hr))
goto cleanup;
}
// lookup the entry in the map file once we know _which_ map file to look in
if (SUCCEEDED(hr = RcKeyFromIndexHbt(pInfo->hbt, pInfo->hmapbt,
(KEY) &rgbKeyBuf[0], ITWW_CBKEY_MAX, lIndex)) &&
SUCCEEDED(hr = CheckWordWheelKeyType(pInfo->hbt, &pITSortKey)))
{
DWORD cbKey;
// Check to see if the key we got back will fit in the caller's buffer.
// If it will fit, copy it, otherwise return an error.
if ((cbKey = CbKeyWordWheel((LPVOID) &rgbKeyBuf[0], pITSortKey)) <= cbKeyBuf)
MEMCPY(lpvKeyBuf, (LPVOID) &rgbKeyBuf[0], cbKey);
else
hr = E_INVALIDARG;
}
if (pITSortKey != NULL)
pITSortKey->Release();
#ifdef _MAC
StringMapWinToMac (pInfo->hbt, lpBuf);
#endif
}
else
hr = E_OUTOFRANGE;
cleanup:
if (pWheel!=NULL)
_GLOBALUNLOCK(hWheel);
return hr;
}
/*****************************************************************************
*
* WordWheelPrefix
*
*
* @doc EXTERNAL
*
* @api long | WordWheelPrefix | This function locates a word-wheel entry
* whose text starts with the specified prefix.
*
* @parm HWHEEL | hWheel | Specifies the handle to the word wheel.
*
* @parm LPCSTR | lpszPrefix | Specifies a far pointer to a string
* containing the text of the prefix.
*
* @parm PHRESULT | lpErrb | Error return value if failed.
*
* @rdesc Returns the index of the first entry containing the specified
* prefix. If no entry contains the prefix, the function returns the index
* of the entry immediately prior to the point where a word with the
* specified prefix would be found. The lowest index returned is zero.
*
* If an error occurs, the function returns -1.
*
* @comm Word-wheel entries are numbered starting at zero.
*
* @xref WordWheelLength WordWheelLookup WordWheelOpen
*
*
*****************************************************************************/
PUBLIC long FAR PASCAL EXPORT_API WordWheelPrefix(HWHEEL hWheel, LPCVOID lpcvPrefix,
BOOL fExactMatch, PHRESULT phr)
{
PWHEEL pWheel = NULL; // pointer to locked-down structure
BTPOS btpos; // position in BTREE for prefix
BYTE rgbKeyTemp[ITWW_CBKEY_MAX +1]; // holds key nearest prefix for single or Update
long lRval = -1; // assume failure
RC rc; // to catch return codes
PWHEELINFO pInfo = NULL;
BOOL ifOver1 = FALSE;
#ifdef MERGE_UPDATE
BYTE rgbKeyTemp2[ITWW_CBKEY_MAX +1]; // holds key nearest prefix for Main
long lRval2 = -1;
BOOL ifOver2 = FALSE;
#endif
#ifdef _MAC
BYTE szSearchKey[ITWW_CBKEY_MAX+1];
LPBYTE lpb;
LPCMAP lpCMap;
LPCHARTAB FAR * lplpCharTab;
#endif
// validate the parameters and lock down the structure
if ((pWheel = (PWHEEL)_GLOBALLOCK(hWheel))==NULL)
{
*phr = E_HANDLE;
warning_abort;
}
if (!PWHEEL_OK(pWheel))
{
*phr = E_INVALIDARG;
warning_abort;
}
pInfo = pWheel->pInfo;
#ifdef _MAC
if (lplpCharTab = (LPCHARTAB FAR *)BtreeGetCMap (pInfo->hbt))
{
lpCMap = (LPCMAP)lplpCharTab[0]->lpCMapTab;
// Map Mac string back to Windows string
for (lpb = szSearchKey; ; lpb++, lpstrPrefix++ )
{
if ((*lpb = *lpstrPrefix) == EMBEDFONT_BYTE_TAG)
{
/* Load new table */
lpstrPrefix++;
lpb++;
lpCMap = lplpCharTab[*lpb = *lpstrPrefix]->lpCMapTab;
lpstrPrefix++;
lpb++;
}
*lpb = lpCMap[*lpstrPrefix].MacToWin;
if (*lpstrPrefix == 0)
break;
}
// lookup the entry in the btree file.
rc=RcLookupByKey(pInfo->hbt, (KEY)szSearchKey, &btpos, NULL);
}
else
#endif
// look up the prefix in the btree.
rc=RcLookupByKey(pInfo->hbt, (KEY)lpcvPrefix, &btpos, NULL);
// if caller asked for exact match and it didn't happen,
// return w/ an error
if (fExactMatch)
{
if (rc != S_OK)
{
SetErrCode(phr, rc);
warning_abort;
}
}
if (rc != S_OK && rc != E_NOTEXIST)
{
SetErrCode(phr, rc);
warning_abort;
}
// If we ran off the end, then position ourselves at the
// last key in the btree.
if (!FValidPos(&btpos))
{
// maybe this was here for merge update; at any rate,
// setting lRval to btpos.cKey is wrong
#if 0
if ((rc = RcLastHbt(pInfo->hbt, (KEY)NULL, NULL, &btpos))!= S_OK)
{
SetErrCode(phr, rc);
warning_abort;
}
lRval = btpos.cKey; //ericjut: Putting the good value
#endif
if ((rc = RcLastHbt(pInfo->hbt, (KEY)NULL, NULL, &btpos)) != S_OK)
warning_abort;
lRval = pInfo->lNumKws - 1;
ifOver1 = TRUE;
}
else
{
// We are somewhere in the btree. We have either typed in
// a string which is a prefix to a keyword in the btree or not.
// See where we landed in the btree and compare the keyword in
// the dialog with where we are.
rc = RcLookupByPos(pInfo->hbt,&btpos, (KEY)rgbKeyTemp, ITWW_CBKEY_MAX ,NULL);
if (rc == S_OK)
rc = RcIndexFromKeyHbt(pInfo->hbt, pInfo->hmapbt, (LPLONG)&lRval,
(KEY)rgbKeyTemp);
if (rc != S_OK)
{
lRval = -1;
SetErrCode(phr, rc);
warning_abort;
}
// If the keyword we looked for is not a prefix of the
// string at btpos, then we are positioned at the keyword
// that would follow this keyword if it were in fact in the
// btree. Back up one keyword to let him see the previous
// one to give enough context so he sees his is not present.
// If already at the first keyword, don't back up any farther.
if (!FIsPrefix(pInfo->hbt, (KEY)lpcvPrefix, (KEY)rgbKeyTemp))
if (lRval > 0) lRval--;
}
#ifdef MERGE_UPDATE
if (pWheel->wNumWheels==2) // Look up in update as well
{
pInfo = pWheel->pInfo+1;
// Getting rid of the unwanted duplicates.
if (ifOver1)
lRval = WWDuplicateRemove(lRval, pWheel);
#ifdef _MAC
if (lplpCharTab = (LPCHARTAB FAR *)BtreeGetCMap (pInfo->hbt))
{
lpCMap = (LPCMAP)lplpCharTab[0]->lpCMapTab;
for (lpb = szSearchKey; ; lpb++, lpstrPrefix++ )
{
if ((*lpb = *lpstrPrefix) == EMBEDFONT_BYTE_TAG)
{
/* Load new table */
lpstrPrefix++;
lpb++;
lpCMap = lplpCharTab[*lpb = *lpstrPrefix]->lpCMapTab;
lpstrPrefix++;
lpb++;
}
*lpb = lpCMap[*lpstrPrefix].MacToWin;
if (*lpstrPrefix == 0)
break;
}
rc=RcLookupByKey(pInfo->hbt, (KEY)szSearchKey, &btpos, NULL);
}
else
#endif
rc=RcLookupByKey(pInfo->hbt, (KEY)lpcvPrefix, &btpos, NULL);
if (rc != S_OK && rc != ERR_NOTEXIST)
{
SetErrCode(phr, rc);
warning_abort;
}
if (!FValidPos(&btpos))
{
if ((rc = RcLastHbt(pInfo->hbt, (KEY)NULL, NULL, &btpos)) != S_OK)
{
SetErrCode(phr, rc);
warning_abort;
}
lRval2 = btpos.cKey; //ericjut: Putting the good value
ifOver2 = TRUE;
}
else
{
rc = RcLookupByPos(pInfo->hbt,&btpos,(KEY)rgbKeyTemp2,ITWW_CBKEY_MAX,NULL);
if (rc == S_OK)
rc = RcIndexFromKeyHbt(pInfo->hbt, pInfo->hmapbt, (LPLONG)&lRval2,
(KEY)rgbKeyTemp2);
if (rc != S_OK)
{
lRval2 = -1;
SetErrCode(phr, rc);
warning_abort;
}
if (!FIsPrefix(pInfo->hbt,(KEY)lpcvPrefix,(KEY)rgbKeyTemp2))
if (lRval2 > 0) lRval2--;
}
// Now find lowest virtual index for tree 0, index lRval or tree 1, index lRval2
lRval=RealToVirtual(lRval, 0, pWheel);
lRval2=RealToVirtual(lRval2, 1, pWheel);
if ((lRval2<lRval && !ifOver2) || (!(lRval2<lRval) && ifOver1))
lRval=lRval2;
}
else
{
if (pWheel->hMergeData)
lRval=RealToVirtual(lRval, 0, pWheel);
}
#endif // MERGE_UPDATE
if (pWheel->pIITGroup)
{
// In a filtered situation, let's find the proper offset.
*phr = (pWheel->pIITGroup)->FindOffset((DWORD)lRval, (DWORD*)(&lRval));
if (FAILED(*phr) && (E_NOTEXIST != *phr))
goto cleanup;
}
*phr = S_OK;
cleanup:
if (pWheel!=NULL)
_GLOBALUNLOCK(hWheel);
return lRval;
}
// Little internal function to figure out if a UID is part of
BOOL static IsInFilter(_LPGROUP qFilter, LONG lOffset)
{
LONG lNbBytes = lOffset / 8;
LONG lNbBits = lOffset % 8;
BYTE bMask = 1 << lNbBits;
return ((BYTE)*(qFilter->lpbGrpBitVect+lNbBytes)) & bMask;
}
// Returns S_OK if the btree's key type is a valid one for the word wheel.
// *ppITSortKey is always set based on one of the following cases:
//
// to NULL : if any error occurs, which includes an unsupported
// key type or if the key type is KT_EXTSORT but no
// pointer to the external sort instance has been specified.
//
// to non-NULL : the key type is KT_EXTSORT and a pointer to an
// external sort instance has been specified.
HRESULT FAR PASCAL CheckWordWheelKeyType(HBT hbt, IITSortKey **ppITSortKey)
{
BTREE_PARAMS btp;
HRESULT hr = S_OK;
if (ppITSortKey == NULL)
return (E_POINTER);
*ppITSortKey = NULL;
GetBtreeParams(hbt, &btp);
switch (btp.rgchFormat[0])
{
case KT_EXTSORT:
BtreeGetExtSort(hbt, ppITSortKey);
if (*ppITSortKey == NULL)
hr = E_INVALIDSTATE;
break;
case KT_SZ:
case KT_SZMAP:
break;
default:
// Word wheel doesn't support any other key types.
hr = E_BADFORMAT;
break;
};
return (hr);
}
DWORD FAR PASCAL CbKeyWordWheel(LPVOID lpvKey, IITSortKey *pITSortKey)
{
DWORD cbKey;
if (pITSortKey == NULL)
{
// Btree key type is a KT_SZx which we understand, so we'll determine
// the key size ourselves.
cbKey = (DWORD) STRLEN((char *) lpvKey) + 1;
}
else
{
// Get the key size from the sort object.
if (FAILED(pITSortKey->GetSize(lpvKey, &cbKey)))
{
cbKey = 0;
ITASSERT(FALSE);
}
}
return (cbKey);
}