Leaked source code of windows server 2003
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.

2726 lines
106 KiB

  1. #include "precomp.h"
  2. //
  3. // BCD.CPP
  4. // Bitmap Compression-Decompression
  5. //
  6. // Copyright(c) Microsoft 1997-
  7. //
  8. #define MLZ_FILE_ZONE ZONE_ORDER
  9. //
  10. // Introduction
  11. //
  12. // These functions take a bitmap and encode it according to the codes
  13. // defined in bcd.h. Although there are some complexities in the
  14. // encoding (particularly with the "sliding palette" encoding for
  15. // compressing 8 bit down to 4 bit) the encodings should be self
  16. // explanatory. bcd describes some nuances of the encoding scheme.
  17. //
  18. // The important thing to note is that, when used in conjunction with a
  19. // dictionary based compression scheme the objective of this function is
  20. // not to minimize the output but to "prime" it such that the GDC can
  21. // perform faster and more effectively on the data.
  22. //
  23. // Specifically we must NOT encode short runs in the data, even though we
  24. // know that they reduce the output from this stage, as they will
  25. // invariably reduce the efficiency of the GDC compression by a greater
  26. // factor! The break even point seems to be about a 5/6 byte run. To
  27. // illustrate this, consider the following run
  28. // xxxxyyyyyxxxyyyxxxxxyyyyyyxxxyyyxxxxyyy We would encode this as
  29. // 4x5y3x3y5x5y3x3y4x3y The compression factor is only *2 and yet the
  30. // output data is now much more random - the tokenized look of the input
  31. // has been lost.
  32. //
  33. // Encodings that are not context independent are particularly bad. A FG
  34. // run in one position may become a SET+FG run in another position, thus
  35. // "randomizing" the data.
  36. //
  37. // Bottom line is that all of the apparently arbitrary numbers below have
  38. // been carefully tuned to prep the data for input to GDC. Screwing them
  39. // down does increase the compression of this stage in some cases by as
  40. // much as 20%, but loses about 20% post GDC. Frustrating! Be warned.
  41. //
  42. //
  43. //
  44. // BCD_ShareStarting()
  45. // Creates resources needed for bitmap compression/decompression
  46. //
  47. BOOL ASShare::BCD_ShareStarting(void)
  48. {
  49. BOOL rc = FALSE;
  50. DebugEntry(ASShare::BCD_ShareStarting);
  51. // Allocate BCD scratch buffers
  52. m_abNormal = new BYTE[BCD_NORMALSIZE];
  53. if (!m_abNormal)
  54. {
  55. ERROR_OUT(("BCD_ShareStarting: failed to alloc m_abNormal"));
  56. DC_QUIT;
  57. }
  58. m_abXor = new BYTE[BCD_XORSIZE];
  59. if (!m_abXor)
  60. {
  61. ERROR_OUT(("BCD_ShareStarting: failed to alloc m_abXor"));
  62. DC_QUIT;
  63. }
  64. m_amatch = new MATCH[BCD_MATCHCOUNT];
  65. if (!m_amatch)
  66. {
  67. ERROR_OUT(("BCD_ShareStarting: failed to alloc m_amatch"));
  68. DC_QUIT;
  69. }
  70. rc = TRUE;
  71. DC_EXIT_POINT:
  72. DebugExitBOOL(ASShare::BCD_ShareStarting, rc);
  73. return(rc);
  74. }
  75. //
  76. // BCD_ShareEnded()
  77. //
  78. void ASShare::BCD_ShareEnded(void)
  79. {
  80. DebugEntry(ASShare::BCD_ShareEnded);
  81. //
  82. // Free the BCD scratch buffers
  83. //
  84. if (m_amatch)
  85. {
  86. delete[] m_amatch;
  87. m_amatch = NULL;
  88. }
  89. if (m_abXor)
  90. {
  91. delete[] m_abXor;
  92. m_abXor = NULL;
  93. }
  94. if (m_abNormal)
  95. {
  96. delete[] m_abNormal;
  97. m_abNormal = NULL;
  98. }
  99. DebugExitVOID(ASShare::BCD_ShareEnded);
  100. }
  101. //
  102. // BC_CompressBitmap(..)
  103. //
  104. BOOL ASShare::BC_CompressBitmap
  105. (
  106. LPBYTE pSrcBitmap,
  107. LPBYTE pDstBuffer,
  108. LPUINT pDstBufferSize,
  109. UINT bitmapWidth,
  110. UINT bitmapHeight,
  111. UINT cBpp,
  112. LPBOOL pLossy
  113. )
  114. {
  115. BOOL fCompressedData = FALSE;
  116. UINT cbScanWidth;
  117. PCD_HEADER pCompDataHeader;
  118. LPBYTE pCompData;
  119. UINT cbUncompressedDataSize;
  120. UINT cbFreeDstBytes;
  121. UINT cbCompFirstRowSize;
  122. UINT cbCompMainBodySize;
  123. DebugEntry(ASShare::BC_CompressBitmap);
  124. //
  125. // We support 4 and 8 bpp only
  126. //
  127. if ((cBpp != 4) && (cBpp != 8))
  128. {
  129. TRACE_OUT(("BC_CompressBitmap: No compression at %d bpp", cBpp));
  130. DC_QUIT;
  131. }
  132. //
  133. // If we don't have scratch buffers, can't do it either
  134. // But for now, we just won't enter into a share if we can't allocate
  135. // themm.
  136. //
  137. ASSERT(m_abNormal);
  138. ASSERT(m_abXor);
  139. ASSERT(m_amatch);
  140. cbScanWidth = BYTES_IN_SCANLINE(bitmapWidth, cBpp);
  141. //
  142. // Take a local copy of the destination buffer size.
  143. //
  144. cbFreeDstBytes = *pDstBufferSize;
  145. //
  146. // Calculate the size of the uncompressed src data.
  147. //
  148. cbUncompressedDataSize = cbScanWidth * bitmapHeight;
  149. //
  150. // Check that the size of the uncompressed data is less than our max.
  151. //
  152. ASSERT(cbUncompressedDataSize < TSHR_MAX_SEND_PKT);
  153. //
  154. // We write a compressed data header at the start of the dst buffer.
  155. // Reserve space for it now, and fill in the size of the uncompressed
  156. // data.
  157. //
  158. if (sizeof(CD_HEADER) >= cbFreeDstBytes)
  159. {
  160. WARNING_OUT(("BC_CompressBitmap: Dest buffer too small: %d", cbFreeDstBytes));
  161. DC_QUIT;
  162. }
  163. pCompDataHeader = (PCD_HEADER)pDstBuffer;
  164. pCompDataHeader->cbUncompressedSize = (TSHR_UINT16)cbUncompressedDataSize;
  165. pCompData = ((LPBYTE)pCompDataHeader) + sizeof(CD_HEADER);
  166. cbFreeDstBytes -= sizeof(CD_HEADER);
  167. //
  168. // Compress the bitmap data.
  169. // We just pass the complete image into the compression function.
  170. // The header size in the packet is set to 0 and the whole thing
  171. // flows as the main body
  172. //
  173. cbCompFirstRowSize = 0; // lonchanc: a must for V2
  174. cbCompMainBodySize = CompressV2Int(pSrcBitmap, pCompData,
  175. bitmapWidth*bitmapHeight, cBpp, cbScanWidth, cbFreeDstBytes,
  176. pLossy, m_abNormal, m_abXor, m_amatch);
  177. if (cbCompMainBodySize == 0)
  178. {
  179. WARNING_OUT(("BC_CompressBitmap: Compression failed"));
  180. DC_QUIT;
  181. }
  182. //
  183. // Fill in the compressed data header.
  184. //
  185. pCompDataHeader->cbCompFirstRowSize = (TSHR_UINT16)cbCompFirstRowSize;
  186. pCompDataHeader->cbCompMainBodySize = (TSHR_UINT16)cbCompMainBodySize;
  187. pCompDataHeader->cbScanWidth = (TSHR_UINT16)cbScanWidth;
  188. ASSERT(IsV2CompressedDataHeader(pCompDataHeader));
  189. //
  190. // Write back the new (compressed) packet size.
  191. //
  192. *pDstBufferSize = sizeof(CD_HEADER) + cbCompFirstRowSize + cbCompMainBodySize;
  193. TRACE_OUT(("Bitmap Compressed %u bytes to %u",
  194. cbUncompressedDataSize, *pDstBufferSize));
  195. fCompressedData = TRUE;
  196. DC_EXIT_POINT:
  197. DebugExitBOOL(ASShare::BC_CompressBitmap, fCompressedData);
  198. return(fCompressedData);
  199. }
  200. //
  201. // BD_DecompressBitmap(..)
  202. //
  203. BOOL ASShare::BD_DecompressBitmap
  204. (
  205. LPBYTE pCompressedData,
  206. LPBYTE pDstBitmap,
  207. UINT cbSrcData,
  208. UINT bitmapWidth,
  209. UINT bitmapHeight,
  210. UINT cBpp
  211. )
  212. {
  213. BOOL fDecompressedData = FALSE;
  214. PCD_HEADER pCompDataHeader;
  215. LPBYTE pCompDataFirstRow;
  216. LPBYTE pCompDataMainBody;
  217. UINT decompSize;
  218. DebugEntry(ASShare::BD_DecompressBitmap);
  219. //
  220. // We currently support 4 and 8 bpp bitmaps only
  221. //
  222. if ((cBpp != 4) && (cBpp != 8))
  223. {
  224. ERROR_OUT(("BD_DecompressBitmap: Unsupported bpp %d", cBpp));
  225. DC_QUIT;
  226. }
  227. //
  228. // Work out the location in the source data of each component.
  229. //
  230. pCompDataHeader = (PCD_HEADER)pCompressedData;
  231. pCompDataFirstRow = (LPBYTE)pCompDataHeader + sizeof(CD_HEADER);
  232. pCompDataMainBody = pCompDataFirstRow +
  233. pCompDataHeader->cbCompFirstRowSize;
  234. ASSERT(IsV2CompressedDataHeader(pCompDataHeader));
  235. TRACE_OUT(( "FirstRowSize(%u) MainBodySize(%u) ScanWidth(%u)",
  236. pCompDataHeader->cbCompFirstRowSize,
  237. pCompDataHeader->cbCompMainBodySize,
  238. pCompDataHeader->cbScanWidth ));
  239. //
  240. // Check that the supplied data size matches our expectations.
  241. //
  242. if (cbSrcData != sizeof(CD_HEADER) +
  243. pCompDataHeader->cbCompFirstRowSize +
  244. pCompDataHeader->cbCompMainBodySize )
  245. {
  246. ERROR_OUT(("BD_DecompressBitmap: Supplied packet size %u does not match bitmap header",
  247. cbSrcData));
  248. DC_QUIT;
  249. }
  250. //
  251. // As with compression, the V2 decompression function just takes
  252. // the whole image for decompression.
  253. // THE ABSENCE OF A FIRST LINE COUNT DOES, IN FACT, INDICATE TO US
  254. // THAT THIS IS A V2 COMPRESSED BITMAP.
  255. //
  256. if (pCompDataHeader->cbCompFirstRowSize != 0)
  257. {
  258. ERROR_OUT(("BD_DecompressBitmap: Bogus header data"));
  259. }
  260. else
  261. {
  262. ASSERT(m_abXor);
  263. decompSize = DecompressV2Int(pCompDataFirstRow, pDstBitmap,
  264. pCompDataHeader->cbCompMainBodySize, cBpp,
  265. pCompDataHeader->cbScanWidth, m_abXor);
  266. TRACE_OUT(("Bitmap Exploded %u bytes from %u", decompSize, cbSrcData));
  267. fDecompressedData = TRUE;
  268. }
  269. DC_EXIT_POINT:
  270. DebugExitBOOL(ASShare::BD_DecompressBitmap, fDecompressedData);
  271. return(fDecompressedData);
  272. }
  273. //
  274. //
  275. // Create a second copy of the source, which consists of all lines XORed,
  276. // if there is a rowDelta specified
  277. //
  278. // Scan both the non-xored and the xored buffers for matches
  279. //
  280. // A best matches are built up in an array which contains an index to the
  281. // match type, together with the match type. Non repetetive sequences are
  282. // stored in this array as color image strings.
  283. //
  284. //
  285. //
  286. // The following constant controls the threshold at which we decide that
  287. // a lossy compress is a pointless overhead. For low bandwidth connections
  288. // DC-Share will always initially request a lossy compress to get some
  289. // data out quickly. If we find that the percentage of COLOR_IMAGE data
  290. // is below this threshold then we turn off lossy compression for this
  291. // bitmap, redo the analysis, perform non-lossy compression and return
  292. // an indication to the caller that the compression was non-lossy.
  293. //
  294. #define LOSSY_THRESHOLD 75
  295. //
  296. // The following functions have been carefully coded to ensure that the
  297. // 16 bit compiler can minimize its switching of segment registers.
  298. // However, this will not impair its performance on 32 bit systems.
  299. //
  300. //
  301. // Utility macros for encoding orders
  302. //
  303. //
  304. // Encode a combined order and set fg color
  305. //
  306. #define ENCODE_SET_ORDER_MEGA(buffer, \
  307. order_code, \
  308. length, \
  309. mega_order_code, \
  310. DEF_LENGTH_ORDER, \
  311. DEF_LENGTH_LONG_ORDER) \
  312. if (length <= DEF_LENGTH_ORDER) \
  313. { \
  314. *buffer++ = (BYTE)((BYTE)order_code | (BYTE)length); \
  315. } \
  316. else \
  317. { \
  318. if (length <= DEF_LENGTH_LONG_ORDER) \
  319. { \
  320. *buffer++ = (BYTE)order_code; \
  321. *buffer++ = (BYTE)(length-DEF_LENGTH_ORDER-1); \
  322. } \
  323. else \
  324. { \
  325. *buffer++ = (BYTE)mega_order_code; \
  326. INSERT_TSHR_UINT16_UA( buffer, (TSHR_UINT16)length); \
  327. buffer += 2; \
  328. } \
  329. } \
  330. *buffer++ = fgChar;
  331. //
  332. // Encode a combined order and set fg color for a special FGBG image
  333. //
  334. #define ENCODE_SET_ORDER_MEGA_FGBG(buffer, \
  335. order_code, \
  336. length, \
  337. mega_order_code, \
  338. DEF_LENGTH_ORDER, \
  339. DEF_LENGTH_LONG_ORDER) \
  340. if (((length & 0x0007) == 0) && \
  341. (length <= DEF_LENGTH_ORDER)) \
  342. { \
  343. *buffer++ = (BYTE)((BYTE)order_code | (BYTE)(length/8));\
  344. } \
  345. else \
  346. { \
  347. if (length <= DEF_LENGTH_LONG_ORDER) \
  348. { \
  349. *buffer++ = (BYTE)order_code; \
  350. *buffer++ = (BYTE)(length-1); \
  351. } \
  352. else \
  353. { \
  354. *buffer++ = (BYTE)mega_order_code; \
  355. INSERT_TSHR_UINT16_UA( buffer, (TSHR_UINT16)length); \
  356. buffer += 2; \
  357. } \
  358. } \
  359. *buffer++ = fgChar;
  360. //
  361. // Encode an order for a standard run
  362. //
  363. #define ENCODE_ORDER_MEGA(buffer, \
  364. order_code, \
  365. length, \
  366. mega_order_code, \
  367. DEF_LENGTH_ORDER, \
  368. DEF_LENGTH_LONG_ORDER) \
  369. if (length <= DEF_LENGTH_ORDER) \
  370. { \
  371. *buffer++ = (BYTE)((BYTE)order_code | (BYTE)length); \
  372. } \
  373. else \
  374. { \
  375. if (length <= DEF_LENGTH_LONG_ORDER) \
  376. { \
  377. *buffer++ = (BYTE)order_code; \
  378. *buffer++ = (BYTE)(length-DEF_LENGTH_ORDER-1); \
  379. } \
  380. else \
  381. { \
  382. *buffer++ = (BYTE)mega_order_code; \
  383. INSERT_TSHR_UINT16_UA( buffer, (TSHR_UINT16)length); \
  384. buffer += 2; \
  385. } \
  386. }
  387. //
  388. // Encode a special FGBG image
  389. //
  390. #define ENCODE_ORDER_MEGA_FGBG(buffer, \
  391. order_code, \
  392. length, \
  393. mega_order_code, \
  394. DEF_LENGTH_ORDER, \
  395. DEF_LENGTH_LONG_ORDER) \
  396. if (((length & 0x0007) == 0) && \
  397. (length <= DEF_LENGTH_ORDER)) \
  398. { \
  399. *buffer++ = (BYTE)((BYTE)order_code | (BYTE)(length/8));\
  400. } \
  401. else \
  402. { \
  403. if (length <= DEF_LENGTH_LONG_ORDER) \
  404. { \
  405. *buffer++ = (BYTE)order_code; \
  406. *buffer++ = (BYTE)(length-1); \
  407. } \
  408. else \
  409. { \
  410. *buffer++ = (BYTE)mega_order_code; \
  411. INSERT_TSHR_UINT16_UA( buffer, (TSHR_UINT16)length); \
  412. buffer += 2; \
  413. } \
  414. }
  415. //
  416. // Macros to extract the length from order codes
  417. //
  418. #define EXTRACT_LENGTH(buffer, length) \
  419. length = *buffer++ & MAX_LENGTH_ORDER; \
  420. if (length == 0) \
  421. { \
  422. length = *buffer++ + MAX_LENGTH_ORDER + 1; \
  423. }
  424. #define EXTRACT_LENGTH_LITE(buffer, length) \
  425. length = *buffer++ & MAX_LENGTH_ORDER_LITE; \
  426. if (length == 0) \
  427. { \
  428. length = *buffer++ + MAX_LENGTH_ORDER_LITE + 1; \
  429. }
  430. #define EXTRACT_LENGTH_FGBG(buffer, length) \
  431. length = *buffer++ & MAX_LENGTH_ORDER; \
  432. if (length == 0) \
  433. { \
  434. length = *buffer++ + 1; \
  435. } \
  436. else \
  437. { \
  438. length = length << 3; \
  439. }
  440. #define EXTRACT_LENGTH_FGBG_LITE(buffer, length) \
  441. length = *buffer++ & MAX_LENGTH_ORDER_LITE; \
  442. if (length == 0) \
  443. { \
  444. length = *buffer++ + 1; \
  445. } \
  446. else \
  447. { \
  448. length = length << 3; \
  449. }
  450. //
  451. // RunSingle
  452. //
  453. // Determine the length of the current run
  454. //
  455. // RunSingle may only be called if the buffer has at least four
  456. // consecutive identical bytes from the start position
  457. //
  458. // For 16 bit processing there are two versions of this macro. For 32
  459. // bit the nulling of NEAR/FAR will make them the same.
  460. //
  461. #define RUNSINGLE_XOR(buffer, length, result) \
  462. { \
  463. BYTE NEAR *buf = buffer+4; \
  464. BYTE NEAR *endbuf = buffer+length-4; \
  465. while ((buf < endbuf) && \
  466. (EXTRACT_TSHR_UINT32_UA(buf) == EXTRACT_TSHR_UINT32_UA(buf-4))) \
  467. { \
  468. buf += 4; \
  469. } \
  470. endbuf += 4; \
  471. while(buf < endbuf && (*buf == *(buf-1))) \
  472. { \
  473. buf++; \
  474. } \
  475. result = (DWORD)(buf - (buffer)); \
  476. }
  477. #define RUNSINGLE_NRM(buffer, length, result) \
  478. { \
  479. BYTE FAR *buf = buffer+4; \
  480. BYTE FAR *endbuf = buffer+length-4; \
  481. while ((buf < endbuf) && \
  482. (EXTRACT_TSHR_UINT32_UA(buf) == EXTRACT_TSHR_UINT32_UA(buf-4))) \
  483. { \
  484. buf += 4; \
  485. } \
  486. endbuf += 4; \
  487. while(buf < endbuf && (*buf == *(buf-1))) \
  488. { \
  489. buf++; \
  490. } \
  491. result = (DWORD)(buf - (buffer)); \
  492. }
  493. //
  494. // RunDouble
  495. //
  496. // Determine the length of the current run of paired bytes
  497. //
  498. #define RunDouble(buffer, length, result) \
  499. { \
  500. int len = ((int)length); \
  501. BYTE FAR *buf = buffer; \
  502. BYTE testchar1 = *buf; \
  503. BYTE testchar2 = *(buf+1); \
  504. result = 0; \
  505. while(len > 1) \
  506. { \
  507. if (*buf++ != testchar1) \
  508. { \
  509. break; \
  510. } \
  511. if (*buf++ != testchar2) \
  512. { \
  513. break; \
  514. } \
  515. result += 2; \
  516. len -= 2; \
  517. } \
  518. }
  519. //
  520. // RUNFGBG
  521. //
  522. // Determine the length of the run of bytes that consist
  523. // only of black or a single FG color
  524. // We exit the loop when
  525. // - the next character is not a fg or bg color
  526. // - we hit a run of 24 of the FG or BG color
  527. // 24 may seem excessive, but note the following sample compression:
  528. // 12 16 20 24 28
  529. // Pre GDC 3845 3756 3712 3794 3822
  530. // Post GDC 2401 2313 2286 2189 2209
  531. //
  532. //
  533. #define RUNFGBG(buffer, length, result, work) \
  534. { \
  535. BYTE NEAR *buf = buffer; \
  536. BYTE NEAR *endbuf = buffer + length; \
  537. result = 0; \
  538. work = *buf; \
  539. while (TRUE) \
  540. { \
  541. buf++; \
  542. result++; \
  543. if (buf >= endbuf) \
  544. { \
  545. break; \
  546. } \
  547. \
  548. if ((*buf != work) && (*buf != 0)) \
  549. { \
  550. break; \
  551. } \
  552. \
  553. if ((result & 0x0007) == 0) \
  554. { \
  555. if ((*buf == *(buf+1)) && \
  556. (EXTRACT_TSHR_UINT16_UA(buf) == \
  557. EXTRACT_TSHR_UINT16_UA(buf+ 2)) && \
  558. (EXTRACT_TSHR_UINT32_UA(buf) == \
  559. EXTRACT_TSHR_UINT32_UA(buf+ 4)) && \
  560. (EXTRACT_TSHR_UINT32_UA(buf) == \
  561. EXTRACT_TSHR_UINT32_UA(buf+ 8)) && \
  562. (EXTRACT_TSHR_UINT32_UA(buf) == \
  563. EXTRACT_TSHR_UINT32_UA(buf+12)) && \
  564. (EXTRACT_TSHR_UINT32_UA(buf) == \
  565. EXTRACT_TSHR_UINT32_UA(buf+16)) && \
  566. (EXTRACT_TSHR_UINT32_UA(buf) == \
  567. EXTRACT_TSHR_UINT32_UA(buf+20)) ) \
  568. { \
  569. break; \
  570. } \
  571. } \
  572. } \
  573. }
  574. //
  575. // Determine whether a run is better than any previous run
  576. // For efficiency we take any run of 32 pels or more without looking
  577. // further.
  578. //
  579. #define CHECK_BEST_RUN(run_type, run_length, bestrun_length, bestrun_type) \
  580. if (run_length > bestrun_length) \
  581. { \
  582. bestrun_length = run_length; \
  583. bestrun_type = run_type; \
  584. if (bestrun_length >= 32) \
  585. { \
  586. break; \
  587. } \
  588. }
  589. //
  590. // SETFGCHAR
  591. //
  592. // Set up a new value in fgChar and recalculate the shift
  593. //
  594. #define CHECK_WORK(workchar)
  595. #define SETFGCHAR(newchar, curchar, curshift) \
  596. curchar = newchar; \
  597. { \
  598. BYTE workchar = curchar; \
  599. curshift = 0; \
  600. CHECK_WORK(workchar); \
  601. while ((workchar & 0x01) == 0) \
  602. { \
  603. curshift++; \
  604. workchar = (BYTE)(workchar>>1); \
  605. } \
  606. }
  607. //
  608. // Macro to store an FGBG image
  609. //
  610. #define STORE_FGBG(xorbyte, fgbgChar, fgChar, bits) \
  611. { \
  612. UINT numbits = bits; \
  613. if (fgbgChar & 0x01) \
  614. { \
  615. *destbuf++ = (BYTE)(xorbyte ^ fgChar); \
  616. } \
  617. else \
  618. { \
  619. *destbuf++ = xorbyte; \
  620. } \
  621. if (--numbits > 0) \
  622. { \
  623. if (fgbgChar & 0x02) \
  624. { \
  625. *destbuf++ = (BYTE)(xorbyte ^ fgChar); \
  626. } \
  627. else \
  628. { \
  629. *destbuf++ = xorbyte; \
  630. } \
  631. if (--numbits > 0) \
  632. { \
  633. if (fgbgChar & 0x04) \
  634. { \
  635. *destbuf++ = (BYTE)(xorbyte ^ fgChar); \
  636. } \
  637. else \
  638. { \
  639. *destbuf++ = xorbyte; \
  640. } \
  641. if (--numbits > 0) \
  642. { \
  643. if (fgbgChar & 0x08) \
  644. { \
  645. *destbuf++ = (BYTE)(xorbyte ^ fgChar); \
  646. } \
  647. else \
  648. { \
  649. *destbuf++ = xorbyte; \
  650. } \
  651. if (--numbits > 0) \
  652. { \
  653. if (fgbgChar & 0x10) \
  654. { \
  655. *destbuf++ = (BYTE)(xorbyte ^ fgChar); \
  656. } \
  657. else \
  658. { \
  659. *destbuf++ = xorbyte; \
  660. } \
  661. if (--numbits > 0) \
  662. { \
  663. if (fgbgChar & 0x20) \
  664. { \
  665. *destbuf++ = (BYTE)(xorbyte ^ fgChar); \
  666. } \
  667. else \
  668. { \
  669. *destbuf++ = xorbyte; \
  670. } \
  671. if (--numbits > 0) \
  672. { \
  673. if (fgbgChar & 0x40) \
  674. { \
  675. *destbuf++ = (BYTE)(xorbyte ^ fgChar); \
  676. } \
  677. else \
  678. { \
  679. *destbuf++ = xorbyte; \
  680. } \
  681. if (--numbits > 0) \
  682. { \
  683. if (fgbgChar & 0x80) \
  684. { \
  685. *destbuf++ = (BYTE)(xorbyte ^ fgChar); \
  686. } \
  687. else \
  688. { \
  689. *destbuf++ = xorbyte; \
  690. } \
  691. } \
  692. } \
  693. } \
  694. } \
  695. } \
  696. } \
  697. } \
  698. }
  699. //
  700. // ENCODEFGBG
  701. //
  702. // Encode 8 bytes of FG and black into a one byte bitmap representation
  703. //
  704. // The FgChar will always be non-zero, and therefore must have at least one
  705. // bit set.
  706. //
  707. // We arrange that all bytes have this bit in their lowest position
  708. //
  709. // The zero pels will still have a 0 in the lowest bit.
  710. //
  711. // Getting the result is a 4 stage process
  712. //
  713. // 1) Get the wanted bits into bit 0 of each byte
  714. //
  715. // <***************work1*****************>
  716. // 31 0
  717. // 0000 000d 0000 000c 0000 000b 0000 000a
  718. // ^ ^ ^ ^
  719. // <***************work2*****************>
  720. // 31 0
  721. // 0000 000h 0000 000g 0000 000f 0000 000e
  722. // ^ ^ ^ ^
  723. //
  724. // a..h = bits that we want to output
  725. //
  726. // We just need to collect the indicated bits and squash them into a single
  727. // byte.
  728. //
  729. // 2) Compress down to 32 bits
  730. //
  731. // <***************work1*****************>
  732. // 31 0
  733. // 000h 000d 000g 000c 000f 000b 000e 000a
  734. // ^ ^ ^ ^ ^ ^ ^ ^
  735. //
  736. // 3) Compress down to 16 bits
  737. //
  738. // <******work*******>
  739. // 15 0
  740. // 0h0f 0d0b 0g0e 0c0a
  741. // ^ ^ ^ ^
  742. //
  743. // 4) Compress down to 8 bits
  744. //
  745. // hgfedcba
  746. //
  747. #define ENCODEFGBG(result) \
  748. { \
  749. UINT work1; \
  750. UINT work2; \
  751. UINT work; \
  752. \
  753. work1 = (((UINT)(xorbuf[srcOffset]) ) | \
  754. ((UINT)(xorbuf[srcOffset+1]) << 8) | \
  755. ((UINT)(xorbuf[srcOffset+2]) << 16) | \
  756. ((UINT)(xorbuf[srcOffset+3]) << 24)); \
  757. work2 = (((UINT)(xorbuf[srcOffset+4]) ) | \
  758. ((UINT)(xorbuf[srcOffset+5]) << 8) | \
  759. ((UINT)(xorbuf[srcOffset+6]) << 16) | \
  760. ((UINT)(xorbuf[srcOffset+7]) << 24)); \
  761. \
  762. work1 = (work1 >> fgShift) & 0x01010101; \
  763. work2 = (work2 >> fgShift) & 0x01010101; \
  764. \
  765. work1 = (work2 << 4) | work1; \
  766. \
  767. work = work1 | (work1 >> 14); \
  768. \
  769. result = ((BYTE)(((BYTE)(work>>7)) | ((BYTE)work))); \
  770. }
  771. //
  772. // Unpack4bpp
  773. //
  774. // Convert a 4bpp bitmap into an 8bpp one
  775. //
  776. void Unpack4bpp(LPBYTE destbuf,
  777. LPBYTE srcbuf,
  778. UINT srclen)
  779. {
  780. do
  781. {
  782. *destbuf++ = (BYTE)((*srcbuf) >> 4);
  783. *destbuf++ = (BYTE)((*srcbuf) & 0x0F);
  784. srcbuf++;
  785. } while (--srclen > 0);
  786. }
  787. //
  788. // Pack4bpp
  789. //
  790. // Convert an 8bpp bitmap back to 4bpp
  791. //
  792. void Pack4bpp(LPBYTE destbuf,
  793. LPBYTE srcbuf,
  794. UINT srclen)
  795. {
  796. BYTE work1, work2;
  797. DebugEntry(Pack4bpp);
  798. while (srclen > 1)
  799. {
  800. work1 = (BYTE)(*srcbuf++ << 4);
  801. work2 = (BYTE)(*srcbuf++ & 0x0F);
  802. *destbuf++ = (BYTE)(work1 | work2);
  803. srclen -= 2;
  804. }
  805. if (srclen > 0)
  806. {
  807. *destbuf++ = (BYTE)(*srcbuf++ << 4);
  808. }
  809. DebugExitVOID(Pack4bpp);
  810. }
  811. //
  812. // XORBuffer
  813. //
  814. // Create an XOR image of the input bitmap
  815. //
  816. // Note: This function assumes that rowDelta is always a multiple of 4, and
  817. // that destbuf and srcbuf start on a 4 byte boundary. It does not deal
  818. // with unaligned accesses if this is not true.
  819. //
  820. void XORBuffer(BYTE NEAR *destbuf,
  821. BYTE FAR *srcbuf,
  822. UINT srclen,
  823. int rowDelta)
  824. {
  825. UINT NEAR *dwdest = (UINT NEAR *)destbuf;
  826. DebugEntry(XORBuffer);
  827. ASSERT((rowDelta % 4 == 0));
  828. ASSERT((((UINT_PTR)destbuf) % 4 == 0));
  829. ASSERT((((UINT_PTR)srcbuf) % 4 == 0));
  830. while (srclen > 8)
  831. {
  832. *dwdest++ = *((LPUINT)srcbuf) ^ *((LPUINT)(srcbuf+rowDelta));
  833. srclen -= 4;
  834. srcbuf += 4;
  835. *dwdest++ = *((LPUINT)srcbuf) ^ *((LPUINT)(srcbuf+rowDelta));
  836. srclen -= 4;
  837. srcbuf += 4;
  838. }
  839. if (srclen)
  840. {
  841. destbuf = (BYTE NEAR *)dwdest;
  842. while(srclen)
  843. {
  844. *destbuf++ = (BYTE)(*srcbuf++ ^ *(srcbuf+rowDelta));
  845. srclen--;
  846. }
  847. }
  848. DebugExitVOID(XORBuffer);
  849. }
  850. //
  851. // CompressV2Int
  852. //
  853. // Internal compresssion function
  854. //
  855. // The work buffer addresses are moved onto the stack, thus eliminating any
  856. // need to use DS to address the default data segment. This allows the
  857. // compiler to perform more general optimizations.
  858. //
  859. UINT CompressV2Int(LPBYTE pSrc,
  860. LPBYTE pDst,
  861. UINT numPels,
  862. UINT bpp,
  863. UINT rowDelta,
  864. UINT dstBufferSize,
  865. LPBOOL pLossy,
  866. LPBYTE nrmbuf,
  867. LPBYTE xorbuf,
  868. MATCH FAR *match)
  869. {
  870. int i;
  871. UINT srcOffset;
  872. UINT matchindex;
  873. UINT bestRunLength;
  874. UINT nextRunLength;
  875. UINT runLength;
  876. UINT bestFGRunLength;
  877. UINT checkFGBGLength;
  878. UINT scanCount;
  879. BOOL firstLine;
  880. UINT saveNumPels;
  881. BOOL saveLossy;
  882. BOOL lossy;
  883. BYTE bestRunType = 0;
  884. LPBYTE destbuf = pDst;
  885. BYTE fgChar = 0xFF;
  886. BYTE fgCharWork = 0xFF;
  887. BYTE fgShift = 0;
  888. BOOL lossyStarted = FALSE;
  889. BOOL inColorRun = FALSE;
  890. UINT compressedLength = 0;
  891. DebugEntry(CompressV2Int);
  892. //
  893. // Validate the line length
  894. //
  895. if ((numPels < rowDelta) ||
  896. (rowDelta & 0x0003) ||
  897. (numPels & 0x0003))
  898. {
  899. WARNING_OUT(( "Lines must be a multiple of 4 pels"));
  900. DC_QUIT;
  901. }
  902. //
  903. // First create the character and XOR buffers
  904. //
  905. if (bpp == 4)
  906. {
  907. Unpack4bpp(nrmbuf, pSrc, numPels/2);
  908. }
  909. else
  910. {
  911. nrmbuf = pSrc;
  912. }
  913. //
  914. // Set up the first portion of the XORBUF to contain the source buffer
  915. //
  916. memcpy(xorbuf, nrmbuf, rowDelta);
  917. //
  918. // Calculate the rest of the XOR buffer
  919. //
  920. XORBuffer( xorbuf+rowDelta,
  921. nrmbuf+rowDelta,
  922. numPels-rowDelta,
  923. -(int)rowDelta);
  924. //
  925. // Loop processing the input
  926. // We perform the loop twice, the first time for the non-xor portion
  927. // of the buffer and the second for the XOR portion
  928. // Note that we start the run at a match index of 2 to avoid having
  929. // to special case the startup condition in some of the match
  930. // merging code
  931. // The first time through is always a non-lossy pass. If we find
  932. // enough incompressible data then we redo the compression in lossy
  933. // mode. To achieve this we set saveLossy = FALSE here and reset it
  934. // following the first scan.
  935. //
  936. saveLossy = FALSE;
  937. RESTART_COMPRESSION_IN_LOSSY_MODE:
  938. srcOffset = 0;
  939. firstLine = TRUE;
  940. match[0].type = 0;
  941. match[1].type = 0;
  942. matchindex = 2;
  943. saveNumPels = numPels;
  944. //
  945. // Until we enter XOR mode we do not allow lossy compression on a
  946. // non-XOR request so set up to process just the first line.
  947. // Also, if the user is requesting a lossy compression then we
  948. // perform an initial full non-lossy pass to see if the request is
  949. // worthwhile.
  950. //
  951. lossy = FALSE;
  952. numPels = rowDelta;
  953. for (scanCount = 0; scanCount < 2; scanCount++)
  954. {
  955. while (srcOffset < numPels)
  956. {
  957. //
  958. // Give up if we are nearing the end of the match array
  959. //
  960. if (matchindex >= BCD_MATCHCOUNT)
  961. {
  962. DC_QUIT;
  963. }
  964. //
  965. // Start a while loop to allow a more structured break when we
  966. // hit the first run type we want to encode (We can't afford
  967. // the overheads of a function call to provide the scope here.)
  968. //
  969. while (TRUE)
  970. {
  971. bestRunLength = 0;
  972. bestFGRunLength = 0;
  973. //
  974. // If we are hitting the end of the buffer then just take
  975. // color characters now - take them one at a time so that
  976. // lossy encoding still works. We will only hit this
  977. // condition if we break out of a run just before the end
  978. // of the buffer, so this should not be too common a
  979. // situation, which is good given that we are encoding the
  980. // final 6 bytes uncompressed.
  981. //
  982. if (srcOffset+6 >= numPels)
  983. {
  984. bestRunType = IMAGE_COLOR;
  985. bestRunLength = 1;
  986. break;
  987. }
  988. //
  989. // First do the scans on the XOR buffer. Look for a
  990. // character run or a BG run. Note that if there is no row
  991. // delta then xorbuf actually points to the normal buffer.
  992. // We must do the test independent of how long the run
  993. // might be because even for a 1 pel BG run our later logic
  994. // requires that we detect it seperately. This code is
  995. // absolute main path so fastpath as much as possible. In
  996. // particular detect short bg runs early and allow
  997. // RunSingle to presuppose at least 4 matching bytes
  998. //
  999. if (xorbuf[srcOffset] == 0x00)
  1000. {
  1001. if (((srcOffset+1) >= numPels) ||
  1002. (xorbuf[srcOffset+1] != 0x00))
  1003. {
  1004. bestRunType = RUN_BG;
  1005. bestRunLength = 1;
  1006. if (!inColorRun)
  1007. {
  1008. break;
  1009. }
  1010. }
  1011. else
  1012. {
  1013. if (((srcOffset+2) >= numPels) ||
  1014. (xorbuf[srcOffset+2] != 0x00))
  1015. {
  1016. bestRunType = RUN_BG;
  1017. bestRunLength = 2;
  1018. if (!inColorRun)
  1019. {
  1020. break;
  1021. }
  1022. }
  1023. else
  1024. {
  1025. if (((srcOffset+3) >= numPels) ||
  1026. (xorbuf[srcOffset+3] != 0x00))
  1027. {
  1028. bestRunType = RUN_BG;
  1029. bestRunLength = 3;
  1030. if (!inColorRun)
  1031. {
  1032. break;
  1033. }
  1034. }
  1035. else
  1036. {
  1037. RUNSINGLE_XOR(xorbuf+srcOffset,
  1038. numPels-srcOffset,
  1039. bestFGRunLength);
  1040. CHECK_BEST_RUN(RUN_BG,
  1041. bestFGRunLength,
  1042. bestRunLength,
  1043. bestRunType);
  1044. if (!inColorRun)
  1045. {
  1046. break;
  1047. }
  1048. }
  1049. }
  1050. }
  1051. }
  1052. else
  1053. {
  1054. //
  1055. // No point in starting if FG run less than 4 bytes so
  1056. // check the first dword as quickly as possible Note
  1057. // that we don't need to check for an end-buffer
  1058. // condition here because our XOR buffer always has
  1059. // some free space at the end and the RUNSINGLE_XOR
  1060. // will break at the correct place
  1061. //
  1062. if ( (xorbuf[srcOffset] == xorbuf[srcOffset+1]) &&
  1063. (xorbuf[srcOffset] == xorbuf[srcOffset+2]) &&
  1064. (xorbuf[srcOffset] == xorbuf[srcOffset+3]) )
  1065. {
  1066. RUNSINGLE_XOR(xorbuf+srcOffset,
  1067. numPels-srcOffset,
  1068. bestFGRunLength);
  1069. //
  1070. // Don't permit a short FG run to prevent a FGBG
  1071. // image from starting up. Only take if >= 5
  1072. //
  1073. if (bestFGRunLength > 5)
  1074. {
  1075. CHECK_BEST_RUN(RUN_FG,
  1076. bestFGRunLength,
  1077. bestRunLength,
  1078. bestRunType);
  1079. }
  1080. }
  1081. }
  1082. //
  1083. // Look for sequences in the non XOR buffer In this case we
  1084. // insist upon a run of at least 6 pels
  1085. //
  1086. if ( (nrmbuf[srcOffset] == nrmbuf[srcOffset + 2]) &&
  1087. (nrmbuf[srcOffset] == nrmbuf[srcOffset + 4]) &&
  1088. (nrmbuf[srcOffset + 1] == nrmbuf[srcOffset + 3]) &&
  1089. (nrmbuf[srcOffset + 1] == nrmbuf[srcOffset + 5]) )
  1090. {
  1091. //
  1092. // Now do the scan on the normal buffer for a character
  1093. // run Don't bother if first line because we will have
  1094. // found it already in the XOR buffer, since we just
  1095. // copy nrmbuf to xorbuf for the first line
  1096. //
  1097. if (*(nrmbuf+srcOffset) == *(nrmbuf+srcOffset+1))
  1098. {
  1099. if (!firstLine)
  1100. {
  1101. RUNSINGLE_NRM(nrmbuf+srcOffset,
  1102. numPels-srcOffset,
  1103. nextRunLength);
  1104. if (nextRunLength > 5)
  1105. {
  1106. CHECK_BEST_RUN(RUN_COLOR,
  1107. nextRunLength,
  1108. bestRunLength,
  1109. bestRunType);
  1110. }
  1111. }
  1112. }
  1113. else
  1114. {
  1115. //
  1116. // Look for a dither on the nrm buffer Dithers are
  1117. // not very efficient for short runs so only take
  1118. // if 8 or longer
  1119. //
  1120. RunDouble(nrmbuf+srcOffset,
  1121. numPels-srcOffset,
  1122. nextRunLength);
  1123. if (nextRunLength > 9)
  1124. {
  1125. CHECK_BEST_RUN(RUN_DITHER,
  1126. nextRunLength,
  1127. bestRunLength,
  1128. bestRunType);
  1129. }
  1130. }
  1131. }
  1132. //
  1133. // If nothing so far then look for a FGBG run (The 6 is
  1134. // carefully tuned!)
  1135. //
  1136. if (bestRunLength < 6)
  1137. {
  1138. //
  1139. // But first look for a single fg bit breaking up a BG
  1140. // run. If so then encode a BG run. Careful of the
  1141. // enforced BG run break across the first line
  1142. // non-XOR/XOR boundary.
  1143. //
  1144. if ((EXTRACT_TSHR_UINT32_UA(xorbuf+srcOffset+1) == 0) &&
  1145. (*(xorbuf+srcOffset) == fgChar) &&
  1146. (match[matchindex-1].type == RUN_BG) &&
  1147. (srcOffset != (TSHR_UINT16)rowDelta))
  1148. {
  1149. RUNSINGLE_XOR(xorbuf+srcOffset+1,
  1150. numPels-srcOffset-1,
  1151. nextRunLength);
  1152. nextRunLength++;
  1153. CHECK_BEST_RUN(RUN_BG_PEL,
  1154. nextRunLength,
  1155. bestRunLength,
  1156. bestRunType);
  1157. }
  1158. else
  1159. {
  1160. //
  1161. // If we have not found a run then look for a FG/BG
  1162. // image. The disruptive effect of a short FGBG
  1163. // run on GDC is such that it is worth preventing
  1164. // one unless we are certain of the benefits.
  1165. // However, if the alternative is a color run then
  1166. // allow a lower value.
  1167. //
  1168. RUNFGBG( xorbuf+srcOffset,
  1169. numPels-srcOffset,
  1170. nextRunLength,
  1171. fgCharWork );
  1172. checkFGBGLength = 48;
  1173. if (fgCharWork == fgChar)
  1174. {
  1175. checkFGBGLength -= 16;
  1176. }
  1177. if ((nextRunLength & 0x0007) == 0)
  1178. {
  1179. checkFGBGLength -= 8;
  1180. }
  1181. if (nextRunLength >= checkFGBGLength)
  1182. {
  1183. CHECK_BEST_RUN(IMAGE_FGBG,
  1184. nextRunLength,
  1185. bestRunLength,
  1186. bestRunType);
  1187. }
  1188. }
  1189. }
  1190. //
  1191. // If nothing useful so far then allow a short run, if any
  1192. // Don't do this if we are accumulating a color run because
  1193. // it will really mess up GDC compression if we allow lots
  1194. // of little runs. Also require that it is a regular short
  1195. // run, rather than one that disturbs the fgChar
  1196. //
  1197. if (!inColorRun)
  1198. {
  1199. if (bestRunLength < 6)
  1200. {
  1201. if ((bestFGRunLength > 4) &&
  1202. (xorbuf[srcOffset] == fgChar))
  1203. {
  1204. if (match[matchindex-1].type == RUN_FG)
  1205. {
  1206. match[matchindex-1].length += (WORD)bestFGRunLength;
  1207. srcOffset += bestFGRunLength;
  1208. continue;
  1209. }
  1210. else
  1211. {
  1212. bestRunLength = bestFGRunLength;
  1213. bestRunType = RUN_FG;
  1214. }
  1215. }
  1216. else
  1217. {
  1218. //
  1219. // If we decided to take a run earlier then
  1220. // allow it now. (May be a short BG run, for
  1221. // example) If nothing so far then take color
  1222. // image)
  1223. //
  1224. if (bestRunLength == 0)
  1225. {
  1226. bestRunType = IMAGE_COLOR;
  1227. bestRunLength = 1;
  1228. }
  1229. }
  1230. }
  1231. }
  1232. else
  1233. {
  1234. //
  1235. // May seem restrictive, but it is important for our
  1236. // lossy compression that a color run is rather
  1237. // "sticky", in particular not broken by random FGBG
  1238. // runs which do appear from time to time.
  1239. //
  1240. if (lossy)
  1241. {
  1242. if ((bestRunLength < 8) ||
  1243. ((bestRunType == IMAGE_FGBG) &&
  1244. (bestRunLength < 16)))
  1245. {
  1246. bestRunType = IMAGE_COLOR;
  1247. bestRunLength = 1;
  1248. }
  1249. }
  1250. else
  1251. {
  1252. if ((bestRunLength < 6) ||
  1253. ((bestRunType != RUN_BG) && (bestRunLength < 8)))
  1254. {
  1255. bestRunType = IMAGE_COLOR;
  1256. bestRunLength = 1;
  1257. }
  1258. }
  1259. }
  1260. break;
  1261. }
  1262. //
  1263. // When we get here we have found the best run. Now check for
  1264. // various amalamation conditions with the previous run type.
  1265. // Note that we may already have done amalgamation of short
  1266. // runs, but we had to do multiple samples for the longer runs
  1267. // so we repeat the checks here
  1268. //
  1269. //
  1270. // If we are encoding a color run then
  1271. // - process it for lossy compression
  1272. // - combine it with an existing run if possible
  1273. //
  1274. if (bestRunType == IMAGE_COLOR)
  1275. {
  1276. //
  1277. // Flag that we are within a color run
  1278. //
  1279. inColorRun = TRUE;
  1280. //
  1281. // If we are doing a lossy compression then process
  1282. // even/odd lines differently
  1283. //
  1284. if (lossy)
  1285. {
  1286. //
  1287. // For even lines duplicate every other character,
  1288. // discarding the original value
  1289. //
  1290. if (((srcOffset/rowDelta)%2) == 0)
  1291. {
  1292. if ((match[matchindex-1].type == IMAGE_COLOR) &&
  1293. (match[matchindex-1].length%2 == 1))
  1294. {
  1295. nrmbuf[srcOffset] = nrmbuf[srcOffset-1];
  1296. //
  1297. // If we are not on the final line of the
  1298. // bitmap then propagate the update down to the
  1299. // next XORed line
  1300. //
  1301. if (numPels-srcOffset > rowDelta)
  1302. {
  1303. xorbuf[srcOffset+rowDelta] =
  1304. (BYTE)(nrmbuf[srcOffset+rowDelta] ^
  1305. nrmbuf[srcOffset]);
  1306. }
  1307. }
  1308. }
  1309. else
  1310. {
  1311. //
  1312. // For odd lines we will just encode nulls which
  1313. // will replicate the previous line. However, if
  1314. // the last run was a BG run then we will
  1315. // inadvertently insert a pel, so if we hit this
  1316. // situation then leave a single color char
  1317. //
  1318. bestRunType = IMAGE_LOSSY_ODD;
  1319. //
  1320. // No need to adjust the buffers for this, except
  1321. // to update the next XOR line to reflect the fact
  1322. // that the decoder will be operating on a
  1323. // replicated line. Therefore we replace the
  1324. // character in the next line of the XOR buffer
  1325. // with the value it would have if the current line
  1326. // was identical with the previous line
  1327. //
  1328. if (numPels-srcOffset > (TSHR_UINT16)rowDelta)
  1329. {
  1330. xorbuf[srcOffset+rowDelta] =
  1331. (BYTE)(nrmbuf[srcOffset+rowDelta] ^
  1332. nrmbuf[srcOffset-rowDelta]);
  1333. }
  1334. }
  1335. }
  1336. //
  1337. // Merge the color run immediately, if possible
  1338. //
  1339. if (match[matchindex-1].type == bestRunType)
  1340. {
  1341. match[matchindex-1].length += (WORD)bestRunLength;
  1342. srcOffset += bestRunLength;
  1343. continue;
  1344. }
  1345. }
  1346. else
  1347. {
  1348. //
  1349. // We are no longer encoding a COLOR_IMAGE of any kind
  1350. //
  1351. inColorRun = FALSE;
  1352. //
  1353. // Keep track of the fg Color The macro that searches for
  1354. // FGBG runs leaves the character in fgCharWork.
  1355. //
  1356. if (bestRunType == RUN_FG)
  1357. {
  1358. fgChar = xorbuf[srcOffset];
  1359. }
  1360. else
  1361. {
  1362. if (bestRunType == IMAGE_FGBG)
  1363. {
  1364. fgChar = fgCharWork;
  1365. }
  1366. }
  1367. }
  1368. //
  1369. // If we can amalgamate the entry then do so without creating a
  1370. // new array entry. We must amalgamate a lossy ODD with a
  1371. // RUN_BG because otherwise the lossy would trigger a pel
  1372. // insertion. Our search for FGBG runs is dependent upon that
  1373. // type of run being amalgamated because we break every 64
  1374. // characters so that our mode switch detection works OK.
  1375. //
  1376. // Take care not to merge across the non-xor/xor boundary
  1377. //
  1378. if (srcOffset == (TSHR_UINT16)rowDelta)
  1379. {
  1380. //
  1381. // Just bump the source offset
  1382. //
  1383. srcOffset += bestRunLength;
  1384. }
  1385. else
  1386. {
  1387. //
  1388. // Bump srcOffset and try a merge
  1389. //
  1390. srcOffset += bestRunLength;
  1391. //
  1392. // The simpler merges are where the types are identical
  1393. //
  1394. if (bestRunType == match[matchindex-1].type)
  1395. {
  1396. //
  1397. // COLOR IMAGES and BG images are trivial
  1398. //
  1399. if ((bestRunType == IMAGE_LOSSY_ODD) ||
  1400. (bestRunType == RUN_BG))
  1401. {
  1402. match[matchindex-1].length += (WORD)bestRunLength;
  1403. continue;
  1404. }
  1405. //
  1406. // FG runs and FGBG images merge if fgChars match
  1407. //
  1408. if (((bestRunType == RUN_FG) ||
  1409. (bestRunType == IMAGE_FGBG)) &&
  1410. (fgChar == match[matchindex-1].fgChar))
  1411. {
  1412. match[matchindex-1].length += (WORD)bestRunLength;
  1413. TRACE_OUT(( "Merged %u with preceding, giving %u",
  1414. match[matchindex-1].type,
  1415. match[matchindex-1].length));
  1416. continue;
  1417. }
  1418. }
  1419. //
  1420. // BG RUNs merge with LOSSY odd lines It is important that
  1421. // we do this merging because otherwise we will get
  1422. // inadvertent pel insertion due to the broken BG runs.
  1423. //
  1424. if (((bestRunType == RUN_BG) ||
  1425. (bestRunType == IMAGE_LOSSY_ODD)) &&
  1426. ((match[matchindex-1].type == RUN_BG) ||
  1427. (match[matchindex-1].type == IMAGE_LOSSY_ODD) ||
  1428. (match[matchindex-1].type == RUN_BG_PEL)))
  1429. {
  1430. match[matchindex-1].length += (WORD)bestRunLength;
  1431. continue;
  1432. }
  1433. //
  1434. // If it is a normal FGBG run which follows a short BG run
  1435. // then it is better to merge them.
  1436. //
  1437. if ((bestRunType == IMAGE_FGBG) &&
  1438. (match[matchindex-1].type == RUN_BG) &&
  1439. (match[matchindex-1].length < 8))
  1440. {
  1441. match[matchindex-1].type = IMAGE_FGBG;
  1442. match[matchindex-1].length += (WORD)bestRunLength;
  1443. match[matchindex-1].fgChar = fgChar;
  1444. TRACE_OUT(( "Merged FGBG with preceding BG run -> %u",
  1445. match[matchindex-1].length));
  1446. continue;
  1447. }
  1448. //
  1449. // If it is a BG run following a FGBG run then merge in the
  1450. // pels to make the FGBG a multiple of 8 bits. The if the
  1451. // remaining BG run is < 16 merge it in also otherwise just
  1452. // write the shortened BG run
  1453. //
  1454. if (((bestRunType == RUN_BG) ||
  1455. (bestRunType == RUN_BG_PEL)) &&
  1456. (match[matchindex-1].type == IMAGE_FGBG) &&
  1457. (match[matchindex-1].length & 0x0007))
  1458. {
  1459. UINT mergelen = 8 -
  1460. (match[matchindex-1].length & 0x0007);
  1461. if (mergelen > bestRunLength)
  1462. {
  1463. mergelen = bestRunLength;
  1464. }
  1465. match[matchindex-1].length += (WORD)mergelen;
  1466. bestRunLength -= mergelen;
  1467. TRACE_OUT(( "Added %u pels to FGBG giving %u leaving %u",
  1468. mergelen, match[matchindex-1].length,bestRunLength));
  1469. if (bestRunLength < 9)
  1470. {
  1471. match[matchindex-1].length += (WORD)bestRunLength;
  1472. TRACE_OUT(( "Merged BG with preceding FGBG gives %u",
  1473. match[matchindex-1].length));
  1474. continue;
  1475. }
  1476. }
  1477. //
  1478. // Finally, if it is a color run spanning any kind of
  1479. // single pel entity then merge that last two entries.
  1480. //
  1481. if ((bestRunType == IMAGE_COLOR) &&
  1482. (match[matchindex-2].type == IMAGE_COLOR) &&
  1483. (match[matchindex-1].length == 1))
  1484. {
  1485. match[matchindex-2].length += bestRunLength + 1;
  1486. matchindex--;
  1487. TRACE_OUT(( "Merged color with preceding color gives %u",
  1488. match[matchindex-1].length));
  1489. continue;
  1490. }
  1491. }
  1492. //
  1493. // Handle runs that will not amalgamate by adding a new array
  1494. // entry
  1495. //
  1496. match[matchindex].type = bestRunType;
  1497. match[matchindex].length = (WORD)bestRunLength;
  1498. match[matchindex].fgChar = fgChar;
  1499. TRACE_OUT(( "Best run of type %u (index %u) has length %u",
  1500. match[matchindex-1].type,
  1501. matchindex-1,
  1502. match[matchindex-1].length));
  1503. TRACE_OUT(( "Trying run of type %u (index %u) length %u",
  1504. match[matchindex].type,
  1505. matchindex,
  1506. match[matchindex].length));
  1507. matchindex++;
  1508. }
  1509. //
  1510. // If we have just done our scan of the first line then now do the
  1511. // rest of the buffer. Reset our saved pel count.
  1512. //
  1513. numPels = saveNumPels;
  1514. lossy = saveLossy;
  1515. firstLine = FALSE;
  1516. }
  1517. //
  1518. // END OF INITIAL TWO PASS SCAN OF THE INPUT
  1519. //
  1520. //
  1521. // We have parsed the buffer so now we can go ahead and encode it.
  1522. // First we should check to see whether we want to redo the encoding
  1523. // in lossy mode. We only do this if requested and worthwhile.
  1524. //
  1525. if (!saveLossy && (pLossy != NULL) && *pLossy)
  1526. {
  1527. UINT lossyCharCount = 0;
  1528. UINT divisor;
  1529. for (i = 2; i < (int)matchindex; i++)
  1530. {
  1531. if ((match[i].type == IMAGE_COLOR) ||
  1532. (match[i].type == IMAGE_LOSSY_ODD))
  1533. {
  1534. lossyCharCount += match[i].length;
  1535. }
  1536. }
  1537. divisor = max(numPels/100, 1);
  1538. if (lossyCharCount/divisor > LOSSY_THRESHOLD)
  1539. {
  1540. saveLossy = TRUE;
  1541. goto RESTART_COMPRESSION_IN_LOSSY_MODE;
  1542. }
  1543. else
  1544. {
  1545. *pLossy = FALSE;
  1546. }
  1547. }
  1548. //
  1549. // Now do the encoding
  1550. //
  1551. srcOffset = 0;
  1552. firstLine = TRUE;
  1553. lossy = FALSE;
  1554. fgChar = 0xFF;
  1555. for (i = 2; i < (int)matchindex; i++)
  1556. {
  1557. //
  1558. // First check for our approaching the end of the destination
  1559. // buffer and get out if this is the case. We allow for the
  1560. // largest general run order (a mega-mega set run = 4 bytes).
  1561. // Orders which may be larger are checked within the case arm
  1562. //
  1563. if ((UINT)(destbuf - pDst + 4) > dstBufferSize)
  1564. {
  1565. //
  1566. // We are about to blow it so just get out
  1567. //
  1568. DC_QUIT;
  1569. }
  1570. //
  1571. // While we are encoding the first line keep checking for the end
  1572. // of line to switch encoding states
  1573. //
  1574. if (firstLine)
  1575. {
  1576. if (srcOffset >= rowDelta)
  1577. {
  1578. firstLine = FALSE;
  1579. lossy = saveLossy;
  1580. }
  1581. }
  1582. switch (match[i].type)
  1583. {
  1584. //
  1585. // BG_RUN, FG_RUN, COLOR, PACKED COLOR and FGBG are normal
  1586. // precision codes
  1587. //
  1588. case RUN_BG:
  1589. case RUN_BG_PEL:
  1590. ENCODE_ORDER_MEGA(destbuf,
  1591. CODE_BG_RUN,
  1592. match[i].length,
  1593. CODE_MEGA_MEGA_BG_RUN,
  1594. MAX_LENGTH_ORDER,
  1595. MAX_LENGTH_LONG_ORDER);
  1596. TRACE_OUT(( "BG RUN %u",match[i].length));
  1597. srcOffset += match[i].length;
  1598. break;
  1599. case IMAGE_LOSSY_ODD:
  1600. //
  1601. // For a lossy odd line we encode a background run
  1602. // Note that we do not need to encode a start lossy
  1603. // because the decode does not need to distinguish this
  1604. // from a regular bg run
  1605. //
  1606. ENCODE_ORDER_MEGA(destbuf,
  1607. CODE_BG_RUN,
  1608. match[i].length,
  1609. CODE_MEGA_MEGA_BG_RUN,
  1610. MAX_LENGTH_ORDER,
  1611. MAX_LENGTH_LONG_ORDER);
  1612. TRACE_OUT(( "BG RUN %u",match[i].length));
  1613. srcOffset += match[i].length;
  1614. break;
  1615. case RUN_FG:
  1616. //
  1617. // If the fg char is not yet set then encode a set+run code
  1618. //
  1619. if (fgChar != match[i].fgChar)
  1620. {
  1621. SETFGCHAR(match[i].fgChar, fgChar, fgShift);
  1622. //
  1623. // Encode the order
  1624. //
  1625. ENCODE_SET_ORDER_MEGA(destbuf,
  1626. CODE_SET_FG_FG_RUN,
  1627. match[i].length,
  1628. CODE_MEGA_MEGA_SET_FG_RUN,
  1629. MAX_LENGTH_ORDER_LITE,
  1630. MAX_LENGTH_LONG_ORDER_LITE);
  1631. TRACE_OUT(( "SET_FG_FG_RUN %u",match[i].length));
  1632. srcOffset += match[i].length;
  1633. }
  1634. else
  1635. {
  1636. ENCODE_ORDER_MEGA(destbuf,
  1637. CODE_FG_RUN,
  1638. match[i].length,
  1639. CODE_MEGA_MEGA_FG_RUN,
  1640. MAX_LENGTH_ORDER,
  1641. MAX_LENGTH_LONG_ORDER);
  1642. TRACE_OUT(( "FG_RUN %u",match[i].length));
  1643. srcOffset += match[i].length;
  1644. }
  1645. break;
  1646. case IMAGE_FGBG:
  1647. //
  1648. // IMAGE_FGBG
  1649. //
  1650. runLength = match[i].length;
  1651. //
  1652. // First check for our approaching the end of the
  1653. // destination buffer and get out if this is the case.
  1654. //
  1655. if ((destbuf-pDst+(runLength+7)/8+4) > dstBufferSize)
  1656. {
  1657. //
  1658. // We are about to blow it so just get out
  1659. //
  1660. DC_QUIT;
  1661. }
  1662. //
  1663. // We need to convert FGBG runs into the pixel form
  1664. //
  1665. if (fgChar != match[i].fgChar)
  1666. {
  1667. SETFGCHAR(match[i].fgChar, fgChar, fgShift);
  1668. ENCODE_SET_ORDER_MEGA_FGBG(destbuf,
  1669. CODE_SET_FG_FG_BG,
  1670. runLength,
  1671. CODE_MEGA_MEGA_SET_FGBG,
  1672. MAX_LENGTH_FGBG_ORDER_LITE,
  1673. MAX_LENGTH_LONG_FGBG_ORDER);
  1674. TRACE_OUT(( "SET_FG_FG_BG %u",match[i].length));
  1675. while (runLength >= 8)
  1676. {
  1677. ENCODEFGBG(*destbuf);
  1678. destbuf++;
  1679. srcOffset += 8;
  1680. runLength -= 8;
  1681. }
  1682. if (runLength)
  1683. {
  1684. ENCODEFGBG(*destbuf);
  1685. //
  1686. // Keep the final partial byte clean to help GDC
  1687. // packing
  1688. //
  1689. *destbuf &= ((0x01 << runLength) - 1);
  1690. destbuf++;
  1691. srcOffset += runLength;
  1692. }
  1693. }
  1694. else
  1695. {
  1696. if (runLength == 8)
  1697. {
  1698. BYTE fgbgChar;
  1699. //
  1700. // See if it is one of the high probability bytes
  1701. //
  1702. ENCODEFGBG(fgbgChar);
  1703. //
  1704. // Check for single byte encoding of FGBG images
  1705. //
  1706. switch (fgbgChar)
  1707. {
  1708. case SPECIAL_FGBG_CODE_1:
  1709. *destbuf++ = CODE_SPECIAL_FGBG_1;
  1710. break;
  1711. case SPECIAL_FGBG_CODE_2:
  1712. *destbuf++ = CODE_SPECIAL_FGBG_2;
  1713. break;
  1714. default:
  1715. ENCODE_ORDER_MEGA_FGBG(destbuf,
  1716. CODE_FG_BG_IMAGE,
  1717. runLength,
  1718. CODE_MEGA_MEGA_FGBG,
  1719. MAX_LENGTH_FGBG_ORDER,
  1720. MAX_LENGTH_LONG_FGBG_ORDER);
  1721. *destbuf++ = fgbgChar;
  1722. break;
  1723. }
  1724. srcOffset += 8;
  1725. }
  1726. else
  1727. {
  1728. //
  1729. // Encode as standard FGBG
  1730. //
  1731. ENCODE_ORDER_MEGA_FGBG(destbuf,
  1732. CODE_FG_BG_IMAGE,
  1733. runLength,
  1734. CODE_MEGA_MEGA_FGBG,
  1735. MAX_LENGTH_FGBG_ORDER,
  1736. MAX_LENGTH_LONG_FGBG_ORDER);
  1737. TRACE_OUT(( "FG_BG %u",match[i].length));
  1738. while (runLength >= 8)
  1739. {
  1740. ENCODEFGBG(*destbuf);
  1741. destbuf++;
  1742. srcOffset += 8;
  1743. runLength -= 8;
  1744. }
  1745. if (runLength)
  1746. {
  1747. ENCODEFGBG(*destbuf);
  1748. *destbuf &= ((0x01 << runLength) - 1);
  1749. destbuf++;
  1750. srcOffset += runLength;
  1751. }
  1752. }
  1753. }
  1754. break;
  1755. case RUN_COLOR:
  1756. //
  1757. // COLOR RUN
  1758. //
  1759. ENCODE_ORDER_MEGA(destbuf,
  1760. CODE_COLOR_RUN,
  1761. match[i].length,
  1762. CODE_MEGA_MEGA_COLOR_RUN,
  1763. MAX_LENGTH_ORDER,
  1764. MAX_LENGTH_LONG_ORDER);
  1765. TRACE_OUT(( "COLOR_RUN %u",match[i].length));
  1766. *destbuf++ = nrmbuf[srcOffset];
  1767. srcOffset += match[i].length;
  1768. break;
  1769. case RUN_DITHER:
  1770. //
  1771. // DITHERED RUN
  1772. //
  1773. {
  1774. UINT ditherlen = match[i].length/2;
  1775. ENCODE_ORDER_MEGA(destbuf,
  1776. CODE_DITHERED_RUN,
  1777. ditherlen,
  1778. CODE_MEGA_MEGA_DITHER,
  1779. MAX_LENGTH_ORDER_LITE,
  1780. MAX_LENGTH_LONG_ORDER_LITE);
  1781. TRACE_OUT(( "DITHERED_RUN %u",match[i].length));
  1782. //
  1783. // First check for our approaching the end of the
  1784. // destination buffer and get out if this is the case.
  1785. //
  1786. if ((UINT)(destbuf - pDst + 2) > dstBufferSize)
  1787. {
  1788. //
  1789. // We are about to blow it so just get out
  1790. //
  1791. DC_QUIT;
  1792. }
  1793. *destbuf++ = nrmbuf[srcOffset];
  1794. *destbuf++ = nrmbuf[srcOffset+1];
  1795. srcOffset += match[i].length;
  1796. }
  1797. break;
  1798. case IMAGE_COLOR:
  1799. //
  1800. // IMAGE_COLOR
  1801. //
  1802. //
  1803. // A length of 1 can possibly be encoded as a single
  1804. // "BLACK"
  1805. //
  1806. if (match[i].length == 1)
  1807. {
  1808. if (nrmbuf[srcOffset] == 0x00)
  1809. {
  1810. *destbuf++ = CODE_BLACK;
  1811. srcOffset++;
  1812. break;
  1813. }
  1814. if (nrmbuf[srcOffset] == 0xFF)
  1815. {
  1816. *destbuf++ = CODE_WHITE;
  1817. srcOffset++;
  1818. break;
  1819. }
  1820. }
  1821. //
  1822. // If lossy compression is requested then indicate it
  1823. // immediately we get a color image to encode here
  1824. //
  1825. if (lossy & !lossyStarted)
  1826. {
  1827. lossyStarted = TRUE;
  1828. *destbuf++ = CODE_START_LOSSY;
  1829. }
  1830. //
  1831. // For 4bpp data pack color runs into nibbles
  1832. //
  1833. if (bpp == 4)
  1834. {
  1835. //
  1836. // Store the data in packed format
  1837. //
  1838. ENCODE_ORDER_MEGA(destbuf,
  1839. CODE_PACKED_COLOR_IMAGE,
  1840. match[i].length,
  1841. CODE_MEGA_MEGA_PACKED_CLR,
  1842. MAX_LENGTH_ORDER,
  1843. MAX_LENGTH_LONG_ORDER);
  1844. TRACE_OUT(( "PACKED COLOR %u",match[i].length));
  1845. //
  1846. // If we are not doing lossy compress then just copy
  1847. // the data over, packing two to a byte
  1848. //
  1849. if (!lossy)
  1850. {
  1851. //
  1852. // First check for our approaching the end of the
  1853. // destination buffer and get out if this is the
  1854. // case.
  1855. //
  1856. if ((destbuf - pDst + (UINT)(match[i].length + 1) / 2) >
  1857. dstBufferSize)
  1858. {
  1859. //
  1860. // We are about to blow it so just get out
  1861. //
  1862. DC_QUIT;
  1863. }
  1864. Pack4bpp(destbuf, nrmbuf+srcOffset, match[i].length);
  1865. destbuf += (match[i].length+1)/2;
  1866. srcOffset += match[i].length;
  1867. }
  1868. else
  1869. {
  1870. //
  1871. // First check for our approaching the end of the
  1872. // destination buffer and get out if this is the
  1873. // case.
  1874. //
  1875. if ((destbuf - pDst + (UINT)(match[i].length + 3) / 4) >
  1876. dstBufferSize)
  1877. {
  1878. //
  1879. // We are about to blow it so just get out
  1880. //
  1881. DC_QUIT;
  1882. }
  1883. //
  1884. // For a lossy compress we need to discard every
  1885. // even byte
  1886. //
  1887. while (match[i].length > 2)
  1888. {
  1889. *destbuf++ =
  1890. (BYTE)((*(nrmbuf+srcOffset)<<4) |
  1891. (*(nrmbuf+srcOffset+2) & 0x0F));
  1892. if (match[i].length > 3)
  1893. {
  1894. srcOffset += 4;
  1895. match[i].length -= 4;
  1896. }
  1897. else
  1898. {
  1899. srcOffset += 3;
  1900. match[i].length -= 3;
  1901. }
  1902. }
  1903. if (match[i].length > 0)
  1904. {
  1905. *destbuf++ = (BYTE)(*(nrmbuf+srcOffset)<<4);
  1906. srcOffset += match[i].length;
  1907. }
  1908. }
  1909. }
  1910. else
  1911. {
  1912. //
  1913. // For 8bpp we don't bother trying to detect packed
  1914. // data. Doing so disturbs GDC.
  1915. //
  1916. if (!lossy)
  1917. {
  1918. //
  1919. // Store the data in non-compressed form
  1920. //
  1921. ENCODE_ORDER_MEGA(destbuf,
  1922. CODE_COLOR_IMAGE,
  1923. match[i].length,
  1924. CODE_MEGA_MEGA_CLR_IMG,
  1925. MAX_LENGTH_ORDER,
  1926. MAX_LENGTH_LONG_ORDER);
  1927. TRACE_OUT(( "COLOR_IMAGE %u",match[i].length));
  1928. //
  1929. // First check for our approaching the end of the
  1930. // destination buffer and get out if this is the
  1931. // case.
  1932. //
  1933. if ((destbuf - pDst + (UINT)match[i].length) > dstBufferSize)
  1934. {
  1935. //
  1936. // We are about to blow it so just get out
  1937. //
  1938. DC_QUIT;
  1939. }
  1940. //
  1941. // Now just copy the data over
  1942. //
  1943. memcpy(destbuf, nrmbuf+srcOffset, match[i].length);
  1944. destbuf += match[i].length;
  1945. srcOffset += match[i].length;
  1946. }
  1947. else
  1948. {
  1949. //
  1950. // Lossy compression - store the data with
  1951. // discarding
  1952. //
  1953. ENCODE_ORDER_MEGA(destbuf,
  1954. CODE_COLOR_IMAGE,
  1955. match[i].length,
  1956. CODE_MEGA_MEGA_CLR_IMG,
  1957. MAX_LENGTH_ORDER,
  1958. MAX_LENGTH_LONG_ORDER);
  1959. TRACE_OUT(( "COLOR_IMAGE %u",match[i].length));
  1960. //
  1961. // First check for our approaching the end of the
  1962. // destination buffer and get out if this is the
  1963. // case.
  1964. //
  1965. if ((destbuf - pDst + (UINT)(match[i].length + 1) / 2) >
  1966. dstBufferSize)
  1967. {
  1968. //
  1969. // We are about to blow it so just get out
  1970. //
  1971. DC_QUIT;
  1972. }
  1973. //
  1974. // For a lossy compress we need to discard every
  1975. // even byte
  1976. //
  1977. while (match[i].length > 1)
  1978. {
  1979. *destbuf++ = *(nrmbuf+srcOffset);
  1980. srcOffset += 2;
  1981. match[i].length -= 2;
  1982. }
  1983. if (match[i].length == 1)
  1984. {
  1985. *destbuf++ = *(nrmbuf+srcOffset);
  1986. srcOffset++;
  1987. }
  1988. }
  1989. }
  1990. break;
  1991. default:
  1992. ERROR_OUT(( "Invalid run type %u",match[i].type));
  1993. }
  1994. }
  1995. //
  1996. // return the size of the compressed buffer
  1997. //
  1998. compressedLength = (UINT)(destbuf-pDst);
  1999. DC_EXIT_POINT:
  2000. DebugExitDWORD(CompressV2Int, compressedLength);
  2001. return(compressedLength);
  2002. }
  2003. //
  2004. // DecompressV2Int
  2005. //
  2006. UINT DecompressV2Int(LPBYTE pSrc,
  2007. LPBYTE pDst,
  2008. UINT bytes,
  2009. UINT bpp,
  2010. UINT rowDelta,
  2011. LPBYTE nrmbuf)
  2012. {
  2013. UINT codeLength;
  2014. BYTE codeByte;
  2015. BYTE codeByte2;
  2016. BYTE decode;
  2017. BYTE decodeLite;
  2018. BYTE decodeMega;
  2019. BYTE fgChar = 0xFF;
  2020. BYTE NEAR *destbuf = nrmbuf;
  2021. LPBYTE endSrc = pSrc + bytes;
  2022. BOOL backgroundNeedsPel = FALSE;
  2023. BOOL lossyStarted = FALSE;
  2024. UINT resultSize = 0;
  2025. BOOL firstLine = TRUE;
  2026. DebugEntry(DecompressV2Int);
  2027. //
  2028. // Loop processing the input
  2029. //
  2030. while(pSrc < endSrc)
  2031. {
  2032. //
  2033. // While we are processing the first line we should keep a look out
  2034. // for the end of the line
  2035. //
  2036. if (firstLine)
  2037. {
  2038. if ((UINT)(destbuf - nrmbuf) >= rowDelta)
  2039. {
  2040. firstLine = FALSE;
  2041. backgroundNeedsPel = FALSE;
  2042. }
  2043. }
  2044. //
  2045. // Trace out the source data for debugging
  2046. //
  2047. TRACE_OUT(( "Next code is %2.2x%2.2x%2.2x%2.2x",
  2048. *pSrc,
  2049. *(pSrc+1),
  2050. *(pSrc+2),
  2051. *(pSrc+3)));
  2052. //
  2053. // Get the decode
  2054. //
  2055. decode = (BYTE)(*pSrc & CODE_MASK);
  2056. decodeLite = (BYTE)(*pSrc & CODE_MASK_LITE);
  2057. decodeMega = (BYTE)(*pSrc);
  2058. //
  2059. // BG RUN
  2060. //
  2061. if ((decode == CODE_BG_RUN) ||
  2062. (decodeMega == CODE_MEGA_MEGA_BG_RUN))
  2063. {
  2064. if (decode == CODE_BG_RUN)
  2065. {
  2066. EXTRACT_LENGTH(pSrc, codeLength);
  2067. }
  2068. else
  2069. {
  2070. codeLength = EXTRACT_TSHR_UINT16_UA(pSrc+1);
  2071. pSrc += 3;
  2072. }
  2073. TRACE_OUT(( "Background run %u",codeLength));
  2074. if (!firstLine)
  2075. {
  2076. if (backgroundNeedsPel)
  2077. {
  2078. *destbuf++ = (BYTE)(*(destbuf - rowDelta) ^ fgChar);
  2079. codeLength--;
  2080. }
  2081. while (codeLength-- > 0)
  2082. {
  2083. *destbuf++ = *(destbuf - rowDelta);
  2084. }
  2085. }
  2086. else
  2087. {
  2088. if (backgroundNeedsPel)
  2089. {
  2090. *destbuf++ = fgChar;
  2091. codeLength--;
  2092. }
  2093. while (codeLength-- > 0)
  2094. {
  2095. *destbuf++ = 0x00;
  2096. }
  2097. }
  2098. //
  2099. // A follow on BG run will need a pel inserted
  2100. //
  2101. backgroundNeedsPel = TRUE;
  2102. continue;
  2103. }
  2104. //
  2105. // For any of the other runtypes a follow on BG run does not need
  2106. // a FG pel inserted
  2107. //
  2108. backgroundNeedsPel = FALSE;
  2109. //
  2110. // FGBG IMAGE
  2111. //
  2112. if ((decode == CODE_FG_BG_IMAGE) ||
  2113. (decodeLite == CODE_SET_FG_FG_BG) ||
  2114. (decodeMega == CODE_MEGA_MEGA_FGBG) ||
  2115. (decodeMega == CODE_MEGA_MEGA_SET_FGBG))
  2116. {
  2117. if ((decodeMega == CODE_MEGA_MEGA_FGBG) ||
  2118. (decodeMega == CODE_MEGA_MEGA_SET_FGBG))
  2119. {
  2120. codeLength = EXTRACT_TSHR_UINT16_UA(pSrc+1);
  2121. pSrc += 3;
  2122. }
  2123. else
  2124. {
  2125. if (decode == CODE_FG_BG_IMAGE)
  2126. {
  2127. EXTRACT_LENGTH_FGBG(pSrc, codeLength);
  2128. }
  2129. else
  2130. {
  2131. EXTRACT_LENGTH_FGBG_LITE(pSrc, codeLength);
  2132. }
  2133. }
  2134. if ((decodeLite == CODE_SET_FG_FG_BG) ||
  2135. (decodeMega == CODE_MEGA_MEGA_SET_FGBG))
  2136. {
  2137. fgChar = *pSrc++;
  2138. TRACE_OUT(( "Set FGBG image %u",codeLength));
  2139. }
  2140. else
  2141. {
  2142. TRACE_OUT(( "FGBG image %u",codeLength));
  2143. }
  2144. while (codeLength > 8)
  2145. {
  2146. codeByte = *pSrc++;
  2147. if (firstLine)
  2148. {
  2149. STORE_FGBG(0x00, codeByte, fgChar, 8);
  2150. }
  2151. else
  2152. {
  2153. STORE_FGBG(*(destbuf - rowDelta), codeByte, fgChar, 8);
  2154. }
  2155. codeLength -= 8;
  2156. }
  2157. if (codeLength > 0)
  2158. {
  2159. codeByte = *pSrc++;
  2160. if (firstLine)
  2161. {
  2162. STORE_FGBG(0x00, codeByte, fgChar, codeLength);
  2163. }
  2164. else
  2165. {
  2166. STORE_FGBG(*(destbuf - rowDelta),
  2167. codeByte,
  2168. fgChar,
  2169. codeLength);
  2170. }
  2171. }
  2172. continue;
  2173. }
  2174. //
  2175. // FG RUN
  2176. //
  2177. if ((decode == CODE_FG_RUN) ||
  2178. (decodeLite == CODE_SET_FG_FG_RUN) ||
  2179. (decodeMega == CODE_MEGA_MEGA_FG_RUN) ||
  2180. (decodeMega == CODE_MEGA_MEGA_SET_FG_RUN))
  2181. {
  2182. if ((decodeMega == CODE_MEGA_MEGA_FG_RUN) ||
  2183. (decodeMega == CODE_MEGA_MEGA_SET_FG_RUN))
  2184. {
  2185. codeLength = EXTRACT_TSHR_UINT16_UA(pSrc+1);
  2186. pSrc += 3;
  2187. }
  2188. else
  2189. {
  2190. if (decode == CODE_FG_RUN)
  2191. {
  2192. EXTRACT_LENGTH(pSrc, codeLength);
  2193. }
  2194. else
  2195. {
  2196. EXTRACT_LENGTH_LITE(pSrc, codeLength);
  2197. }
  2198. }
  2199. //
  2200. // Push the old fgChar down to the ALT position
  2201. //
  2202. if ((decodeLite == CODE_SET_FG_FG_RUN) ||
  2203. (decodeMega == CODE_MEGA_MEGA_SET_FG_RUN))
  2204. {
  2205. TRACE_OUT(( "Set FG run %u",codeLength));
  2206. fgChar = *pSrc++;
  2207. }
  2208. else
  2209. {
  2210. TRACE_OUT(( "FG run %u",codeLength));
  2211. }
  2212. while (codeLength-- > 0)
  2213. {
  2214. if (!firstLine)
  2215. {
  2216. *destbuf++ = (BYTE)(*(destbuf - rowDelta) ^ fgChar);
  2217. }
  2218. else
  2219. {
  2220. *destbuf++ = fgChar;
  2221. }
  2222. }
  2223. continue;
  2224. }
  2225. //
  2226. // DITHERED RUN
  2227. //
  2228. if ((decodeLite == CODE_DITHERED_RUN) ||
  2229. (decodeMega == CODE_MEGA_MEGA_DITHER))
  2230. {
  2231. if (decodeMega == CODE_MEGA_MEGA_DITHER)
  2232. {
  2233. codeLength = EXTRACT_TSHR_UINT16_UA(pSrc+1);
  2234. pSrc += 3;
  2235. }
  2236. else
  2237. {
  2238. EXTRACT_LENGTH_LITE(pSrc, codeLength);
  2239. }
  2240. TRACE_OUT(( "Dithered run %u",codeLength));
  2241. codeByte = *pSrc++;
  2242. codeByte2 = *pSrc++;
  2243. while (codeLength-- > 0)
  2244. {
  2245. *destbuf++ = codeByte;
  2246. *destbuf++ = codeByte2;
  2247. }
  2248. continue;
  2249. }
  2250. //
  2251. // COLOR IMAGE
  2252. //
  2253. if ((decode == CODE_COLOR_IMAGE) ||
  2254. (decodeMega == CODE_MEGA_MEGA_CLR_IMG))
  2255. {
  2256. if (decodeMega == CODE_MEGA_MEGA_CLR_IMG)
  2257. {
  2258. codeLength = EXTRACT_TSHR_UINT16_UA(pSrc+1);
  2259. pSrc += 3;
  2260. }
  2261. else
  2262. {
  2263. EXTRACT_LENGTH(pSrc, codeLength);
  2264. }
  2265. TRACE_OUT(( "Color image %u",codeLength));
  2266. //
  2267. // If not doing lossy compression then just copy the bytes
  2268. //
  2269. if (!lossyStarted)
  2270. {
  2271. while (codeLength-- > 0)
  2272. {
  2273. //
  2274. // Update the target with the character
  2275. //
  2276. *destbuf++ = *pSrc++;
  2277. }
  2278. }
  2279. else
  2280. {
  2281. //
  2282. // For lossy compression we must duplicate all the bytes,
  2283. // bar the final odd byte
  2284. //
  2285. while (codeLength > 3)
  2286. {
  2287. //
  2288. // Dither the bytes unless they are black in which
  2289. // case a non-dither is preferable
  2290. //
  2291. *destbuf++ = *pSrc;
  2292. if (*pSrc == 0)
  2293. {
  2294. *destbuf++ = *(pSrc);
  2295. *destbuf++ = *(pSrc+1);
  2296. *destbuf++ = *(pSrc+1);
  2297. pSrc += 2;
  2298. }
  2299. else
  2300. {
  2301. *destbuf++ = *(pSrc+1);
  2302. *destbuf++ = *pSrc++;
  2303. *destbuf++ = *pSrc++;
  2304. }
  2305. codeLength -= 4;
  2306. }
  2307. if (codeLength == 3)
  2308. {
  2309. *destbuf++ = *pSrc;
  2310. *destbuf++ = *(pSrc+1);
  2311. *destbuf++ = *pSrc;
  2312. pSrc += 2;
  2313. }
  2314. else
  2315. {
  2316. if (codeLength == 2)
  2317. {
  2318. *destbuf++ = *pSrc;
  2319. *destbuf++ = *pSrc++;
  2320. }
  2321. else
  2322. {
  2323. if (codeLength == 1)
  2324. {
  2325. *destbuf++ = *pSrc++;
  2326. }
  2327. }
  2328. }
  2329. }
  2330. continue;
  2331. }
  2332. //
  2333. // PACKED COLOR IMAGE
  2334. //
  2335. if ((decode == CODE_PACKED_COLOR_IMAGE) ||
  2336. (decodeMega == CODE_MEGA_MEGA_PACKED_CLR))
  2337. {
  2338. if (decodeMega == CODE_MEGA_MEGA_PACKED_CLR)
  2339. {
  2340. codeLength = EXTRACT_TSHR_UINT16_UA(pSrc+1);
  2341. pSrc += 3;
  2342. }
  2343. else
  2344. {
  2345. EXTRACT_LENGTH(pSrc, codeLength);
  2346. }
  2347. TRACE_OUT(( "Packed color %u",codeLength));
  2348. //
  2349. // If not doing lossy compression then we just unpack the 4bpp
  2350. // data two pels per byte
  2351. //
  2352. if (!lossyStarted)
  2353. {
  2354. if (bpp == 4)
  2355. {
  2356. UINT worklen = (codeLength)/2;
  2357. BYTE workchar;
  2358. while (worklen--)
  2359. {
  2360. workchar = *pSrc++;
  2361. *destbuf++ = (BYTE)(workchar>>4);
  2362. *destbuf++ = (BYTE)(workchar & 0x0F);
  2363. }
  2364. if (codeLength & 0x0001)
  2365. {
  2366. *destbuf++ = (BYTE)(*pSrc++>>4);
  2367. }
  2368. }
  2369. else
  2370. {
  2371. ERROR_OUT(( "Don't support packed color for 8bpp"));
  2372. }
  2373. }
  2374. else
  2375. {
  2376. //
  2377. // For lossy compression we must duplicate all the bytes,
  2378. // bar the final odd byte, again unpacking as we go
  2379. //
  2380. while (codeLength > 3)
  2381. {
  2382. *destbuf++ = (BYTE)((*pSrc) >> 4);
  2383. *destbuf++ = (BYTE)((*pSrc) >> 4);
  2384. *destbuf++ = (BYTE)((*pSrc) & 0x0F);
  2385. *destbuf++ = (BYTE)((*pSrc) & 0x0F);
  2386. pSrc++;
  2387. codeLength -= 4;
  2388. }
  2389. if (codeLength > 0)
  2390. {
  2391. if (codeLength-- > 0)
  2392. {
  2393. *destbuf++ = (BYTE)((*pSrc) >> 4);
  2394. }
  2395. if (codeLength-- > 0)
  2396. {
  2397. *destbuf++ = (BYTE)((*pSrc) >> 4);
  2398. }
  2399. if (codeLength-- > 0)
  2400. {
  2401. *destbuf++ = (BYTE)((*pSrc) & 0x0F);
  2402. }
  2403. if (codeLength-- > 0)
  2404. {
  2405. *destbuf++ = (BYTE)((*pSrc) & 0x0F);
  2406. }
  2407. pSrc++;
  2408. }
  2409. }
  2410. continue;
  2411. }
  2412. //
  2413. // COLOR RUN
  2414. //
  2415. if ((decode == CODE_COLOR_RUN) ||
  2416. (decodeMega == CODE_MEGA_MEGA_COLOR_RUN))
  2417. {
  2418. if (decodeMega == CODE_MEGA_MEGA_COLOR_RUN)
  2419. {
  2420. codeLength = EXTRACT_TSHR_UINT16_UA(pSrc+1);
  2421. pSrc += 3;
  2422. }
  2423. else
  2424. {
  2425. EXTRACT_LENGTH(pSrc, codeLength);
  2426. }
  2427. TRACE_OUT(( "Color run %u",codeLength));
  2428. codeByte = *pSrc++;
  2429. while (codeLength-- > 0)
  2430. {
  2431. *destbuf++ = codeByte;
  2432. }
  2433. continue;
  2434. }
  2435. //
  2436. // If we get here then the code must be a special one
  2437. //
  2438. TRACE_OUT(( "Special code %x",decodeMega));
  2439. switch (decodeMega)
  2440. {
  2441. case CODE_BLACK:
  2442. *destbuf++ = 0x00;
  2443. break;
  2444. case CODE_WHITE:
  2445. *destbuf++ = 0xFF;
  2446. break;
  2447. //
  2448. // Ignore the unreachable code warnings that follow
  2449. // Simply because we use the STORE_FGBG macro with a constant
  2450. // value
  2451. //
  2452. case CODE_SPECIAL_FGBG_1:
  2453. if (firstLine)
  2454. {
  2455. STORE_FGBG(0x00, SPECIAL_FGBG_CODE_1, fgChar, 8);
  2456. }
  2457. else
  2458. {
  2459. STORE_FGBG(*(destbuf - rowDelta),
  2460. SPECIAL_FGBG_CODE_1,
  2461. fgChar,
  2462. 8);
  2463. }
  2464. break;
  2465. case CODE_SPECIAL_FGBG_2:
  2466. if (firstLine)
  2467. {
  2468. STORE_FGBG(0x00,
  2469. SPECIAL_FGBG_CODE_2,
  2470. fgChar,
  2471. 8);
  2472. }
  2473. else
  2474. {
  2475. STORE_FGBG(*(destbuf - rowDelta),
  2476. SPECIAL_FGBG_CODE_2,
  2477. fgChar,
  2478. 8);
  2479. }
  2480. break;
  2481. case CODE_START_LOSSY:
  2482. lossyStarted = TRUE;
  2483. break;
  2484. default:
  2485. ERROR_OUT(( "Invalid compression data %x",decodeMega));
  2486. break;
  2487. }
  2488. pSrc++;
  2489. }
  2490. //
  2491. // Our final task is to copy the decoded image into the target buffer
  2492. // compacting if we are generating a 4bpp image
  2493. //
  2494. resultSize = (UINT)(destbuf-nrmbuf);
  2495. if (bpp == 4)
  2496. {
  2497. //
  2498. // Zero the final byte to eliminate single byte packing problems
  2499. //
  2500. *destbuf = 0x00;
  2501. Pack4bpp(pDst, nrmbuf, resultSize);
  2502. }
  2503. else
  2504. {
  2505. memcpy(pDst, nrmbuf, resultSize);
  2506. }
  2507. TRACE_OUT(( "Returning %u bytes",resultSize));
  2508. //
  2509. // Return the number of pixels decoded
  2510. //
  2511. DebugExitDWORD(DecompressV2Int, resultSize);
  2512. return(resultSize);
  2513. }
  2514.