Windows NT 4.0 source code leak
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.

818 lines
21 KiB

4 years ago
  1. /*****************************************************************************
  2. * *
  3. * ZECK2.C *
  4. * *
  5. * Copyright (C) Microsoft Corporation 1990. *
  6. * All Rights reserved. *
  7. * *
  8. ******************************************************************************
  9. * *
  10. * Module Intent *
  11. * *
  12. * Zeck compression routines for bitmaps & topic 2K blocks.
  13. *
  14. * Note: this is a 2nd version based on t-SteveF's stuff in this directory.
  15. * This new version is designed to work with both topic 2K blocks and
  16. * (possibly huge) bitmaps. It retains the ability to suppress compression
  17. * to allow back patching into the topic.
  18. *
  19. * It does NOT retain the ability to be called repeatedly to resume
  20. * previous compression states.
  21. * *
  22. *****************************************************************************/
  23. /*****************************************************************************
  24. *
  25. * Revision History: Created 09/20/90 by Tomsn
  26. * 12/17/90 Use based pointers for the tree to save space.
  27. * 02/04/91 Maha - changed ints to INT
  28. *
  29. *****************************************************************************/
  30. #include "stdafx.h"
  31. #ifdef _DEBUG
  32. #undef THIS_FILE
  33. static char THIS_FILE[] = __FILE__;
  34. #endif
  35. #include "zeckdat.h"
  36. typedef struct insertretval {
  37. DWORD uiBackwardsOffset; // backwards offset of the match from current pos.
  38. DWORD cbPatternLen; // the length of the match.
  39. } INSERTRETVAL;
  40. static INSERTRETVAL INLINE InsertNode(PBYTE pbByte);
  41. static void STDCALL InitTree(void);
  42. static void INLINE DeleteNode(void);
  43. // We support both _based and non-based forms for the tree:
  44. // compression nodes for building tree used to find repetitions:
  45. typedef struct nd ND, *QND, **QQND;
  46. struct nd {
  47. PBYTE pbVal; // pointer to buff location
  48. QND qndRight; // left and right node
  49. QND qndLeft;
  50. QQND qqndPar; // parent node
  51. };
  52. #define RING_BUF_LEN 4096 // used for node recycling.
  53. #define GRIND_UPDATE 1024 // when to update grinder
  54. QQND qqndRoots;
  55. QND qndNodes;
  56. PBYTE qbSuppressBuf;
  57. QSUPPRESSZECK pSuppressNext; // next suppress guy to watch out for.
  58. static int iCurrent; // current insertion index into the ring buffer.
  59. /* LcbCompressZeck -
  60. *
  61. * This is the only entry point into zeck compression. Compresses 'cbSrc'
  62. * bytes at 'pbSrc' into the buffer at 'pbDst', suppressing compression
  63. * for bytes specified by the qSuppress linked list.
  64. *
  65. * pbSrc - IN huge pointer to source buffer.
  66. * pbDst- IN huge pointer to dest buffer.
  67. * cbSrc - IN count of bytes to be compressed.
  68. * cbDest- IN limit count of bytes to put in pbDst - used to create
  69. * the 4K topic blocks.
  70. *
  71. * NOTE: if cbDest != COMPRESS_CBNONE it will try to fill the whole dest
  72. * buffer EVEN IF THAT MEANS PERFORMING LESS COMPRESSION. This is done
  73. * to handle the 4K topic blocks which must be 4K and no less.
  74. *
  75. * pcbSrcUsed- OUT count of src bytes compressed into pbDst (needed when
  76. * a cbDest limit is used).
  77. * qSuppress IN OUT linked list of compression suppression specifiers,
  78. * the out value is where the suppression ranges ended
  79. * up in the pbDst buffer.
  80. *
  81. * RETURNS: length of compressed data put in pbDst, 0 for error.
  82. */
  83. PBYTE pbSrcBase; // used for suppression coordination based on 4K
  84. // wrap around suppression buffer.
  85. /*
  86. * [ralphw] I no longer allow COMPRESS_CBNONE (0) to be passed for
  87. * cbDest. If you really don't care about checking the destination,
  88. * then pass in 2147483647 (INT_MAX) for cbDest.
  89. */
  90. static const BYTE abBitFlags[] =
  91. { 0x1, 0x2, 0x4, 0x8, 0x10, 0x20, 0x40, 0x80 };
  92. int STDCALL LcbCompressZeck(PBYTE pbSrc, PBYTE pbDst, int cbSrc, int cbDest,
  93. int* pcbSrcUsed, QSUPPRESSZECK pSuppress)
  94. {
  95. PBYTE pbStop; // pts to last byte to compress
  96. PBYTE pbLast, pbOrgDst, pbBitFlagsSpot;
  97. UINT iBitdex;
  98. BYTE bBitFlags;
  99. INSERTRETVAL insretval;
  100. ZECKPACKBLOCK zpb;
  101. int cbSuppress = 0;
  102. cGrind = 0;
  103. FAllocateZeckGlobals();
  104. InitTree();
  105. pbOrgDst = pbDst; // save away beginning of dest buffer.
  106. pbSrcBase = pbSrc; // for compression suppression in InsertNode().
  107. iBitdex = 8; // so we get fresh bitflags stuff 1st time through.
  108. bBitFlags = 0;
  109. pbBitFlagsSpot = pbDst; // so initial insertion won't hurt.
  110. pSuppressNext = pSuppress;
  111. // Stop all compression MAX_PATTERN_LEN away from end of buffer so we
  112. // don't accidentally find a pattern running off the end of the buffer:
  113. pbStop = pbSrc + cbSrc - MAX_PATTERN_LEN;
  114. pbLast = pbSrc + cbSrc;
  115. while (pbSrc < pbStop && cbDest > 0) {
  116. // increment the bit flags dex:
  117. ++iBitdex;
  118. if (iBitdex > 7) {
  119. // it overflowed, insert bitflags into buffer and start anew:
  120. *pbBitFlagsSpot = bBitFlags;
  121. iBitdex = 0;
  122. bBitFlags = 0;
  123. pbBitFlagsSpot = pbDst++;
  124. --cbDest;
  125. if (cbDest <= 0)
  126. break;
  127. if (++cGrind == GRIND_UPDATE) {
  128. cGrind = 0;
  129. doGrind();
  130. }
  131. }
  132. // Check for zeck compression block:
  133. if (cbSuppress ||
  134. (pSuppressNext && pbSrc >= pSuppressNext->rbSuppress)) {
  135. ASSERT(cbSuppress || pbSrc == pSuppressNext->rbSuppress);
  136. // record the destination position:
  137. if (!cbSuppress) {
  138. pSuppressNext->rbNewpos = pbDst;
  139. pSuppressNext->iBitdex = iBitdex;
  140. cbSuppress = pSuppressNext->cbSuppress;
  141. if (!cbSuppress) {
  142. cbSuppress = 1;
  143. }
  144. }
  145. // copy the raw byte & mark the suppression buffer:
  146. DeleteNode();
  147. qbSuppressBuf[iCurrent] = TRUE;
  148. *pbDst++ = *pbSrc++;
  149. --cbDest;
  150. ++iCurrent;
  151. if (iCurrent >= RING_BUF_LEN) {
  152. iCurrent = 0;
  153. }
  154. --cbSuppress;
  155. if (!cbSuppress) {
  156. pSuppressNext = pSuppressNext->next;
  157. }
  158. }
  159. else {
  160. insretval = InsertNode(pbSrc);
  161. if (insretval.uiBackwardsOffset != 0
  162. && insretval.cbPatternLen >= MIN_PATTERN_LEN) {
  163. // must have room in dest buffer for patter & two-byte code:
  164. if (cbDest < 2)
  165. goto copy_raw;
  166. // make sure we don't run into a suppression zone:
  167. if (pSuppressNext &&
  168. pbSrc + insretval.cbPatternLen >
  169. pSuppressNext->rbSuppress) {
  170. // prune the match:
  171. insretval.cbPatternLen =
  172. (pSuppressNext->rbSuppress - pbSrc);
  173. }
  174. // make sure it's still worth it:
  175. if (insretval.cbPatternLen < MIN_PATTERN_LEN)
  176. goto copy_raw;
  177. // a pattern match has been found:
  178. ASSERT(insretval.uiBackwardsOffset <= RING_BUF_LEN);
  179. zpb.uiBackwardsOffset = (WORD)
  180. ENCODE_FROM_BACKWARDS(insretval.uiBackwardsOffset);
  181. zpb.cbPatternLen = (WORD)
  182. ENCODE_FROM_PATTERNLEN(insretval.cbPatternLen);
  183. *pbDst++ = zpb.bytes[0];
  184. *pbDst++ = zpb.bytes[1];
  185. cbDest -= 2;
  186. // mark flags byte:
  187. bBitFlags |= abBitFlags[iBitdex];
  188. // Insert nodes for the body of the pattern:
  189. /*
  190. * [ralphw] There are now two almost identical loops
  191. * here. The first one is what usually gets called and saves
  192. * us from having to compare pbSrc with pbStop on every
  193. * iteration.
  194. */
  195. if (pbSrc < pbStop - MAX_PATTERN_LEN) {
  196. for (--insretval.cbPatternLen; insretval.cbPatternLen;
  197. --insretval.cbPatternLen) {
  198. #ifdef _DEBUG
  199. ASSERT(pbSrc + 1 < pbStop);
  200. #endif
  201. InsertNode(++pbSrc);
  202. }
  203. }
  204. else {
  205. for (--insretval.cbPatternLen; insretval.cbPatternLen;
  206. --insretval.cbPatternLen) {
  207. if (++pbSrc >= pbStop) { // dont insert past pbStop
  208. // inc past pattern...
  209. pbSrc += insretval.cbPatternLen - 1;
  210. break;
  211. }
  212. InsertNode(pbSrc);
  213. }
  214. }
  215. ++pbSrc;
  216. }
  217. else { // copy raw byte:
  218. copy_raw:
  219. *pbDst++ = *pbSrc++;
  220. --cbDest;
  221. }
  222. }
  223. } // while (pbSrc < pbStop && cbDest > 0)
  224. // copy in the last raw bytes:
  225. while(pbSrc < pbLast && cbDest > 0) {
  226. ++iBitdex;
  227. if (iBitdex > 7) {
  228. // it overflowed, insert bitflags into buffer and start anew:
  229. *pbBitFlagsSpot = bBitFlags;
  230. iBitdex = 0;
  231. bBitFlags = 0;
  232. pbBitFlagsSpot = pbDst++;
  233. --cbDest;
  234. if (cbDest <= 0)
  235. break;
  236. }
  237. /*
  238. * Check for compression suppression zone -- we don't have to
  239. * suppress compression (since we're not even trying), but we must
  240. * update the rbNewPos pointer.
  241. */
  242. if (pSuppressNext && pbSrc == pSuppressNext->rbSuppress) {
  243. pSuppressNext->rbNewpos = pbDst;
  244. pSuppressNext->iBitdex = iBitdex;
  245. pSuppressNext = pSuppressNext->next;
  246. }
  247. *pbDst++ = *pbSrc++;
  248. --cbDest;
  249. }
  250. *pbBitFlagsSpot = bBitFlags;
  251. if (pcbSrcUsed) {
  252. *pcbSrcUsed = (DWORD) (pbSrc - pbSrcBase);
  253. }
  254. // ASSERT(pbSrc == pbLast); // no, we may only compress until cbDest == 0
  255. ConfirmOrDie(cbDest >= 0); // This would be really, really bad...
  256. return (pbDst - pbOrgDst);
  257. }
  258. /***************************************************************************
  259. FUNCTION: InitTree
  260. PURPOSE: Initialize the tree used in the compression
  261. PARAMETERS:
  262. void
  263. RETURNS:
  264. COMMENTS:
  265. MODIFICATION DATES:
  266. 18-Jun-1994 [ralphw] - now assumes lcCalloc is called before
  267. we enter, so we don't need to do so much work to initialize.
  268. ***************************************************************************/
  269. static void STDCALL InitTree(void)
  270. {
  271. int i;
  272. iCurrent = 0;
  273. /*
  274. * [ralphw] Since qqndRoots and qndNodes are lcCalloc'd, they should
  275. * already have been set to zero.
  276. */
  277. ASSERT(!qqndRoots[0] && !qqndRoots[255] && !qndNodes[0].qndRight
  278. && !qndNodes[RING_BUF_LEN - 1].qndRight);
  279. // for (i = 0; i < 256; i++)
  280. // qqndRoots[i] = NULL;
  281. for (i = 0; i < RING_BUF_LEN; i++) {
  282. // qndNodes[i].qndRight = NULL;
  283. // qndNodes[i].qndLeft = NULL;
  284. // qndNodes[i].qqndPar = NULL;
  285. // qndNodes[i].pbVal = NULL;
  286. qbSuppressBuf[i] = TRUE; // initially all is supressed to prevent
  287. // matches from running into unset buffer area.
  288. }
  289. }
  290. /***************************************************************************
  291. *
  292. - DeleteNode
  293. -
  294. * Purpose:
  295. * Delete a specified node from the tree
  296. *
  297. * Arguments:
  298. *
  299. * Returns:
  300. * nothing
  301. *
  302. * Globals Used:
  303. * QND qndNodes
  304. *
  305. * +++
  306. *
  307. * Notes:
  308. *
  309. ***************************************************************************/
  310. static void INLINE DeleteNode(void)
  311. {
  312. QND qndDel = (QND) &qndNodes[iCurrent];
  313. QND qnd;
  314. ASSERT(iCurrent < RING_BUF_LEN);
  315. if (qndDel->qqndPar == NULL)
  316. return; // not in tree
  317. // if the node is a leaf, the insert ND is easy
  318. if (qndDel->qndRight == NULL)
  319. qnd = qndDel->qndLeft;
  320. else if (qndDel->qndLeft == NULL)
  321. qnd = qndDel->qndRight;
  322. else { // node to be deleted is an interior node
  323. qnd = qndDel->qndLeft;
  324. if (qnd->qndRight != NULL) {
  325. do {
  326. qnd = qnd->qndRight;
  327. } while (qnd->qndRight != NULL);
  328. *(qnd->qqndPar) = qnd->qndLeft;
  329. if (qnd->qndLeft != NULL)
  330. qnd->qndLeft->qqndPar = qnd->qqndPar;
  331. qnd->qndLeft = qndDel->qndLeft;
  332. if (qnd->qndLeft != NULL)
  333. qnd->qndLeft->qqndPar = &(qnd->qndLeft);
  334. }
  335. qnd->qndRight = qndDel->qndRight;
  336. if (qnd->qndRight != NULL)
  337. qnd->qndRight->qqndPar = &(qnd->qndRight);
  338. }
  339. if (qnd != NULL)
  340. qnd->qqndPar = qndDel->qqndPar;
  341. *(qndDel->qqndPar) = qnd;
  342. qndDel->qqndPar = NULL;
  343. }
  344. /***************************************************************************
  345. *
  346. - InsertNode
  347. -
  348. * Purpose:
  349. * Inserts string of length cbStrMax, qbRingBuf[r..r+cbStrMax-1], into
  350. * one of the trees (qqndRoots[*iString]'th tree) and returns the
  351. * longest-match position and length via the global variables iMatchCur and
  352. * cbMatchCur. If cbMatchCur = cbStrMax, then removes the old node in favor
  353. * of the new one, because the old one will be deleted sooner.
  354. *
  355. * Arguments:
  356. * UINT iString - index in qbRingBuf of the string to insert
  357. *
  358. * Returns:
  359. * nothing
  360. *
  361. * Globals Used:
  362. * QND qndNodes, QQND qqndRoots, QB qbRingBuf
  363. * UINT iMatchCur - index in qbRingBuf of longest match
  364. * UINT cbMatchCur - length of longest match
  365. *
  366. * +++
  367. *
  368. * Notes:
  369. * There is a one to one relationship with the i'th position in the
  370. * qbRingBuf and the i'th position in the qndNodes.
  371. *
  372. * We must take care not to use bytes which have not yet been initialized
  373. * in qbRingBuff when finding patters (this differs from previous versions).
  374. * iMax faciliates this check.
  375. *
  376. ***************************************************************************/
  377. static INSERTRETVAL INLINE InsertNode(PBYTE pbByte)
  378. {
  379. QQND qqnd;
  380. QND qndNew;
  381. int fComp; // must be signed
  382. UINT cbMatchND, cbMatchCur;
  383. INSERTRETVAL insretval;
  384. PBYTE rbThis, rbLook, rbBestVal;
  385. insretval.uiBackwardsOffset = 0; // indicating no match.
  386. // delete previous string at this position of the circular buffer:
  387. DeleteNode();
  388. // clear the suppression buffer since insertion means it's not suppressed
  389. qbSuppressBuf[iCurrent] = FALSE;
  390. // start with tree index by first in string
  391. qqnd = (QQND) &qqndRoots[*pbByte];
  392. qndNew = (QND) &qndNodes[iCurrent];
  393. ASSERT(iCurrent < RING_BUF_LEN);
  394. qndNew->qndLeft = qndNew->qndRight = NULL;
  395. qndNew->pbVal = pbByte;
  396. // goto first;
  397. rbBestVal = NULL;
  398. cbMatchCur = 0;
  399. do {
  400. if (*qqnd == NULL) {
  401. *qqnd = qndNew; // insert it.
  402. qndNew->qqndPar = qqnd;
  403. goto ret;
  404. }
  405. // compare the string at the current node with the string
  406. // that we are looking for.
  407. rbThis = pbByte;
  408. rbLook = (*qqnd)->pbVal;
  409. for (cbMatchND = 0; cbMatchND <= MAX_PATTERN_LEN; cbMatchND++) {
  410. if ((fComp = (signed char) rbThis[cbMatchND]
  411. - (signed char) rbLook[cbMatchND]) != 0)
  412. break; // no match.
  413. if (qbSuppressBuf[((rbLook + cbMatchND) - pbSrcBase) %
  414. RING_BUF_LEN]) {
  415. break; // running into compression suppression zone.
  416. }
  417. }
  418. // if the length of the matched string is greater then the
  419. // current, make the iMatchCur point the qnd
  420. if (cbMatchND > cbMatchCur) {
  421. rbBestVal = (*qqnd)->pbVal;
  422. cbMatchCur = cbMatchND;
  423. }
  424. // Follow the tree down to the leaves depending on the result
  425. // of the last string compare. When you come the a leaf in the
  426. // tree, you are done and insert the node.
  427. if (fComp >= 0) {
  428. qqnd = &((*qqnd)->qndRight);
  429. } else {
  430. qqnd = &((*qqnd)->qndLeft);
  431. }
  432. // Search for strings while a less then maxium length string
  433. // is found
  434. } while (cbMatchCur <= MAX_PATTERN_LEN);
  435. // replace an older ND with the new node in the tree,
  436. // by replacing the current qnd with the new node qndNew
  437. if (*qqnd != NULL) {
  438. if ((qndNew->qndLeft = (*qqnd)->qndLeft) != NULL) {
  439. (*qqnd) ->qndLeft->qqndPar = &(qndNew->qndLeft);
  440. }
  441. if ((qndNew->qndRight = (*qqnd)->qndRight) != NULL) {
  442. (*qqnd)->qndRight->qqndPar = &(qndNew->qndRight);
  443. }
  444. // insert into left/right side of parent
  445. qndNew->qqndPar = qqnd;
  446. (*qqnd) ->qqndPar = NULL;
  447. *qqnd = qndNew;
  448. }
  449. ret:
  450. // translate the index of the match into a backwards offset:
  451. if (rbBestVal) {
  452. insretval.uiBackwardsOffset = (UINT) (pbByte - rbBestVal);
  453. insretval.cbPatternLen = cbMatchCur > MAX_PATTERN_LEN ?
  454. MAX_PATTERN_LEN : cbMatchCur;
  455. }
  456. // increment iCurrent:
  457. ++iCurrent;
  458. if (iCurrent >= RING_BUF_LEN) {
  459. iCurrent = 0;
  460. }
  461. return(insretval);
  462. }
  463. /***************************************************************************
  464. *
  465. - FAllocateZeckGlobals
  466. -
  467. * Purpose: Allocate global ring buffer & pattern match tree nodes.
  468. *
  469. * Arguments: none.
  470. *
  471. * Returns: TRUE if successful, FALSE if failure.
  472. *
  473. * Globals Used: qndNodes, qqndRoots, qbRingBuff.
  474. *
  475. ***************************************************************************/
  476. void STDCALL FAllocateZeckGlobals(void)
  477. {
  478. if (qndNodes)
  479. ZeroMemory(qndNodes, RING_BUF_LEN * sizeof(ND));
  480. else
  481. qndNodes = (QND) lcCalloc(RING_BUF_LEN * sizeof(ND));
  482. if (qqndRoots)
  483. ZeroMemory(qqndRoots, 256 * sizeof(QND));
  484. else
  485. qqndRoots = (QQND) lcCalloc(256 * sizeof(QND));
  486. if (qbSuppressBuf)
  487. ZeroMemory(qbSuppressBuf, RING_BUF_LEN * sizeof(BYTE));
  488. else
  489. qbSuppressBuf = (PBYTE) lcCalloc(RING_BUF_LEN * sizeof(BYTE));
  490. }
  491. /***************************************************************************
  492. *
  493. - FreeZeckGlobals
  494. -
  495. * Purpose: Free the global ring buffer and pattern tree nodes.
  496. *
  497. * Arguments: None.
  498. *
  499. * Returns: Nothing.
  500. *
  501. * Globals Used: qndNodes, qqndRoots, qbRingBuff.
  502. *
  503. ***************************************************************************/
  504. void STDCALL FreeZeckGlobals()
  505. {
  506. if (qndNodes)
  507. lcClearFree(&qndNodes);
  508. if (qqndRoots)
  509. lcClearFree(&qqndRoots);
  510. if (qbSuppressBuf)
  511. lcClearFree(&qbSuppressBuf);
  512. }
  513. int STDCALL LcbUncompressZeck(PBYTE pbSrc, PBYTE pbDst, int cbSrc)
  514. {
  515. BYTE bBitFlags, bBitShift;
  516. PBYTE pbLast, pbOrgDst;
  517. ZECKPACKBLOCK zpb;
  518. bBitShift = 0;
  519. pbLast = pbSrc + cbSrc;
  520. pbOrgDst = pbDst; // save away origional dest.
  521. #ifdef DUMP
  522. rbOrgSrc = pbSrc;
  523. #endif
  524. while (pbSrc < pbLast) {
  525. if (!bBitShift) { // overflowed, get the next flags byte:
  526. bBitFlags = *pbSrc++;
  527. bBitShift = 1;
  528. if (pbSrc >= pbLast)
  529. break;
  530. }
  531. if (bBitFlags & bBitShift) {
  532. int cbPatternLen;
  533. PBYTE pbPattern;
  534. // is a zeck encoding pack:
  535. zpb.bytes[0] = *pbSrc++;
  536. zpb.bytes[1] = *pbSrc++;
  537. cbPatternLen = PATTERNLEN_FROM_ENCODE(zpb.cbPatternLen);
  538. pbPattern = pbDst - BACKWARDS_FROM_ENCODE(zpb.uiBackwardsOffset);
  539. for (; cbPatternLen > 0; --cbPatternLen)
  540. *pbDst++ = *pbPattern++;
  541. }
  542. else {
  543. *pbDst++ = *pbSrc++; // just copy raw byte in:
  544. }
  545. // bump up the bit mask flag:
  546. bBitShift <<= 1;
  547. }
  548. return (pbDst - pbOrgDst);
  549. }
  550. /* Backpatch support -------------------------------------------------
  551. *
  552. * As we compress, the suppression zones get the zeck-code bits
  553. * mingled in. So, while the compression-suppression zones are
  554. * not compressed, they must be backpatched in very special manner
  555. * to handle the mingled zeck-code bits. These routines perform this
  556. * special backpatching.
  557. *
  558. * Currently only long value backpatching is supported.
  559. *
  560. * We use the special suppresszeck.iCodeBits backwards offset to
  561. * determine where the code bits are. If the offset is zero, then
  562. * the 1st byte of code bits immediately preceeds rbNewpos, and
  563. * subsequent bytes of code bits come every 8 bytes.
  564. *
  565. * NOTE: magic -- if the suppresszeck.iBitdex == BITDEX_NONE, then no
  566. * compression was done & simply backpatch using direct access.
  567. */
  568. /***************************************************************************
  569. *
  570. - Name: VMemBackpatchZeck
  571. -
  572. * Purpose:
  573. * Backpatches a zeck compressed block with longwords. Used to update the
  574. * topic size and VA next & prev ptrs in several structures. Special
  575. * magic is performed to deal with code-bytes which are within the
  576. * zeck-compressed image.
  577. *
  578. * Arguments:
  579. * qsuppresszeck - a suppresszeck node specifiying the beginning of the
  580. * struct to backpatch.
  581. * ulOffset - offset into structure of long to backpatch (relative to
  582. * fcl).
  583. * iBitdex - special bitdex value giving the backwards offset of zeck
  584. * code byte.
  585. *
  586. * Returns: Nothing.
  587. *
  588. ************************************************************************/
  589. VOID STDCALL VMemBackpatchZeck(QSUPPRESSZECK qsuppresszeck, DWORD ulOffset,
  590. int value)
  591. {
  592. PBYTE qbDest, pbSrc;
  593. UINT iBitdex;
  594. ASSERT(qsuppresszeck->rbNewpos);
  595. iBitdex = qsuppresszeck->iBitdex;
  596. qbDest = qsuppresszeck->rbNewpos + ulOffset;
  597. if (iBitdex == (WORD) BITDEX_NONE) { // if no compression:
  598. *(int*) (qsuppresszeck->rbNewpos + ulOffset) = value;
  599. }
  600. else {
  601. pbSrc = (PBYTE) &value;
  602. qbDest += ulOffset / 8;
  603. iBitdex += (UINT) (ulOffset % 8);
  604. if (iBitdex > 7) {
  605. ++qbDest;
  606. iBitdex = iBitdex - 8;
  607. ASSERT(iBitdex < 8);
  608. }
  609. // insert the backpatch:
  610. // REVIEW: if iBitdex < 4, looks like we could just drop the long
  611. // value in, and update iBitdex, pbDest, and pbSrc by 4.
  612. for (int cbSrc = 4; cbSrc; --cbSrc) {
  613. if (iBitdex > 7) {
  614. // skip past that code-bits byte:
  615. ++qbDest;
  616. iBitdex = 0;
  617. }
  618. *qbDest++ = *pbSrc++;
  619. ++iBitdex;
  620. }
  621. }
  622. }
  623. /***************************************************************************
  624. *
  625. - Name: FDiskBackpatchZeck
  626. -
  627. * Purpose:
  628. * Backpatches a zeck compressed file with longwords. Used to update the
  629. * topic size and VA next & prev ptrs in several structures. Special
  630. * magic is performed to deal with code-bytes which are within the
  631. * zeck-compressed image.
  632. *
  633. * Arguments:
  634. * hf - Handle to filesystem file to backpatch (hfTopic)
  635. * fcl - Beginning of structure to backpatch.
  636. * ulOffset - offset into structure of long to backpatch (relative to
  637. * fcl).
  638. * iBitdex - special bitdex value giving the backwards offset of zeck
  639. * code byte.
  640. *
  641. * Returns: FALSE on error, TRUE otherwise.
  642. *
  643. ************************************************************************/
  644. void STDCALL FDiskBackpatchZeck(HF hf, DWORD fcl, DWORD ulOffset,
  645. int iBitdex, DWORD value)
  646. {
  647. DWORD fclT;
  648. fcl += ulOffset;
  649. fclT = LSeekHf(hf, 0, SEEK_CUR);
  650. if (iBitdex == (WORD) BITDEX_NONE) { // if no compression:
  651. LSeekHf(hf, fcl, SEEK_SET);
  652. LcbWriteHf(hf, &value, sizeof(DWORD));
  653. }
  654. else {
  655. PBYTE pbSrc = (PBYTE) &value;
  656. fcl += ulOffset / 8;
  657. iBitdex += (UINT) (ulOffset % 8);
  658. if (iBitdex > 7) { // check for bitdex rollover.
  659. fcl += 1;
  660. iBitdex = iBitdex - 8;
  661. ASSERT(iBitdex < 8);
  662. }
  663. LSeekHf(hf, fcl, SEEK_SET);
  664. // insert the backpatch:
  665. // REVIEW: if iBitdex < 4, we should be able to simply write
  666. // out pbSrc as a single call
  667. for (int cbSrc = 4; cbSrc; --cbSrc) {
  668. if (iBitdex > 7) {
  669. // skip past that code-bits byte:
  670. LSeekHf(hf, 1, SEEK_CUR);
  671. iBitdex = 0;
  672. }
  673. LcbWriteHf(hf, pbSrc, 1);
  674. ++pbSrc;
  675. ++iBitdex;
  676. }
  677. }
  678. LSeekHf(hf, fclT, SEEK_SET);
  679. }