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.

721 lines
20 KiB

  1. /*************************************************************************
  2. * *
  3. * FTCOMMON.C *
  4. * *
  5. * Copyright (C) Microsoft Corporation 1990-1994 *
  6. * All Rights reserved. *
  7. * *
  8. **************************************************************************
  9. * *
  10. * Module Intent *
  11. * Routine common for both index & search *
  12. * *
  13. **************************************************************************
  14. * *
  15. * Current Owner: BinhN *
  16. * *
  17. **************************************************************************/
  18. #include <mvopsys.h>
  19. #include <mem.h>
  20. #include <mvsearch.h>
  21. #include <groups.h>
  22. #include <orkin.h>
  23. #include "common.h"
  24. static BYTE NEAR s_aszModule[] = __FILE__; // Used by error return functions.
  25. /*************************************************************************
  26. * EXTERNAL VARIABLES
  27. * All those variables must be read only
  28. *************************************************************************/
  29. FDECODE DecodeTable[] =
  30. {
  31. GetBitStreamDWord,
  32. GetFixedDWord,
  33. GetBellDWord,
  34. };
  35. /*
  36. * The mask table. Its values correspond to the maximum number
  37. * we can get depending on how many bits are left in the byte.
  38. * For ease of usage, the table should be used starting at 1
  39. * intead of 0
  40. */
  41. static BYTE NEAR BitLeftMask [] =
  42. {
  43. 0x00,
  44. 0x01,
  45. 0x03,
  46. 0x07,
  47. 0x0f,
  48. 0x1f,
  49. 0x3f,
  50. 0x7f,
  51. 0xff,
  52. };
  53. /*
  54. * The bit mask table. This is used to speed up FGetBool()
  55. */
  56. static BYTE BitMask [] =
  57. {
  58. 0x01,
  59. 0x02,
  60. 0x04,
  61. 0x08,
  62. 0x10,
  63. 0x20,
  64. 0x40,
  65. 0x80,
  66. };
  67. /*************************************************************************
  68. *
  69. * INTERNAL GLOBAL FUNCTIONS
  70. * All of them should be declared far, unless they are known to be called
  71. * in the same segment
  72. *************************************************************************/
  73. PUBLIC LST PASCAL FAR ExtractWord(LST, LST, LPW);
  74. PUBLIC HRESULT PASCAL FAR ReadStemNode (PNODEINFO, int);
  75. PUBLIC HRESULT PASCAL FAR ReadLeafNode (PNODEINFO, int);
  76. PUBLIC int PASCAL FAR StrCmpPascal2(LPB lpStr1, LPB lpStr2);
  77. PUBLIC HRESULT PASCAL FAR GetBellDWord (PNODEINFO, CKEY, LPDW);
  78. PUBLIC HRESULT PASCAL FAR GetBitStreamDWord (PNODEINFO, CKEY, LPDW);
  79. PUBLIC HRESULT PASCAL FAR GetFixedDWord (PNODEINFO, CKEY, LPDW);
  80. PUBLIC HRESULT PASCAL FAR ReadNewData(PNODEINFO pNodeInfo);
  81. PUBLIC int PASCAL FAR ReadFileOffset (FILEOFFSET FAR *, LPB);
  82. PUBLIC HRESULT PASCAL FAR FGetBits(PNODEINFO, LPDW, CBIT);
  83. PUBLIC HRESULT PASCAL FAR ReadIndexHeader(HFPB, PIH20);
  84. PUBLIC HRESULT PASCAL FAR CopyFileOffset (LPB pDest, FILEOFFSET fo);
  85. PUBLIC CB PASCAL FAR CbBytePack (LPB lpbOut, DWORD dwIn);
  86. /*************************************************************************
  87. *
  88. * INTERNAL PRIVATE FUNCTIONS
  89. * All of them should be declared near
  90. *************************************************************************/
  91. PRIVATE HRESULT PASCAL NEAR FGetBool(PNODEINFO pNodeInfo);
  92. PRIVATE HRESULT PASCAL NEAR FGetScheme(PNODEINFO, LPCKEY);
  93. /*************************************************************************
  94. * @doc INTERNAL
  95. *
  96. * @func LST PASCAL FAR | ExtractWord |
  97. * Extract a compacted word from the input buffer and store
  98. * it as a Pascal string.
  99. *
  100. * @parm LST | lstWord |
  101. * Buffer in which to put the Pascal word.
  102. *
  103. * @parm LST | lstCurPtr |
  104. * Current pointer to the source. The word here is compacted
  105. *
  106. * @parm LPW | pWlen |
  107. * pointer to word's length buffer to be udpated
  108. *
  109. * @rdesc
  110. * The function will return the new position of the source pointer
  111. *
  112. * @comm
  113. * There is a trick in the compression. This function works on
  114. * the assumption that the SAME buffer is used for lstWord on
  115. * successive call to it. The first word is always whole. Subsequent
  116. * words may be part of the 1st one
  117. * Ex: "solid" and "solidarity" will be encoded as:
  118. * [0:5]solid and [5:5]arity
  119. * The first call will be made for "solid" which will fill lstWord
  120. * with:
  121. * 5solid
  122. * The next call will update the postfix and the word length
  123. * 10solidarity
  124. * Note that "solid" is the remain of last call buffer
  125. *
  126. * Note: Tehre is no error checking for speed
  127. *************************************************************************/
  128. PUBLIC LST PASCAL FAR ExtractWord(LST lstWord, LST lstCurPtr,
  129. LPW pwRealLength)
  130. {
  131. SHORT cbPrefix;
  132. SHORT cbPostfix;
  133. DWORD dwPrefixLength;
  134. BYTE fHasWordLength;
  135. // Get the prefix length
  136. lstCurPtr += CbByteUnpack (&dwPrefixLength, lstCurPtr);
  137. cbPostfix = (USHORT)dwPrefixLength - 1;
  138. cbPrefix = (*lstCurPtr) & 0x7f;
  139. fHasWordLength = (*lstCurPtr) & 0x80;
  140. lstCurPtr++;
  141. // Update word length
  142. *pwRealLength = *(PUSHORT)lstWord = (USHORT)(cbPrefix + cbPostfix);
  143. lstWord += sizeof(SHORT);
  144. // Copy postfix
  145. MEMCPY (lstWord + cbPrefix, lstCurPtr, cbPostfix);
  146. lstCurPtr += cbPostfix;
  147. if (fHasWordLength)
  148. {
  149. lstCurPtr += CbByteUnpack(&dwPrefixLength, lstCurPtr);
  150. *pwRealLength = (WORD)dwPrefixLength;
  151. }
  152. CbBytePack (lstWord + cbPrefix + cbPostfix, (DWORD)(*pwRealLength));
  153. return lstCurPtr;
  154. }
  155. PUBLIC CB PASCAL NEAR CbBytePack (LPB lpbOut, DWORD dwIn)
  156. {
  157. LPB lpbOldOut;
  158. /* Save the old offset */
  159. lpbOldOut = lpbOut;
  160. do
  161. {
  162. *lpbOut = (BYTE)(dwIn & 0x7F); /* Get 7 bits. */
  163. dwIn >>= 7;
  164. if (dwIn)
  165. *lpbOut |= 0x80; /* To be continued... */
  166. lpbOut++;
  167. } while (dwIn);
  168. return (CB)(lpbOut - lpbOldOut); /* Return compressed width */
  169. }
  170. int FAR PASCAL StrCmpPascal2(LPB lpStr1, LPB lpStr2)
  171. {
  172. int fRet;
  173. int register len;
  174. // Get the minimum length
  175. if ((fRet = *(LPUW)lpStr1 - *(LPUW)lpStr2 ) > 0)
  176. len = *(LPUW)lpStr2;
  177. else
  178. len = *(LPUW)lpStr1;
  179. // Skip the lengths */
  180. lpStr1 += sizeof (SHORT);
  181. lpStr2 += sizeof (SHORT);
  182. // Start compare byte per byte */
  183. for (; len > 0; len--, lpStr1++, lpStr2++)
  184. {
  185. if (*lpStr1 != *lpStr2)
  186. break;
  187. }
  188. if (len == 0)
  189. return fRet;
  190. return (*lpStr1 - *lpStr2);
  191. }
  192. int PASCAL FAR ReadFileOffset (FILEOFFSET FAR *pFo, LPB pSrc)
  193. {
  194. pFo->dwOffset = GETLONG ((LPUL)pSrc);
  195. pSrc += sizeof (DWORD);
  196. pFo->dwHigh = GETWORD ((LPUL)pSrc);
  197. return FOFFSET_SIZE;
  198. }
  199. PUBLIC HRESULT PASCAL FAR CopyFileOffset (LPB pDest, FILEOFFSET fo)
  200. {
  201. *(LPUL)pDest = fo.dwOffset;
  202. pDest += sizeof (DWORD);
  203. *(LPUW)pDest = (WORD)fo.dwHigh;
  204. pDest += sizeof (WORD);
  205. return FOFFSET_SIZE;
  206. }
  207. /*************************************************************************
  208. * @doc INTERNAL
  209. *
  210. * @func HRESULT FAR PASCAL | ReadIndexHeader |
  211. * Read the index header
  212. *
  213. * @parm HFPB | hfpb |
  214. * Handle of index file
  215. *
  216. * @parm PIH20 | pHeader |
  217. * Pointer to header info structure
  218. *
  219. * @rdesc S_OK if succeeded, errors otherwise
  220. *************************************************************************/
  221. PUBLIC HRESULT FAR PASCAL ReadIndexHeader(HFPB hfpbSubFile, PIH20 pHeader)
  222. {
  223. ERRB errb;
  224. // foNil should, of course, be nil
  225. ITASSERT(0 == foNil.dwOffset && 0 == foNil.dwHigh);
  226. if (FileSeekRead(hfpbSubFile, pHeader, foNil,
  227. sizeof(IH20), &errb) != sizeof(IH20))
  228. {
  229. return errb;
  230. }
  231. /* Mac code. Those following lines will be optimized out */
  232. pHeader->FileStamp = SWAPWORD(pHeader->FileStamp);
  233. pHeader->version = SWAPWORD(pHeader->version);
  234. pHeader->lcTopics = SWAPLONG(pHeader->lcTopics);
  235. pHeader->foIdxRoot.dwOffset = SWAPLONG(pHeader->foIdxRoot.dwOffset);
  236. pHeader->foIdxRoot.dwHigh = SWAPLONG(pHeader->foIdxRoot.dwHigh);
  237. pHeader->nidLast = SWAPLONG(pHeader->nidLast);
  238. pHeader->nidIdxRoot = SWAPLONG(pHeader->nidIdxRoot);
  239. pHeader->cIdxLevels = SWAPWORD(pHeader->cIdxLevels);
  240. pHeader->occf = SWAPWORD(pHeader->occf);
  241. pHeader->idxf = SWAPWORD(pHeader->idxf);
  242. /* Index statistics */
  243. pHeader->dwMaxFieldId = SWAPLONG(pHeader->dwMaxFieldId);
  244. pHeader->dwMaxWCount = SWAPLONG(pHeader->dwMaxWCount);
  245. pHeader->dwMaxOffset = SWAPLONG(pHeader->dwMaxOffset);
  246. pHeader->dwMaxWLen = SWAPLONG(pHeader->dwMaxWLen);
  247. pHeader->dwBlockSize = SWAPLONG(pHeader->dwBlockSize);
  248. pHeader->dwMinTopicId = SWAPLONG(pHeader->dwMinTopicId);
  249. pHeader->dwMaxTopicId = SWAPLONG(pHeader->dwMaxTopicId);
  250. /* New members for index file version 4.0 */
  251. pHeader->dwCodePageID = SWAPLONG(pHeader->dwCodePageID);
  252. pHeader->lcid = SWAPLONG(pHeader->lcid);
  253. pHeader->dwBreakerInstID = SWAPLONG(pHeader->dwBreakerInstID);
  254. return S_OK;
  255. }
  256. /*************************************************************************
  257. * @doc INTERNAL
  258. *
  259. * @func HRESULT PASCAL FAR | ReadNewData|
  260. * Read in mode data
  261. *
  262. * @parm PNODEINFO | pNodeInfo |
  263. * Pointer to data node info
  264. * @rdesc S_OK if succesful, otherwise other errors
  265. *************************************************************************/
  266. PUBLIC HRESULT PASCAL FAR ReadNewData(PNODEINFO pNodeInfo)
  267. {
  268. ERRB errb;
  269. DWORD cbDataRead;
  270. LONG cbRead;
  271. if ((cbDataRead = pNodeInfo->dwDataSizeLeft) == 0)
  272. return(S_OK); // Nothing else to read
  273. if (cbDataRead > FILE_BUFFER)
  274. cbDataRead = FILE_BUFFER;
  275. #if defined(_DEBUG) && defined(_DUMPALL)
  276. _DPF2("Data read @ %lu, size = %lu\n", pNodeInfo->nodeOffset.dwOffset, \
  277. cbDataRead);
  278. #endif
  279. // Read the data block
  280. if ((cbRead = FileSeekRead (pNodeInfo->hfpbIdx, pNodeInfo->pBuffer,
  281. pNodeInfo->nodeOffset, cbDataRead, &errb)) != (LONG)cbDataRead)
  282. {
  283. SetErrCode (&errb, E_ASSERT);
  284. }
  285. pNodeInfo->pMaxAddress = pNodeInfo->pBuffer + cbRead;
  286. pNodeInfo->dwDataSizeLeft -= cbRead;
  287. pNodeInfo->nodeOffset = FoAddDw(pNodeInfo->nodeOffset, cbRead);
  288. pNodeInfo->pCurPtr = pNodeInfo->pBuffer;
  289. pNodeInfo->ibit = cbitBYTE - 1;
  290. return S_OK;
  291. }
  292. /*************************************************************************
  293. * @doc INTERNAL
  294. *
  295. * @func HRESULT PASCAL FAR | ReadLeafNode |
  296. * Leaf node structure:
  297. * Next block Ptr | CbLeft |* Word | PointerToNode *| Slack
  298. * 6b 2b | Var | 6b
  299. *
  300. * @parm PNODEINFO | pNodeInfo |
  301. * Pointer to leaf info
  302. *
  303. * @parm HRESULT | cLevel |
  304. * Level of the node. 0 is the top node
  305. *
  306. * @rdesc S_OK if succesful, otherwise other errors
  307. *************************************************************************/
  308. PUBLIC HRESULT PASCAL FAR ReadLeafNode (PNODEINFO pNodeInfo, int cLevel)
  309. {
  310. ERRB errb;
  311. #if defined(_DEBUG) && defined(_DUMPALL)
  312. _DPF2("Leaf read @ %lu, size = %lu\n", pNodeInfo->nodeOffset.dwOffset, \
  313. pNodeInfo->dwBlockSize);
  314. #endif
  315. pNodeInfo->pBuffer = pNodeInfo->pLeafNode;
  316. if (FileSeekRead (pNodeInfo->hfpbIdx, pNodeInfo->pBuffer,
  317. pNodeInfo->nodeOffset, pNodeInfo->dwBlockSize,
  318. &errb) != (long)pNodeInfo->dwBlockSize)
  319. {
  320. return (errb);
  321. }
  322. // Remember to subtract cbLeft from the node size
  323. pNodeInfo->cbLeft = GETWORD((LPUW)(pNodeInfo->pBuffer + FOFFSET_SIZE));
  324. pNodeInfo->pCurPtr = pNodeInfo->pBuffer + FOFFSET_SIZE + sizeof(WORD);
  325. pNodeInfo->pMaxAddress = pNodeInfo->pBuffer +
  326. pNodeInfo->dwBlockSize - pNodeInfo->cbLeft;
  327. return S_OK;
  328. }
  329. /*************************************************************************
  330. * @doc INTERNAL
  331. *
  332. * @func HRESULT PASCAL FAR | ReadStemNode |
  333. * Read in a new node from the disk if it is not the top node.
  334. * For the top node, just reset various pointers
  335. * Stem node structure:
  336. * CbLeft |* Word | PointerToNode *| Slack
  337. * 2b | Var | 6b
  338. *
  339. * @parm PNODEINFO | pNodeInfo |
  340. * Pointer to leaf info
  341. *
  342. * @parm int | cLevel |
  343. * Level of the node. 0 is the top node
  344. *
  345. * @rdesc S_OK if succesful, otherwise other errors
  346. *************************************************************************/
  347. PUBLIC HRESULT PASCAL FAR ReadStemNode (PNODEINFO pNodeInfo, int cLevel)
  348. {
  349. ERRB errb;
  350. #if 0
  351. DWORD cbLeft;
  352. #endif
  353. if (cLevel == 0)
  354. { // The top node is buffered.
  355. pNodeInfo->pBuffer = pNodeInfo->pTopNode;
  356. }
  357. else
  358. { // The rest isn't.
  359. #if defined(_DEBUG) && defined(_DUMPALL)
  360. _DPF2("Stem read @ %lu, size = %lu\n", pNodeInfo->nodeOffset.dwOffset, \
  361. pNodeInfo->dwBlockSize);
  362. #endif
  363. pNodeInfo->pBuffer = pNodeInfo->pStemNode;
  364. if (FileSeekRead (pNodeInfo->hfpbIdx, pNodeInfo->pBuffer,
  365. pNodeInfo->nodeOffset, pNodeInfo->dwBlockSize,
  366. &errb) != (long)pNodeInfo->dwBlockSize)
  367. {
  368. return (errb);
  369. }
  370. }
  371. // Remember to subtract cbLeft from the node size
  372. #if 0
  373. pNodeInfo->pCurPtr = pNodeInfo->pBuffer +
  374. CbByteUnpack (&cbLeft, pNodeInfo->pBuffer);
  375. #else
  376. pNodeInfo->cbLeft = GETWORD(pNodeInfo->pBuffer);
  377. pNodeInfo->pCurPtr = pNodeInfo->pBuffer + sizeof(WORD);
  378. #endif
  379. pNodeInfo->pMaxAddress = pNodeInfo->pBuffer +
  380. pNodeInfo->dwBlockSize - pNodeInfo->cbLeft;
  381. return S_OK;
  382. }
  383. PUBLIC HRESULT PASCAL FAR GetFixedDWord (PNODEINFO pNodeInfo, CKEY ckey, LPDW lpdw)
  384. {
  385. return FGetBits(pNodeInfo, lpdw, (CBIT)(ckey.ucCenter + 1));
  386. }
  387. /*************************************************************************
  388. * @doc INTERNAL
  389. *
  390. * @func PUBLIC HRESULT PASCAL FAR | GetBellDWord |
  391. * This function decode a dword encoded with the Bell scheme
  392. *
  393. * @parm PNODEINFO | pNodeInfo |
  394. * Pointer to NODEINFO structure
  395. *
  396. * @parm CKEY | ckey |
  397. * Decoding key
  398. *
  399. * @parm LPDW | lpdw |
  400. * Place to store the result
  401. *
  402. * @rdesc S_OK if everything is OK, errors otherwise
  403. *
  404. * @comm
  405. * The Bell compression scheme works as followed. If we have 1000
  406. * numbers, 90% of them require 6 bits, and 10% require more than
  407. * 6 bits. In this case, ckey.ucCenter will be 6, ie. the minimum
  408. * number of bits. The extra number of bits needed to store the
  409. * extra numbers is stored as a series of 1's
  410. * - First, we check the next bit. If it is 1, then extra bits
  411. * are needed. We then keep reading all the 1's bits to know
  412. * the number of extra bits needed
  413. * - We then read the number using the number of bits needed
  414. *************************************************************************/
  415. PUBLIC HRESULT PASCAL FAR GetBellDWord (PNODEINFO pNodeInfo, CKEY ckey, LPDW lpdw)
  416. {
  417. register BYTE bData;
  418. register int cBitLeft;
  419. register int cCount;
  420. HRESULT fRet;
  421. LPB lpbCurPtr;
  422. DWORD dwVal;
  423. LPB lpMaxAddress = pNodeInfo->pMaxAddress;
  424. int tmp;
  425. DWORD dwBlockSize = pNodeInfo->dwBlockSize;
  426. cCount = ckey.ucCenter;
  427. dwVal = 0L;
  428. if ((lpbCurPtr = pNodeInfo->pCurPtr) >= lpMaxAddress)
  429. {
  430. if ((fRet = ReadNewData (pNodeInfo)) != S_OK)
  431. return fRet;
  432. lpbCurPtr = pNodeInfo->pCurPtr;
  433. lpMaxAddress = pNodeInfo->pMaxAddress;
  434. }
  435. /* This is duplicate of FGetBool() to speed things up */
  436. /* Make copy of pNodeInfo->lrgbCurPtr and pNodeInfo->ibit to avoid indexed
  437. * references
  438. */
  439. bData = *lpbCurPtr;
  440. /* Check to make suere that we do have enough data */
  441. if ((cBitLeft = pNodeInfo->ibit) < 0)
  442. {
  443. if (++lpbCurPtr >= lpMaxAddress)
  444. {
  445. if ((fRet = ReadNewData (pNodeInfo)) != S_OK)
  446. return fRet;
  447. lpbCurPtr = pNodeInfo->pCurPtr;
  448. lpMaxAddress = pNodeInfo->pMaxAddress;
  449. }
  450. bData = *lpbCurPtr;
  451. cBitLeft = cbitBYTE - 1;
  452. }
  453. if ((bData & BitMask[cBitLeft--]) > 0)
  454. {
  455. /* Get the number of all extra bits */
  456. for (;;)
  457. {
  458. /* This is duplicate of FGetBool() to speed things up */
  459. if (cBitLeft < 0)
  460. {
  461. if (++lpbCurPtr >= lpMaxAddress)
  462. {
  463. if ((fRet = ReadNewData (pNodeInfo)) != S_OK)
  464. return fRet;
  465. lpbCurPtr = pNodeInfo->pCurPtr;
  466. lpMaxAddress = pNodeInfo->pMaxAddress;
  467. }
  468. bData = *lpbCurPtr;
  469. cBitLeft = cbitBYTE - 1;
  470. }
  471. if ((bData & BitMask[cBitLeft--]) > 0)
  472. cCount++;
  473. else
  474. break;
  475. }
  476. dwVal = (1L << cCount);
  477. }
  478. cBitLeft ++;
  479. if (cCount)
  480. {
  481. /* Duplicate of FGetBits() to speed things up */
  482. do
  483. {
  484. if (cBitLeft <= 0)
  485. {
  486. if (++lpbCurPtr >= lpMaxAddress)
  487. {
  488. if ((fRet = ReadNewData (pNodeInfo)) != S_OK)
  489. return fRet;
  490. lpbCurPtr = pNodeInfo->pCurPtr;
  491. lpMaxAddress = pNodeInfo->pMaxAddress;
  492. }
  493. cBitLeft = cbitBYTE;
  494. bData = *lpbCurPtr;
  495. }
  496. if (cCount >= (tmp = cBitLeft))
  497. {
  498. dwVal |= ((DWORD)(bData & BitLeftMask[cBitLeft]))
  499. << (cCount -= cBitLeft);
  500. cBitLeft = 0;
  501. }
  502. else
  503. {
  504. dwVal |= (((DWORD)(bData& BitLeftMask[tmp]))
  505. >> (cBitLeft -= cCount));
  506. break;
  507. }
  508. } while (cCount);
  509. }
  510. /* Update values */
  511. *lpdw = dwVal;
  512. pNodeInfo->ibit = cBitLeft - 1;
  513. pNodeInfo->pCurPtr = lpbCurPtr;
  514. return S_OK;
  515. }
  516. PUBLIC HRESULT PASCAL FAR GetBitStreamDWord (PNODEINFO pNodeInfo, CKEY ckey, LPDW lpdw)
  517. {
  518. int fBit;
  519. *lpdw = 0;
  520. for (;;)
  521. {
  522. if ((fBit = FGetBool(pNodeInfo)) > 0)
  523. (*lpdw)++;
  524. else if (!fBit)
  525. return S_OK;
  526. else
  527. return E_FAIL;
  528. }
  529. }
  530. /*************************************************************************
  531. *
  532. * INTERNAL PRIVATE FUNCTIONS
  533. * All of them should be declared near
  534. *************************************************************************/
  535. // Get a single bit from the index.
  536. PRIVATE HRESULT PASCAL FAR FGetBool (
  537. PNODEINFO pNodeInfo) // Current leaf info.
  538. {
  539. if ((short)pNodeInfo->ibit < 0)
  540. {
  541. pNodeInfo->pCurPtr++;
  542. pNodeInfo->ibit = cbitBYTE - 1;
  543. }
  544. return *pNodeInfo->pCurPtr & (1 << pNodeInfo->ibit--);
  545. }
  546. PRIVATE HRESULT PASCAL FAR FGetScheme(
  547. PNODEINFO pNodeInfo, // Current leaf info.
  548. LPCKEY lpckey) // Output buffer.
  549. {
  550. int fSchemeBit; // Scratch boolean.
  551. HRESULT fRet;
  552. lpckey->cschScheme = CSCH_NONE;
  553. if ((fSchemeBit = FGetBool(pNodeInfo)) == (int)-1)
  554. {
  555. return E_FAIL;
  556. }
  557. if (fSchemeBit)
  558. lpckey->cschScheme = CSCH_FIXED;
  559. else
  560. {
  561. if ((fSchemeBit = FGetBool(pNodeInfo)) == (int)-1)
  562. {
  563. return E_FAIL;
  564. }
  565. if (fSchemeBit)
  566. lpckey->cschScheme = CSCH_BELL;
  567. }
  568. if ((lpckey->cschScheme == CSCH_BELL) ||
  569. (lpckey->cschScheme == CSCH_FIXED))
  570. {
  571. DWORD dwTmp;
  572. if ((fRet = FGetBits(pNodeInfo, &dwTmp, 5)) != S_OK)
  573. {
  574. return fRet;
  575. }
  576. lpckey->ucCenter = (BYTE)dwTmp;
  577. }
  578. return S_OK;
  579. }
  580. // - - - - - - - - -
  581. // Get some number of bits from the index. If this function were
  582. // faster life would be better. It's called incredibly frequently.
  583. PUBLIC HRESULT PASCAL FAR FGetBits(
  584. PNODEINFO pNodeInfo, // Current leaf info.
  585. LPDW lpdw, // Output buffer.
  586. register CBIT cbit) // How many bits to get.
  587. {
  588. register BYTE cBitLeft;
  589. register BYTE tmp;
  590. LPB lpbCurPtr;
  591. DWORD dwVal;
  592. // HRESULT fRet;
  593. if (cbit == 0)
  594. {
  595. *lpdw = 0;
  596. return S_OK;
  597. }
  598. dwVal = 0;
  599. cBitLeft = pNodeInfo->ibit + 1;
  600. lpbCurPtr = pNodeInfo->pCurPtr;
  601. do
  602. {
  603. HRESULT fRet;
  604. if (cBitLeft <= 0)
  605. {
  606. lpbCurPtr++;
  607. if (lpbCurPtr >= pNodeInfo->pMaxAddress)
  608. {
  609. if ((fRet = ReadNewData (pNodeInfo)) != S_OK)
  610. return fRet;
  611. lpbCurPtr = pNodeInfo->pCurPtr;
  612. }
  613. cBitLeft = cbitBYTE;
  614. }
  615. if (cbit >= (CBIT)(tmp = cBitLeft))
  616. {
  617. dwVal |= ((DWORD)(*lpbCurPtr & BitLeftMask[cBitLeft]))
  618. << (cbit -= cBitLeft);
  619. cBitLeft = 0;
  620. }
  621. else
  622. {
  623. dwVal |= (((DWORD)(*lpbCurPtr & BitLeftMask[tmp]))
  624. >> (cBitLeft -= cbit));
  625. break;
  626. }
  627. } while (cbit);
  628. /* Update values */
  629. *lpdw = dwVal;
  630. pNodeInfo->ibit = cBitLeft - 1;
  631. pNodeInfo->pCurPtr = lpbCurPtr;
  632. return S_OK;
  633. }