Windows2003-3790/termsrv/drivers/rdp/inc/abcapi.c
2020-09-30 16:53:55 +02:00

2623 lines
131 KiB
C

/****************************************************************************/
/* abcapi.cpp */
/* */
/* Bitmap Compressor API functions. */
/* */
/* Copyright(c) Microsoft, PictureTel 1992-1997 */
/* Copyright(c) Microsoft 1997-1999 */
/****************************************************************************/
#ifdef DLL_DISP
#include <adcg.h>
#include <adcs.h>
#include <abcapi.h>
#include <abcdata.c>
#define _pShm pddShm
#else
#include <as_conf.hpp>
#define _pShm m_pShm
#endif
#ifdef COMP_STATS
/****************************************************************************/
/* Define some globals for storing useful stats data. */
/****************************************************************************/
UINT32 ulPreCompData = 0;
UINT32 ulTotalCompTime = 0;
UINT32 ulCompRate = 0;
#endif
#ifdef DC_DEBUG
// compression testing
#include <abdapi.h>
#endif
#ifdef Unused
// Restore this instead of macro if data added to abcdata.c
/****************************************************************************/
/* API FUNCTION: BC_Init */
/* */
/* Initializes the Bitmap Compressor. */
/****************************************************************************/
void RDPCALL SHCLASS BC_Init(void)
{
DC_BEGIN_FN("BC_Init");
#define DC_INIT_DATA
#include <abcdata.c>
#undef DC_INIT_DATA
DC_END_FN();
}
#endif
/****************************************************************************/
/* API FUNCTION: BC_CompressBitmap */
/* */
/* Compresses the supplied bitmap into the supplied memory buffer. */
/* */
/* PARAMETERS: */
/* */
/* pSrcBitmap - a pointer to the source bitmap data bits. */
/* */
/* pDstBuffer - a pointer to the destination memory buffer (where the */
/* compressed data will be written). */
/* */
/* dstBufferSize - the size in bytes of the destination buffer */
/* */
/* pCompressedDataSize - pointer to variable that receives the compressed */
/* data size */
/* */
/* bitmapWidth - width of the src bitmap in pels, should be divisible by 4. */
/* */
/* bitmapHeight - the height of the source bitmap in pels. */
/* */
/* RETURNS: */
/* */
/* TRUE - the bitmap data was successfully compressed. */
/* *pCompressedDataSize is updated */
/* */
/* FALSE - the bitmap data could not be compressed. */
/****************************************************************************/
#ifdef DC_HICOLOR
BOOL RDPCALL SHCLASS BC_CompressBitmap(
PBYTE pSrcBitmap,
PBYTE pDstBuffer,
PBYTE pBCWorkingBuffer,
unsigned dstBufferSize,
unsigned *pCompressedDataSize,
unsigned bitmapWidth,
unsigned bitmapHeight,
unsigned bpp)
#else
BOOL RDPCALL SHCLASS BC_CompressBitmap(
PBYTE pSrcBitmap,
PBYTE pDstBuffer,
unsigned dstBufferSize,
unsigned *pCompressedDataSize,
unsigned bitmapWidth,
unsigned bitmapHeight)
#endif
{
BOOL rc;
PTS_CD_HEADER_UA pCompDataHeader;
unsigned cbUncompressedDataSize;
unsigned cbCompMainBodySize;
#ifdef COMP_STATS
UINT32 ulStartCompTime;
UINT32 ulEndCompTime;
#endif
DC_BEGIN_FN("BC_CompressBitmap");
#ifdef COMP_STATS
/************************************************************************/
/* Record the start time. */
/************************************************************************/
COM_GETTICKCOUNT(ulStartCompTime);
#endif
TRC_ASSERT(((bitmapWidth & 3) == 0),(TB,"Width not divisible by 4"));
TRC_ASSERT((dstBufferSize > 0),(TB,"No destination space!"));
// Trace the important parameters.
TRC_DBG((TB, "pSrc(%p) pDst(%p) dstBufferSize(%#x)",
pSrcBitmap, pDstBuffer, dstBufferSize));
TRC_DBG((TB, "width(%u) height(%u)", bitmapWidth, bitmapHeight));
// Calculate the size of the uncompressed src data. Make sure it
// is within our allowed size.
#ifdef DC_HICOLOR
cbUncompressedDataSize = bitmapWidth * bitmapHeight * ((bpp + 7) / 8);
#else
cbUncompressedDataSize = bitmapWidth * bitmapHeight;
#endif
TRC_ASSERT((cbUncompressedDataSize <= MAX_UNCOMPRESSED_DATA_SIZE || pBCWorkingBuffer),
(TB,"Bitmap size > max: size=%u, max=%u",
cbUncompressedDataSize, MAX_UNCOMPRESSED_DATA_SIZE));
// Do we send the bitmap compression header?
if (_pShm->bc.noBitmapCompressionHdr)
{
#ifdef DC_HICOLOR
switch (bpp)
{
case 32:
{
TRC_DBG((TB, "Compress 32 bpp"));
cbCompMainBodySize = CompressV2Int32(pSrcBitmap,
pDstBuffer,
cbUncompressedDataSize,
bitmapWidth * 4,
dstBufferSize,
pBCWorkingBuffer ? pBCWorkingBuffer :
_pShm->bc.xor_buffer,
_pShm->bc.match);
}
break;
case 24:
{
TRC_DBG((TB, "Compress 24 bpp"));
cbCompMainBodySize = CompressV2Int24(pSrcBitmap,
pDstBuffer,
cbUncompressedDataSize,
bitmapWidth * 3,
dstBufferSize,
pBCWorkingBuffer ? pBCWorkingBuffer :
_pShm->bc.xor_buffer,
_pShm->bc.match);
}
break;
case 16:
{
TRC_DBG((TB, "Compress 16bpp"));
cbCompMainBodySize = CompressV2Int16(pSrcBitmap,
pDstBuffer,
cbUncompressedDataSize,
bitmapWidth * 2,
dstBufferSize,
pBCWorkingBuffer ? pBCWorkingBuffer :
_pShm->bc.xor_buffer,
_pShm->bc.match);
}
break;
case 15:
{
TRC_DBG((TB, "Compress 15bpp"));
cbCompMainBodySize = CompressV2Int15(pSrcBitmap,
pDstBuffer,
cbUncompressedDataSize,
bitmapWidth * 2,
dstBufferSize,
pBCWorkingBuffer ? pBCWorkingBuffer :
_pShm->bc.xor_buffer,
_pShm->bc.match);
}
break;
case 8:
default:
{
TRC_DBG((TB, "Compress 8bpp"));
cbCompMainBodySize = CompressV2Int(pSrcBitmap,
pDstBuffer,
cbUncompressedDataSize,
bitmapWidth,
dstBufferSize,
pBCWorkingBuffer ? pBCWorkingBuffer :
_pShm->bc.xor_buffer);
}
break;
}
#else
cbCompMainBodySize = CompressV2Int(pSrcBitmap,
pDstBuffer,
cbUncompressedDataSize,
bitmapWidth,
dstBufferSize,
_pShm->bc.xor_buffer);
#endif
if (cbCompMainBodySize != 0) {
// Write back the new (compressed) packet size.
*pCompressedDataSize = cbCompMainBodySize;
TRC_DBG((TB, "*pCompressedDataSize(%u)",
*pCompressedDataSize));
rc = TRUE;
}
else {
TRC_NRM((TB, "Failed to compress main body"));
rc = FALSE;
}
}
else {
if (dstBufferSize > sizeof(TS_CD_HEADER)) {
// Compress the bitmap data.
#ifdef DC_HICOLOR
switch (bpp)
{
case 32:
{
TRC_DBG((TB, "Compress 32 bpp"));
cbCompMainBodySize = CompressV2Int32(pSrcBitmap,
pDstBuffer + sizeof(TS_CD_HEADER),
cbUncompressedDataSize,
bitmapWidth * 4,
dstBufferSize - sizeof(TS_CD_HEADER),
pBCWorkingBuffer ? pBCWorkingBuffer :
_pShm->bc.xor_buffer,
_pShm->bc.match);
}
break;
case 24:
{
TRC_DBG((TB, "Compress 24 bpp"));
cbCompMainBodySize = CompressV2Int24(pSrcBitmap,
pDstBuffer + sizeof(TS_CD_HEADER),
cbUncompressedDataSize,
bitmapWidth * 3,
dstBufferSize - sizeof(TS_CD_HEADER),
pBCWorkingBuffer ? pBCWorkingBuffer :
_pShm->bc.xor_buffer,
_pShm->bc.match);
}
break;
case 16:
{
TRC_DBG((TB, "Compress 16bpp"));
cbCompMainBodySize = CompressV2Int16(pSrcBitmap,
pDstBuffer + sizeof(TS_CD_HEADER),
cbUncompressedDataSize,
bitmapWidth * 2,
dstBufferSize - sizeof(TS_CD_HEADER),
pBCWorkingBuffer ? pBCWorkingBuffer :
_pShm->bc.xor_buffer,
_pShm->bc.match);
}
break;
case 15:
{
TRC_DBG((TB, "Compress 15bpp"));
cbCompMainBodySize = CompressV2Int15(pSrcBitmap,
pDstBuffer + sizeof(TS_CD_HEADER),
cbUncompressedDataSize,
bitmapWidth * 2,
dstBufferSize - sizeof(TS_CD_HEADER),
pBCWorkingBuffer ? pBCWorkingBuffer :
_pShm->bc.xor_buffer,
_pShm->bc.match);
}
break;
case 8:
default:
{
TRC_DBG((TB, "Compress 8bpp"));
cbCompMainBodySize = CompressV2Int(pSrcBitmap,
pDstBuffer + sizeof(TS_CD_HEADER),
cbUncompressedDataSize,
bitmapWidth,
dstBufferSize - sizeof(TS_CD_HEADER),
pBCWorkingBuffer ? pBCWorkingBuffer :
_pShm->bc.xor_buffer);
}
break;
}
#else
cbCompMainBodySize = CompressV2Int(pSrcBitmap,
pDstBuffer + sizeof(TS_CD_HEADER),
cbUncompressedDataSize,
bitmapWidth,
dstBufferSize - sizeof(TS_CD_HEADER),
_pShm->bc.xor_buffer);
#endif
if (cbCompMainBodySize != 0) {
// Fill in the compressed data header.
// FirstRowSize is 0 by historical convention.
pCompDataHeader = (PTS_CD_HEADER_UA)pDstBuffer;
pCompDataHeader->cbCompFirstRowSize = 0;
pCompDataHeader->cbCompMainBodySize =
(UINT16)cbCompMainBodySize;
if (bpp > 8) {
pCompDataHeader->cbScanWidth = TS_BYTES_IN_SCANLINE(bitmapWidth, bpp);
}
else {
pCompDataHeader->cbScanWidth = (UINT16)bitmapWidth;
}
pCompDataHeader->cbUncompressedSize =
(UINT16)cbUncompressedDataSize;
// Write back the new (compressed) packet size.
*pCompressedDataSize = sizeof(TS_CD_HEADER) +
cbCompMainBodySize;
TRC_DBG((TB, "*pCompressedDataSize(%u)",
*pCompressedDataSize));
rc = TRUE;
}
else {
TRC_NRM((TB, "Failed to compress main body"));
rc = FALSE;
}
}
else {
TRC_NRM((TB, "Not enough buffer space for header: %u",
dstBufferSize));
rc = FALSE;
}
}
#if 0
/************************************************************************/
/* Check that the compressed output decompresses to the same thing */
/************************************************************************/
if (cbCompMainBodySize)
{
HRESULT hr;
hr = BD_DecompressBitmap(
#ifndef DLL_DISP
m_pTSWd,
#endif
pDstBuffer + (_pShm->bc.noBitmapCompressionHdr ? 0 : 8),
_pShm->bc.decompBuffer,
cbCompMainBodySize,
TRUE,
(BYTE)bpp,
(UINT16)bitmapWidth,
(UINT16)bitmapHeight);
if (FAILED(hr) || memcmp(pSrcBitmap, _pShm->bc.decompBuffer,cbUncompressedDataSize))
{
// TRC_ASSERT(FALSE, (TB, "Decompression failure"));
}
}
#endif
#ifdef COMP_STATS
/************************************************************************/
/* Work out how long the compression took, in ms. */
/************************************************************************/
COM_GETTICKCOUNT(ulEndCompTime);
ulTotalCompTime += (ulEndCompTime - ulStartCompTime) / 10000;
if (ulTotalCompTime != 0)
ulCompRate = ulPreCompData / ulTotalCompTime;
#endif
DC_END_FN();
return rc;
}
/****************************************************************************/
/* Bitmap Compression core code. */
/* */
/* A cunning multidimensional RLE compression scheme, particularly suitable */
/* for compressing bitmaps containing captured images of Windows */
/* applications. For images which use lots of different colors intermixed */
/* (full-color pictures, etc.) this compression sceme will be inefficient. */
/* */
/* These functions and macros encode a bitmap according to the codes */
/* defined in abcapi.h. Although there are some complexities in the */
/* encoding, the encodings should be self-explanatory. abcapi.h describes */
/* some nuances of the encoding scheme. */
/****************************************************************************/
/****************************************************************************/
/* Utility macros for encoding orders */
/****************************************************************************/
/****************************************************************************/
/* Encode an order for a standard run */
/****************************************************************************/
#define ENCODE_ORDER_MEGA(buffer, \
order_code, \
length, \
mega_order_code, \
DEF_LENGTH_ORDER, \
DEF_LENGTH_LONG_ORDER) \
if (length <= DEF_LENGTH_ORDER) { \
*buffer++ = (BYTE)((BYTE)order_code | (BYTE)length); \
} \
else if (length <= DEF_LENGTH_LONG_ORDER) { \
*buffer++ = (BYTE)order_code; \
*buffer++ = (BYTE)(length - DEF_LENGTH_ORDER - 1); \
} \
else { \
*buffer++ = (BYTE)mega_order_code; \
*(PUINT16_UA)(buffer) = (UINT16)length; \
buffer += 2; \
}
/****************************************************************************/
/* Encode a special FGBG image */
/****************************************************************************/
#define ENCODE_ORDER_MEGA_FGBG(buffer, \
order_code, \
length, \
mega_order_code, \
DEF_LENGTH_ORDER, \
DEF_LENGTH_LONG_ORDER) \
if ((length & 0x0007) == 0 && length <= DEF_LENGTH_ORDER) { \
*buffer++ = (BYTE)((BYTE)order_code | (BYTE)(length / 8)); \
} \
else if (length <= DEF_LENGTH_LONG_ORDER) { \
*buffer++ = (BYTE)order_code; \
*buffer++ = (BYTE)(length-1); \
} \
else { \
*buffer++ = (BYTE)mega_order_code; \
*(PUINT16_UA)(buffer) = (UINT16)length; \
buffer += 2; \
}
/****************************************************************************/
/* RunSingle */
/* */
/* Determine the length of the current run */
/* */
/* RunSingle may only be called if the buffer has at least four */
/* consecutive identical bytes from the start position */
/****************************************************************************/
#define RUNSINGLE(buffer, length, result) \
{ \
BYTE *buf = buffer + 4; \
BYTE *endbuf = buffer + length - 4; \
while (buf < endbuf && \
(*(PUINT32_UA)(buf) == *(PUINT32_UA)(buf - 4))) \
buf += 4; \
endbuf += 4; \
while (buf < endbuf && *buf == *(buf - 1)) \
buf++; \
result = (unsigned)(buf - (buffer)); \
}
/****************************************************************************/
// RunDouble
//
// Determine the length of the current run of dithered bytes. Assumes that
// the dither pattern resides in the first 2 bytes of buffer.
/****************************************************************************/
#define RunDouble(buffer, length, result) \
{ \
int len = ((int)length) - 2; \
BYTE *buf = (buffer) + 2; \
UINT16 Pattern = *(PUINT16_UA)(buffer); \
result = 2; \
while (len > 1) { \
if (*(PUINT16_UA)buf != Pattern) \
break; \
buf += 2; \
result += 2; \
len -= 2; \
} \
}
/****************************************************************************/
// RUNFGBG
//
// Determine the length of the run of bytes that consist only of black (0x00)
// or a single FG color. We exit the loop when
// - the next character is not a fg or bg color
// - we hit a run of 24 of the FG or BG color
// Example compression calculations:
// Lookahead KBytes* Comp CPU ("hits")
// 24 54846 148497
// 20 54885 151827
// 16 54967 156809
// * = KBytes server->client WinBench98 Graphics WinMark minus CorelDRAW,
// measured in NetMon on Ethernet.
/****************************************************************************/
#define RUNFGBG(buffer, length, result, work) \
{ \
BYTE *buf = buffer; \
BYTE *endbuf = buffer + length; \
result = 0; \
work = *buf; \
while (TRUE) { \
buf++; \
result++; \
if (buf < endbuf) { \
if (*buf != work && *buf != 0) \
break; \
\
if ((result & 0x0007) == 0) { \
if ((*buf == *(buf + 1)) && \
(*(PUINT16_UA)(buf) == *(PUINT16_UA)(buf + 2)) && \
(*(PUINT32_UA)(buf) == *(PUINT32_UA)(buf + 4)) && \
(*(PUINT32_UA)(buf) == *(PUINT32_UA)(buf + 8)) && \
(*(PUINT32_UA)(buf) == *(PUINT32_UA)(buf + 12)) && \
(*(PUINT32_UA)(buf) == *(PUINT32_UA)(buf + 16)) && \
(*(PUINT32_UA)(buf) == *(PUINT32_UA)(buf + 20))) \
{ \
break; \
} \
} \
} \
else { \
break; \
} \
} \
}
/****************************************************************************/
// Determine whether a run is better than any previous run.
// For efficiency we take the run if over a threshold. Threshold comparisons:
// Threshold KBytes* Comp CPU ("hits")
// 32 54846 148497
// 28 54817 145085
// 24 54825 144366
// 20 54852 143662
// 16 54858 146343
// * = KBytes server->client WinBench98 Graphics WinMark minus CorelDRAW,
// measured in NetMon on Ethernet.
/****************************************************************************/
#define CHECK_BEST_RUN(run_type, run_length, bestrun_length, bestrun_type) \
if (run_length > bestrun_length) { \
bestrun_length = run_length; \
bestrun_type = run_type; \
if (bestrun_length >= 20) \
break; \
}
/****************************************************************************/
/* SETFGCHAR */
/* */
/* Set up a new value in fgChar and recalculate the shift */
/****************************************************************************/
#define SETFGCHAR(newchar, curchar, curshift) \
curchar = newchar; \
{ \
BYTE workchar = curchar; \
curshift = 0; \
while ((workchar & 0x01) == 0) { \
curshift++; \
workchar = (BYTE)(workchar >> 1); \
} \
}
/****************************************************************************/
/* ENCODEFGBG */
/* */
/* Encode 8 bytes of FG and black into a one byte bitmap representation */
/* */
/* The FgChar will always be non-zero, and therefore must have at least one */
/* bit set. */
/* */
/* We arrange that all bytes have this bit in their lowest position */
/* The zero pels will still have a 0 in the lowest bit. */
/* */
/* Getting the result is a 4 stage process */
/* */
/* 1) Get the wanted bits into bit 0 of each byte */
/* */
/* <***************work1*****************> */
/* 31 0 */
/* 0000 000d 0000 000c 0000 000b 0000 000a */
/* ^ ^ ^ ^ */
/* <***************work2*****************> */
/* 31 0 */
/* 0000 000h 0000 000g 0000 000f 0000 000e */
/* ^ ^ ^ ^ */
/* */
/* a..h = bits that we want to output */
/* */
/* We just need to collect the indicated bits and squash them into a single */
/* byte. */
/* */
/* 2) Compress down to 32 bits */
/* */
/* <***************work1*****************> */
/* 31 0 */
/* 000h 000d 000g 000c 000f 000b 000e 000a */
/* ^ ^ ^ ^ ^ ^ ^ ^ */
/* */
/* 3) Compress down to 16 bits */
/* */
/* <******work*******> */
/* 15 0 */
/* 0h0f 0d0b 0g0e 0c0a */
/* ^ ^ ^ ^ ^ ^ ^ ^ */
/* */
/* 4) Compress down to 8 bits */
/* */
/* hgfedcba */
/****************************************************************************/
#define ENCODEFGBG(result) \
{ \
UINT32 work1; \
UINT32 work2; \
unsigned work; \
\
work1 = ((*(PUINT32_UA)(xorbuf + EncodeSrcOffset)) >> fgShift) & \
0x01010101; \
work2 = ((*(PUINT32_UA)(xorbuf + EncodeSrcOffset + 4)) >> fgShift) & \
0x01010101; \
work1 = (work2 << 4) | work1; \
work = work1 | (work1 >> 14); \
result = ((BYTE)(((BYTE)(work >> 7)) | ((BYTE)work))); \
}
#ifndef DC_HICOLOR
/****************************************************************************/
// The following structure contains the results of our intermediate scan of
// the buffer.
/****************************************************************************/
typedef struct {
unsigned length;
BYTE type;
BYTE fgChar;
} MATCH;
#endif
/****************************************************************************/
// Critical minimum limit on a run size -- magic number that determines
// color run search characteristics. Minimum is 4 for hard-coded DWORD-size
// checks below. Comparisons of values:
// MinRunSize KBytes* Comp CPU ("hits")
// 4 52487 115842
// 5 52697 115116
// 6 52980 120565
// 7 53306 123680
// * = KBytes server->client WinBench98 Graphics WinMark minus CorelDRAW,
// measured in NetMon on Ethernet.
/****************************************************************************/
#define MinRunSize 5
/****************************************************************************/
// CompressV2Int
//
// Compresses a bitmap in one call, returning the size of the space used in
// the destination buffer or zero if the buffer was not large enough.
//
// Implementation notes: We use a length-2 array of MATCH elements as a
// running lookbehind buffer, allowing us to combine current run analysis
// results with previous entries before encoding into the destination buffer.
/****************************************************************************/
#ifdef DC_HICOLOR
unsigned RDPCALL SHCLASS CompressV2Int(
PBYTE pSrc,
PBYTE pDst,
unsigned numPels,
unsigned rowDelta,
unsigned dstBufferSize,
BYTE *xorbuf)
{
unsigned srcOffset;
unsigned EncodeSrcOffset;
unsigned bestRunLength;
unsigned nextRunLength;
unsigned runLength;
unsigned bestFGRunLength;
unsigned scanCount;
unsigned saveNumPels;
BOOLEAN inColorRun = FALSE;
BOOLEAN bEncodeAllMatches;
BYTE bestRunType = 0;
BYTE fgPel = 0xFF;
BYTE fgPelWork = 0xFF;
BYTE fgShift = 0;
BYTE EncodeFGPel;
PBYTE destbuf = pDst;
unsigned compressedLength = 0;
MATCH match[2];
DC_BEGIN_FN("CompressV2Int");
/************************************************************************/
// Validate params.
/************************************************************************/
TRC_ASSERT((numPels >= rowDelta),(TB,"numPels < rowDelta"));
TRC_ASSERT((!(rowDelta & 0x3)),(TB,"rowDelta not multiple of 4"));
TRC_ASSERT((!(numPels & 0x3)),(TB,"numPels not multiple of 4"));
TRC_ASSERT((!((UINT_PTR)pSrc & 0x3)),
(TB, "Possible unaligned access, pSrc = %p", pSrc));
/************************************************************************/
// Create XOR buffer - first row is copied from src, succeeding rows
// are the corresponding src row XOR'd with the next src row.
/************************************************************************/
memcpy(xorbuf, pSrc, rowDelta);
{
BYTE *srcbuf = pSrc + rowDelta;
unsigned srclen = numPels - rowDelta;
UINT32 *dwdest = (UINT32 *)(xorbuf + rowDelta);
while (srclen >= 8) {
*dwdest++ = *((PUINT32)srcbuf) ^ *((PUINT32)(srcbuf -
(int)rowDelta));
srcbuf += 4;
*dwdest++ = *((PUINT32)srcbuf) ^ *((PUINT32)(srcbuf -
(int)rowDelta));
srcbuf += 4;
srclen -= 8;
}
if (srclen) {
// Since we're 4-byte aligned we can only have a single DWORD
// remaining.
*dwdest = *((PUINT32)srcbuf) ^ *((PUINT32)(srcbuf -
(int)rowDelta));
}
}
/************************************************************************/
// Set up encoding state variables.
/************************************************************************/
srcOffset = 0; // Offset in src buf where we are analyzing.
EncodeSrcOffset = 0; // Offset in src buf from where we are encoding.
EncodeFGPel = 0xFF; // Foreground color for encoding.
bEncodeAllMatches = FALSE; // Used to force encoding of all matches.
match[0].type = 0; // Initially no match types.
match[1].type = 0;
saveNumPels = numPels;
numPels = rowDelta;
/************************************************************************/
// Loop processing the input.
// We perform the loop twice, the first time for the non-XOR first line
// of the buffer and the second for the XOR portion, adjusting numPels
// to the needed value for each pass.
/************************************************************************/
for (scanCount = 0; ; scanCount++) {
while (srcOffset < numPels) {
/****************************************************************/
/* Start a while loop to allow a more structured break when we */
/* hit the first run type we want to encode (We can't afford */
/* the overheads of a function call to provide the scope here.) */
/****************************************************************/
while (TRUE) {
bestRunLength = 0;
bestFGRunLength = 0;
/************************************************************/
// If we are hitting the end of the buffer then just take
// color characters now. We will only hit this condition if
// we break out of a run just before the end of the buffer,
// so this should not be too common a situation, which is
// good given that we are encoding the final MinRunSize bytes
// uncompressed.
/************************************************************/
if ((srcOffset + MinRunSize) < numPels) {
goto ContinueScan;
}
else {
bestRunType = IMAGE_COLOR;
bestRunLength = numPels - srcOffset;
break;
}
ContinueScan:
/************************************************************/
// First do the scans on the XOR buffer. Look for a
// character run or a BG run.
// We must do the test independent of how long the run
// might be because even for a 1 pel BG run our later logic
// requires that we detect it seperately. This code is
// absolute main path so fastpath as much as possible. In
// particular detect short bg runs early and allow
// RunSingle to presuppose at least 4 matching bytes.
/************************************************************/
if (xorbuf[srcOffset] == 0x00) {
if ((srcOffset + 1) >= numPels ||
xorbuf[srcOffset + 1] != 0x00) {
bestRunType = RUN_BG;
bestRunLength = 1;
if (!inColorRun)
break;
}
else {
if ((srcOffset + 2) >= numPels ||
xorbuf[srcOffset + 2] != 0x00) {
bestRunType = RUN_BG;
bestRunLength = 2;
if (!inColorRun)
break;
}
else {
if ((srcOffset + 3) >= numPels ||
xorbuf[srcOffset + 3] != 0x00) {
bestRunType = RUN_BG;
bestRunLength = 3;
if (!inColorRun)
break;
}
else {
RUNSINGLE(xorbuf + srcOffset,
numPels - srcOffset,
bestFGRunLength);
CHECK_BEST_RUN(RUN_BG,
bestFGRunLength,
bestRunLength,
bestRunType);
if (!inColorRun)
break;
}
}
}
}
else {
/********************************************************/
// No point in starting if FG run less than 4 bytes so
// check the first dword as quickly as possible.
/********************************************************/
if (xorbuf[srcOffset] == xorbuf[srcOffset + 1] &&
*(PUINT16_UA)(xorbuf + srcOffset) ==
*(PUINT16_UA)(xorbuf + srcOffset + 2))
{
RUNSINGLE(xorbuf+srcOffset,
numPels-srcOffset,
bestFGRunLength);
/****************************************************/
// Don't permit a short FG run to prevent a FGBG
// image from starting up.
/****************************************************/
if (bestFGRunLength >= MinRunSize) {
CHECK_BEST_RUN(RUN_FG,
bestFGRunLength,
bestRunLength,
bestRunType);
}
}
}
/************************************************************/
// Look for solid or dithered sequences in the normal
// (non-XOR) buffer.
/************************************************************/
if ( (pSrc[srcOffset] == pSrc[srcOffset + 2]) &&
(pSrc[srcOffset + 1] == pSrc[srcOffset + 3])) {
/********************************************************/
// Now do the scan on the normal buffer for a character
// run. Don't bother if first line because we will have
// found it already in the XOR buffer, since we just
// copy pSrc to xorbuf for the first line. We insist on
// a run of at least MinRunSize pixels.
/********************************************************/
if (*(pSrc + srcOffset) == *(pSrc + srcOffset + 1)) {
if (srcOffset >= rowDelta) {
RUNSINGLE(pSrc + srcOffset,
numPels - srcOffset,
nextRunLength);
if (nextRunLength >= MinRunSize) {
CHECK_BEST_RUN(RUN_COLOR,
nextRunLength,
bestRunLength,
bestRunType);
}
}
}
else {
/****************************************************/
// Look for a dither on the nrm buffer. Dithers are
// not very efficient for short runs so only take
// if 8 or longer. Note that our check against
// numPels above for MinRunSize will be overrun here
// so we need to make sure we don't go over the
// end of the buffer.
/****************************************************/
if (((numPels - srcOffset) > 8) &&
(*(PUINT32_UA)(pSrc + srcOffset) ==
*(PUINT32_UA)(pSrc + srcOffset + 4))) {
RunDouble(pSrc + srcOffset + 6,
numPels - srcOffset - 6,
nextRunLength);
nextRunLength += 6;
CHECK_BEST_RUN(RUN_DITHER,
nextRunLength,
bestRunLength,
bestRunType);
}
}
}
/************************************************************/
// If nothing so far then look for a FGBG run.
/************************************************************/
if (bestRunLength < MinRunSize) {
// Check this is not a single FG bit breaking up a BG
// run. If so then encode a BG_PEL run. Careful of the
// enforced BG run break across the first line
// non-XOR/XOR boundary.
if (*(PUINT32_UA)(xorbuf + srcOffset + 1) != 0 ||
*(xorbuf + srcOffset) != fgPel ||
match[1].type != RUN_BG ||
srcOffset == rowDelta) {
// If we have not found a run then look for a FG/BG
// image. Bandwidth/CPU comparisons:
// chkFGBGLen* KBytes** Comp CPU ("hits")
// 48/16/8 54856 140178
// 32/16/8 53177 129343
// 24/8/8 53020 130583
// 16/8/8 52874 126454
// 8/8/0 52980 120565
// no check 59753 101091
// * = minimum run length for checking best:
// start val / subtract for workchar==fgPel /
// subtract for nextRunLen divisible by 8
// ** = KBytes server->client WinBench98 Graphics
// WinMark minus CorelDRAW, measured in NetMon
// on Ethernet.
RUNFGBG(xorbuf + srcOffset, numPels - srcOffset,
nextRunLength, fgPelWork);
if (fgPelWork == fgPel || nextRunLength >= 8) {
CHECK_BEST_RUN(IMAGE_FGBG,
nextRunLength,
bestRunLength,
bestRunType);
}
}
else {
RUNSINGLE(xorbuf + srcOffset + 1,
numPels - srcOffset - 1,
nextRunLength);
nextRunLength++;
CHECK_BEST_RUN(RUN_BG_PEL,
nextRunLength,
bestRunLength,
bestRunType);
}
}
/************************************************************/
/* If nothing useful so far then allow a short run. */
/* Don't do this if we are accumulating a color run because */
/* it will really mess up GDC compression if we allow lots */
/* of little runs. Also require that it is a regular short */
/* run, rather than one that disturbs the fgPel */
/************************************************************/
if (!inColorRun) {
if (bestRunLength < MinRunSize) {
if (bestFGRunLength >= MinRunSize &&
xorbuf[srcOffset] == fgPel) {
/************************************************/
/* We mustn't merge with the previous code */
/* if we have just crossed the non-XOR/XOR */
/* boundary. */
/************************************************/
if (match[1].type == RUN_FG &&
srcOffset != rowDelta) {
match[1].length += bestFGRunLength;
srcOffset += bestFGRunLength;
continue;
}
else {
bestRunLength = bestFGRunLength;
bestRunType = RUN_FG;
}
}
else {
/************************************************/
/* If we decided to take a run earlier then */
/* allow it now. (May be a short BG run, for */
/* example) If nothing so far then take color */
/* image) */
/************************************************/
if (bestRunLength == 0) {
bestRunType = IMAGE_COLOR;
bestRunLength = 1;
}
}
}
}
else {
// We're in a color run. Keep small runs of other types
// from breaking up the color run and increasing the
// encoded size.
if (bestRunLength < (unsigned)(bestRunType == RUN_BG ?
MinRunSize : (MinRunSize + 2))) {
bestRunType = IMAGE_COLOR;
bestRunLength = 1;
}
}
// Get out of the loop after all checks are completed.
break;
}
/****************************************************************/
/* When we get here we have found the best run. Now check for */
/* various amalgamation conditions with the previous run type. */
/* Note that we may already have done amalgamation of short */
/* runs, but we had to do multiple samples for the longer runs */
/* so we repeat the checks here */
/****************************************************************/
/****************************************************************/
// If we are encoding a color run then combine it with an
// existing run if possible.
/****************************************************************/
if (bestRunType != IMAGE_COLOR) {
/************************************************************/
/* We are no longer encoding a COLOR_IMAGE of any kind */
/************************************************************/
inColorRun = FALSE;
// If we can amalgamate the entry then do so without creating
// a new array entry. Our search for FGBG runs is dependent
// upon that type of run being amalgamated because we break
// every 64 characters so that our mode switch detection
// works OK.
//
// Take care not to merge across the non-xor/xor boundary.
if (srcOffset != rowDelta) {
// Bump srcOffset and try a merge.
srcOffset += bestRunLength;
switch (bestRunType) {
case RUN_BG:
// BG runs merge with BG and BG_PEL runs.
if (match[1].type == RUN_BG ||
match[1].type == RUN_BG_PEL) {
match[1].length += bestRunLength;
TRC_DBG((TB, "Merged BG with preceding, "
"giving %u", match[1].length));
continue;
}
// Deliberate fallthrough to BG_PEL.
case RUN_BG_PEL:
// If it is a BG run following a FGBG run then
// merge in the pels to make the FGBG length a
// multiple of 8. If the remaining BG run is <= 8
// (which would translate to one extra byte in
// the previous FGBG as well as one byte of BG),
// merge it in also, otherwise just write the
// shortened BG run. Note that for RUN_BG_PEL,
// FG color will be the same as for the
// FGBG, no need to check.
if (match[1].type == IMAGE_FGBG &&
match[1].length & 0x0007) {
unsigned mergelen = 8 - (match[1].length &
0x0007);
if (mergelen > bestRunLength)
mergelen = bestRunLength;
match[1].length += mergelen;
bestRunLength -= mergelen;
TRC_DBG((TB,"Add %u pels to FGBG giving %u "
"leaving %u",
mergelen, match[1].length,
bestRunLength));
if (bestRunLength <= 8) {
match[1].length += bestRunLength;
TRC_DBG((TB,"Merge BG with prev FGBG "
"gives %u", match[1].length));
continue;
}
}
break;
case RUN_FG:
// Keep track of the FG color. Remember to
// subtract bestRunLength since we incremented
// it before the switch statement.
fgPel = xorbuf[srcOffset - bestRunLength];
// FG run merges with previous FG if FG color is same.
if (match[1].type == RUN_FG &&
match[1].fgPel == fgPel) {
match[1].length += bestRunLength;
TRC_DBG((TB, "Merged FG with preceding, giving %u",
match[1].length));
continue;
}
break;
case IMAGE_FGBG:
// FGBG leaves the foreground character in
// fgPelWork.
fgPel = fgPelWork;
// FGBG merges with previous if the FG colors are
// the same.
if (match[1].type == IMAGE_FGBG &&
match[1].fgPel == fgPel) {
match[1].length += bestRunLength;
TRC_DBG((TB, "Merged FGBG with preceding "
"FGBG, giving %u", match[1].length));
continue;
}
// FGBG merges with with small BG runs.
if (match[1].type == RUN_BG &&
match[1].length < 8) {
match[1].type = IMAGE_FGBG;
match[1].length += bestRunLength;
match[1].fgPel = fgPel;
TRC_DBG((TB, "Merged FGBG with preceding "
"BG run -> %u", match[1].length));
continue;
}
break;
}
}
else {
// Keep track of the FG color. The macro that searches for
// FGBG runs leaves the character in fgPelWork.
// Note this code is inlined into the merging code
// before.
if (bestRunType == RUN_FG)
fgPel = xorbuf[srcOffset];
else if (bestRunType == IMAGE_FGBG)
fgPel = fgPelWork;
// We're at the end of the first line. Just bump the
// source offset.
srcOffset += bestRunLength;
}
}
else {
/************************************************************/
/* Flag that we are within a color run */
/************************************************************/
inColorRun = TRUE;
srcOffset += bestRunLength;
/************************************************************/
// Merge the color run immediately, if possible. Note color
// runs are not restricted by the non-XOR/XOR boundary.
/************************************************************/
if (match[1].type == IMAGE_COLOR) {
match[1].length += bestRunLength;
continue;
}
if (match[0].type == IMAGE_COLOR && match[1].length == 1) {
// If it is a color run spanning any kind of single pel
// entity then merge all three runs into one.
// We have to create a special match queue condition
// here -- the single merged entry needs to be placed
// in the match[1] position and a null entry into [0]
// to allow the rest of the code to continue to
// be hardcoded to merge with [1].
match[1].length = match[0].length +
bestRunLength + 1;
match[1].type = IMAGE_COLOR;
match[0].type = 0;
TRC_DBG((TB, "Merged color with preceding color gives %u",
match[1].length));
continue;
}
}
/****************************************************************/
// The current run could not be merged with a previous match
// queue entry, We have to encode the [0] slot then add the
// current run the the queue.
/****************************************************************/
TRC_DBG((TB, "Best run of type %u has length %u", bestRunType,
bestRunLength));
DoEncoding:
// First check for our approaching the end of the destination
// buffer and get out if this is the case. We allow for the
// largest general run order (a mega-mega set run = 4 bytes).
// Orders which may be larger are checked within the case arm
if ((unsigned)(destbuf - pDst + 4) <= dstBufferSize)
goto ContinueEncoding;
else
DC_QUIT;
ContinueEncoding:
switch (match[0].type) {
case 0:
// Unused entry.
break;
case RUN_BG:
case RUN_BG_PEL:
// Note that for BG_PEL we utilize the code sequence
// BG,BG which would not otherwise appear as a special
// case meaning insert one current FG char between
// the two runs.
ENCODE_ORDER_MEGA(destbuf,
CODE_BG_RUN,
match[0].length,
CODE_MEGA_MEGA_BG_RUN,
MAX_LENGTH_ORDER,
MAX_LENGTH_LONG_ORDER);
TRC_DBG((TB, "BG RUN %u",match[0].length));
EncodeSrcOffset += match[0].length;
break;
case RUN_FG:
// If the fg value is different from the current
// then encode a set+run code.
if (EncodeFGPel != match[0].fgPel) {
SETFGCHAR((BYTE)match[0].fgPel, EncodeFGPel, fgShift);
ENCODE_ORDER_MEGA(destbuf,
CODE_SET_FG_FG_RUN,
match[0].length,
CODE_MEGA_MEGA_SET_FG_RUN,
MAX_LENGTH_ORDER_LITE,
MAX_LENGTH_LONG_ORDER_LITE);
*destbuf++ = EncodeFGPel;
TRC_DBG((TB, "SET_FG_FG_RUN %u", match[0].length));
}
else {
ENCODE_ORDER_MEGA(destbuf,
CODE_FG_RUN,
match[0].length,
CODE_MEGA_MEGA_FG_RUN,
MAX_LENGTH_ORDER,
MAX_LENGTH_LONG_ORDER);
TRC_DBG((TB, "FG_RUN %u", match[0].length));
}
EncodeSrcOffset += match[0].length;
break;
case IMAGE_FGBG:
runLength = match[0].length;
// Check for our approaching the end of the destination
// buffer and get out if this is the case.
if ((destbuf - pDst + (runLength + 7)/8 + 4) <=
dstBufferSize)
goto ContinueFGBG;
else
DC_QUIT;
ContinueFGBG:
// We need to convert FGBG runs into the pixel form.
if (EncodeFGPel != match[0].fgPel) {
SETFGCHAR((BYTE)match[0].fgPel, EncodeFGPel, fgShift);
ENCODE_ORDER_MEGA_FGBG(destbuf,
CODE_SET_FG_FG_BG,
runLength,
CODE_MEGA_MEGA_SET_FGBG,
MAX_LENGTH_FGBG_ORDER_LITE,
MAX_LENGTH_LONG_FGBG_ORDER);
*destbuf++ = EncodeFGPel;
TRC_DBG((TB, "SET_FG_FG_BG %u", match[0].length));
while (runLength >= 8) {
ENCODEFGBG(*destbuf);
destbuf++;
EncodeSrcOffset += 8;
runLength -= 8;
}
if (runLength) {
ENCODEFGBG(*destbuf);
// Keep the final partial byte clean to help GDC
// packing.
*destbuf &= ((0x01 << runLength) - 1);
destbuf++;
EncodeSrcOffset += runLength;
}
}
else {
if (runLength == 8) {
BYTE fgbgChar;
// See if it is one of the high probability bytes.
ENCODEFGBG(fgbgChar);
// Check for single byte encoding of FGBG images.
switch (fgbgChar) {
case SPECIAL_FGBG_CODE_1:
*destbuf++ = CODE_SPECIAL_FGBG_1;
break;
case SPECIAL_FGBG_CODE_2:
*destbuf++ = CODE_SPECIAL_FGBG_2;
break;
default:
ENCODE_ORDER_MEGA_FGBG(destbuf,
CODE_FG_BG_IMAGE,
runLength,
CODE_MEGA_MEGA_FGBG,
MAX_LENGTH_FGBG_ORDER,
MAX_LENGTH_LONG_FGBG_ORDER);
*destbuf++ = fgbgChar;
break;
}
EncodeSrcOffset += 8;
}
else {
// Encode as standard FGBG.
ENCODE_ORDER_MEGA_FGBG(destbuf,
CODE_FG_BG_IMAGE,
runLength,
CODE_MEGA_MEGA_FGBG,
MAX_LENGTH_FGBG_ORDER,
MAX_LENGTH_LONG_FGBG_ORDER);
TRC_DBG((TB, "FG_BG %u", match[0].length));
while (runLength >= 8) {
ENCODEFGBG(*destbuf);
destbuf++;
EncodeSrcOffset += 8;
runLength -= 8;
}
if (runLength) {
ENCODEFGBG(*destbuf);
*destbuf &= ((0x01 << runLength) - 1);
destbuf++;
EncodeSrcOffset += runLength;
}
}
}
break;
case RUN_COLOR:
ENCODE_ORDER_MEGA(destbuf,
CODE_COLOR_RUN,
match[0].length,
CODE_MEGA_MEGA_COLOR_RUN,
MAX_LENGTH_ORDER,
MAX_LENGTH_LONG_ORDER);
TRC_DBG((TB, "COLOR_RUN %u", match[0].length));
*destbuf++ = pSrc[EncodeSrcOffset];
EncodeSrcOffset += match[0].length;
break;
case RUN_DITHER:
{
unsigned ditherlen = match[0].length / 2;
ENCODE_ORDER_MEGA(destbuf,
CODE_DITHERED_RUN,
ditherlen,
CODE_MEGA_MEGA_DITHER,
MAX_LENGTH_ORDER_LITE,
MAX_LENGTH_LONG_ORDER_LITE);
TRC_DBG((TB, "DITHERED_RUN %u", match[0].length));
// First check for our approaching the end of the
// destination buffer and get out if this is the case.
if ((unsigned)(destbuf - pDst + 2) <= dstBufferSize) {
*destbuf++ = pSrc[EncodeSrcOffset];
*destbuf++ = pSrc[EncodeSrcOffset + 1];
EncodeSrcOffset += match[0].length;
}
else {
DC_QUIT;
}
}
break;
case IMAGE_COLOR:
// Length 1 can possibly be encoded as a single BLACK/WHITE.
if (match[0].length == 1) {
if (pSrc[EncodeSrcOffset] == 0x00) {
*destbuf++ = CODE_BLACK;
EncodeSrcOffset++;
break;
}
if (pSrc[EncodeSrcOffset] == 0xFF) {
*destbuf++ = CODE_WHITE;
EncodeSrcOffset++;
break;
}
}
// Store the data in non-compressed form.
ENCODE_ORDER_MEGA(destbuf,
CODE_COLOR_IMAGE,
match[0].length,
CODE_MEGA_MEGA_CLR_IMG,
MAX_LENGTH_ORDER,
MAX_LENGTH_LONG_ORDER);
TRC_DBG((TB, "COLOR_IMAGE %u", match[0].length));
// First check for our approaching the end of the
// destination buffer and get out if this is the case.
if ((destbuf - pDst + (UINT_PTR)match[0].length) <=
dstBufferSize) {
// Now just copy the data over.
memcpy(destbuf, pSrc+EncodeSrcOffset, match[0].length);
destbuf += match[0].length;
EncodeSrcOffset += match[0].length;
}
else {
DC_QUIT;
}
break;
#ifdef DC_DEBUG
default:
TRC_ERR((TB, "Invalid run type %u",match[0].type));
break;
#endif
}
/****************************************************************/
// Done encoding, what we do next is determined by whether we're
// flushing the match queue after everything is scanned.
/****************************************************************/
match[0] = match[1];
if (!bEncodeAllMatches) {
// Push the current run into the top of the queue.
match[1].type = bestRunType;
match[1].length = bestRunLength;
match[1].fgPel = fgPel;
}
else {
// We need to check to see if we're really finished. Since
// our maximum queue depth is 2, if we're done then the only
// remaining entry has an encoding type of 0.
if (match[0].type == 0) {
goto PostScan;
}
else {
match[1].type = 0;
goto DoEncoding;
}
}
}
if (scanCount == 0) {
// If we have just done our scan of the first line then now do the
// rest of the buffer. Reset our saved pel count.
numPels = saveNumPels;
}
else {
// When we are done with the second pass (we've reached the end of
// the buffer) we have to force the remaining items in the match
// queue to be encoded. Yes this is similar to old BASIC
// code in using gotos, but we cannot place the encoding code into
// a function because of the number of params required, and
// we cannot duplicate it because it is too big. This code is
// some of the most used in the system so the cost is worth it.
bEncodeAllMatches = TRUE;
goto DoEncoding;
}
}
PostScan:
// Success, calculate the amount of space we used.
compressedLength = (unsigned)(destbuf - pDst);
DC_EXIT_POINT:
DC_END_FN();
return compressedLength;
}
#else
unsigned RDPCALL SHCLASS CompressV2Int(
PBYTE pSrc,
PBYTE pDst,
unsigned numPels,
unsigned rowDelta,
unsigned dstBufferSize,
BYTE *xorbuf)
{
unsigned srcOffset;
unsigned EncodeSrcOffset;
unsigned bestRunLength;
unsigned nextRunLength;
unsigned runLength;
unsigned bestFGRunLength;
unsigned scanCount;
unsigned saveNumPels;
BOOLEAN inColorRun = FALSE;
BOOLEAN bEncodeAllMatches;
BYTE bestRunType = 0;
BYTE fgChar = 0xFF;
BYTE fgCharWork = 0xFF;
BYTE fgShift = 0;
BYTE EncodeFGChar;
PBYTE destbuf = pDst;
unsigned compressedLength = 0;
MATCH match[2];
DC_BEGIN_FN("CompressV2Int");
/************************************************************************/
// Validate params.
/************************************************************************/
TRC_ASSERT((numPels >= rowDelta),(TB,"numPels < rowDelta"));
TRC_ASSERT((!(rowDelta & 0x3)),(TB,"rowDelta not multiple of 4"));
TRC_ASSERT((!(numPels & 0x3)),(TB,"numPels not multiple of 4"));
TRC_ASSERT((!((UINT_PTR)pSrc & 0x3)),
(TB, "Possible unaligned access, pSrc = %p", pSrc));
/************************************************************************/
// Create XOR buffer - first row is copied from src, succeeding rows
// are the corresponding src row XOR'd with the next src row.
/************************************************************************/
memcpy(xorbuf, pSrc, rowDelta);
{
BYTE *srcbuf = pSrc + rowDelta;
unsigned srclen = numPels - rowDelta;
UINT32 *dwdest = (UINT32 *)(xorbuf + rowDelta);
while (srclen >= 8) {
*dwdest++ = *((PUINT32)srcbuf) ^ *((PUINT32)(srcbuf -
(int)rowDelta));
srcbuf += 4;
*dwdest++ = *((PUINT32)srcbuf) ^ *((PUINT32)(srcbuf -
(int)rowDelta));
srcbuf += 4;
srclen -= 8;
}
if (srclen) {
// Since we're 4-byte aligned we can only have a single DWORD
// remaining.
*dwdest = *((PUINT32)srcbuf) ^ *((PUINT32)(srcbuf -
(int)rowDelta));
}
}
/************************************************************************/
// Set up encoding state variables.
/************************************************************************/
srcOffset = 0; // Offset in src buf where we are analyzing.
EncodeSrcOffset = 0; // Offset in src buf from where we are encoding.
EncodeFGChar = 0xFF; // Foreground color for encoding.
bEncodeAllMatches = FALSE; // Used to force encoding of all matches.
match[0].type = 0; // Initially no match types.
match[1].type = 0;
saveNumPels = numPels;
numPels = rowDelta;
/************************************************************************/
// Loop processing the input.
// We perform the loop twice, the first time for the non-XOR first line
// of the buffer and the second for the XOR portion, adjusting numPels
// to the needed value for each pass.
/************************************************************************/
for (scanCount = 0; ; scanCount++) {
while (srcOffset < numPels) {
/****************************************************************/
/* Start a while loop to allow a more structured break when we */
/* hit the first run type we want to encode (We can't afford */
/* the overheads of a function call to provide the scope here.) */
/****************************************************************/
while (TRUE) {
bestRunLength = 0;
bestFGRunLength = 0;
/************************************************************/
// If we are hitting the end of the buffer then just take
// color characters now. We will only hit this condition if
// we break out of a run just before the end of the buffer,
// so this should not be too common a situation, which is
// good given that we are encoding the final MinRunSize bytes
// uncompressed.
/************************************************************/
if ((srcOffset + MinRunSize) < numPels) {
goto ContinueScan;
}
else {
bestRunType = IMAGE_COLOR;
bestRunLength = numPels - srcOffset;
break;
}
ContinueScan:
/************************************************************/
// First do the scans on the XOR buffer. Look for a
// character run or a BG run.
// We must do the test independent of how long the run
// might be because even for a 1 pel BG run our later logic
// requires that we detect it seperately. This code is
// absolute main path so fastpath as much as possible. In
// particular detect short bg runs early and allow
// RunSingle to presuppose at least 4 matching bytes.
/************************************************************/
if (xorbuf[srcOffset] == 0x00) {
if ((srcOffset + 1) >= numPels ||
xorbuf[srcOffset + 1] != 0x00) {
bestRunType = RUN_BG;
bestRunLength = 1;
if (!inColorRun)
break;
}
else {
if ((srcOffset + 2) >= numPels ||
xorbuf[srcOffset + 2] != 0x00) {
bestRunType = RUN_BG;
bestRunLength = 2;
if (!inColorRun)
break;
}
else {
if ((srcOffset + 3) >= numPels ||
xorbuf[srcOffset + 3] != 0x00) {
bestRunType = RUN_BG;
bestRunLength = 3;
if (!inColorRun)
break;
}
else {
RUNSINGLE(xorbuf + srcOffset,
numPels - srcOffset,
bestFGRunLength);
CHECK_BEST_RUN(RUN_BG,
bestFGRunLength,
bestRunLength,
bestRunType);
if (!inColorRun)
break;
}
}
}
}
else {
/********************************************************/
// No point in starting if FG run less than 4 bytes so
// check the first dword as quickly as possible.
/********************************************************/
if (xorbuf[srcOffset] == xorbuf[srcOffset + 1] &&
*(PUINT16_UA)(xorbuf + srcOffset) ==
*(PUINT16_UA)(xorbuf + srcOffset + 2))
{
RUNSINGLE(xorbuf + srcOffset,
numPels - srcOffset,
bestFGRunLength);
/****************************************************/
// Don't permit a short FG run to prevent a FGBG
// image from starting up.
/****************************************************/
if (bestFGRunLength >= MinRunSize) {
CHECK_BEST_RUN(RUN_FG,
bestFGRunLength,
bestRunLength,
bestRunType);
}
}
}
/************************************************************/
// Look for solid or dithered sequences in the normal
// (non-XOR) buffer.
/************************************************************/
if ( (pSrc[srcOffset] == pSrc[srcOffset + 2]) &&
(pSrc[srcOffset + 1] == pSrc[srcOffset + 3])) {
/********************************************************/
// Now do the scan on the normal buffer for a character
// run. Don't bother if first line because we will have
// found it already in the XOR buffer, since we just
// copy pSrc to xorbuf for the first line. We insist on
// a run of at least MinRunSize pixels.
/********************************************************/
if (*(pSrc + srcOffset) == *(pSrc + srcOffset + 1)) {
if (srcOffset >= rowDelta) {
RUNSINGLE(pSrc + srcOffset,
numPels - srcOffset,
nextRunLength);
if (nextRunLength >= MinRunSize) {
CHECK_BEST_RUN(RUN_COLOR,
nextRunLength,
bestRunLength,
bestRunType);
}
}
}
else {
/****************************************************/
/* Look for a dither on the nrm buffer Dithers are */
/* not very efficient for short runs so only take */
/* if 8 or longer */
/****************************************************/
if (*(PUINT32_UA)(pSrc + srcOffset) ==
*(PUINT32_UA)(pSrc + srcOffset + 4)) {
RunDouble(pSrc + srcOffset + 6,
numPels - srcOffset - 6,
nextRunLength);
nextRunLength += 6;
CHECK_BEST_RUN(RUN_DITHER,
nextRunLength,
bestRunLength,
bestRunType);
}
}
}
/************************************************************/
// If nothing so far then look for a FGBG run.
/************************************************************/
if (bestRunLength < MinRunSize) {
// Check this is not a single FG bit breaking up a BG
// run. If so then encode a BG_PEL run. Careful of the
// enforced BG run break across the first line
// non-XOR/XOR boundary.
if (*(PUINT32_UA)(xorbuf + srcOffset + 1) != 0 ||
*(xorbuf + srcOffset) != fgChar ||
match[1].type != RUN_BG ||
srcOffset == rowDelta) {
// If we have not found a run then look for a FG/BG
// image. Bandwidth/CPU comparisons:
// chkFGBGLen* KBytes** Comp CPU ("hits")
// 48/16/8 54856 140178
// 32/16/8 53177 129343
// 24/8/8 53020 130583
// 16/8/8 52874 126454
// 8/8/0 52980 120565
// no check 59753 101091
// * = minimum run length for checking best:
// start val / subtract for workchar==fgChar /
// subtract for nextRunLen divisible by 8
// ** = KBytes server->client WinBench98 Graphics
// WinMark minus CorelDRAW, measured in NetMon
// on Ethernet.
RUNFGBG(xorbuf + srcOffset, numPels - srcOffset,
nextRunLength, fgCharWork);
if (fgCharWork == fgChar || nextRunLength >= 8) {
CHECK_BEST_RUN(IMAGE_FGBG,
nextRunLength,
bestRunLength,
bestRunType);
}
}
else {
RUNSINGLE(xorbuf + srcOffset + 1,
numPels - srcOffset - 1,
nextRunLength);
nextRunLength++;
CHECK_BEST_RUN(RUN_BG_PEL,
nextRunLength,
bestRunLength,
bestRunType);
}
}
/************************************************************/
/* If nothing useful so far then allow a short run. */
/* Don't do this if we are accumulating a color run because */
/* it will really mess up GDC compression if we allow lots */
/* of little runs. Also require that it is a regular short */
/* run, rather than one that disturbs the fgChar */
/************************************************************/
if (!inColorRun) {
if (bestRunLength < MinRunSize) {
if (bestFGRunLength >= MinRunSize &&
xorbuf[srcOffset] == fgChar) {
/************************************************/
/* We mustn't merge with the previous code */
/* if we have just crossed the non-XOR/XOR */
/* boundary. */
/************************************************/
if (match[1].type == RUN_FG &&
srcOffset != rowDelta) {
match[1].length += bestFGRunLength;
srcOffset += bestFGRunLength;
continue;
}
else {
bestRunLength = bestFGRunLength;
bestRunType = RUN_FG;
}
}
else {
/************************************************/
/* If we decided to take a run earlier then */
/* allow it now. (May be a short BG run, for */
/* example) If nothing so far then take color */
/* image) */
/************************************************/
if (bestRunLength == 0) {
bestRunType = IMAGE_COLOR;
bestRunLength = 1;
}
}
}
}
else {
// We're in a color run. Keep small runs of other types
// from breaking up the color run and increasing the
// encoded size.
if (bestRunLength < (unsigned)(bestRunType == RUN_BG ?
MinRunSize : (MinRunSize + 2))) {
bestRunType = IMAGE_COLOR;
bestRunLength = 1;
}
}
// Get out of the loop after all checks are completed.
break;
}
/****************************************************************/
/* When we get here we have found the best run. Now check for */
/* various amalgamation conditions with the previous run type. */
/* Note that we may already have done amalgamation of short */
/* runs, but we had to do multiple samples for the longer runs */
/* so we repeat the checks here */
/****************************************************************/
/****************************************************************/
// If we are encoding a color run then combine it with an
// existing run if possible.
/****************************************************************/
if (bestRunType != IMAGE_COLOR) {
/************************************************************/
/* We are no longer encoding a COLOR_IMAGE of any kind */
/************************************************************/
inColorRun = FALSE;
// If we can amalgamate the entry then do so without creating
// a new array entry. Our search for FGBG runs is dependent
// upon that type of run being amalgamated because we break
// every 64 characters so that our mode switch detection
// works OK.
//
// Take care not to merge across the non-xor/xor boundary.
if (srcOffset != rowDelta) {
// Bump srcOffset and try a merge.
srcOffset += bestRunLength;
switch (bestRunType) {
case RUN_BG:
// BG runs merge with BG and BG_PEL runs.
if (match[1].type == RUN_BG ||
match[1].type == RUN_BG_PEL) {
match[1].length += bestRunLength;
TRC_DBG((TB, "Merged BG with preceding, "
"giving %u", match[1].length));
continue;
}
// Deliberate fallthrough to BG_PEL.
case RUN_BG_PEL:
// If it is a BG run following a FGBG run then
// merge in the pels to make the FGBG length a
// multiple of 8. If the remaining BG run is <= 8
// (which would translate to one extra byte in
// the previous FGBG as well as one byte of BG),
// merge it in also, otherwise just write the
// shortened BG run. Note that for RUN_BG_PEL,
// FG color will be the same as for the
// FGBG, no need to check.
if (match[1].type == IMAGE_FGBG &&
match[1].length & 0x0007) {
unsigned mergelen = 8 - (match[1].length &
0x0007);
if (mergelen > bestRunLength)
mergelen = bestRunLength;
match[1].length += mergelen;
bestRunLength -= mergelen;
TRC_DBG((TB,"Add %u pels to FGBG giving %u "
"leaving %u",
mergelen, match[1].length,
bestRunLength));
if (bestRunLength <= 8) {
match[1].length += bestRunLength;
TRC_DBG((TB,"Merge BG with prev FGBG "
"gives %u", match[1].length));
continue;
}
}
break;
case RUN_FG:
// Keep track of the FG color. Remember to
// subtract bestRunLength since we incremented
// it before the switch statement.
fgChar = xorbuf[srcOffset - bestRunLength];
// FG run merges with previous FG if FG color is same.
if (match[1].type == RUN_FG &&
match[1].fgChar == fgChar) {
match[1].length += bestRunLength;
TRC_DBG((TB, "Merged FG with preceding, giving %u",
match[1].length));
continue;
}
break;
case IMAGE_FGBG:
// FGBG leaves the foreground character in
// fgCharWork.
fgChar = fgCharWork;
// FGBG merges with previous if the FG colors are
// the same.
if (match[1].type == IMAGE_FGBG &&
match[1].fgChar == fgChar) {
match[1].length += bestRunLength;
TRC_DBG((TB, "Merged FGBG with preceding "
"FGBG, giving %u", match[1].length));
continue;
}
// FGBG merges with with small BG runs.
if (match[1].type == RUN_BG &&
match[1].length < 8) {
match[1].type = IMAGE_FGBG;
match[1].length += bestRunLength;
match[1].fgChar = fgChar;
TRC_DBG((TB, "Merged FGBG with preceding "
"BG run -> %u", match[1].length));
continue;
}
break;
}
}
else {
// Keep track of the FG color. The macro that searches for
// FGBG runs leaves the character in fgCharWork.
// Note this code is inlined into the merging code
// before.
if (bestRunType == RUN_FG)
fgChar = xorbuf[srcOffset];
else if (bestRunType == IMAGE_FGBG)
fgChar = fgCharWork;
// We're at the end of the first line. Just bump the
// source offset.
srcOffset += bestRunLength;
}
}
else {
/************************************************************/
/* Flag that we are within a color run */
/************************************************************/
inColorRun = TRUE;
srcOffset += bestRunLength;
/************************************************************/
// Merge the color run immediately, if possible. Note color
// runs are not restricted by the non-XOR/XOR boundary.
/************************************************************/
if (match[1].type == IMAGE_COLOR) {
match[1].length += bestRunLength;
continue;
}
if (match[0].type == IMAGE_COLOR && match[1].length == 1) {
// If it is a color run spanning any kind of single pel
// entity then merge all three runs into one.
// We have to create a special match queue condition
// here -- the single merged entry needs to be placed
// in the match[1] position and a null entry into [0]
// to allow the rest of the code to continue to
// be hardcoded to merge with [1].
match[1].length = match[0].length +
bestRunLength + 1;
match[1].type = IMAGE_COLOR;
match[0].type = 0;
TRC_DBG((TB, "Merged color with preceding color gives %u",
match[1].length));
continue;
}
}
/****************************************************************/
// The current run could not be merged with a previous match
// queue entry, We have to encode the [0] slot then add the
// current run the the queue.
/****************************************************************/
TRC_DBG((TB, "Best run of type %u has length %u", bestRunType,
bestRunLength));
DoEncoding:
// First check for our approaching the end of the destination
// buffer and get out if this is the case. We allow for the
// largest general run order (a mega-mega set run = 4 bytes).
// Orders which may be larger are checked within the case arm
if ((unsigned)(destbuf - pDst + 4) <= dstBufferSize)
goto ContinueEncoding;
else
DC_QUIT;
ContinueEncoding:
switch (match[0].type) {
case 0:
// Unused entry.
break;
case RUN_BG:
case RUN_BG_PEL:
// Note that for BG_PEL we utilize the code sequence
// BG,BG which would not otherwise appear as a special
// case meaning insert one current FG char between
// the two runs.
ENCODE_ORDER_MEGA(destbuf,
CODE_BG_RUN,
match[0].length,
CODE_MEGA_MEGA_BG_RUN,
MAX_LENGTH_ORDER,
MAX_LENGTH_LONG_ORDER);
TRC_DBG((TB, "BG RUN %u",match[0].length));
EncodeSrcOffset += match[0].length;
break;
case RUN_FG:
// If the fg value is different from the current
// then encode a set+run code.
if (EncodeFGChar != match[0].fgChar) {
SETFGCHAR(match[0].fgChar, EncodeFGChar, fgShift);
ENCODE_ORDER_MEGA(destbuf,
CODE_SET_FG_FG_RUN,
match[0].length,
CODE_MEGA_MEGA_SET_FG_RUN,
MAX_LENGTH_ORDER_LITE,
MAX_LENGTH_LONG_ORDER_LITE);
*destbuf++ = EncodeFGChar;
TRC_DBG((TB, "SET_FG_FG_RUN %u", match[0].length));
}
else {
ENCODE_ORDER_MEGA(destbuf,
CODE_FG_RUN,
match[0].length,
CODE_MEGA_MEGA_FG_RUN,
MAX_LENGTH_ORDER,
MAX_LENGTH_LONG_ORDER);
TRC_DBG((TB, "FG_RUN %u", match[0].length));
}
EncodeSrcOffset += match[0].length;
break;
case IMAGE_FGBG:
runLength = match[0].length;
// Check for our approaching the end of the destination
// buffer and get out if this is the case.
if ((destbuf - pDst + (runLength + 7)/8 + 4) <=
dstBufferSize)
goto ContinueFGBG;
else
DC_QUIT;
ContinueFGBG:
// We need to convert FGBG runs into the pixel form.
if (EncodeFGChar != match[0].fgChar) {
SETFGCHAR(match[0].fgChar, EncodeFGChar, fgShift);
ENCODE_ORDER_MEGA_FGBG(destbuf,
CODE_SET_FG_FG_BG,
runLength,
CODE_MEGA_MEGA_SET_FGBG,
MAX_LENGTH_FGBG_ORDER_LITE,
MAX_LENGTH_LONG_FGBG_ORDER);
*destbuf++ = EncodeFGChar;
TRC_DBG((TB, "SET_FG_FG_BG %u", match[0].length));
while (runLength >= 8) {
ENCODEFGBG(*destbuf);
destbuf++;
EncodeSrcOffset += 8;
runLength -= 8;
}
if (runLength) {
ENCODEFGBG(*destbuf);
// Keep the final partial byte clean to help GDC
// packing.
*destbuf &= ((0x01 << runLength) - 1);
destbuf++;
EncodeSrcOffset += runLength;
}
}
else {
if (runLength == 8) {
BYTE fgbgChar;
// See if it is one of the high probability bytes.
ENCODEFGBG(fgbgChar);
// Check for single byte encoding of FGBG images.
switch (fgbgChar) {
case SPECIAL_FGBG_CODE_1:
*destbuf++ = CODE_SPECIAL_FGBG_1;
break;
case SPECIAL_FGBG_CODE_2:
*destbuf++ = CODE_SPECIAL_FGBG_2;
break;
default:
ENCODE_ORDER_MEGA_FGBG(destbuf,
CODE_FG_BG_IMAGE,
runLength,
CODE_MEGA_MEGA_FGBG,
MAX_LENGTH_FGBG_ORDER,
MAX_LENGTH_LONG_FGBG_ORDER);
*destbuf++ = fgbgChar;
break;
}
EncodeSrcOffset += 8;
}
else {
// Encode as standard FGBG.
ENCODE_ORDER_MEGA_FGBG(destbuf,
CODE_FG_BG_IMAGE,
runLength,
CODE_MEGA_MEGA_FGBG,
MAX_LENGTH_FGBG_ORDER,
MAX_LENGTH_LONG_FGBG_ORDER);
TRC_DBG((TB, "FG_BG %u", match[0].length));
while (runLength >= 8) {
ENCODEFGBG(*destbuf);
destbuf++;
EncodeSrcOffset += 8;
runLength -= 8;
}
if (runLength) {
ENCODEFGBG(*destbuf);
*destbuf &= ((0x01 << runLength) - 1);
destbuf++;
EncodeSrcOffset += runLength;
}
}
}
break;
case RUN_COLOR:
ENCODE_ORDER_MEGA(destbuf,
CODE_COLOR_RUN,
match[0].length,
CODE_MEGA_MEGA_COLOR_RUN,
MAX_LENGTH_ORDER,
MAX_LENGTH_LONG_ORDER);
TRC_DBG((TB, "COLOR_RUN %u", match[0].length));
*destbuf++ = pSrc[EncodeSrcOffset];
EncodeSrcOffset += match[0].length;
break;
case RUN_DITHER:
{
unsigned ditherlen = match[0].length / 2;
ENCODE_ORDER_MEGA(destbuf,
CODE_DITHERED_RUN,
ditherlen,
CODE_MEGA_MEGA_DITHER,
MAX_LENGTH_ORDER_LITE,
MAX_LENGTH_LONG_ORDER_LITE);
TRC_DBG((TB, "DITHERED_RUN %u", match[0].length));
// First check for our approaching the end of the
// destination buffer and get out if this is the case.
if ((unsigned)(destbuf - pDst + 2) <= dstBufferSize) {
*destbuf++ = pSrc[EncodeSrcOffset];
*destbuf++ = pSrc[EncodeSrcOffset + 1];
EncodeSrcOffset += match[0].length;
}
else {
DC_QUIT;
}
}
break;
case IMAGE_COLOR:
// Length 1 can possibly be encoded as a single BLACK/WHITE.
if (match[0].length == 1) {
if (pSrc[EncodeSrcOffset] == 0x00) {
*destbuf++ = CODE_BLACK;
EncodeSrcOffset++;
break;
}
if (pSrc[EncodeSrcOffset] == 0xFF) {
*destbuf++ = CODE_WHITE;
EncodeSrcOffset++;
break;
}
}
// Store the data in non-compressed form.
ENCODE_ORDER_MEGA(destbuf,
CODE_COLOR_IMAGE,
match[0].length,
CODE_MEGA_MEGA_CLR_IMG,
MAX_LENGTH_ORDER,
MAX_LENGTH_LONG_ORDER);
TRC_DBG((TB, "COLOR_IMAGE %u", match[0].length));
// First check for our approaching the end of the
// destination buffer and get out if this is the case.
if ((destbuf - pDst + (UINT_PTR)match[0].length) <=
dstBufferSize) {
// Now just copy the data over.
memcpy(destbuf, pSrc+EncodeSrcOffset, match[0].length);
destbuf += match[0].length;
EncodeSrcOffset += match[0].length;
}
else {
DC_QUIT;
}
break;
#ifdef DC_DEBUG
default:
TRC_ERR((TB, "Invalid run type %u",match[0].type));
break;
#endif
}
/****************************************************************/
// Done encoding, what we do next is determined by whether we're
// flushing the match queue after everything is scanned.
/****************************************************************/
match[0] = match[1];
if (!bEncodeAllMatches) {
// Push the current run into the top of the queue.
match[1].type = bestRunType;
match[1].length = bestRunLength;
match[1].fgChar = fgChar;
}
else {
// We need to check to see if we're really finished. Since
// our maximum queue depth is 2, if we're done then the only
// remaining entry has an encoding type of 0.
if (match[0].type == 0) {
goto PostScan;
}
else {
match[1].type = 0;
goto DoEncoding;
}
}
}
if (scanCount == 0) {
// If we have just done our scan of the first line then now do the
// rest of the buffer. Reset our saved pel count.
numPels = saveNumPels;
}
else {
// When we are done with the second pass (we've reached the end of
// the buffer) we have to force the remaining items in the match
// queue to be encoded. Yes this is similar to old BASIC
// code in using gotos, but we cannot place the encoding code into
// a function because of the number of params required, and
// we cannot duplicate it because it is too big. This code is
// some of the most used in the system so the cost is worth it.
bEncodeAllMatches = TRUE;
goto DoEncoding;
}
}
PostScan:
// Success, calculate the amount of space we used.
compressedLength = (unsigned)(destbuf - pDst);
DC_EXIT_POINT:
DC_END_FN();
return compressedLength;
}
#endif
#ifdef DC_HICOLOR
/****************************************************************************/
/* Hi res color compression functions */
/****************************************************************************/
/****************************************************************************/
/* 15bpp version of CompressV2Int */
/****************************************************************************/
unsigned RDPCALL SHCLASS CompressV2Int15(PBYTE pSrc,
PBYTE pDst,
unsigned numBytes,
unsigned rowDelta,
unsigned dstBufferSize,
BYTE * xorbuf,
MATCH * match)
{
/****************************************************************************/
/* Function name */
/****************************************************************************/
#define BC_FN_NAME "CompressV2Int15"
/****************************************************************************/
/* Data type of a pixel */
/****************************************************************************/
#define BC_PIXEL TSUINT16
/****************************************************************************/
/* Length in bytes of a pixel */
/****************************************************************************/
#define BC_PIXEL_LEN 2
/****************************************************************************/
/* Default fgPel */
/****************************************************************************/
#define BC_DEFAULT_FGPEL 0x0000FF7F
/****************************************************************************/
/* Macro to move to the next pixel in the buffer (modifies pPos) */
/****************************************************************************/
#define BC_TO_NEXT_PIXEL(pPos) pPos += 2
/****************************************************************************/
/* Macro to returns the value of the pixel at pPos (doesn't modify pPos) */
/****************************************************************************/
#define BC_GET_PIXEL(pPos) ((TSUINT16) ((((PTSUINT8)(pPos))[1]) & 0x7f) | \
(TSUINT16) (((((PTSUINT8)(pPos))[0])) << 8) )
/****************************************************************************/
/* Macro to insert a pixel value pel at position pPos (doesn't modify pPos) */
/* */
/* pel may well be an expression (e.g. a BC_GET_PIXEL macro) so evaluate */
/* it once into a local variable. */
/****************************************************************************/
#define BC_SET_PIXEL(pPos, pel) \
{ \
BC_PIXEL val = pel; \
(((PTSUINT8)(pPos))[1]) = (TSUINT8)( (val) & 0x007F); \
(((PTSUINT8)(pPos))[0]) = (TSUINT8)(((val) >> 8) & 0x00FF); \
}
/****************************************************************************/
/* Include the function body */
/****************************************************************************/
#include <abccom.c>
/****************************************************************************/
/* Undefine everything */
/****************************************************************************/
#undef BC_FN_NAME
#undef BC_PIXEL
#undef BC_PIXEL_LEN
#undef BC_TO_NEXT_PIXEL
#undef BC_GET_PIXEL
#undef BC_SET_PIXEL
#undef BC_DEFAULT_FGPEL
}
/****************************************************************************/
/* 16bpp version of CompressV2Int */
/****************************************************************************/
unsigned RDPCALL SHCLASS CompressV2Int16(PBYTE pSrc,
PBYTE pDst,
unsigned numBytes,
unsigned rowDelta,
unsigned dstBufferSize,
BYTE * xorbuf,
MATCH * match)
{
/****************************************************************************/
/* Function name */
/****************************************************************************/
#define BC_FN_NAME "CompressV2Int16"
/****************************************************************************/
/* Data type of a pixel */
/****************************************************************************/
#define BC_PIXEL TSUINT16
/****************************************************************************/
/* Length in bytes of a pixel */
/****************************************************************************/
#define BC_PIXEL_LEN 2
/****************************************************************************/
/* Default fgPel */
/****************************************************************************/
#define BC_DEFAULT_FGPEL 0x0000FFFF
/****************************************************************************/
/* Macro to move to the next pixel in the buffer (modifies pPos) */
/****************************************************************************/
#define BC_TO_NEXT_PIXEL(pPos) pPos += 2
/****************************************************************************/
/* Macro to returns the value of the pixel at pPos (doesn't modify pPos) */
/****************************************************************************/
#define BC_GET_PIXEL(pPos) ((TSUINT16) (((PTSUINT8)(pPos))[1]) | \
(TSUINT16) ((((PTSUINT8)(pPos))[0]) << 8) )
/****************************************************************************/
/* Macro to insert a pixel value pel at position pPos (doesn't modify pPos) */
/* */
/* pel may well be an expression (e.g. a BC_GET_PIXEL macro) so evaluate */
/* it once into a local variable. */
/****************************************************************************/
#define BC_SET_PIXEL(pPos, pel) \
{ \
BC_PIXEL val = pel; \
(((PTSUINT8)(pPos))[1]) = (TSUINT8)( (val) & 0x00FF); \
(((PTSUINT8)(pPos))[0]) = (TSUINT8)(((val)>>8) & 0x00FF); \
}
/****************************************************************************/
/* Include the function body */
/****************************************************************************/
#include <abccom.c>
/****************************************************************************/
/* Undefine everything */
/****************************************************************************/
#undef BC_FN_NAME
#undef BC_PIXEL
#undef BC_PIXEL_LEN
#undef BC_TO_NEXT_PIXEL
#undef BC_GET_PIXEL
#undef BC_SET_PIXEL
#undef BC_DEFAULT_FGPEL
}
/****************************************************************************/
/* 24bpp version of CompressV2Int */
/****************************************************************************/
unsigned RDPCALL SHCLASS CompressV2Int24(PBYTE pSrc,
PBYTE pDst,
unsigned numBytes,
unsigned rowDelta,
unsigned dstBufferSize,
BYTE * xorbuf,
MATCH * match)
{
/****************************************************************************/
/* Function name */
/****************************************************************************/
#define BC_FN_NAME "CompressV2Int24"
/****************************************************************************/
/* Data type of a pixel */
/****************************************************************************/
#define BC_PIXEL TSUINT32
/****************************************************************************/
/* Length in bytes of a pixel */
/****************************************************************************/
#define BC_PIXEL_LEN 3
/****************************************************************************/
/* Default fgPel */
/****************************************************************************/
#define BC_DEFAULT_FGPEL 0x00FFFFFF
/****************************************************************************/
/* Macro to move to the next pixel in the buffer (modifies pPos) */
/****************************************************************************/
#define BC_TO_NEXT_PIXEL(pPos) pPos += 3
/****************************************************************************/
/* Macro to returns the value of the pixel at pPos (doesn't modify pPos) */
/****************************************************************************/
#define BC_GET_PIXEL(pPos) ((TSUINT32) (((PTSUINT8)(pPos))[2]) | \
(TSUINT32) ((((PTSUINT8)(pPos))[1]) << 8) | \
(TSUINT32) ((((PTSUINT8)(pPos))[0]) << 16) )
/****************************************************************************/
/* Macro to insert a pixel value pel at position pPos (doesn't modify pPos) */
/* */
/* pel may well be an expression (e.g. a BC_GET_PIXEL macro) so evaluate */
/* it once into a local variable. */
/****************************************************************************/
#define BC_SET_PIXEL(pPos, pel) \
{ \
BC_PIXEL val = pel; \
(((PTSUINT8)(pPos))[2]) = (TSUINT8)((val) & 0x000000FF); \
(((PTSUINT8)(pPos))[1]) = (TSUINT8)(((val)>>8) & 0x000000FF); \
(((PTSUINT8)(pPos))[0]) = (TSUINT8)(((val)>>16) & 0x000000FF); \
}
/****************************************************************************/
/* Include the function body */
/****************************************************************************/
#include <abccom.c>
/****************************************************************************/
/* Undefine everything */
/****************************************************************************/
#undef BC_FN_NAME
#undef BC_PIXEL
#undef BC_PIXEL_LEN
#undef BC_TO_NEXT_PIXEL
#undef BC_GET_PIXEL
#undef BC_SET_PIXEL
#undef BC_DEFAULT_FGPEL
}
/****************************************************************************/
/* 32bpp version of CompressV2Int */
/****************************************************************************/
unsigned RDPCALL SHCLASS CompressV2Int32(PBYTE pSrc,
PBYTE pDst,
unsigned numBytes,
unsigned rowDelta,
unsigned dstBufferSize,
BYTE * xorbuf,
MATCH * match)
{
/****************************************************************************/
/* Function name */
/****************************************************************************/
#define BC_FN_NAME "CompressV2Int32"
/****************************************************************************/
/* Data type of a pixel */
/****************************************************************************/
#define BC_PIXEL TSUINT32
/****************************************************************************/
/* Length in bytes of a pixel */
/****************************************************************************/
#define BC_PIXEL_LEN 4
/****************************************************************************/
/* Default fgPel */
/****************************************************************************/
#define BC_DEFAULT_FGPEL 0xFFFFFFFF
/****************************************************************************/
/* Macro to move to the next pixel in the buffer (modifies pPos) */
/****************************************************************************/
#define BC_TO_NEXT_PIXEL(pPos) pPos += 4
/****************************************************************************/
/* Macro to returns the value of the pixel at pPos (doesn't modify pPos) */
/****************************************************************************/
#define BC_GET_PIXEL(pPos) ( \
(TSUINT32) ( (TSUINT16)(((PTSUINT8)(pPos))[3]) ) | \
(TSUINT32) (((TSUINT16)(((PTSUINT8)(pPos))[2])) << 8) | \
(TSUINT32) (((TSUINT32)(((PTSUINT8)(pPos))[1])) << 16) | \
(TSUINT32) (((TSUINT32)(((PTSUINT8)(pPos))[0])) << 24))
/****************************************************************************/
/* Macro to insert a pixel value pel at position pPos (doesn't modify pPos) */
/* */
/* pel may well be an expression (e.g. a BC_GET_PIXEL macro) so evaluate */
/* it once into a local variable. */
/****************************************************************************/
#define BC_SET_PIXEL(pPos, pel) \
{ \
BC_PIXEL val = pel; \
(((PTSUINT8)(pPos))[3]) = (TSUINT8)((val) & 0x000000FF); \
(((PTSUINT8)(pPos))[2]) = (TSUINT8)(((val)>>8) & 0x000000FF); \
(((PTSUINT8)(pPos))[1]) = (TSUINT8)(((val)>>16) & 0x000000FF); \
(((PTSUINT8)(pPos))[0]) = (TSUINT8)(((val)>>24) & 0x000000FF); \
}
/****************************************************************************/
/* Include the function body */
/****************************************************************************/
#include <abccom.c>
/****************************************************************************/
/* Undefine everything */
/****************************************************************************/
#undef BC_FN_NAME
#undef BC_PIXEL
#undef BC_PIXEL_LEN
#undef BC_TO_NEXT_PIXEL
#undef BC_GET_PIXEL
#undef BC_SET_PIXEL
#undef BC_DEFAULT_FGPEL
}
#endif /* DC_HICOLOR */
#ifdef DC_DEBUG
// compression testing
#include <abdapi.c>
#endif