Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

857 lines
22 KiB

  1. #include <mvopsys.h>
  2. #ifdef _DEBUG
  3. static char s_aszModule[] = __FILE__; /* For error report */
  4. #endif
  5. #include <comdef.h>
  6. #include <wwheel.h>
  7. #include <groups.h>
  8. #include <iterror.h>
  9. #include <ccfiles.h>
  10. #include <itww.h>
  11. #include <itdb.h>
  12. #include <itsort.h>
  13. #include <itsortid.h>
  14. BOOL static IsInFilter(_LPGROUP qFilter, LONG lOffset);
  15. /*****************************************************************************
  16. *
  17. * WordWheelOpen
  18. *
  19. * @doc EXTERNAL
  20. *
  21. * @api HWHEEL | WordWheelOpen | This function opens a word wheel.
  22. *
  23. *
  24. * @parm LPCSTR | lpszName | Specifies the name of the word wheel. This name
  25. * should match the name used on the left side of the word-wheel entries
  26. * specified in the [WWHEEL] section of the project file.
  27. *
  28. * @parm PHRESULT | phr | Error return value if failed.
  29. *
  30. * @rdesc Returns a handle to the specified word wheel, or NULL if the
  31. * function fails.
  32. *
  33. *
  34. * Keyword indexes are stored as word wheels in the file system. Word wheels
  35. * for keyword indexes are named using the convention "\|c", where "c" is
  36. * the identification character specified in the "key=" entry in the
  37. * KEYINDEX section of the project file. For example, the default keyword
  38. * index is named "\|0".
  39. *
  40. * @xref WordWheelClose
  41. *
  42. */
  43. HWHEEL FAR PASCAL EXPORT_API WordWheelOpen(IITDatabase* lpITDB,
  44. IStorage* pWWStorage, PHRESULT phr)
  45. {
  46. HWHEEL hWheel = NULL; // handle to the new structure
  47. PWHEEL pWheel = NULL; // pointer to locked-down structure
  48. BOOL fSuccess= FALSE;
  49. char szBtreeFormat[wMaxFormat + 1];
  50. PWHEELINFO pInfo = NULL;
  51. WORD t;
  52. WORD wCount = 1;
  53. DWORD cbSize;
  54. DWORD cbRead;
  55. LARGE_INTEGER dlibMove;
  56. ULARGE_INTEGER libNewPos;
  57. HF pHdr = NULL;
  58. BTREE_PARAMS btp;
  59. BOOL fReadOnly = TRUE;
  60. ERRB errb;
  61. *phr = S_OK; // Assume success
  62. // allocate the structure. must be 0 initialized
  63. if ((hWheel = _GLOBALALLOC(GMEM_MOVEABLE|GMEM_ZEROINIT, sizeof(WHEEL)+sizeof(WHEELINFO)*(wCount-1)))==NULL)
  64. {
  65. *phr = E_OUTOFMEMORY;
  66. return NULL;
  67. }
  68. pWheel = (PWHEEL)_GLOBALLOCK(hWheel);
  69. pWheel->magic = WHEEL_MAGIC;
  70. pWheel->pIITGroup = NULL;
  71. for (t = 0; t < wCount; t++)
  72. {
  73. pInfo = pWheel->pInfo + pWheel->wNumWheels;
  74. // just make sure these are NULL
  75. pInfo->pKeyHdr = NULL;
  76. pInfo->pOccHdr = NULL;
  77. pWheel->wNumWheels++;
  78. pInfo->magic = WHEEL_INFO_MAGIC;
  79. // open the subfiles
  80. if ((pInfo->hmapbt=HmapbtOpenHfs(pWWStorage, SZ_WORDWHEEL_MAP, &errb))==NULL)
  81. {
  82. SetErrCode(phr, errb);
  83. goto ignore_wheel;
  84. }
  85. if ((pInfo->hbt=HbtOpenBtreeSz(SZ_BTREE_BTREE, pWWStorage, fFSOpenReadOnly, &errb))==NULL)
  86. {
  87. SetErrCode(phr, errb);
  88. goto ignore_wheel;
  89. }
  90. GetBtreeParams(pInfo->hbt, &btp);
  91. if (btp.rgchFormat[0] == KT_EXTSORT)
  92. {
  93. IITSortKey *pITSortKey;
  94. ITASSERT(btp.dwExtSortInstID != IITDB_OBJINST_NULL);
  95. if (FAILED(*phr = lpITDB->GetObject(btp.dwExtSortInstID, IID_IITSortKey,
  96. (LPVOID *) &pITSortKey)))
  97. {
  98. goto ignore_wheel;
  99. }
  100. BtreeSetExtSort(pInfo->hbt, pITSortKey);
  101. // We release pITSortKey because BtreeSetExtSort
  102. // should've AddRef'ed it.
  103. pITSortKey->Release();
  104. }
  105. // Open header and save out key/occurrence
  106. if ((pHdr = HfOpenHfs(pWWStorage, SZ_BTREE_HEADER, fFSOpenReadOnly, phr))==hfNil)
  107. goto ignore_wheel;
  108. // read global size and seek ahead to key header
  109. *phr = pHdr->Read(&cbSize, sizeof(DWORD), &cbRead);
  110. if (FAILED(*phr)) goto cleanup;
  111. dlibMove.QuadPart = cbSize;
  112. *phr = pHdr->Seek(dlibMove, STREAM_SEEK_CUR, &libNewPos);
  113. if (FAILED(*phr)) goto cleanup;
  114. // read key header size and read in key header info
  115. *phr = pHdr->Read(&cbSize, sizeof(DWORD), &cbRead);
  116. if (FAILED(*phr)) goto cleanup;
  117. // ALLOCATE memory
  118. if (cbSize)
  119. {
  120. if (NULL == (pInfo->pKeyHdr = new BYTE[cbSize]))
  121. goto cleanup;
  122. *phr = pHdr->Read(pInfo->pKeyHdr, cbSize, &cbRead);
  123. if (FAILED(*phr)) goto cleanup;
  124. }
  125. // read key def. data size and seek ahead to occurrence hdr. size
  126. *phr = pHdr->Read(&cbSize, sizeof(DWORD), &cbRead);
  127. if (FAILED(*phr)) goto cleanup;
  128. dlibMove.QuadPart = cbSize;
  129. *phr = pHdr->Seek(dlibMove, STREAM_SEEK_CUR, &libNewPos);
  130. if (FAILED(*phr)) goto cleanup;
  131. // read occ. header size and read in key header info
  132. *phr = pHdr->Read(&cbSize, sizeof(DWORD), &cbRead);
  133. if (FAILED(*phr)) goto cleanup;
  134. // ALLOCATE memory
  135. if (cbSize)
  136. {
  137. if (NULL == (pInfo->pOccHdr = new BYTE[cbSize]))
  138. goto cleanup;
  139. *phr = pHdr->Read(pInfo->pOccHdr, cbSize, &cbRead);
  140. if (FAILED(*phr)) goto cleanup;
  141. }
  142. // close header
  143. RcCloseHf(pHdr);
  144. // Open data file
  145. if ((pInfo->hf = HfOpenHfs(pWWStorage, SZ_BTREE_DATA, fFSOpenReadOnly,phr))==hfNil)
  146. goto ignore_wheel;
  147. // erinfox: comment out full-text index support temporarily
  148. // REVIEW(billa): If this is re-enabled, then the correct way to open an index
  149. // will be through IITIndex obtained from CoCreateInstance on CLSID_IITIndexLocal.
  150. // Any stop word information will get loaded automatically as part of the breaker
  151. // instance that was associated with the index at build time.
  152. #if 0
  153. // if the index isn't there, that is okay.
  154. pInfo->lpIndex = MVIndexOpen(pTitle->hfpbSysFile, pstrI, phr);
  155. if (pInfo->lpIndex)
  156. { // if the stop file isn't there, that is okay.
  157. pWheel->lpsipb = MVStopListInitiate (0, phr);
  158. // If lpsipb is NULL MVStopListIndexLoad will
  159. // simply return ERR_BADARG, so we don't need to check it
  160. if (S_OK != MVStopListIndexLoad
  161. (pTitle->hfpbSysFile, pWheel->lpsipb, pstrS))
  162. {
  163. MVStopListDispose (pWheel->lpsipb);
  164. pWheel->lpsipb = NULL;
  165. }
  166. }
  167. #endif
  168. // cache the number of keywords
  169. RcGetBtreeInfo(pInfo->hbt, (unsigned char*)szBtreeFormat, &pInfo->lNumKws, NULL);
  170. continue;
  171. ignore_wheel:
  172. // close the subfiles
  173. if (pHdr != NULL)
  174. RcCloseHf(pHdr);
  175. if (pInfo->hmapbt!=NULL)
  176. RcCloseHmapbt(pInfo->hmapbt);
  177. if (pInfo->hbt!=NULL)
  178. RcCloseBtreeHbt(pInfo->hbt);
  179. if (pInfo->hf != hfNil)
  180. RcCloseHf (pInfo->hf);
  181. #if 0
  182. if (pInfo->lpIndex)
  183. MVIndexClose(pInfo->lpIndex);
  184. #endif
  185. pInfo->magic=0;
  186. pWheel->wNumWheels--;
  187. }
  188. if (!pWheel->wNumWheels)
  189. {
  190. // This can happen when we are looking for a-non existing word wheel
  191. goto cleanup;
  192. }
  193. if (pWheel->wNumWheels > 2)
  194. {
  195. *phr = E_TOOMANYTITLES;
  196. warning_abort;
  197. }
  198. if (pWheel->wNumWheels == 2)
  199. {
  200. *phr = E_NOMERGEDDATA;
  201. warning_abort;
  202. }
  203. else if (pWheel->wNumWheels==1)
  204. {
  205. // May STILL need to load from merge file!!!!
  206. pWheel->lNumRealEntries = pWheel->lNumEntries = pWheel->pInfo->lNumKws;
  207. }
  208. fSuccess = TRUE;
  209. cleanup:
  210. if (pWheel != NULL)
  211. _GLOBALUNLOCK(hWheel);
  212. // if we failed, then cleanup.
  213. if (!fSuccess && hWheel != NULL)
  214. {
  215. WordWheelClose(hWheel);
  216. hWheel = NULL;
  217. }
  218. return (hWheel);
  219. }
  220. /*****************************************************************************
  221. *
  222. * WordWheelClose
  223. *
  224. *
  225. * @doc EXTERNAL
  226. *
  227. * @api void | WordWheelClose | This function closes a word wheel.
  228. *
  229. * @parm HWHEEL | hWheel | Specifies the handle to the word wheel.
  230. *
  231. * @comm After a word wheel is closed, the <p hWheel> handle is invalid and
  232. * should not be used.
  233. *
  234. * @xref WordWheelOpen
  235. *
  236. *
  237. *****************************************************************************/
  238. PUBLIC VOID FAR PASCAL EXPORT_API WordWheelClose(HWHEEL hWheel)
  239. {
  240. PWHEEL pWheel = NULL; // pointer to locked-down structure
  241. WORD t;
  242. if (hWheel == NULL)
  243. return;
  244. // validate the parameters and lock down the structure
  245. if ((pWheel = (PWHEEL)_GLOBALLOCK(hWheel))==NULL)
  246. warning_abort;
  247. if (!PWHEEL_OK(pWheel))
  248. warning_abort;
  249. for (t = 0; t < pWheel->wNumWheels; t++)
  250. {
  251. if (pWheel->pInfo[t].magic == WHEEL_INFO_MAGIC)
  252. {
  253. if (NULL != pWheel->pInfo[t].pOccHdr)
  254. delete pWheel->pInfo[t].pOccHdr;
  255. if (NULL != pWheel->pInfo[t].pKeyHdr)
  256. delete pWheel->pInfo[t].pKeyHdr;
  257. // close the subfiles and the file system
  258. if (pWheel->pInfo[t].hmapbt!=NULL)
  259. RcCloseHmapbt(pWheel->pInfo[t].hmapbt);
  260. if (pWheel->pInfo[t].hbt!=NULL)
  261. RcCloseBtreeHbt(pWheel->pInfo[t].hbt);
  262. if (pWheel->pInfo[t].hf != hfNil)
  263. RcCloseHf (pWheel->pInfo[t].hf);
  264. #if 0
  265. // REVIEW(billa): If this is re-enabled, then the correct way
  266. // to close an index will be through IITIndex obtained from
  267. // CoCreateInstance on CLSID_IITIndexLocal at open time.
  268. // Any stop word information will get discarded automatically
  269. // when the index object releases its associated breaker.
  270. if (pWheel->pInfo[t].lpIndex)
  271. MVIndexClose(pWheel->pInfo[t].lpIndex);
  272. #endif
  273. pWheel->pInfo[t].magic=0;
  274. }
  275. }
  276. if (pWheel->hCacheData)
  277. _GLOBALFREE(pWheel->hCacheData);
  278. if (pWheel->lpszCacheData)
  279. DisposeMemory(pWheel->lpszCacheData);
  280. if (pWheel->hMergeData)
  281. _GLOBALFREE(pWheel->hMergeData);
  282. pWheel->magic = 0;
  283. #if 0
  284. if (pWheel->lpsipb)
  285. MVStopListDispose (pWheel->lpsipb);
  286. #endif
  287. _GLOBALUNLOCK(hWheel);
  288. // release the memory used for the structure.
  289. _GLOBALFREE(hWheel);
  290. cleanup:
  291. return;
  292. }
  293. /*****************************************************************************
  294. *
  295. * WordWheelLength
  296. *
  297. *
  298. * @doc EXTERNAL
  299. *
  300. * @api long | WordWheelLength | This function returns the number of entries
  301. * in the word wheel.
  302. *
  303. * @parm HWHEEL | hWheel | Specifies the handle to the word wheel.
  304. *
  305. * @parm PHRESULT | lpErrb | Error return value if failed.
  306. *
  307. * @rdesc Returns the number of entries in the word wheel, or -1 if an
  308. * error occurs.
  309. *
  310. * @xref WordWheelOpen
  311. *
  312. *
  313. *****************************************************************************/
  314. PUBLIC long FAR PASCAL EXPORT_API WordWheelLength(HWHEEL hWheel, PHRESULT phr)
  315. {
  316. PWHEEL pWheel = NULL; // pointer to locked-down structure.
  317. long lRval = -1L; // -1 is the error condition.
  318. PWHEELINFO pInfo = NULL;
  319. // validate the parameters and lock down the structure
  320. if ((pWheel = (PWHEEL)_GLOBALLOCK(hWheel))==NULL)
  321. {
  322. *phr = E_HANDLE;
  323. warning_abort;
  324. }
  325. if (!PWHEEL_OK(pWheel))
  326. {
  327. *phr = E_INVALIDARG;
  328. warning_abort;
  329. }
  330. lRval = pWheel->lNumEntries;
  331. //DPF3("...WordWheelLength returns, %ld\n", lRval);
  332. *phr = S_OK;
  333. cleanup:
  334. if (pWheel!=NULL)
  335. _GLOBALUNLOCK(hWheel);
  336. return lRval;
  337. }
  338. /*****************************************************************************
  339. *
  340. * WordWheelLookup
  341. *
  342. *
  343. * @doc EXTERNAL
  344. *
  345. * @api HRESULT | WordWheelLookup | This function gets a string from a word
  346. * wheel.
  347. *
  348. * @parm HWHEEL | hWheel | Specifies the handle to the word wheel.
  349. *
  350. * @parm long | lIndex | Specifies an index to the word-wheel entry.
  351. *
  352. * @parm LPVOID | lpvKeyBuf | Specifies a far pointer to the buffer to
  353. * receive the text of the word-wheel entry.
  354. *
  355. * @parm DWORD | cbKeyBuf | Specifies the length of the buffer in bytes.
  356. *
  357. * @rdesc Returns S_OK if successful; otherwise returns error code
  358. *
  359. * @comm Word-wheel entries are numbered starting at zero.
  360. *
  361. * @xref WordWheelLength WordWheelOpen
  362. *
  363. *
  364. *****************************************************************************/
  365. PUBLIC HRESULT FAR PASCAL EXPORT_API WordWheelLookup(HWHEEL hWheel, long lIndex,
  366. LPVOID lpvKeyBuf, DWORD cbKeyBuf)
  367. {
  368. PWHEEL pWheel = NULL; // pointer to locked-down structure
  369. HRESULT hr = E_INVALIDARG; // assume failure
  370. BYTE rgbKeyBuf[ITWW_CBKEY_MAX];
  371. // validate the parameters and lock down the structure
  372. if ((pWheel = (PWHEEL)_GLOBALLOCK(hWheel))==NULL) warning_abort;
  373. if (!PWHEEL_OK(pWheel)) warning_abort;
  374. if (lIndex >= 0 && lIndex < pWheel->lNumEntries)
  375. {
  376. PWHEELINFO pInfo = NULL;
  377. LONG lWheelNum = 0;
  378. IITSortKey *pITSortKey = NULL;
  379. #ifdef MERGE_UPDATE
  380. VirtualToReal(lIndex,pWheel,&lIndex,&lWheelNum);
  381. #endif
  382. pInfo = pWheel->pInfo + lWheelNum;
  383. // If there's a filter, let's get the proper entry in the WW.
  384. if (pWheel->pIITGroup)
  385. {
  386. hr = (pWheel->pIITGroup)->FindTopicNum((DWORD)lIndex, (DWORD*)(&lIndex));
  387. if (FAILED(hr))
  388. goto cleanup;
  389. }
  390. // lookup the entry in the map file once we know _which_ map file to look in
  391. if (SUCCEEDED(hr = RcKeyFromIndexHbt(pInfo->hbt, pInfo->hmapbt,
  392. (KEY) &rgbKeyBuf[0], ITWW_CBKEY_MAX, lIndex)) &&
  393. SUCCEEDED(hr = CheckWordWheelKeyType(pInfo->hbt, &pITSortKey)))
  394. {
  395. DWORD cbKey;
  396. // Check to see if the key we got back will fit in the caller's buffer.
  397. // If it will fit, copy it, otherwise return an error.
  398. if ((cbKey = CbKeyWordWheel((LPVOID) &rgbKeyBuf[0], pITSortKey)) <= cbKeyBuf)
  399. MEMCPY(lpvKeyBuf, (LPVOID) &rgbKeyBuf[0], cbKey);
  400. else
  401. hr = E_INVALIDARG;
  402. }
  403. if (pITSortKey != NULL)
  404. pITSortKey->Release();
  405. #ifdef _MAC
  406. StringMapWinToMac (pInfo->hbt, lpBuf);
  407. #endif
  408. }
  409. else
  410. hr = E_OUTOFRANGE;
  411. cleanup:
  412. if (pWheel!=NULL)
  413. _GLOBALUNLOCK(hWheel);
  414. return hr;
  415. }
  416. /*****************************************************************************
  417. *
  418. * WordWheelPrefix
  419. *
  420. *
  421. * @doc EXTERNAL
  422. *
  423. * @api long | WordWheelPrefix | This function locates a word-wheel entry
  424. * whose text starts with the specified prefix.
  425. *
  426. * @parm HWHEEL | hWheel | Specifies the handle to the word wheel.
  427. *
  428. * @parm LPCSTR | lpszPrefix | Specifies a far pointer to a string
  429. * containing the text of the prefix.
  430. *
  431. * @parm PHRESULT | lpErrb | Error return value if failed.
  432. *
  433. * @rdesc Returns the index of the first entry containing the specified
  434. * prefix. If no entry contains the prefix, the function returns the index
  435. * of the entry immediately prior to the point where a word with the
  436. * specified prefix would be found. The lowest index returned is zero.
  437. *
  438. * If an error occurs, the function returns -1.
  439. *
  440. * @comm Word-wheel entries are numbered starting at zero.
  441. *
  442. * @xref WordWheelLength WordWheelLookup WordWheelOpen
  443. *
  444. *
  445. *****************************************************************************/
  446. PUBLIC long FAR PASCAL EXPORT_API WordWheelPrefix(HWHEEL hWheel, LPCVOID lpcvPrefix,
  447. BOOL fExactMatch, PHRESULT phr)
  448. {
  449. PWHEEL pWheel = NULL; // pointer to locked-down structure
  450. BTPOS btpos; // position in BTREE for prefix
  451. BYTE rgbKeyTemp[ITWW_CBKEY_MAX +1]; // holds key nearest prefix for single or Update
  452. long lRval = -1; // assume failure
  453. RC rc; // to catch return codes
  454. PWHEELINFO pInfo = NULL;
  455. BOOL ifOver1 = FALSE;
  456. #ifdef MERGE_UPDATE
  457. BYTE rgbKeyTemp2[ITWW_CBKEY_MAX +1]; // holds key nearest prefix for Main
  458. long lRval2 = -1;
  459. BOOL ifOver2 = FALSE;
  460. #endif
  461. #ifdef _MAC
  462. BYTE szSearchKey[ITWW_CBKEY_MAX+1];
  463. LPBYTE lpb;
  464. LPCMAP lpCMap;
  465. LPCHARTAB FAR * lplpCharTab;
  466. #endif
  467. // validate the parameters and lock down the structure
  468. if ((pWheel = (PWHEEL)_GLOBALLOCK(hWheel))==NULL)
  469. {
  470. *phr = E_HANDLE;
  471. warning_abort;
  472. }
  473. if (!PWHEEL_OK(pWheel))
  474. {
  475. *phr = E_INVALIDARG;
  476. warning_abort;
  477. }
  478. pInfo = pWheel->pInfo;
  479. #ifdef _MAC
  480. if (lplpCharTab = (LPCHARTAB FAR *)BtreeGetCMap (pInfo->hbt))
  481. {
  482. lpCMap = (LPCMAP)lplpCharTab[0]->lpCMapTab;
  483. // Map Mac string back to Windows string
  484. for (lpb = szSearchKey; ; lpb++, lpstrPrefix++ )
  485. {
  486. if ((*lpb = *lpstrPrefix) == EMBEDFONT_BYTE_TAG)
  487. {
  488. /* Load new table */
  489. lpstrPrefix++;
  490. lpb++;
  491. lpCMap = lplpCharTab[*lpb = *lpstrPrefix]->lpCMapTab;
  492. lpstrPrefix++;
  493. lpb++;
  494. }
  495. *lpb = lpCMap[*lpstrPrefix].MacToWin;
  496. if (*lpstrPrefix == 0)
  497. break;
  498. }
  499. // lookup the entry in the btree file.
  500. rc=RcLookupByKey(pInfo->hbt, (KEY)szSearchKey, &btpos, NULL);
  501. }
  502. else
  503. #endif
  504. // look up the prefix in the btree.
  505. rc=RcLookupByKey(pInfo->hbt, (KEY)lpcvPrefix, &btpos, NULL);
  506. // if caller asked for exact match and it didn't happen,
  507. // return w/ an error
  508. if (fExactMatch)
  509. {
  510. if (rc != S_OK)
  511. {
  512. SetErrCode(phr, rc);
  513. warning_abort;
  514. }
  515. }
  516. if (rc != S_OK && rc != E_NOTEXIST)
  517. {
  518. SetErrCode(phr, rc);
  519. warning_abort;
  520. }
  521. // If we ran off the end, then position ourselves at the
  522. // last key in the btree.
  523. if (!FValidPos(&btpos))
  524. {
  525. // maybe this was here for merge update; at any rate,
  526. // setting lRval to btpos.cKey is wrong
  527. #if 0
  528. if ((rc = RcLastHbt(pInfo->hbt, (KEY)NULL, NULL, &btpos))!= S_OK)
  529. {
  530. SetErrCode(phr, rc);
  531. warning_abort;
  532. }
  533. lRval = btpos.cKey; //ericjut: Putting the good value
  534. #endif
  535. if ((rc = RcLastHbt(pInfo->hbt, (KEY)NULL, NULL, &btpos)) != S_OK)
  536. warning_abort;
  537. lRval = pInfo->lNumKws - 1;
  538. ifOver1 = TRUE;
  539. }
  540. else
  541. {
  542. // We are somewhere in the btree. We have either typed in
  543. // a string which is a prefix to a keyword in the btree or not.
  544. // See where we landed in the btree and compare the keyword in
  545. // the dialog with where we are.
  546. rc = RcLookupByPos(pInfo->hbt,&btpos, (KEY)rgbKeyTemp, ITWW_CBKEY_MAX ,NULL);
  547. if (rc == S_OK)
  548. rc = RcIndexFromKeyHbt(pInfo->hbt, pInfo->hmapbt, (LPLONG)&lRval,
  549. (KEY)rgbKeyTemp);
  550. if (rc != S_OK)
  551. {
  552. lRval = -1;
  553. SetErrCode(phr, rc);
  554. warning_abort;
  555. }
  556. // If the keyword we looked for is not a prefix of the
  557. // string at btpos, then we are positioned at the keyword
  558. // that would follow this keyword if it were in fact in the
  559. // btree. Back up one keyword to let him see the previous
  560. // one to give enough context so he sees his is not present.
  561. // If already at the first keyword, don't back up any farther.
  562. if (!FIsPrefix(pInfo->hbt, (KEY)lpcvPrefix, (KEY)rgbKeyTemp))
  563. if (lRval > 0) lRval--;
  564. }
  565. #ifdef MERGE_UPDATE
  566. if (pWheel->wNumWheels==2) // Look up in update as well
  567. {
  568. pInfo = pWheel->pInfo+1;
  569. // Getting rid of the unwanted duplicates.
  570. if (ifOver1)
  571. lRval = WWDuplicateRemove(lRval, pWheel);
  572. #ifdef _MAC
  573. if (lplpCharTab = (LPCHARTAB FAR *)BtreeGetCMap (pInfo->hbt))
  574. {
  575. lpCMap = (LPCMAP)lplpCharTab[0]->lpCMapTab;
  576. for (lpb = szSearchKey; ; lpb++, lpstrPrefix++ )
  577. {
  578. if ((*lpb = *lpstrPrefix) == EMBEDFONT_BYTE_TAG)
  579. {
  580. /* Load new table */
  581. lpstrPrefix++;
  582. lpb++;
  583. lpCMap = lplpCharTab[*lpb = *lpstrPrefix]->lpCMapTab;
  584. lpstrPrefix++;
  585. lpb++;
  586. }
  587. *lpb = lpCMap[*lpstrPrefix].MacToWin;
  588. if (*lpstrPrefix == 0)
  589. break;
  590. }
  591. rc=RcLookupByKey(pInfo->hbt, (KEY)szSearchKey, &btpos, NULL);
  592. }
  593. else
  594. #endif
  595. rc=RcLookupByKey(pInfo->hbt, (KEY)lpcvPrefix, &btpos, NULL);
  596. if (rc != S_OK && rc != ERR_NOTEXIST)
  597. {
  598. SetErrCode(phr, rc);
  599. warning_abort;
  600. }
  601. if (!FValidPos(&btpos))
  602. {
  603. if ((rc = RcLastHbt(pInfo->hbt, (KEY)NULL, NULL, &btpos)) != S_OK)
  604. {
  605. SetErrCode(phr, rc);
  606. warning_abort;
  607. }
  608. lRval2 = btpos.cKey; //ericjut: Putting the good value
  609. ifOver2 = TRUE;
  610. }
  611. else
  612. {
  613. rc = RcLookupByPos(pInfo->hbt,&btpos,(KEY)rgbKeyTemp2,ITWW_CBKEY_MAX,NULL);
  614. if (rc == S_OK)
  615. rc = RcIndexFromKeyHbt(pInfo->hbt, pInfo->hmapbt, (LPLONG)&lRval2,
  616. (KEY)rgbKeyTemp2);
  617. if (rc != S_OK)
  618. {
  619. lRval2 = -1;
  620. SetErrCode(phr, rc);
  621. warning_abort;
  622. }
  623. if (!FIsPrefix(pInfo->hbt,(KEY)lpcvPrefix,(KEY)rgbKeyTemp2))
  624. if (lRval2 > 0) lRval2--;
  625. }
  626. // Now find lowest virtual index for tree 0, index lRval or tree 1, index lRval2
  627. lRval=RealToVirtual(lRval, 0, pWheel);
  628. lRval2=RealToVirtual(lRval2, 1, pWheel);
  629. if ((lRval2<lRval && !ifOver2) || (!(lRval2<lRval) && ifOver1))
  630. lRval=lRval2;
  631. }
  632. else
  633. {
  634. if (pWheel->hMergeData)
  635. lRval=RealToVirtual(lRval, 0, pWheel);
  636. }
  637. #endif // MERGE_UPDATE
  638. if (pWheel->pIITGroup)
  639. {
  640. // In a filtered situation, let's find the proper offset.
  641. *phr = (pWheel->pIITGroup)->FindOffset((DWORD)lRval, (DWORD*)(&lRval));
  642. if (FAILED(*phr) && (E_NOTEXIST != *phr))
  643. goto cleanup;
  644. }
  645. *phr = S_OK;
  646. cleanup:
  647. if (pWheel!=NULL)
  648. _GLOBALUNLOCK(hWheel);
  649. return lRval;
  650. }
  651. // Little internal function to figure out if a UID is part of
  652. BOOL static IsInFilter(_LPGROUP qFilter, LONG lOffset)
  653. {
  654. LONG lNbBytes = lOffset / 8;
  655. LONG lNbBits = lOffset % 8;
  656. BYTE bMask = 1 << lNbBits;
  657. return ((BYTE)*(qFilter->lpbGrpBitVect+lNbBytes)) & bMask;
  658. }
  659. // Returns S_OK if the btree's key type is a valid one for the word wheel.
  660. // *ppITSortKey is always set based on one of the following cases:
  661. //
  662. // to NULL : if any error occurs, which includes an unsupported
  663. // key type or if the key type is KT_EXTSORT but no
  664. // pointer to the external sort instance has been specified.
  665. //
  666. // to non-NULL : the key type is KT_EXTSORT and a pointer to an
  667. // external sort instance has been specified.
  668. HRESULT FAR PASCAL CheckWordWheelKeyType(HBT hbt, IITSortKey **ppITSortKey)
  669. {
  670. BTREE_PARAMS btp;
  671. HRESULT hr = S_OK;
  672. if (ppITSortKey == NULL)
  673. return (E_POINTER);
  674. *ppITSortKey = NULL;
  675. GetBtreeParams(hbt, &btp);
  676. switch (btp.rgchFormat[0])
  677. {
  678. case KT_EXTSORT:
  679. BtreeGetExtSort(hbt, ppITSortKey);
  680. if (*ppITSortKey == NULL)
  681. hr = E_INVALIDSTATE;
  682. break;
  683. case KT_SZ:
  684. case KT_SZMAP:
  685. break;
  686. default:
  687. // Word wheel doesn't support any other key types.
  688. hr = E_BADFORMAT;
  689. break;
  690. };
  691. return (hr);
  692. }
  693. DWORD FAR PASCAL CbKeyWordWheel(LPVOID lpvKey, IITSortKey *pITSortKey)
  694. {
  695. DWORD cbKey;
  696. if (pITSortKey == NULL)
  697. {
  698. // Btree key type is a KT_SZx which we understand, so we'll determine
  699. // the key size ourselves.
  700. cbKey = (DWORD) STRLEN((char *) lpvKey) + 1;
  701. }
  702. else
  703. {
  704. // Get the key size from the sort object.
  705. if (FAILED(pITSortKey->GetSize(lpvKey, &cbKey)))
  706. {
  707. cbKey = 0;
  708. ITASSERT(FALSE);
  709. }
  710. }
  711. return (cbKey);
  712. }