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.

662 lines
19 KiB

  1. #include <mvopsys.h>
  2. #include <mem.h>
  3. #include <orkin.h>
  4. #include <mvsearch.h>
  5. #include "common.h"
  6. #include "index.h"
  7. #ifdef _DEBUG
  8. static BYTE NEAR s_aszModule[] = __FILE__; /* Used by error return functions.*/
  9. #endif
  10. extern FDECODE DecodeTable[];
  11. extern DWORD argdwBits[];
  12. typedef VOID (PASCAL NEAR *ENCODEDWORD) (PNODEINFO, DWORD, int);
  13. PRIVATE VOID PASCAL NEAR EmitBitStreamDWord (PNODEINFO, DWORD, int);
  14. PRIVATE VOID PASCAL NEAR EmitFixedDWord (PNODEINFO, DWORD, int);
  15. PRIVATE VOID PASCAL NEAR EmitBellDWord (PNODEINFO, DWORD, int);
  16. static ENCODEDWORD EncodeTable[] =
  17. {
  18. EmitBitStreamDWord,
  19. EmitFixedDWord,
  20. EmitBellDWord,
  21. NULL,
  22. };
  23. #define EmitDword(p,dw,key) EncodeTable[(key).cschScheme]((p), (dw), (key).ucCenter)
  24. #define FGetDword(a,b,c) (*DecodeTable[b.cschScheme])(a, b, c)
  25. /*************************************************************************
  26. *
  27. * INTERNAL PRIVATE FUNCTIONS
  28. *
  29. * All of them should be declared near
  30. *
  31. *************************************************************************/
  32. PRIVATE int PASCAL NEAR TraverseLeafNode (_LPIPB, PNODEINFO,
  33. DWORD FAR *, DWORD);
  34. PRIVATE int PASCAL NEAR DeleteTopicFromData (_LPIPB lpipb,
  35. FILEOFFSET dataOffset, DWORD FAR *, DWORD,
  36. LPDW pTopicIdArray, DWORD dwArraySize);
  37. VOID PRIVATE PASCAL NEAR RemapData (_LPIPB, PNODEINFO, PNODEINFO,
  38. DWORD, DWORD);
  39. VOID PRIVATE PASCAL NEAR EmitBits (PNODEINFO pNode, DWORD dwVal, BYTE cBits);
  40. PRIVATE VOID PASCAL NEAR EmitBool (PNODEINFO pNode, BOOL fVal);
  41. PUBLIC LONG PASCAL FAR CompareDWord (DWORD, DWORD, LPV lpParm);
  42. /*************************************************************************
  43. * @doc API
  44. * @func HRESULT FAR PASCAL | MVIndexTopicDelete |
  45. * Delete topics from an index
  46. * @parm HFPB | hSysFile |
  47. * Handle to an opened system file, maybe NULL
  48. * @parm _LPIPB | lpipb |
  49. * Pointer to index info. This structure is obtained through
  50. * IndexInitiate()
  51. * @parm SZ | szIndexName |
  52. * Name of the index. If hSysFile is NULL, this is a regular DOS file
  53. * else it is a subfile of hSysFile
  54. * @parm DWORD FAR * | rgTopicId |
  55. * Array of topic ids to be deleted from the index
  56. * @parm DWORD | dwCount |
  57. * Number of elements in the array
  58. * @rdesc S_OK, or other errors
  59. *************************************************************************/
  60. HRESULT PUBLIC EXPORT_API FAR PASCAL MVIndexTopicDelete (HFPB hSysFile,
  61. _LPIPB lpipb, SZ szIndexName, DWORD FAR * rgTopicId, DWORD dwCount)
  62. {
  63. PNODEINFO pNodeInfo;
  64. int fRet;
  65. int cLevel;
  66. int cMaxLevel;
  67. WORD wLen;
  68. LPB pCur;
  69. if (lpipb == NULL || rgTopicId == NULL || dwCount == 0)
  70. return(E_INVALIDARG);
  71. // Set the bState
  72. lpipb->bState = DELETING_STATE;
  73. // Open the index file
  74. if ((fRet = IndexOpenRW(lpipb, hSysFile, szIndexName)) != S_OK)
  75. {
  76. exit00:
  77. if (lpipb->idxf & IDXF_NORMALIZE)
  78. {
  79. FreeHandle (lpipb->wi.hSigma);
  80. FreeHandle (lpipb->wi.hLog);
  81. lpipb->wi.hSigma = lpipb->wi.hLog = NULL;
  82. }
  83. return(fRet);
  84. }
  85. // Allocate buffer
  86. if ((pNodeInfo = AllocBTreeNode (lpipb)) == NULL)
  87. {
  88. fRet = E_OUTOFMEMORY;
  89. exit0:
  90. FileClose(lpipb->hfpbIdxFile);
  91. FreeBTreeNode (pNodeInfo);
  92. goto exit00;
  93. }
  94. if ((lpipb->hTmpBuf = _GLOBALALLOC (DLLGMEM_ZEROINIT,
  95. lpipb->BTreeData.Header.dwMaxWLen * 2)) == NULL)
  96. goto exit0;
  97. lpipb->pTmpBuf = (LPB)_GLOBALLOCK (lpipb->hTmpBuf);
  98. if (((lpipb->pIndexDataNode =
  99. AllocBTreeNode (lpipb))) == NULL)
  100. {
  101. fRet = E_OUTOFMEMORY;
  102. exit1:
  103. _GLOBALUNLOCK(lpipb->hTmpBuf);
  104. _GLOBALFREE(lpipb->hTmpBuf);
  105. lpipb->hTmpBuf = NULL;
  106. goto exit0;
  107. }
  108. pNodeInfo->nodeOffset = lpipb->BTreeData.Header.foIdxRoot;
  109. cMaxLevel = lpipb->BTreeData.Header.cIdxLevels - 1;
  110. // Sort the incoming array
  111. if ((fRet = HugeDataSort((LPV HUGE*)rgTopicId, dwCount,
  112. (FCOMPARE)CompareDWord, NULL, NULL, NULL)) != S_OK)
  113. goto exit1;
  114. // Move down the tree, based on the first offset of the block
  115. for (cLevel = 0; cLevel < cMaxLevel; cLevel++)
  116. {
  117. if ((fRet = ReadNewNode(lpipb->hfpbIdxFile, pNodeInfo,
  118. FALSE)) != S_OK)
  119. {
  120. _GLOBALUNLOCK(lpipb->hData);
  121. _GLOBALFREE(lpipb->hData);
  122. lpipb->hData = NULL;
  123. exit2:
  124. FreeBTreeNode (lpipb->pIndexDataNode);
  125. lpipb->pIndexDataNode = NULL;
  126. goto exit1;
  127. }
  128. pCur = pNodeInfo->pBuffer + sizeof(WORD); // Skip cbLeft
  129. pCur = ExtractWord (lpipb->pTmpBuf, pCur, &wLen);
  130. pCur += ReadFileOffset (&pNodeInfo->nodeOffset, pCur);
  131. }
  132. // Handle leaf node
  133. while (!FoEquals (pNodeInfo->nodeOffset, foNil))
  134. {
  135. if ((fRet = ReadNewNode(lpipb->hfpbIdxFile, pNodeInfo,
  136. TRUE)) != S_OK)
  137. return fRet;
  138. if ((fRet = TraverseLeafNode (lpipb, pNodeInfo, rgTopicId, dwCount)) !=
  139. S_OK)
  140. {
  141. goto exit2;
  142. }
  143. ReadFileOffset (&pNodeInfo->nodeOffset, pNodeInfo->pBuffer);
  144. }
  145. fRet = S_OK;
  146. goto exit2;
  147. }
  148. PRIVATE int PASCAL NEAR TraverseLeafNode (_LPIPB lpipb, PNODEINFO pNodeInfo,
  149. DWORD FAR *rgTopicId, DWORD dwCount)
  150. {
  151. LPB pCur;
  152. LPB pMaxAddress;
  153. OCCF occf = lpipb->occf;
  154. WORD wLen;
  155. FILEOFFSET dataOffset;
  156. DWORD dataSize;
  157. BYTE TopicCnt[20];
  158. BYTE cbOldCount;
  159. BYTE cbNewCount;
  160. ERRB errb;
  161. BYTE fChange = FALSE;
  162. HRESULT fRet;
  163. pCur = pNodeInfo->pCurPtr;
  164. pMaxAddress = pNodeInfo->pMaxAddress;
  165. while (pCur < pMaxAddress)
  166. {
  167. DWORD dwTemp;
  168. DWORD dwTopicCount;
  169. DWORD dwOldTopicCount;
  170. LPB pSaved;
  171. LPB pTemp;
  172. pCur = ExtractWord (lpipb->pTmpBuf, pCur, &wLen);
  173. // Skip field id, topic count. fileoffset, datasize
  174. if (occf & OCCF_FIELDID)
  175. pCur += CbByteUnpack (&dwTemp, pCur); // FieldId
  176. pTemp = pSaved = pCur; // Save the pointer to the topic count offset
  177. cbOldCount = (BYTE)CbByteUnpack (&dwTopicCount, pCur);
  178. pCur += cbOldCount;
  179. pCur += ReadFileOffset (&dataOffset, pCur);
  180. pCur += CbByteUnpack (&dataSize, pCur);
  181. if (dwTopicCount == 0)
  182. continue;
  183. dwOldTopicCount = dwTopicCount;
  184. if ((fRet = DeleteTopicFromData (lpipb, dataOffset, &dwTopicCount,
  185. dataSize, rgTopicId, dwCount)) != S_OK)
  186. return(fRet);
  187. if (dwOldTopicCount == dwTopicCount)
  188. continue;
  189. cbNewCount = (BYTE)CbBytePack (TopicCnt, dwTopicCount);
  190. // Update the topic count
  191. if (cbOldCount > cbNewCount)
  192. {
  193. TopicCnt[cbNewCount - 1] |= 0x80; // Set the high bit
  194. }
  195. MEMCPY(pSaved, TopicCnt, cbNewCount);
  196. pSaved += cbNewCount;
  197. switch (cbOldCount - cbNewCount)
  198. {
  199. // Do we need 16 bytes to compress 4-bytes. YES!
  200. // Sometimes. we index/compress based on insufficient data
  201. // If subsequent updates contain value way larger than the
  202. // original data, then we may end up using 16 bytes to compress
  203. // 4 bytes!!
  204. case 16:
  205. *pSaved++ = 0x80; // Set the high bit
  206. break;
  207. case 15:
  208. *pSaved++ = 0x80; // Set the high bit
  209. break;
  210. case 14:
  211. *pSaved++ = 0x80; // Set the high bit
  212. break;
  213. case 13:
  214. *pSaved++ = 0x80; // Set the high bit
  215. break;
  216. case 12:
  217. *pSaved++ = 0x80; // Set the high bit
  218. break;
  219. case 11:
  220. *pSaved++ = 0x80; // Set the high bit
  221. break;
  222. case 10:
  223. *pSaved++ = 0x80; // Set the high bit
  224. break;
  225. case 9:
  226. *pSaved++ = 0x80; // Set the high bit
  227. break;
  228. case 7:
  229. *pSaved++ = 0x80; // Set the high bit
  230. break;
  231. case 6:
  232. *pSaved++ = 0x80; // Set the high bit
  233. break;
  234. case 5:
  235. *pSaved++ = 0x80; // Set the high bit
  236. case 4:
  237. *pSaved++ = 0x80; // Set the high bit
  238. case 3:
  239. *pSaved++ = 0x80; // Set the high bit
  240. case 2:
  241. *pSaved++ = 0x80; // Set the high bit
  242. case 1:
  243. *pSaved = 0x00;
  244. case 0:
  245. break;
  246. }
  247. #ifdef _DEBUG
  248. CbByteUnpack (&dwOldTopicCount, pTemp); // FieldId
  249. assert (dwOldTopicCount == dwTopicCount);
  250. #endif
  251. fChange = TRUE; // The node have been changed
  252. }
  253. if (fChange == FALSE)
  254. return(S_OK);
  255. // Update the node
  256. if ((FileSeekWrite(lpipb->hfpbIdxFile,
  257. pNodeInfo->pBuffer, pNodeInfo->nodeOffset,
  258. lpipb->BTreeData.Header.dwBlockSize, &errb)) !=
  259. (LONG)lpipb->BTreeData.Header.dwBlockSize)
  260. {
  261. return(errb);
  262. }
  263. return(S_OK);
  264. }
  265. PRIVATE int PASCAL NEAR DeleteTopicFromData (_LPIPB lpipb,
  266. FILEOFFSET dataOffset, DWORD FAR * pTopicCount, DWORD dataSize,
  267. LPDW pTopicIdArray, DWORD dwArraySize)
  268. {
  269. HRESULT fRet;
  270. ERRB errb;
  271. DWORD dwOldTopicCount;
  272. DWORD dwTopicId;
  273. DWORD dwTopicIdDelta;
  274. DWORD dwIndex;
  275. PNODEINFO pIndexDataNode = lpipb->pIndexDataNode;
  276. NODEINFO CopyNode;
  277. PNODEINFO pCopyNode = &CopyNode;
  278. PIH20 pHeader = &lpipb->BTreeData.Header;
  279. OCCF occf = lpipb->occf;
  280. LPB pStart;
  281. DWORD dwOldTopicId = 0;
  282. BYTE fetchOldData;
  283. BYTE fChanged;
  284. BYTE fNormalize = (lpipb->idxf & IDXF_NORMALIZE);
  285. // Make sure that we have enough memory to hold the data
  286. if (dataSize > pIndexDataNode->dwBlockSize)
  287. {
  288. _GLOBALUNLOCK (pIndexDataNode->hMem);
  289. if ((pIndexDataNode->hMem = _GLOBALREALLOC (pIndexDataNode->hMem,
  290. pIndexDataNode->dwBlockSize = dataSize, DLLGMEM_ZEROINIT)) == NULL)
  291. return(E_OUTOFMEMORY);
  292. pIndexDataNode->pBuffer = _GLOBALLOCK (pIndexDataNode->hMem);
  293. }
  294. // Read in the data
  295. if (FileSeekRead (lpipb->hfpbIdxFile, pIndexDataNode->pCurPtr =
  296. pIndexDataNode->pBuffer, dataOffset,
  297. dataSize, &errb) != (long)dataSize)
  298. return E_BADFILE;
  299. pIndexDataNode->pMaxAddress = pIndexDataNode->pBuffer + dataSize;
  300. pIndexDataNode->ibit = cbitBYTE - 1;
  301. // Copy the prelimary node info
  302. CopyNode = *pIndexDataNode;
  303. dwOldTopicCount = *pTopicCount;
  304. dwTopicId = dwIndex = 0;
  305. fetchOldData = TRUE;
  306. fChanged = FALSE;
  307. while (dwOldTopicCount > 0)
  308. {
  309. DWORD dwTmp;
  310. if (fetchOldData)
  311. {
  312. // Byte align
  313. if (pIndexDataNode->ibit != cbitBYTE - 1)
  314. {
  315. pIndexDataNode->ibit = cbitBYTE - 1;
  316. pIndexDataNode->pCurPtr ++;
  317. }
  318. // Keep track of the starting position
  319. pStart = pIndexDataNode->pCurPtr;
  320. if (fChanged == FALSE)
  321. pCopyNode->pCurPtr = pIndexDataNode->pCurPtr;
  322. // Get the topicId from the index file
  323. if ((fRet = FGetDword(pIndexDataNode, pHeader->ckeyTopicId,
  324. &dwTopicIdDelta)) != S_OK)
  325. return fRet;
  326. dwTopicId += dwTopicIdDelta;
  327. fetchOldData = FALSE;
  328. }
  329. if (dwTopicId < pTopicIdArray[dwIndex])
  330. {
  331. if (fChanged == FALSE)
  332. {
  333. if (fNormalize)
  334. {
  335. if ((fRet = FGetBits(pIndexDataNode, &dwTmp,
  336. sizeof (USHORT) * cbitBYTE)) != S_OK)
  337. return fRet;
  338. }
  339. SkipOldData (lpipb, pIndexDataNode);
  340. }
  341. else
  342. {
  343. pIndexDataNode->pCurPtr = pStart;
  344. RemapData (lpipb, pCopyNode, pIndexDataNode,
  345. dwTopicId, dwOldTopicId);
  346. }
  347. fetchOldData = TRUE;
  348. dwOldTopicId = dwTopicId;
  349. dwOldTopicCount --;
  350. continue;
  351. }
  352. if (dwTopicId > pTopicIdArray[dwIndex])
  353. {
  354. if (dwIndex < dwArraySize - 1)
  355. {
  356. dwIndex++;
  357. continue;
  358. }
  359. if (fChanged == FALSE)
  360. return(S_OK);
  361. pIndexDataNode->pCurPtr = pStart;
  362. RemapData (lpipb, pCopyNode, pIndexDataNode,
  363. dwTopicId, dwOldTopicId);
  364. fetchOldData =TRUE;
  365. dwOldTopicId = dwTopicId;
  366. dwOldTopicCount --;
  367. continue;
  368. }
  369. // Both TopicId are equal. Ignore the current data
  370. fChanged = TRUE; // We have changes
  371. if (fNormalize)
  372. {
  373. if ((fRet = FGetBits(pIndexDataNode, &dwTmp,
  374. sizeof (USHORT) * cbitBYTE)) != S_OK)
  375. return fRet;
  376. }
  377. if (occf & OCCF_HAVE_OCCURRENCE)
  378. {
  379. if ((fRet = SkipOldData (lpipb, pIndexDataNode)) != S_OK)
  380. return(fRet);
  381. }
  382. (*pTopicCount)--;
  383. fetchOldData = TRUE;
  384. dwOldTopicCount--;
  385. }
  386. if (fChanged)
  387. {
  388. MEMSET(pCopyNode->pCurPtr, 0,
  389. (size_t) (pCopyNode->pMaxAddress - pCopyNode->pCurPtr));
  390. // Write out the new data
  391. if (FileSeekWrite (lpipb->hfpbIdxFile, pIndexDataNode->pBuffer, dataOffset,
  392. dataSize, &errb) != (long)dataSize)
  393. return errb;
  394. }
  395. return(S_OK);
  396. }
  397. VOID PRIVATE PASCAL NEAR RemapData (_LPIPB lpipb, PNODEINFO pCopyNode,
  398. PNODEINFO pIndexDataNode, DWORD dwTopicId, DWORD dwOldTopicId)
  399. {
  400. DWORD dwTmp;
  401. DWORD dwOccs;
  402. PIH20 pHeader = &lpipb->BTreeData.Header;
  403. OCCF occf = lpipb->occf;
  404. pIndexDataNode->ibit = cbitBYTE - 1;
  405. // Skip TopicIdDelta, since we already have TopicId
  406. FGetDword(pIndexDataNode, pHeader->ckeyTopicId, &dwTmp);
  407. EmitDword (pCopyNode, dwTopicId - dwOldTopicId, pHeader->ckeyTopicId);
  408. // EmitDword (pCopyNode, dwTopicDelta, pHeader->ckeyTopicId);
  409. if (lpipb->idxf & IDXF_NORMALIZE)
  410. {
  411. FGetBits(pIndexDataNode, &dwTmp, sizeof (USHORT) * cbitBYTE);
  412. EmitBits(pCopyNode, dwTmp, (BYTE)(sizeof (WORD) * cbitBYTE));
  413. }
  414. if ((occf & OCCF_HAVE_OCCURRENCE) == 0)
  415. return;
  416. // Get the number of occurrences
  417. FGetDword(pIndexDataNode, pHeader->ckeyOccCount, &dwOccs);
  418. EmitDword (pCopyNode, dwOccs, pHeader->ckeyOccCount);
  419. //
  420. // One pass through here for each occurence in the
  421. // current sub-list.
  422. //
  423. for (; dwOccs; dwOccs--)
  424. {
  425. //
  426. // Keeping word-counts? If so, get it.
  427. //
  428. if (occf & OCCF_COUNT)
  429. {
  430. FGetDword(pIndexDataNode, pHeader->ckeyWordCount, &dwTmp);
  431. EmitDword(pCopyNode, dwTmp, pHeader->ckeyWordCount);
  432. }
  433. //
  434. // Keeping byte-offsets? If so, get it.
  435. //
  436. if (occf & OCCF_OFFSET)
  437. {
  438. FGetDword(pIndexDataNode, pHeader->ckeyOffset, &dwTmp);
  439. EmitDword(pCopyNode, dwTmp, pHeader->ckeyOffset);
  440. }
  441. }
  442. if (pCopyNode->ibit != cbitBYTE - 1)
  443. {
  444. pCopyNode->ibit = cbitBYTE - 1;
  445. pCopyNode->pCurPtr ++;
  446. }
  447. }
  448. PRIVATE VOID PASCAL NEAR EmitBitStreamDWord (PNODEINFO pNode, DWORD dw,
  449. int ckeyCenter)
  450. {
  451. BYTE ucBits;
  452. // Bitstream scheme.
  453. //
  454. // This writes "dw" one-bits followed by a zero-bit.
  455. //
  456. for (; dw;)
  457. {
  458. if (dw < cbitBYTE * sizeof(DWORD))
  459. {
  460. ucBits = (BYTE)dw;
  461. dw = 0;
  462. }
  463. else
  464. {
  465. ucBits = cbitBYTE * sizeof(DWORD);
  466. dw -= cbitBYTE * sizeof(DWORD);
  467. }
  468. EmitBits(pNode, argdwBits[ucBits], (BYTE)ucBits);
  469. }
  470. EmitBool(pNode, 0);
  471. }
  472. PRIVATE VOID PASCAL NEAR EmitFixedDWord (PNODEINFO pNode, DWORD dw,
  473. int ckeyCenter)
  474. {
  475. // This just writes "ckey.ucCenter" bits of data.
  476. EmitBits (pNode, dw, (BYTE)(ckeyCenter + 1));
  477. }
  478. PRIVATE VOID PASCAL NEAR EmitBellDWord (PNODEINFO pNode, DWORD dw,
  479. int ckeyCenter)
  480. {
  481. BYTE ucBits;
  482. // The "BELL" scheme is more complicated.
  483. ucBits = (BYTE)CbitBitsDw(dw);
  484. if (ucBits <= ckeyCenter)
  485. {
  486. //
  487. // Encoding a small value. Write a zero, then write
  488. // "ckey.ucCenter" bits of the value, which
  489. // is guaranteed to be enough.
  490. //
  491. EmitBool(pNode, 0);
  492. EmitBits(pNode, dw, (BYTE)(ckeyCenter));
  493. return;
  494. }
  495. //
  496. // Encoding a value that won't fit in "ckey.ucCenter" bits.
  497. // "ucBits" is how many bits it will really take.
  498. //
  499. // First, write out "ucBits - ckey.ucCenter" one-bits.
  500. //
  501. EmitBits(pNode, argdwBits[ucBits - ckeyCenter],
  502. (BYTE)(ucBits - ckeyCenter));
  503. //
  504. // Now, write out the value in "ucBits" bits,
  505. // but zero the high-bit first.
  506. //
  507. EmitBits(pNode, dw & argdwBits[ucBits - 1], ucBits);
  508. }
  509. /*************************************************************************
  510. *
  511. * @doc PRIVATE INDEXING
  512. *
  513. * @func VOID | EmitBits |
  514. * Writes a bunch of bits into the output buffer.
  515. *
  516. * @parm PNODEINFO | pNode |
  517. * Pointer to the output data structure
  518. *
  519. * @parm DWORD | dwVal |
  520. * DWORD value to write
  521. *
  522. * @parm BYTE | cbits |
  523. * Number of bits to write from dwVal
  524. *************************************************************************/
  525. PRIVATE VOID PASCAL NEAR EmitBits (PNODEINFO pNode, DWORD dwVal, BYTE cBits)
  526. {
  527. BYTE cbitThisPassBits;
  528. BYTE bThis;
  529. // Loop until no bits left
  530. for (; cBits;)
  531. {
  532. if (pNode->ibit < 0)
  533. {
  534. pNode->pCurPtr++;
  535. pNode->ibit = cbitBYTE - 1;
  536. }
  537. cbitThisPassBits = (pNode->ibit + 1 < cBits) ?
  538. pNode->ibit + 1 : cBits;
  539. bThis = (pNode->ibit == cbitBYTE - 1) ?
  540. 0 : *pNode->pCurPtr;
  541. bThis |= ((dwVal >> (cBits - cbitThisPassBits)) <<
  542. (pNode->ibit - cbitThisPassBits + 1));
  543. *pNode->pCurPtr = (BYTE)bThis;
  544. pNode->ibit -= cbitThisPassBits;
  545. cBits -= (BYTE)cbitThisPassBits;
  546. }
  547. }
  548. /*************************************************************************
  549. *
  550. * @doc PRIVATE INDEXING
  551. *
  552. * @func VOID | EmitBool |
  553. * Writes a single bit into the output buffer.
  554. *
  555. * @parm PNODEINFO | pNode |
  556. * Pointer to the output data structure
  557. *
  558. * @parm BOOL | dwVal |
  559. * BOOL value to write
  560. *************************************************************************/
  561. PRIVATE VOID PASCAL NEAR EmitBool (PNODEINFO pNode, BOOL fVal)
  562. {
  563. if (pNode->ibit < 0)
  564. { // This byte is full, point to a new byte
  565. pNode->pCurPtr++;
  566. pNode->ibit = cbitBYTE - 1;
  567. }
  568. if (pNode->ibit == cbitBYTE - 1) // Zero out a brand-new byte.
  569. *pNode->pCurPtr = (BYTE)0;
  570. if (fVal) // Write my boolean.
  571. *pNode->pCurPtr |= 1 << pNode->ibit;
  572. pNode->ibit--;
  573. }
  574. PUBLIC LONG PASCAL FAR CompareDWord (DWORD dw1, DWORD dw2, LPV lpParm)
  575. {
  576. return (dw1 - dw2);
  577. }